Correct reference updates in error resilient mode Error resilient mode disables show_existing_frame, but it is still necessary to keep track of which frames would have originally been show_existing in order to properly update the gf_group index and reference buffers. BUG=aomedia:2021 BUG=aomedia:1994 Change-Id: Idc1f3038f313fd6c1efb90c992780a17a1423f8e
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index 2070755..dab5184 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c
@@ -2954,7 +2954,7 @@ assert(cm->frame_type == KEY_FRAME); } if (!seq_params->reduced_still_picture_hdr) { - if (cm->show_existing_frame) { + if (encode_show_existing_frame(cm)) { RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; const int frame_to_show = cm->ref_frame_map[cpi->existing_fb_idx_to_show]; @@ -3990,7 +3990,8 @@ data += obu_header_size + obu_payload_size + length_field_size; } - const int write_frame_header = (cm->num_tg > 1 || cm->show_existing_frame); + const int write_frame_header = + (cm->num_tg > 1 || encode_show_existing_frame(cm)); struct aom_write_bit_buffer saved_wb; if (write_frame_header) { // Write Frame Header OBU. @@ -4017,7 +4018,7 @@ saved_wb.bit_buffer += length_field_size; } - if (cm->show_existing_frame) { + if (encode_show_existing_frame(cm)) { data_size = 0; } else { // Each tile group obu will be preceded by 4-byte size of the tile group
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 849086a..f4af986 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -3424,6 +3424,21 @@ // for the purpose to verify no mismatch between encoder and decoder. if (cm->show_frame) cpi->last_show_frame_buf_idx = cm->new_fb_idx; + // In the case of show_existing frame, we will not send fresh flag + // to decoder. Any change in the reference frame buffer can be done by + // switching the virtual indices. + if (cm->show_existing_frame) { + cpi->refresh_last_frame = 0; + cpi->refresh_golden_frame = 0; + cpi->refresh_bwd_ref_frame = 0; + cpi->refresh_alt2_ref_frame = 0; + cpi->refresh_alt_ref_frame = 0; + + cpi->rc.is_bwd_ref_frame = 0; + cpi->rc.is_last_bipred_frame = 0; + cpi->rc.is_bipred_frame = 0; + } + #if USE_GF16_MULTI_LAYER if (cpi->rc.baseline_gf_interval == 16) { update_reference_frames_gf16(cpi); @@ -4914,7 +4929,7 @@ if (cm->current_video_frame > 0) cpi->ref_frame_flags = get_ref_frame_flags(cpi); - if (cm->show_existing_frame) { + if (encode_show_existing_frame(cm)) { // NOTE(zoeliu): In BIDIR_PRED, the existing frame to show is the current // BWDREF_FRAME in the reference frame buffer. if (cm->frame_type == KEY_FRAME) { @@ -4925,20 +4940,6 @@ cm->show_frame = 1; cpi->frame_flags = *frame_flags; - // In the case of show_existing frame, we will not send fresh flag - // to decoder. Any change in the reference frame buffer can be done by - // switching the virtual indices. - - cpi->refresh_last_frame = 0; - cpi->refresh_golden_frame = 0; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; - - cpi->rc.is_bwd_ref_frame = 0; - cpi->rc.is_last_bipred_frame = 0; - cpi->rc.is_bipred_frame = 0; - restore_coding_context(cpi); // Build the bitstream @@ -5320,11 +5321,17 @@ #endif // Do not do post-encoding update for those frames that do not have a spot - // in - // a gf group, but note that an OVERLAY frame always has a spot in a gf - // group, - // even when show_existing_frame is used. - if (!cpi->common.show_existing_frame || cpi->rc.is_src_frame_alt_ref) { + // in a gf group, but note that an OVERLAY frame always has a spot in a gf + // group, even when show_existing_frame is used. + // Error resilient frames cannot be true show_existing_frames, as this + // would require displaying a frame that was encoded in the past. + // In this case, any frame that would traditionally be a + // show_existing_frame will need to be re-encoded at display time, + // making it necessary to do this postencode_update. If error resilient mode + // is disabled, a show_existing_frame should never enter this function unless + // it was the source of an altref. + if (cpi->common.error_resilient_mode || !cpi->common.show_existing_frame || + cpi->rc.is_src_frame_alt_ref) { av1_twopass_postencode_update(cpi); } check_show_existing_frame(cpi); @@ -5850,16 +5857,15 @@ struct lookahead_entry *lookahead_src = NULL; if (cm->current_video_frame > 0) lookahead_src = av1_lookahead_peek(cpi->lookahead, 0); - if (lookahead_src != NULL && - ((cpi->oxcf.error_resilient_mode | - ((lookahead_src->flags & AOM_EFLAG_ERROR_RESILIENT) != 0)) || - (cpi->oxcf.s_frame_mode | - ((lookahead_src->flags & AOM_EFLAG_SET_S_FRAME) != 0))) && - !(rc->frames_to_key == 0 || (cpi->frame_flags & FRAMEFLAGS_KEY))) { - cm->show_existing_frame = 0; - } + int use_show_existing = + !(lookahead_src != NULL && + ((cpi->oxcf.error_resilient_mode | + ((lookahead_src->flags & AOM_EFLAG_ERROR_RESILIENT) != 0)) || + (cpi->oxcf.s_frame_mode | + ((lookahead_src->flags & AOM_EFLAG_SET_S_FRAME) != 0))) && + !(rc->frames_to_key == 0 || (cpi->frame_flags & FRAMEFLAGS_KEY))); - if (oxcf->pass == 2 && cm->show_existing_frame) { + if (oxcf->pass == 2 && cm->show_existing_frame && use_show_existing) { // Manage the source buffer and flush out the source frame that has been // coded already; Also get prepared for PSNR calculation if needed. if ((source = av1_lookahead_pop(cpi->lookahead, flush)) == NULL) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index 6cb531c..86101b1 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -887,6 +887,14 @@ return !av1_superres_scaled(cm) && av1_resize_scaled(cm); } +// Don't allow a show_existing_frame to coincide with an error resilient +// frame. An exception can be made for a forward keyframe since it has no +// previous dependencies. +static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) { + return cm->show_existing_frame && + (!cm->error_resilient_mode || cm->frame_type == KEY_FRAME); +} + #ifdef __cplusplus } // extern "C" #endif
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c index fdba252..f73aebe 100644 --- a/av1/encoder/firstpass.c +++ b/av1/encoder/firstpass.c
@@ -4025,6 +4025,9 @@ RATE_CONTROL *const rc = &cpi->rc; const int bits_used = rc->base_frame_target; + assert(IMPLIES(cpi->common.show_existing_frame && !rc->is_src_frame_alt_ref, + cpi->common.error_resilient_mode)); + // VBR correction is done through rc->vbr_bits_off_target. Based on the // sign of this value, a limited % adjustment is made to the target rate // of subsequent frames, to try and push it back towards 0. This method @@ -4048,8 +4051,12 @@ } twopass->kf_group_bits = AOMMAX(twopass->kf_group_bits, 0); - // Increment the gf group index ready for the next frame. - ++twopass->gf_group.index; + // Increment the gf group index ready for the next frame. If this is + // a show_existing_frame with a source other than altref, the index + // was incremented when it was originally encoded. + if (!cpi->common.show_existing_frame || rc->is_src_frame_alt_ref) { + ++twopass->gf_group.index; + } // If the rate control is drifting consider adjustment to min or maxq. if ((cpi->oxcf.rc_mode != AOM_Q) &&