Move substream finalization to LCU coding job

Having some of the termination bits in the LCU coding and some in the
substream finalization was needlessly confusing. Doing substream
finalization directly after LCU coding makes it easy to verify that the
finalization is done correctly.

Removes one job per WPP row from the job queue.

Removes kvz_cabac_flush, because I don't like bits being put into the
bitstream implicitly. Better to have it all in the open.
This commit is contained in:
Ari Koivula 2017-01-31 12:56:04 +02:00
parent ead490b7b7
commit 04cd875b2c
5 changed files with 46 additions and 71 deletions

View file

@ -210,17 +210,6 @@ void kvz_cabac_encode_bin_trm(cabac_data_t * const data, const uint8_t bin_value
} }
} }
/**
* \brief
*/
void kvz_cabac_flush(cabac_data_t * const data)
{
kvz_cabac_finish(data);
kvz_bitstream_put(data->stream, 1, 1);
kvz_bitstream_align_zero(data->stream);
kvz_cabac_start(data);
}
/** /**
* \brief * \brief
*/ */

View file

@ -103,7 +103,6 @@ void kvz_cabac_encode_bins_ep(cabac_data_t *data, uint32_t bin_values, int num_b
void kvz_cabac_encode_bin_trm(cabac_data_t *data, uint8_t bin_value); void kvz_cabac_encode_bin_trm(cabac_data_t *data, uint8_t bin_value);
void kvz_cabac_write(cabac_data_t *data); void kvz_cabac_write(cabac_data_t *data);
void kvz_cabac_finish(cabac_data_t *data); void kvz_cabac_finish(cabac_data_t *data);
void kvz_cabac_flush(cabac_data_t *data);
void kvz_cabac_write_coeff_remain(cabac_data_t *cabac, uint32_t symbol, void kvz_cabac_write_coeff_remain(cabac_data_t *cabac, uint32_t symbol,
uint32_t r_param); uint32_t r_param);
void kvz_cabac_write_coeff_remain_encry(struct encoder_state_t * const state, cabac_data_t * const cabac, const uint32_t symbol, void kvz_cabac_write_coeff_remain_encry(struct encoder_state_t * const state, cabac_data_t * const cabac, const uint32_t symbol,

View file

@ -976,36 +976,6 @@ static void encoder_state_write_bitstream_main(encoder_state_t * const state)
state->frame->cur_gop_bits_coded += newpos - curpos; state->frame->cur_gop_bits_coded += newpos - curpos;
} }
void kvz_encoder_state_write_bitstream_leaf(encoder_state_t * const state)
{
const encoder_control_t * const encoder = state->encoder_control;
//Write terminator of the leaf
assert(state->is_leaf);
//Last LCU
{
const lcu_order_element_t * const lcu = &state->lcu_order[state->lcu_order_count - 1];
const int lcu_addr_in_ts = lcu->id + state->tile->lcu_offset_in_ts;
const int end_of_slice_segment_flag = kvz_lcu_at_slice_end(encoder, lcu_addr_in_ts);
kvz_cabac_encode_bin_trm(&state->cabac, end_of_slice_segment_flag); // end_of_slice_segment_flag
if (!end_of_slice_segment_flag) {
assert(kvz_lcu_at_tile_end(encoder, lcu_addr_in_ts) || lcu->position.x == (state->tile->frame->width_in_lcu - 1));
kvz_cabac_encode_bin_trm(&state->cabac, 1); // end_of_sub_stream_one_bit == 1
kvz_cabac_flush(&state->cabac);
} else {
kvz_cabac_flush(&state->cabac);
kvz_bitstream_align_zero(&state->stream);
}
}
}
void kvz_encoder_state_worker_write_bitstream_leaf(void * opaque)
{
kvz_encoder_state_write_bitstream_leaf((encoder_state_t *) opaque);
}
static void encoder_state_write_bitstream_tile(encoder_state_t * const state) static void encoder_state_write_bitstream_tile(encoder_state_t * const state)
{ {
encoder_state_write_bitstream_children(state); encoder_state_write_bitstream_children(state);

View file

@ -38,7 +38,6 @@ struct bitstream_t;
void kvz_encoder_state_write_bitstream_slice_header(struct encoder_state_t * const state); void kvz_encoder_state_write_bitstream_slice_header(struct encoder_state_t * const state);
void kvz_encoder_state_write_bitstream(struct encoder_state_t * const state); void kvz_encoder_state_write_bitstream(struct encoder_state_t * const state);
void kvz_encoder_state_write_bitstream_leaf(struct encoder_state_t * const state); void kvz_encoder_state_write_bitstream_leaf(struct encoder_state_t * const state);
void kvz_encoder_state_worker_write_bitstream_leaf(void * opaque);
void kvz_encoder_state_worker_write_bitstream(void * opaque); void kvz_encoder_state_worker_write_bitstream(void * opaque);
void kvz_encoder_state_write_parameter_sets(struct bitstream_t *stream, void kvz_encoder_state_write_parameter_sets(struct bitstream_t *stream,
struct encoder_state_t * const state); struct encoder_state_t * const state);

View file

@ -336,11 +336,37 @@ static void encoder_state_worker_encode_lcu(void * opaque)
//Encode coding tree //Encode coding tree
kvz_encode_coding_tree(state, lcu->position.x << MAX_DEPTH, lcu->position.y << MAX_DEPTH, 0); kvz_encode_coding_tree(state, lcu->position.x << MAX_DEPTH, lcu->position.y << MAX_DEPTH, 0);
//Terminator bool end_of_slice_segment_flag;
if (lcu->index < state->lcu_order_count - 1) { {
//Since we don't handle slice segments, end of slice segment == end of slice // Slice ends after the last row of the last tile.
//Always 0 since otherwise it would be split int last_tile_id = -1 + encoder->tiles_num_tile_columns * encoder->tiles_num_tile_rows;
kvz_cabac_encode_bin_trm(&state->cabac, 0); // end_of_slice_segment_flag bool is_last_tile = state->tile->id == last_tile_id;
end_of_slice_segment_flag = is_last_tile && lcu->last_column && lcu->last_row;
}
kvz_cabac_encode_bin_trm(&state->cabac, end_of_slice_segment_flag);
{
const bool end_of_tile = lcu->last_column && lcu->last_row;
const bool end_of_wpp_row = encoder->cfg->wpp && lcu->last_column;
if (end_of_tile || end_of_wpp_row) {
if (!end_of_slice_segment_flag) {
// end_of_sub_stream_one_bit
kvz_cabac_encode_bin_trm(&state->cabac, 1);
}
// Finish the substream by writing out remaining state.
kvz_cabac_finish(&state->cabac);
// Write a rbsp_trailing_bits or a byte_alignment. The first one is used
// for ending a slice_segment_layer_rbsp and the second one for ending
// a substream. They are identical and align the byte stream.
kvz_bitstream_put(state->cabac.stream, 1, 1);
kvz_bitstream_align_zero(state->cabac.stream);
kvz_cabac_start(&state->cabac);
}
} }
const uint32_t bits = kvz_bitstream_tell(&state->stream) - existing_bits; const uint32_t bits = kvz_bitstream_tell(&state->stream) - existing_bits;
@ -503,31 +529,23 @@ static void encoder_state_encode_leaf(encoder_state_t * const state) {
static void encoder_state_encode(encoder_state_t * const main_state); static void encoder_state_encode(encoder_state_t * const main_state);
static void encoder_state_worker_encode_children(void * opaque) { static void encoder_state_worker_encode_children(void * opaque)
{
encoder_state_t *sub_state = opaque; encoder_state_t *sub_state = opaque;
encoder_state_encode(sub_state); encoder_state_encode(sub_state);
if (sub_state->is_leaf) {
if (sub_state->type != ENCODER_STATE_TYPE_WAVEFRONT_ROW) { if (sub_state->type == ENCODER_STATE_TYPE_WAVEFRONT_ROW) {
PERFORMANCE_MEASURE_START(KVZ_PERF_BSLEAF); // Set the last wavefront job of this row as the job that completes
kvz_encoder_state_write_bitstream_leaf(sub_state); // the bitstream for this wavefront row state.
PERFORMANCE_MEASURE_END(KVZ_PERF_BSLEAF, sub_state->encoder_control->threadqueue, "type=encoder_state_write_bitstream_leaf,frame=%d,tile=%d,slice=%d,px_x=%d-%d,px_y=%d-%d", sub_state->frame->num, sub_state->tile->id, sub_state->slice->id, sub_state->lcu_order[0].position_px.x + sub_state->tile->lcu_offset_x * LCU_WIDTH, sub_state->lcu_order[sub_state->lcu_order_count - 1].position_px.x + sub_state->lcu_order[sub_state->lcu_order_count - 1].size.x + sub_state->tile->lcu_offset_x * LCU_WIDTH - 1, sub_state->lcu_order[0].position_px.y + sub_state->tile->lcu_offset_y * LCU_WIDTH, sub_state->lcu_order[sub_state->lcu_order_count - 1].position_px.y + sub_state->lcu_order[sub_state->lcu_order_count - 1].size.y + sub_state->tile->lcu_offset_y * LCU_WIDTH - 1);
} else { int wpp_row = sub_state->wfrow->lcu_offset_y;
threadqueue_job_t *job; int tile_width = sub_state->tile->frame->width_in_lcu;
#ifdef KVZ_DEBUG int end_of_row = (wpp_row + 1) * tile_width - 1;
char job_description[256]; threadqueue_job_t *job = sub_state->tile->wf_jobs[end_of_row];
sprintf(job_description, "type=encoder_state_write_bitstream_leaf,frame=%d,tile=%d,slice=%d,px_x=%d-%d,px_y=%d-%d", sub_state->frame->num, sub_state->tile->id, sub_state->slice->id, sub_state->lcu_order[0].position_px.x + sub_state->tile->lcu_offset_x * LCU_WIDTH, sub_state->lcu_order[sub_state->lcu_order_count-1].position_px.x + sub_state->lcu_order[sub_state->lcu_order_count-1].size.x + sub_state->tile->lcu_offset_x * LCU_WIDTH - 1, sub_state->lcu_order[0].position_px.y + sub_state->tile->lcu_offset_y * LCU_WIDTH, sub_state->lcu_order[sub_state->lcu_order_count-1].position_px.y + sub_state->lcu_order[sub_state->lcu_order_count-1].size.y + sub_state->tile->lcu_offset_y * LCU_WIDTH - 1);
#else assert(!sub_state->tqj_bitstream_written);
char* job_description = NULL; sub_state->tqj_bitstream_written = job;
#endif return;
job = kvz_threadqueue_submit(sub_state->encoder_control->threadqueue, kvz_encoder_state_worker_write_bitstream_leaf, sub_state, 1, job_description);
kvz_threadqueue_job_dep_add(job, sub_state->tile->wf_jobs[sub_state->wfrow->lcu_offset_y * sub_state->tile->frame->width_in_lcu + sub_state->lcu_order_count - 1]);
kvz_threadqueue_job_unwait_job(sub_state->encoder_control->threadqueue, job);
assert(!sub_state->tqj_bitstream_written);
//Bitstream is written for the row, if we're at the last LCU
sub_state->tqj_bitstream_written = job;
return;
}
} }
} }