Refactor refresh_frame_flags/refresh_frame_mask
* Introduce a new finalize_encoded_frame() function which is called
after encoding a frame but before packing the bitstream. This will
take care of a few things which are currently inside
av1_pack_bitstream but aren't anything to do with actually writing out
the bitstream.
* Move get_refresh_mask() from bitstream.c to encoder.c, rename it to
get_refresh_frame_flags(), call it from finalize_encoded_frame()
instead of write_uncompressed_header().
* Merge cpi->refresh_frame_mask in the encoder and
pbi->refresh_frame_flags in the decoder to the common variable
cm->current_frame.refresh_frame_flags
* Clean-up get_refresh_frame_flags()
* Clean-up some of write_uncompressed_header()
This forms part of wider restructuring and refactoring in order to
achieve a clean API separation at the entry to the low-level encoder.
BUG=aomedia:2244
Change-Id: I0e3a12fa3cfa986164512a41e7aeaf3130929e65
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index d3ed571..227a0f6 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -908,7 +908,8 @@
AVxWorker *const worker = ctx->frame_workers;
FrameWorkerData *const frame_worker_data =
(FrameWorkerData *)worker->data1;
- *update_info = frame_worker_data->pbi->refresh_frame_flags;
+ *update_info =
+ frame_worker_data->pbi->common.current_frame.refresh_frame_flags;
return AOM_CODEC_OK;
} else {
return AOM_CODEC_ERROR;
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 8773a49..c114148 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -315,6 +315,7 @@
unsigned int order_hint;
unsigned int frame_number;
SkipModeInfo skip_mode_info;
+ int refresh_frame_flags; // Which ref frames are overwritten by this frame
} CurrentFrame;
typedef struct AV1Common {
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 802c2eb..cb9cad8 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -4696,7 +4696,7 @@
// frame buffer index in cm->next_ref_frame_map, we need to increase the
// frame buffer's ref_count.
int ref_index = 0;
- for (int mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
+ for (int mask = cm->current_frame.refresh_frame_flags; mask; mask >>= 1) {
if (mask & 1) {
cm->next_ref_frame_map[ref_index] = cm->cur_frame;
} else {
@@ -4724,7 +4724,7 @@
cm->current_frame.frame_type = KEY_FRAME;
- pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1;
+ cm->current_frame.refresh_frame_flags = (1 << REF_FRAMES) - 1;
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
cm->remapped_ref_idx[i] = INVALID_IDX;
@@ -4741,7 +4741,7 @@
Note that the displayed frame be valid for referencing
in order to have been selected.
*/
- int refresh_frame_flags = pbi->refresh_frame_flags;
+ int refresh_frame_flags = cm->current_frame.refresh_frame_flags;
int display_frame_id = cm->ref_frame_id[existing_frame_idx];
for (int i = 0; i < REF_FRAMES; i++) {
if ((refresh_frame_flags >> i) & 1) {
@@ -4870,7 +4870,7 @@
if (cm->reset_decoder_state) {
show_existing_frame_reset(pbi, existing_frame_idx);
} else {
- pbi->refresh_frame_flags = 0;
+ current_frame->refresh_frame_flags = 0;
}
return 0;
@@ -5015,10 +5015,11 @@
}
}
if (current_frame->frame_type == KEY_FRAME) {
- if (!cm->show_frame) // unshown keyframe (forward keyframe)
- pbi->refresh_frame_flags = aom_rb_read_literal(rb, REF_FRAMES);
- else // shown keyframe
- pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1;
+ if (!cm->show_frame) { // unshown keyframe (forward keyframe)
+ current_frame->refresh_frame_flags = aom_rb_read_literal(rb, REF_FRAMES);
+ } else { // shown keyframe
+ current_frame->refresh_frame_flags = (1 << REF_FRAMES) - 1;
+ }
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
cm->remapped_ref_idx[i] = INVALID_IDX;
@@ -5029,8 +5030,8 @@
}
} else {
if (current_frame->frame_type == INTRA_ONLY_FRAME) {
- pbi->refresh_frame_flags = aom_rb_read_literal(rb, REF_FRAMES);
- if (pbi->refresh_frame_flags == 0xFF) {
+ current_frame->refresh_frame_flags = aom_rb_read_literal(rb, REF_FRAMES);
+ if (current_frame->refresh_frame_flags == 0xFF) {
aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
"Intra only frames cannot have refresh flags 0xFF");
}
@@ -5039,12 +5040,12 @@
pbi->need_resync = 0;
}
} else if (pbi->need_resync != 1) { /* Skip if need resync */
- pbi->refresh_frame_flags =
+ current_frame->refresh_frame_flags =
frame_is_sframe(cm) ? 0xFF : aom_rb_read_literal(rb, REF_FRAMES);
}
}
- if (!frame_is_intra_only(cm) || pbi->refresh_frame_flags != 0xFF) {
+ if (!frame_is_intra_only(cm) || current_frame->refresh_frame_flags != 0xFF) {
// Read all ref frame order hints if error_resilient_mode == 1
if (cm->error_resilient_mode &&
seq_params->order_hint_info.enable_order_hint) {
@@ -5229,7 +5230,7 @@
if (seq_params->frame_id_numbers_present_flag) {
/* If bitmask is set, update reference frame id values and
mark frames as valid for reference */
- int refresh_frame_flags = pbi->refresh_frame_flags;
+ int refresh_frame_flags = current_frame->refresh_frame_flags;
for (int i = 0; i < REF_FRAMES; i++) {
if ((refresh_frame_flags >> i) & 1) {
cm->ref_frame_id[i] = cm->current_frame_id;
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c
index 082e9ed..31edd1d 100644
--- a/av1/decoder/decoder.c
+++ b/av1/decoder/decoder.c
@@ -358,14 +358,15 @@
if (!pbi->camera_frame_header_ready) {
// If we are not holding reference buffers in cm->next_ref_frame_map,
// assert that the following two for loops are no-ops.
- assert(IMPLIES(!pbi->hold_ref_buf, pbi->refresh_frame_flags == 0));
+ assert(IMPLIES(!pbi->hold_ref_buf,
+ cm->current_frame.refresh_frame_flags == 0));
assert(IMPLIES(!pbi->hold_ref_buf,
cm->show_existing_frame && !cm->reset_decoder_state));
// The following two for loops need to release the reference stored in
// cm->ref_frame_map[ref_index] before transferring the reference stored
// in cm->next_ref_frame_map[ref_index] to cm->ref_frame_map[ref_index].
- for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
+ for (mask = cm->current_frame.refresh_frame_flags; mask; mask >>= 1) {
decrease_ref_count(cm->ref_frame_map[ref_index], pool);
cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
cm->next_ref_frame_map[ref_index] = NULL;
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index 72e117c..885f9d8 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -163,8 +163,6 @@
DECLARE_ALIGNED(32, AV1_COMMON, common);
- int refresh_frame_flags;
-
AVxWorker lf_worker;
AV1LfSync lf_row_sync;
AV1LrSync lr_row_sync;
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index dd56d1e..1e6dd16 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2190,65 +2190,6 @@
}
}
-static int get_refresh_mask(AV1_COMP *cpi) {
- const AV1_COMMON *const cm = &cpi->common;
-
- if ((cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) ||
- frame_is_sframe(cm))
- return 0xFF;
-
- int refresh_mask = 0;
-
- // NOTE(zoeliu): When LAST_FRAME is to get refreshed, the decoder will be
- // notified to get LAST3_FRAME refreshed and then the virtual indexes for all
- // the 3 LAST reference frames will be updated accordingly, i.e.:
- // (1) The original virtual index for LAST3_FRAME will become the new virtual
- // index for LAST_FRAME; and
- // (2) The original virtual indexes for LAST_FRAME and LAST2_FRAME will be
- // shifted and become the new virtual indexes for LAST2_FRAME and
- // LAST3_FRAME.
- refresh_mask |=
- (cpi->refresh_last_frame << get_ref_frame_map_idx(cm, LAST3_FRAME));
-
-#if USE_SYMM_MULTI_LAYER
- const int bwd_ref_frame =
- (cpi->new_bwdref_update_rule == 1) ? EXTREF_FRAME : BWDREF_FRAME;
-#else
- const int bwd_ref_frame = BWDREF_FRAME;
-#endif
- refresh_mask |=
- (cpi->refresh_bwd_ref_frame << get_ref_frame_map_idx(cm, bwd_ref_frame));
-
- refresh_mask |=
- (cpi->refresh_alt2_ref_frame << get_ref_frame_map_idx(cm, ALTREF2_FRAME));
-
- if (av1_preserve_existing_gf(cpi)) {
- // We have decided to preserve the previously existing golden frame as our
- // new ARF frame. However, in the short term we leave it in the GF slot and,
- // if we're updating the GF with the current decoded frame, we save it
- // instead to the ARF slot.
- // Later, in the function av1_encoder.c:av1_update_reference_frames() we
- // will swap gld_fb_idx and alt_fb_idx to achieve our objective. We do it
- // there so that it can be done outside of the recode loop.
- // Note: This is highly specific to the use of ARF as a forward reference,
- // and this needs to be generalized as other uses are implemented
- // (like RTC/temporal scalability).
-
- if (cpi->preserve_arf_as_gld) {
- return refresh_mask;
- } else {
- return refresh_mask | (cpi->refresh_golden_frame
- << get_ref_frame_map_idx(cm, ALTREF_FRAME));
- }
- } else {
- const int arf_idx = get_ref_frame_map_idx(cm, ALTREF_FRAME);
- return refresh_mask |
- (cpi->refresh_golden_frame
- << get_ref_frame_map_idx(cm, GOLDEN_FRAME)) |
- (cpi->refresh_alt_ref_frame << arf_idx);
- }
-}
-
static INLINE int find_identical_tile(
const int tile_row, const int tile_col,
TileBufferEnc (*const tile_buffers)[MAX_TILE_COLS]) {
@@ -3018,63 +2959,33 @@
}
}
}
- cpi->refresh_frame_mask = get_refresh_mask(cpi);
- if (current_frame->frame_type == KEY_FRAME) {
- if (!cm->show_frame) { // unshown keyframe (forward keyframe)
- aom_wb_write_literal(wb, cpi->refresh_frame_mask, REF_FRAMES);
- } else {
- assert(cpi->refresh_frame_mask == 0xFF);
- }
- } else {
- if (current_frame->frame_type == INTRA_ONLY_FRAME) {
- assert(cpi->refresh_frame_mask != 0xFF);
- int updated_fb = -1;
- for (int i = 0; i < REF_FRAMES; i++) {
- // If more than one frame is refreshed, it doesn't matter which one
- // we pick, so pick the first.
- if (cpi->refresh_frame_mask & (1 << i)) {
- updated_fb = i;
- break;
- }
- }
- assert(updated_fb >= 0);
- cm->fb_of_context_type[cm->frame_context_idx] = updated_fb;
- aom_wb_write_literal(wb, cpi->refresh_frame_mask, REF_FRAMES);
- } else if (current_frame->frame_type == INTER_FRAME ||
- frame_is_sframe(cm)) {
- if (current_frame->frame_type == INTER_FRAME) {
- aom_wb_write_literal(wb, cpi->refresh_frame_mask, REF_FRAMES);
- } else {
- assert(frame_is_sframe(cm) && cpi->refresh_frame_mask == 0xFF);
- }
- int updated_fb = -1;
- for (int i = 0; i < REF_FRAMES; i++) {
- // If more than one frame is refreshed, it doesn't matter which one
- // we pick, so pick the first.
- if (cpi->refresh_frame_mask & (1 << i)) {
- updated_fb = i;
- break;
- }
- }
- // large scale tile sometimes won't refresh any fbs
- if (updated_fb >= 0) {
- cm->fb_of_context_type[cm->frame_context_idx] = updated_fb;
+
+ // Shown keyframes and switch-frames automatically refreshes all reference
+ // frames. For all other frame types, we need to write refresh_frame_flags.
+ if ((current_frame->frame_type == KEY_FRAME && !cm->show_frame) ||
+ current_frame->frame_type == INTER_FRAME ||
+ current_frame->frame_type == INTRA_ONLY_FRAME)
+ aom_wb_write_literal(wb, current_frame->refresh_frame_flags, REF_FRAMES);
+
+ // For non-keyframes, we need to update the buffer of reference frame ids.
+ // If more than one frame is refreshed, it doesn't matter which one we pick,
+ // so pick the first. LST sometimes doesn't refresh any: this is ok
+ if (current_frame->frame_type != KEY_FRAME) {
+ for (int i = 0; i < REF_FRAMES; i++) {
+ if (current_frame->refresh_frame_flags & (1 << i)) {
+ cm->fb_of_context_type[cm->frame_context_idx] = i;
+ break;
}
}
}
- if (!frame_is_intra_only(cm) || cpi->refresh_frame_mask != 0xFF) {
+ if (!frame_is_intra_only(cm) || current_frame->refresh_frame_flags != 0xff) {
// Write all ref frame order hints if error_resilient_mode == 1
if (cm->error_resilient_mode &&
seq_params->order_hint_info.enable_order_hint) {
for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
- // Get buffer index
- const RefCntBuffer *buf = cm->ref_frame_map[ref_idx];
- assert(buf != NULL);
-
- // Write order hint to bit stream
aom_wb_write_literal(
- wb, buf->order_hint,
+ wb, cm->ref_frame_map[ref_idx]->order_hint,
seq_params->order_hint_info.order_hint_bits_minus_1 + 1);
}
}
diff --git a/av1/encoder/bitstream.h b/av1/encoder/bitstream.h
index 465ccae..9f9166a 100644
--- a/av1/encoder/bitstream.h
+++ b/av1/encoder/bitstream.h
@@ -35,7 +35,7 @@
int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dest, size_t *size);
-static INLINE int av1_preserve_existing_gf(AV1_COMP *cpi) {
+static INLINE int av1_preserve_existing_gf(const AV1_COMP *const cpi) {
// Do not swap gf and arf indices for internal overlay frames
return cpi->rc.is_src_frame_alt_ref && !cpi->rc.is_src_frame_ext_arf;
}
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 708cc34..c3f6917 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -4522,6 +4522,72 @@
return AOM_CODEC_OK;
}
+static int get_refresh_frame_flags(const AV1_COMP *const cpi) {
+ const AV1_COMMON *const cm = &cpi->common;
+
+ // Switch frames and shown key-frames overwrite all reference slots
+ if ((cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) ||
+ frame_is_sframe(cm))
+ return 0xFF;
+
+ int refresh_mask = 0;
+
+ // NOTE(zoeliu): When LAST_FRAME is to get refreshed, the decoder will be
+ // notified to get LAST3_FRAME refreshed and then the virtual indexes for all
+ // the 3 LAST reference frames will be updated accordingly, i.e.:
+ // (1) The original virtual index for LAST3_FRAME will become the new virtual
+ // index for LAST_FRAME; and
+ // (2) The original virtual indexes for LAST_FRAME and LAST2_FRAME will be
+ // shifted and become the new virtual indexes for LAST2_FRAME and
+ // LAST3_FRAME.
+ refresh_mask |=
+ (cpi->refresh_last_frame << get_ref_frame_map_idx(cm, LAST3_FRAME));
+
+#if USE_SYMM_MULTI_LAYER
+ const int bwd_ref_frame =
+ (cpi->new_bwdref_update_rule == 1) ? EXTREF_FRAME : BWDREF_FRAME;
+#else
+ const int bwd_ref_frame = BWDREF_FRAME;
+#endif
+ refresh_mask |=
+ (cpi->refresh_bwd_ref_frame << get_ref_frame_map_idx(cm, bwd_ref_frame));
+
+ refresh_mask |=
+ (cpi->refresh_alt2_ref_frame << get_ref_frame_map_idx(cm, ALTREF2_FRAME));
+
+ if (av1_preserve_existing_gf(cpi)) {
+ // We have decided to preserve the previously existing golden frame as our
+ // new ARF frame. However, in the short term we leave it in the GF slot and,
+ // if we're updating the GF with the current decoded frame, we save it
+ // instead to the ARF slot.
+ // Later, in the function av1_encoder.c:av1_update_reference_frames() we
+ // will swap gld_fb_idx and alt_fb_idx to achieve our objective. We do it
+ // there so that it can be done outside of the recode loop.
+ // Note: This is highly specific to the use of ARF as a forward reference,
+ // and this needs to be generalized as other uses are implemented
+ // (like RTC/temporal scalability).
+
+ if (!cpi->preserve_arf_as_gld) {
+ refresh_mask |= (cpi->refresh_golden_frame
+ << get_ref_frame_map_idx(cm, ALTREF_FRAME));
+ }
+ } else {
+ refresh_mask |=
+ (cpi->refresh_golden_frame << get_ref_frame_map_idx(cm, GOLDEN_FRAME));
+ refresh_mask |=
+ (cpi->refresh_alt_ref_frame << get_ref_frame_map_idx(cm, ALTREF_FRAME));
+ }
+ return refresh_mask;
+}
+
+static void finalize_encoded_frame(AV1_COMP *const cpi) {
+ AV1_COMMON *const cm = &cpi->common;
+
+ // This bitfield indicates which reference frame slots will be overwritten by
+ // the current frame
+ cm->current_frame.refresh_frame_flags = get_refresh_frame_flags(cpi);
+}
+
static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) {
AV1_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
@@ -4632,6 +4698,7 @@
if (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF) {
restore_coding_context(cpi);
+ finalize_encoded_frame(cpi);
if (av1_pack_bitstream(cpi, dest, size) != AOM_CODEC_OK)
return AOM_CODEC_ERROR;
@@ -5054,6 +5121,7 @@
restore_coding_context(cpi);
+ finalize_encoded_frame(cpi);
// Build the bitstream
if (av1_pack_bitstream(cpi, dest, size) != AOM_CODEC_OK)
return AOM_CODEC_ERROR;
@@ -5266,6 +5334,7 @@
aom_write_one_yuv_frame(cm, &cm->cur_frame->buf);
#endif
+ finalize_encoded_frame(cpi);
// Build the bitstream
if (av1_pack_bitstream(cpi, dest, size) != AOM_CODEC_OK)
return AOM_CODEC_ERROR;
@@ -5274,11 +5343,10 @@
if (skip_adapt) return AOM_CODEC_OK;
+ // Update reference frame ids for reference frames this frame will overwrite
if (seq_params->frame_id_numbers_present_flag) {
- int i;
- // Update reference frame id values based on the value of refresh_frame_mask
- for (i = 0; i < REF_FRAMES; i++) {
- if ((cpi->refresh_frame_mask >> i) & 1) {
+ for (int i = 0; i < REF_FRAMES; i++) {
+ if ((current_frame->refresh_frame_flags >> i) & 1) {
cm->ref_frame_id[i] = cm->current_frame_id;
}
}
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 6945cd3..29cb51a 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -798,7 +798,6 @@
int num_workers;
AVxWorker *workers;
struct EncWorkerData *tile_thr_data;
- int refresh_frame_mask;
int existing_fb_idx_to_show;
int is_arf_filter_off[MAX_EXT_ARFS + 1];
int num_extra_arfs;