Enable TMVP with B-frames

This commit is contained in:
Marko Viitanen 2016-09-30 14:59:47 +03:00
parent 363b8b49a2
commit e538a94eda
3 changed files with 52 additions and 29 deletions

View file

@ -955,10 +955,6 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
cfg->lossless = (bool)atobool(value);
else if OPT("tmvp") {
cfg->tmvp_enable = atobool(value);
if (cfg->gop_len && cfg->tmvp_enable) {
fprintf(stderr, "Cannot enable TMVP because GOP is used.\n");
cfg->tmvp_enable = false;
}
if (cfg->tiles_width_count > 1 || cfg->tiles_height_count > 1) {
fprintf(stderr, "Cannot enable TMVP because tiles are used.\n");
cfg->tmvp_enable = false;

View file

@ -460,7 +460,7 @@ static void encoder_state_write_bitstream_pic_parameter_set(bitstream_t* stream,
WRITE_U(stream, 1, 1, "cu_qp_delta_enabled_flag");
WRITE_UE(stream, 0, "diff_cu_qp_delta_depth");
} else {
WRITE_U(stream, 0, 1, "cu_qp_delta_enabled_flag");
WRITE_U(stream, 0, 1, "cu_qp_delta_enabled_flag");
}
//TODO: add QP offsets
@ -704,10 +704,10 @@ static void kvz_encoder_state_write_bitstream_slice_header_independent(
int last_poc = 0;
int poc_shift = 0;
WRITE_U(stream, state->frame->poc&0x1f, 5, "pic_order_cnt_lsb");
WRITE_U(stream, 0, 1, "short_term_ref_pic_set_sps_flag");
WRITE_UE(stream, ref_negative, "num_negative_pics");
WRITE_UE(stream, ref_positive, "num_positive_pics");
WRITE_U(stream, state->frame->poc&0x1f, 5, "pic_order_cnt_lsb");
WRITE_U(stream, 0, 1, "short_term_ref_pic_set_sps_flag");
WRITE_UE(stream, ref_negative, "num_negative_pics");
WRITE_UE(stream, ref_positive, "num_positive_pics");
for (j = 0; j < ref_negative; j++) {
int8_t delta_poc = 0;
@ -777,18 +777,27 @@ static void kvz_encoder_state_write_bitstream_slice_header_independent(
WRITE_U(stream, 1, 1, "slice_sao_chroma_flag");
}
}
if (state->frame->slicetype != KVZ_SLICE_I) {
WRITE_U(stream, 1, 1, "num_ref_idx_active_override_flag");
WRITE_UE(stream, ref_negative != 0 ? ref_negative - 1: 0, "num_ref_idx_l0_active_minus1");
if (state->frame->slicetype == KVZ_SLICE_B) {
WRITE_UE(stream, ref_positive != 0 ? ref_positive - 1 : 0, "num_ref_idx_l1_active_minus1");
WRITE_U(stream, 0, 1, "mvd_l1_zero_flag");
}
// Temporal Motion Vector Prediction flags
if (state->encoder_control->cfg->tmvp_enable && ref_negative > 1) {
if (state->frame->slicetype == KVZ_SLICE_B) {
WRITE_UE(stream, ref_positive != 0 ? ref_positive - 1 : 0, "num_ref_idx_l1_active_minus1");
WRITE_U(stream, 0, 1, "mvd_l1_zero_flag");
// Always use L0 for prediction
WRITE_U(stream, 1, 1, "collocated_from_l0_flag");
}
// ToDo: handle B-frames with TMVP
if (state->encoder_control->cfg.tmvp_enable && ref_negative > 1) {
WRITE_UE(stream, 0, "collocated_ref_idx");
if (ref_negative > 1) {
// Use first reference from L0
// ToDo: use better reference
WRITE_UE(stream, 0, "collocated_ref_idx");
}
}
WRITE_UE(stream, 5-MRG_MAX_NUM_CANDS, "five_minus_max_num_merge_cand");
@ -852,7 +861,7 @@ void kvz_encoder_state_write_bitstream_slice_header(
if (state->is_leaf) {
num_entry_points = 1;
} else {
encoder_state_entry_points_explore(state, &num_entry_points, &max_length_seen);
encoder_state_entry_points_explore(state, &num_entry_points, &max_length_seen);
}
int num_offsets = num_entry_points - 1;
@ -1031,7 +1040,7 @@ static void encoder_state_write_bitstream_main(encoder_state_t * const state)
}
state->frame->total_bits_coded += newpos - curpos;
state->frame->cur_gop_bits_coded = state->previous_encoder_state->frame->cur_gop_bits_coded;
state->frame->cur_gop_bits_coded = state->previous_encoder_state->frame->cur_gop_bits_coded;
state->frame->cur_gop_bits_coded += newpos - curpos;
}

View file

@ -679,7 +679,7 @@ static void kvz_inter_get_temporal_merge_candidates(const encoder_state_t * cons
for (int temporal_cand = 0; temporal_cand < state->frame->ref->used_size; temporal_cand++) {
int td = state->frame->poc - state->frame->ref->pocs[temporal_cand];
td = td < 0 ? -td : td;
td = td < 0 ? UINT_MAX : td;
if (td < poc_diff) {
closest_ref = temporal_cand;
poc_diff = td;
@ -1088,12 +1088,12 @@ static void get_mv_cand_from_spatial(const encoder_state_t * const state,
if (state->encoder_control->cfg.tmvp_enable) {
/*
Predictor block locations
_________
__________
|CurrentPU|
| |C0|__ |
| |C3| |
|_________|_
|H|
|H|
*/
// Find temporal reference, closest POC
@ -1102,7 +1102,7 @@ static void get_mv_cand_from_spatial(const encoder_state_t * const state,
for (int temporal_cand = 0; temporal_cand < state->frame->ref->used_size; temporal_cand++) {
int td = state->frame->poc - state->frame->ref->pocs[temporal_cand];
td = td < 0 ? -td : td;
td = td < 0 ? UINT_MAX : td;
if (td < poc_diff) {
poc_diff = td;
}
@ -1113,6 +1113,10 @@ static void get_mv_cand_from_spatial(const encoder_state_t * const state,
if (selected_CU) {
int td = selected_CU->inter.mv_ref[reflist] + 1;
int tb = cur_cu->inter.mv_ref[reflist] + 1;
// If the selected CU does not have the correct list (L0/L1) vector, use the other
if (!selected_CU->inter.mv_dir & (1 << reflist)) {
td = selected_CU->inter.mv_ref[reflist2nd] + 1;
}
int scale = CALCULATE_SCALE(NULL, tb, td);
mv_cand[candidates][0] = ((scale * selected_CU->inter.mv[0][0] + 127 + (scale * selected_CU->inter.mv[0][0] < 0)) >> 8);
@ -1330,18 +1334,32 @@ uint8_t kvz_inter_get_merge_cand(const encoder_state_t * const state,
const cu_info_t *selected_CU = (h != NULL) ? h : (c3 != NULL) ? c3 : NULL;
if (selected_CU) {
uint32_t poc_diff = UINT_MAX;
for (int temporal_cand = 0; temporal_cand < state->frame->ref->used_size; temporal_cand++) {
int td = state->frame->poc - state->frame->ref->pocs[temporal_cand];
td = td < 0 ? UINT_MAX : td;
if (td < poc_diff) {
poc_diff = td;
}
}
int td = selected_CU->inter.mv_ref[0] + 1;
int tb = 1;
int tb = poc_diff;
int scale = CALCULATE_SCALE(NULL, tb, td);
mv_cand[candidates].mv[0][0] = ((scale * selected_CU->inter.mv[0][0] + 127 + (scale * selected_CU->inter.mv[0][0] < 0)) >> 8);
mv_cand[candidates].mv[0][1] = ((scale * selected_CU->inter.mv[0][1] + 127 + (scale * selected_CU->inter.mv[0][1] < 0)) >> 8);
/*
ToDo: temporal prediction in B-pictures
mv_cand[candidates].mv[1][0] = selected_CU->inter.mv[1][0];
mv_cand[candidates].mv[1][1] = selected_CU->inter.mv[1][1];
*/
// L0 list
if (selected_CU->inter.mv_dir & 0x1) {
mv_cand[candidates].mv[0][0] = ((scale * selected_CU->inter.mv[0][0] + 127 + (scale * selected_CU->inter.mv[0][0] < 0)) >> 8);
mv_cand[candidates].mv[0][1] = ((scale * selected_CU->inter.mv[0][1] + 127 + (scale * selected_CU->inter.mv[0][1] < 0)) >> 8);
}
// L1 list
if (selected_CU->inter.mv_dir & 0x2) {
mv_cand[candidates].mv[1][0] = ((scale * selected_CU->inter.mv[1][0] + 127 + (scale * selected_CU->inter.mv[1][0] < 0)) >> 8);
mv_cand[candidates].mv[1][1] = ((scale * selected_CU->inter.mv[1][1] + 127 + (scale * selected_CU->inter.mv[1][1] < 0)) >> 8);
}
mv_cand[candidates].dir = selected_CU->inter.mv_dir;
mv_cand[candidates].ref[0] = 0;
candidates++;