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) &&