Move ref updates to strategy, refresh from flags
Previously, encoder.c:update_reference_frames() in the low-level encoder
handled reference buffer assignment as well as refreshing reference
frames. This patch separates these two, moving reference buffer
refreshing to encoder.c:refresh_reference_frames() called from the
low-level and update_reference_frames() called from the high-level
strategy.
refresh_reference_frames() now refreshes just based on
refresh_frame_flags, which ensures our reference buffer refreshing is in
sync with the decoder. Previously get_refresh_frame_flags() and
update_reference_frames() effectively duplicated the decision of which
reference frames to refresh.
In the case of frame_refs_short_signaling=1, av1_set_frame_refs modifies
the reference buffer assignment. I move calls to av1_set_frame_refs()
to update_reference_frames() so that all reference buffer assignment is
done in one place. I also modify av1_set_frame_refs() to modify a
specific array so that check_frame_refs_short_signaling can write to a
temporary array instead of having to make a backup copy of
remapped_ref_idx.
I also add remapped_ref_idx to EncodeFrameParams to provide a clear
point where it could be modified to use an alternative reference buffer
assignment strategy.
get_refresh_frame_flags is modified to ensure refresh_frame_flags=0 when
we send show_existing_frame=1. This keeps things consistent, since the
decoder won't refresh any buffers for a show_existing_frame.
Change-Id: Id98c73ed06b9e79c2bc424d600e4aa7801c6ff39
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index 1c63319..0373b5e 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -1362,15 +1362,15 @@
return info_a->map_idx - info_b->map_idx;
}
-static void set_ref_frame_info(AV1_COMMON *const cm, int frame_idx,
+static void set_ref_frame_info(int *remapped_ref_idx, int frame_idx,
REF_FRAME_INFO *ref_info) {
assert(frame_idx >= 0 && frame_idx < INTER_REFS_PER_FRAME);
- cm->remapped_ref_idx[frame_idx] = ref_info->map_idx;
+ remapped_ref_idx[frame_idx] = ref_info->map_idx;
}
-void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
- int gld_map_idx) {
+void av1_set_frame_refs(AV1_COMMON *const cm, int *remapped_ref_idx,
+ int lst_map_idx, int gld_map_idx) {
int lst_frame_sort_idx = -1;
int gld_frame_sort_idx = -1;
@@ -1449,7 +1449,7 @@
// == ALTREF_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
- set_ref_frame_info(cm, ALTREF_FRAME - LAST_FRAME,
+ set_ref_frame_info(remapped_ref_idx, ALTREF_FRAME - LAST_FRAME,
&ref_frame_info[bwd_end_idx]);
ref_flag_list[ALTREF_FRAME - LAST_FRAME] = 1;
bwd_end_idx--;
@@ -1457,7 +1457,7 @@
// == BWDREF_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
- set_ref_frame_info(cm, BWDREF_FRAME - LAST_FRAME,
+ set_ref_frame_info(remapped_ref_idx, BWDREF_FRAME - LAST_FRAME,
&ref_frame_info[bwd_start_idx]);
ref_flag_list[BWDREF_FRAME - LAST_FRAME] = 1;
bwd_start_idx++;
@@ -1465,7 +1465,7 @@
// == ALTREF2_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
- set_ref_frame_info(cm, ALTREF2_FRAME - LAST_FRAME,
+ set_ref_frame_info(remapped_ref_idx, ALTREF2_FRAME - LAST_FRAME,
&ref_frame_info[bwd_start_idx]);
ref_flag_list[ALTREF2_FRAME - LAST_FRAME] = 1;
}
@@ -1475,13 +1475,15 @@
for (int i = fwd_start_idx; i <= fwd_end_idx; ++i) {
// == LAST_FRAME ==
if (ref_frame_info[i].map_idx == lst_map_idx) {
- set_ref_frame_info(cm, LAST_FRAME - LAST_FRAME, &ref_frame_info[i]);
+ set_ref_frame_info(remapped_ref_idx, LAST_FRAME - LAST_FRAME,
+ &ref_frame_info[i]);
ref_flag_list[LAST_FRAME - LAST_FRAME] = 1;
}
// == GOLDEN_FRAME ==
if (ref_frame_info[i].map_idx == gld_map_idx) {
- set_ref_frame_info(cm, GOLDEN_FRAME - LAST_FRAME, &ref_frame_info[i]);
+ set_ref_frame_info(remapped_ref_idx, GOLDEN_FRAME - LAST_FRAME,
+ &ref_frame_info[i]);
ref_flag_list[GOLDEN_FRAME - LAST_FRAME] = 1;
}
}
@@ -1513,7 +1515,7 @@
}
if (fwd_start_idx > fwd_end_idx) break;
- set_ref_frame_info(cm, ref_frame - LAST_FRAME,
+ set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME,
&ref_frame_info[fwd_end_idx]);
ref_flag_list[ref_frame - LAST_FRAME] = 1;
@@ -1524,7 +1526,7 @@
for (; ref_idx < (INTER_REFS_PER_FRAME - 2); ref_idx++) {
const MV_REFERENCE_FRAME ref_frame = ref_frame_list[ref_idx];
if (ref_flag_list[ref_frame - LAST_FRAME] == 1) continue;
- set_ref_frame_info(cm, ref_frame - LAST_FRAME,
+ set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME,
&ref_frame_info[fwd_start_idx]);
ref_flag_list[ref_frame - LAST_FRAME] = 1;
}
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index 8db4095..0aa9d38 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -210,7 +210,8 @@
void av1_setup_frame_sign_bias(AV1_COMMON *cm);
void av1_setup_skip_mode_allowed(AV1_COMMON *cm);
void av1_setup_motion_field(AV1_COMMON *cm);
-void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, int gld_map_idx);
+void av1_set_frame_refs(AV1_COMMON *const cm, int *remapped_ref_idx,
+ int lst_map_idx, int gld_map_idx);
static INLINE void av1_collect_neighbors_ref_counts(MACROBLOCKD *const xd) {
av1_zero(xd->neighbors_ref_counts);
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index cfaa1a4..d5668a7 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -314,6 +314,7 @@
unsigned int frame_number;
SkipModeInfo skip_mode_info;
int refresh_frame_flags; // Which ref frames are overwritten by this frame
+ int frame_refs_short_signaling;
} CurrentFrame;
typedef struct AV1Common {
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 26e91d5..1f3a50b 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -5179,7 +5179,7 @@
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Inter frame requests nonexistent reference");
- av1_set_frame_refs(cm, lst_ref, gld_ref);
+ av1_set_frame_refs(cm, cm->remapped_ref_idx, lst_ref, gld_ref);
}
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 0f05ee8..8e4daf7 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2743,21 +2743,14 @@
// Check whether the encoder side ref frame choices are aligned with that to
// be derived at the decoder side.
- int remapped_ref_idx_copy[REF_FRAMES];
- struct scale_factors ref_scale_factors_copy[REF_FRAMES];
-
- // Backup the frame refs info
- memcpy(remapped_ref_idx_copy, cm->remapped_ref_idx,
- REF_FRAMES * sizeof(*remapped_ref_idx_copy));
- memcpy(ref_scale_factors_copy, cm->ref_scale_factors,
- REF_FRAMES * sizeof(*ref_scale_factors_copy));
+ int remapped_ref_idx_decoder[REF_FRAMES];
const int lst_map_idx = get_ref_frame_map_idx(cm, LAST_FRAME);
const int gld_map_idx = get_ref_frame_map_idx(cm, GOLDEN_FRAME);
// Set up the frame refs mapping indexes according to the
// frame_refs_short_signaling policy.
- av1_set_frame_refs(cm, lst_map_idx, gld_map_idx);
+ av1_set_frame_refs(cm, remapped_ref_idx_decoder, lst_map_idx, gld_map_idx);
// We only turn on frame_refs_short_signaling when the encoder side decision
// on ref frames is identical to that at the decoder side.
@@ -2765,10 +2758,11 @@
for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ++ref_idx) {
// Compare the buffer index between two reference frames indexed
// respectively by the encoder and the decoder side decisions.
- RefCntBuffer *ref_frame_buf_copy = NULL;
- if (remapped_ref_idx_copy[ref_idx] != INVALID_IDX)
- ref_frame_buf_copy = cm->ref_frame_map[remapped_ref_idx_copy[ref_idx]];
- if (get_ref_frame_buf(cm, LAST_FRAME + ref_idx) != ref_frame_buf_copy) {
+ RefCntBuffer *ref_frame_buf_new = NULL;
+ if (remapped_ref_idx_decoder[ref_idx] != INVALID_IDX) {
+ ref_frame_buf_new = cm->ref_frame_map[remapped_ref_idx_decoder[ref_idx]];
+ }
+ if (get_ref_frame_buf(cm, LAST_FRAME + ref_idx) != ref_frame_buf_new) {
frame_refs_short_signaling = 0;
break;
}
@@ -2786,13 +2780,6 @@
}
#endif // 0
- // Restore the frame refs info if frame_refs_short_signaling is off.
- if (!frame_refs_short_signaling) {
- memcpy(cm->remapped_ref_idx, remapped_ref_idx_copy,
- REF_FRAMES * sizeof(*remapped_ref_idx_copy));
- memcpy(cm->ref_scale_factors, ref_scale_factors_copy,
- REF_FRAMES * sizeof(*ref_scale_factors_copy));
- }
return frame_refs_short_signaling;
}
@@ -2805,6 +2792,8 @@
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
CurrentFrame *const current_frame = &cm->current_frame;
+ current_frame->frame_refs_short_signaling = 0;
+
if (seq_params->still_picture) {
assert(cm->show_existing_frame == 0);
assert(cm->show_frame == 1);
@@ -2961,25 +2950,25 @@
// NOTE: Error resilient mode turns off frame_refs_short_signaling
// automatically.
- int frame_refs_short_signaling = 0;
#define FRAME_REFS_SHORT_SIGNALING 0
#if FRAME_REFS_SHORT_SIGNALING
- frame_refs_short_signaling =
+ current_frame->frame_refs_short_signaling =
seq_params->order_hint_info.enable_order_hint;
#endif // FRAME_REFS_SHORT_SIGNALING
- if (frame_refs_short_signaling) {
+ if (current_frame->frame_refs_short_signaling) {
// NOTE(zoeliu@google.com):
// An example solution for encoder-side implementation on frame refs
// short signaling, which is only turned on when the encoder side
// decision on ref frames is identical to that at the decoder side.
- frame_refs_short_signaling = check_frame_refs_short_signaling(cm);
+ current_frame->frame_refs_short_signaling =
+ check_frame_refs_short_signaling(cm);
}
if (seq_params->order_hint_info.enable_order_hint)
- aom_wb_write_bit(wb, frame_refs_short_signaling);
+ aom_wb_write_bit(wb, current_frame->frame_refs_short_signaling);
- if (frame_refs_short_signaling) {
+ if (current_frame->frame_refs_short_signaling) {
const int lst_ref = get_ref_frame_map_idx(cm, LAST_FRAME);
aom_wb_write_literal(wb, lst_ref, REF_FRAMES_LOG2);
@@ -2989,7 +2978,7 @@
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
assert(get_ref_frame_map_idx(cm, ref_frame) != INVALID_IDX);
- if (!frame_refs_short_signaling)
+ if (!current_frame->frame_refs_short_signaling)
aom_wb_write_literal(wb, get_ref_frame_map_idx(cm, ref_frame),
REF_FRAMES_LOG2);
if (seq_params->frame_id_numbers_present_flag) {
diff --git a/av1/encoder/bitstream.h b/av1/encoder/bitstream.h
index a567086..153026a 100644
--- a/av1/encoder/bitstream.h
+++ b/av1/encoder/bitstream.h
@@ -36,11 +36,6 @@
int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size,
int *const largest_tile_id);
-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;
-}
-
void av1_write_tx_type(const AV1_COMMON *const cm, const MACROBLOCKD *xd,
int blk_row, int blk_col, int plane, TX_SIZE tx_size,
aom_writer *w);
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 365a503..f47eef2 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -698,7 +698,8 @@
// Don't allow a show_existing_frame to coincide with an error resilient or
// S-Frame. An exception can be made in the case of a keyframe, since it does
// not depend on any previous frames.
-static int allow_show_existing(const AV1_COMP *const cpi) {
+static int allow_show_existing(const AV1_COMP *const cpi,
+ unsigned int frame_flags) {
if (cpi->common.current_frame.frame_number == 0) return 0;
const struct lookahead_entry *lookahead_src =
@@ -711,10 +712,333 @@
const int is_s_frame =
cpi->oxcf.s_frame_mode || (lookahead_src->flags & AOM_EFLAG_SET_S_FRAME);
const int is_key_frame =
- (cpi->rc.frames_to_key == 0) || (cpi->frame_flags & FRAMEFLAGS_KEY);
+ (cpi->rc.frames_to_key == 0) || (frame_flags & FRAMEFLAGS_KEY);
return !(is_error_resilient || is_s_frame) || is_key_frame;
}
+// Update frame_flags to tell the encoder's caller what sort of frame was
+// encoded.
+static void update_frame_flags(AV1_COMP *cpi, unsigned int *frame_flags) {
+ if (encode_show_existing_frame(&cpi->common)) {
+ *frame_flags &= ~FRAMEFLAGS_GOLDEN;
+ *frame_flags &= ~FRAMEFLAGS_BWDREF;
+ *frame_flags &= ~FRAMEFLAGS_ALTREF;
+ *frame_flags &= ~FRAMEFLAGS_KEY;
+ return;
+ }
+
+ if (cpi->refresh_golden_frame == 1) {
+ *frame_flags |= FRAMEFLAGS_GOLDEN;
+ } else {
+ *frame_flags &= ~FRAMEFLAGS_GOLDEN;
+ }
+
+ if (cpi->refresh_alt_ref_frame == 1) {
+ *frame_flags |= FRAMEFLAGS_ALTREF;
+ } else {
+ *frame_flags &= ~FRAMEFLAGS_ALTREF;
+ }
+
+ if (cpi->refresh_bwd_ref_frame == 1) {
+ *frame_flags |= FRAMEFLAGS_BWDREF;
+ } else {
+ *frame_flags &= ~FRAMEFLAGS_BWDREF;
+ }
+
+ if (cpi->common.current_frame.frame_type == KEY_FRAME) {
+ *frame_flags |= FRAMEFLAGS_KEY;
+ } else {
+ *frame_flags &= ~FRAMEFLAGS_KEY;
+ }
+}
+
+#define DUMP_REF_FRAME_IMAGES 0
+
+#if DUMP_REF_FRAME_IMAGES == 1
+static int dump_one_image(AV1_COMMON *cm,
+ const YV12_BUFFER_CONFIG *const ref_buf,
+ char *file_name) {
+ int h;
+ FILE *f_ref = NULL;
+
+ if (ref_buf == NULL) {
+ printf("Frame data buffer is NULL.\n");
+ return AOM_CODEC_MEM_ERROR;
+ }
+
+ if ((f_ref = fopen(file_name, "wb")) == NULL) {
+ printf("Unable to open file %s to write.\n", file_name);
+ return AOM_CODEC_MEM_ERROR;
+ }
+
+ // --- Y ---
+ for (h = 0; h < cm->height; ++h) {
+ fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref);
+ }
+ // --- U ---
+ for (h = 0; h < (cm->height >> 1); ++h) {
+ fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
+ f_ref);
+ }
+ // --- V ---
+ for (h = 0; h < (cm->height >> 1); ++h) {
+ fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
+ f_ref);
+ }
+
+ fclose(f_ref);
+
+ return AOM_CODEC_OK;
+}
+
+static void dump_ref_frame_images(AV1_COMP *cpi) {
+ AV1_COMMON *const cm = &cpi->common;
+ MV_REFERENCE_FRAME ref_frame;
+
+ for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+ char file_name[256] = "";
+ snprintf(file_name, sizeof(file_name), "/tmp/enc_F%d_ref_%d.yuv",
+ cm->current_frame.frame_number, ref_frame);
+ dump_one_image(cm, get_ref_frame_yv12_buf(cpi, ref_frame), file_name);
+ }
+}
+#endif // DUMP_REF_FRAME_IMAGES == 1
+
+// This function is used to shift the virtual indices of last reference frames
+// as follows:
+// LAST_FRAME -> LAST2_FRAME -> LAST3_FRAME
+// when the LAST_FRAME is updated.
+static INLINE void shift_last_ref_frames(AV1_COMP *cpi) {
+ // TODO(isbs): shift the scaled indices as well
+ for (int ref_frame = LAST3_FRAME; ref_frame > LAST_FRAME; --ref_frame) {
+ const int ref_idx = ref_frame - LAST_FRAME;
+ cpi->common.remapped_ref_idx[ref_idx] =
+ cpi->common.remapped_ref_idx[ref_idx - 1];
+
+ if (!cpi->rc.is_src_frame_alt_ref) {
+ memcpy(cpi->interp_filter_selected[ref_frame],
+ cpi->interp_filter_selected[ref_frame - 1],
+ sizeof(cpi->interp_filter_selected[ref_frame - 1]));
+ }
+ }
+}
+
+// This function is used to shift the virtual indices of bwd reference
+// frames as follows:
+// BWD_REF -> ALT2_REF -> EXT_REF
+// to clear a space to store the closest bwdref
+static INLINE void rshift_bwd_ref_frames(AV1_COMP *cpi) {
+ // TODO(isbs): shift the scaled indices as well
+ static const int ordered_bwd[3] = { BWDREF_FRAME, ALTREF2_FRAME,
+ EXTREF_FRAME };
+
+ for (int i = 2; i > 0; --i) {
+ // [0] is allocated to the current coded frame, i.e. bwdref
+ memcpy(cpi->interp_filter_selected[ordered_bwd[i]],
+ cpi->interp_filter_selected[ordered_bwd[i - 1]],
+ sizeof(cpi->interp_filter_selected[ordered_bwd[i - 1]]));
+
+ cpi->common.remapped_ref_idx[ordered_bwd[i] - LAST_FRAME] =
+ cpi->common.remapped_ref_idx[ordered_bwd[i - 1] - LAST_FRAME];
+ }
+}
+
+// This function is used to shift the virtual indices of bwd reference
+// frames as follows:
+// BWD_REF <- ALT2_REF <- EXT_REF
+// to update the bwd reference frame for coding the next frame.
+static INLINE void lshift_bwd_ref_frames(AV1_COMP *cpi) {
+ // TODO(isbs): shift the scaled indices as well
+ static const int ordered_bwd[3] = { BWDREF_FRAME, ALTREF2_FRAME,
+ EXTREF_FRAME };
+
+ for (int i = 0; i < 2; ++i) {
+ // [0] is allocated to the current coded frame, i.e. bwdref
+ memcpy(cpi->interp_filter_selected[ordered_bwd[i]],
+ cpi->interp_filter_selected[ordered_bwd[i + 1]],
+ sizeof(cpi->interp_filter_selected[ordered_bwd[i + 1]]));
+
+ cpi->common.remapped_ref_idx[ordered_bwd[i] - LAST_FRAME] =
+ cpi->common.remapped_ref_idx[ordered_bwd[i + 1] - LAST_FRAME];
+ }
+}
+
+static void update_reference_frames(AV1_COMP *cpi) {
+ AV1_COMMON *const cm = &cpi->common;
+
+ // If check_frame_refs_short_signaling() decided to set
+ // frame_refs_short_signaling=1 then we update remapped_ref_idx[] here. Every
+ // reference will still map to the same RefCntBuffer (through ref_frame_map[])
+ // after this, but that does not necessarily mean that remapped_ref_idx[] is
+ // unchanged.
+ if (cm->current_frame.frame_refs_short_signaling) {
+ const int lst_map_idx = get_ref_frame_map_idx(cm, LAST_FRAME);
+ const int gld_map_idx = get_ref_frame_map_idx(cm, GOLDEN_FRAME);
+ av1_set_frame_refs(cm, cm->remapped_ref_idx, lst_map_idx, gld_map_idx);
+ }
+
+ // For shown keyframes and S-frames all buffers are refreshed, but we don't
+ // change any of the mapping.
+ if ((cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) ||
+ frame_is_sframe(cm)) {
+ return;
+ }
+
+ if (cpi->rc.is_src_frame_alt_ref && !cpi->rc.is_src_frame_ext_arf) {
+ // We have decided to preserve the previously existing golden frame as our
+ // new ARF frame. However, in the short term in function
+ // av1_bitstream.c::get_refresh_mask() we left it in the GF slot and, if
+ // we're updating the GF with the current decoded frame, we save it to the
+ // ARF slot instead.
+ // We now have to update the ARF with the current frame and swap gld_fb_idx
+ // and alt_fb_idx so that, overall, we've stored the old GF in the new ARF
+ // slot and, if we're updating the GF, the current frame becomes the new GF.
+
+ // ARF in general is a better reference than overlay. We shouldkeep ARF as
+ // reference instead of replacing it with overlay.
+
+ const int tmp = get_ref_frame_map_idx(cm, ALTREF_FRAME);
+ cm->remapped_ref_idx[ALTREF_FRAME - LAST_FRAME] =
+ get_ref_frame_map_idx(cm, GOLDEN_FRAME);
+ cm->remapped_ref_idx[GOLDEN_FRAME - LAST_FRAME] = tmp;
+
+ // TODO(zoeliu): Do we need to copy cpi->interp_filter_selected[0] over to
+ // cpi->interp_filter_selected[GOLDEN_FRAME]?
+ } else if (cpi->rc.is_src_frame_ext_arf && encode_show_existing_frame(cm)) {
+ const int bwdref_to_show =
+ (cpi->new_bwdref_update_rule == 1) ? BWDREF_FRAME : ALTREF2_FRAME;
+ // Deal with the special case for showing existing internal ALTREF_FRAME
+ // Refresh the LAST_FRAME with the ALTREF_FRAME and retire the LAST3_FRAME
+ // by updating the virtual indices.
+ const int last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME);
+ shift_last_ref_frames(cpi);
+
+ cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] =
+ get_ref_frame_map_idx(cm, bwdref_to_show);
+
+ memcpy(cpi->interp_filter_selected[LAST_FRAME],
+ cpi->interp_filter_selected[bwdref_to_show],
+ sizeof(cpi->interp_filter_selected[bwdref_to_show]));
+ if (cpi->new_bwdref_update_rule == 1) {
+ lshift_bwd_ref_frames(cpi);
+ // pass outdated forward reference frame (previous LAST3) to the
+ // spared space
+ cm->remapped_ref_idx[EXTREF_FRAME - LAST_FRAME] = last3_remapped_idx;
+ } else {
+ cm->remapped_ref_idx[bwdref_to_show - LAST_FRAME] = last3_remapped_idx;
+ }
+ } else { /* For non key/golden frames */
+ if (cpi->refresh_alt_ref_frame && !cm->show_existing_frame) {
+ // === ALTREF_FRAME ===
+ memcpy(cpi->interp_filter_selected[ALTREF_FRAME],
+ cpi->interp_filter_selected[0],
+ sizeof(cpi->interp_filter_selected[0]));
+ } else if (cpi->refresh_golden_frame && !cm->show_existing_frame) {
+ // === GOLDEN_FRAME ===
+ memcpy(cpi->interp_filter_selected[GOLDEN_FRAME],
+ cpi->interp_filter_selected[0],
+ sizeof(cpi->interp_filter_selected[0]));
+
+ } else if (cpi->refresh_bwd_ref_frame && !cm->show_existing_frame) {
+ if (cpi->new_bwdref_update_rule) {
+ // === BWDREF_FRAME ===
+ // (Nothing to do for BWDREF_FRAME show_existing_frame because the
+ // reference frame update has been done previously when handling the
+ // LAST_BIPRED_FRAME right before BWDREF_FRAME (in the display order))
+ // We shift the backward reference frame as follows:
+ // BWDREF -> ALTREF2 -> EXTREF
+ // and assign the newly coded frame to BWDREF so that it always
+ // keeps the nearest future frame
+ const int tmp = get_ref_frame_map_idx(cm, EXTREF_FRAME);
+ rshift_bwd_ref_frames(cpi);
+ cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = tmp;
+ }
+ memcpy(cpi->interp_filter_selected[BWDREF_FRAME],
+ cpi->interp_filter_selected[0],
+ sizeof(cpi->interp_filter_selected[0]));
+ } else if (cpi->refresh_alt2_ref_frame && !cm->show_existing_frame) {
+ // === ALTREF2_FRAME ===
+ memcpy(cpi->interp_filter_selected[ALTREF2_FRAME],
+ cpi->interp_filter_selected[0],
+ sizeof(cpi->interp_filter_selected[0]));
+ }
+ }
+
+ if (cpi->refresh_last_frame && !encode_show_existing_frame(cm) &&
+ (!cm->show_existing_frame || cpi->rc.is_src_frame_ext_arf)) {
+ // NOTE(zoeliu): We have two layers of mapping (1) from the per-frame
+ // reference to the reference frame buffer virtual index; and then (2) from
+ // the virtual index to the reference frame buffer (RefCntBuffer):
+ //
+ // LAST_FRAME, ..., EXTREF_FRAME
+ // | |
+ // v v
+ // remapped_ref_idx[LAST_FRAME - 1], ..., remapped_ref_idx[EXTREF_FRAME - 1]
+ // | |
+ // v v
+ // ref_frame_map[], ..., ref_frame_map[]
+ //
+ // When refresh_last_frame is set, it is intended to retire LAST3_FRAME,
+ // have the other 2 LAST reference frames shifted as follows:
+ // LAST_FRAME -> LAST2_FRAME -> LAST3_FRAME
+ // , and then have LAST_FRAME refreshed by the newly coded frame.
+ //
+ // To fulfill it, the decoder will be notified to execute following 2 steps:
+ //
+ // (a) To change ref_frame_map[] and have the virtual index of LAST3_FRAME
+ // to point to the newly coded frame, i.e.
+ // ref_frame_map[lst_fb_idexes[2]] => cur_frame;
+ //
+ // (b) To change the 1st layer mapping to have LAST_FRAME mapped to the
+ // original virtual index of LAST3_FRAME and have the other mappings
+ // shifted as follows:
+ // LAST_FRAME, LAST2_FRAME, LAST3_FRAME
+ // | | |
+ // v v v
+ // remapped_ref_idx[2], remapped_ref_idx[0], remapped_ref_idx[1]
+
+ int last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME);
+
+ shift_last_ref_frames(cpi);
+ cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] = last3_remapped_idx;
+
+ // TODO(dwt): This copy should actually follow the assign_frame_buffer.
+ memcpy(cpi->interp_filter_selected[LAST_FRAME],
+ cpi->interp_filter_selected[0],
+ sizeof(cpi->interp_filter_selected[0]));
+
+ // If the new structure is used, we will always have overlay frames coupled
+ // with bwdref frames. Therefore, we won't have to perform this update
+ // in advance (we do this update when the overlay frame shows up).
+ if (cpi->new_bwdref_update_rule == 0 && cpi->rc.is_last_bipred_frame &&
+ !cm->show_existing_frame) {
+ // Refresh the LAST_FRAME with the BWDREF_FRAME and retire the
+ // LAST3_FRAME by updating the virtual indices.
+ //
+ // NOTE: The source frame for BWDREF does not have a holding position as
+ // the OVERLAY frame for ALTREF's. Hence, to resolve the reference
+ // virtual index reshuffling for BWDREF, the encoder always
+ // specifies a LAST_BIPRED right before BWDREF and completes the
+ // reshuffling job accordingly.
+ last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME);
+
+ shift_last_ref_frames(cpi);
+ cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] =
+ get_ref_frame_map_idx(cm, BWDREF_FRAME);
+ cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = last3_remapped_idx;
+
+ memcpy(cpi->interp_filter_selected[LAST_FRAME],
+ cpi->interp_filter_selected[BWDREF_FRAME],
+ sizeof(cpi->interp_filter_selected[BWDREF_FRAME]));
+ }
+ }
+
+#if DUMP_REF_FRAME_IMAGES == 1
+ // Dump out all reference frame images.
+ dump_ref_frame_images(cpi);
+#endif // DUMP_REF_FRAME_IMAGES
+}
+
int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
uint8_t *const dest, unsigned int *frame_flags,
int64_t *const time_stamp, int64_t *const time_end,
@@ -731,7 +1055,7 @@
if (oxcf->pass == 0 || oxcf->pass == 2) {
check_show_existing_frame(cpi);
- cm->show_existing_frame &= allow_show_existing(cpi);
+ cm->show_existing_frame &= allow_show_existing(cpi, *frame_flags);
} else {
cm->show_existing_frame = 0;
}
@@ -776,7 +1100,6 @@
av1_apply_encoding_flags(cpi, source->flags);
if (!cm->show_existing_frame)
*frame_flags = (source->flags & AOM_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
- cpi->frame_flags = *frame_flags;
const int is_overlay =
cm->show_existing_frame && (frame_update_type == OVERLAY_UPDATE ||
@@ -810,7 +1133,7 @@
if (oxcf->pass == 2 && (!cm->show_existing_frame || is_overlay)) {
// GF_GROUP needs updating for arf overlays as well as non-show-existing
- av1_get_second_pass_params(cpi, &frame_params);
+ av1_get_second_pass_params(cpi, &frame_params, *frame_flags);
frame_update_type =
cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index];
}
@@ -820,8 +1143,6 @@
frame_params.frame_type = INTER_FRAME;
}
- frame_params.frame_flags = frame_flags;
-
// TODO(david.turner@argondesign.com): Move all the encode strategy
// (largely near av1_get_compressed_data) in here
@@ -847,14 +1168,16 @@
// Work out some encoding parameters specific to the pass:
if (oxcf->pass == 0) {
if (cpi->oxcf.rc_mode == AOM_CBR) {
- av1_rc_get_one_pass_cbr_params(cpi, &frame_update_type, &frame_params);
+ av1_rc_get_one_pass_cbr_params(cpi, &frame_update_type, &frame_params,
+ *frame_flags);
} else {
- av1_rc_get_one_pass_vbr_params(cpi, &frame_update_type, &frame_params);
+ av1_rc_get_one_pass_vbr_params(cpi, &frame_update_type, &frame_params,
+ *frame_flags);
}
} else if (oxcf->pass == 1) {
cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(&cpi->oxcf);
const int kf_requested = (cm->current_frame.frame_number == 0 ||
- (cpi->frame_flags & FRAMEFLAGS_KEY));
+ (*frame_flags & FRAMEFLAGS_KEY));
if (kf_requested && frame_update_type != OVERLAY_UPDATE &&
frame_update_type != INTNL_OVERLAY_UPDATE) {
frame_params.frame_type = KEY_FRAME;
@@ -891,11 +1214,29 @@
frame_params.order_offset = get_order_offset(cpi, &frame_params);
}
+ // The way frame_params->remapped_ref_idx is setup is a placeholder.
+ // Currently, reference buffer assignment is done by update_reference_frames()
+ // which is called by high-level strategy AFTER encoding a frame. It modifies
+ // cm->remapped_ref_idx. If you want to use an alternative method to
+ // determine reference buffer assignment, just put your assignments into
+ // frame_params->remapped_ref_idx here and they will be used when encoding
+ // this frame. If frame_params->remapped_ref_idx is setup independently of
+ // cm->remapped_ref_idx then update_reference_frames() will have no effect.
+ memcpy(frame_params.remapped_ref_idx, cm->remapped_ref_idx,
+ REF_FRAMES * sizeof(*cm->remapped_ref_idx));
+
if (av1_encode(cpi, dest, &frame_input, &frame_params, &frame_results) !=
AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
}
+ if (oxcf->pass == 0 || oxcf->pass == 2) {
+ // First pass doesn't modify reference buffer assignment or produce frame
+ // flags
+ update_frame_flags(cpi, frame_flags);
+ update_reference_frames(cpi);
+ }
+
if (oxcf->pass == 2) {
#if TXCOEFF_COST_TIMER
cm->cum_txcoeff_cost_timer += cm->txcoeff_cost_timer;
@@ -910,7 +1251,7 @@
if (oxcf->pass == 0 || oxcf->pass == 2) {
update_fb_of_context_type(cpi, &frame_params, cpi->fb_of_context_type);
- set_additional_frame_flags(cm, frame_params.frame_flags);
+ set_additional_frame_flags(cm, frame_flags);
update_rc_counts(cpi);
}
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 9462ff8..97f658f 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -3388,344 +3388,6 @@
return force_recode;
}
-#define DUMP_REF_FRAME_IMAGES 0
-
-#if DUMP_REF_FRAME_IMAGES == 1
-static int dump_one_image(AV1_COMMON *cm,
- const YV12_BUFFER_CONFIG *const ref_buf,
- char *file_name) {
- int h;
- FILE *f_ref = NULL;
-
- if (ref_buf == NULL) {
- printf("Frame data buffer is NULL.\n");
- return AOM_CODEC_MEM_ERROR;
- }
-
- if ((f_ref = fopen(file_name, "wb")) == NULL) {
- printf("Unable to open file %s to write.\n", file_name);
- return AOM_CODEC_MEM_ERROR;
- }
-
- // --- Y ---
- for (h = 0; h < cm->height; ++h) {
- fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref);
- }
- // --- U ---
- for (h = 0; h < (cm->height >> 1); ++h) {
- fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
- f_ref);
- }
- // --- V ---
- for (h = 0; h < (cm->height >> 1); ++h) {
- fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
- f_ref);
- }
-
- fclose(f_ref);
-
- return AOM_CODEC_OK;
-}
-
-static void dump_ref_frame_images(AV1_COMP *cpi) {
- AV1_COMMON *const cm = &cpi->common;
- MV_REFERENCE_FRAME ref_frame;
-
- for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
- char file_name[256] = "";
- snprintf(file_name, sizeof(file_name), "/tmp/enc_F%d_ref_%d.yuv",
- cm->current_frame.frame_number, ref_frame);
- dump_one_image(cm, get_ref_frame_yv12_buf(cpi, ref_frame), file_name);
- }
-}
-#endif // DUMP_REF_FRAME_IMAGES == 1
-
-// This function is used to shift the virtual indices of last reference frames
-// as follows:
-// LAST_FRAME -> LAST2_FRAME -> LAST3_FRAME
-// when the LAST_FRAME is updated.
-static INLINE void shift_last_ref_frames(AV1_COMP *cpi) {
- // TODO(isbs): shift the scaled indices as well
- for (int ref_frame = LAST3_FRAME; ref_frame > LAST_FRAME; --ref_frame) {
- const int ref_idx = ref_frame - LAST_FRAME;
- cpi->common.remapped_ref_idx[ref_idx] =
- cpi->common.remapped_ref_idx[ref_idx - 1];
-
- if (!cpi->rc.is_src_frame_alt_ref) {
- memcpy(cpi->interp_filter_selected[ref_frame],
- cpi->interp_filter_selected[ref_frame - 1],
- sizeof(cpi->interp_filter_selected[ref_frame - 1]));
- }
- }
-}
-
-// This function is used to shift the virtual indices of bwd reference
-// frames as follows:
-// BWD_REF -> ALT2_REF -> EXT_REF
-// to clear a space to store the closest bwdref
-static INLINE void rshift_bwd_ref_frames(AV1_COMP *cpi) {
- // TODO(isbs): shift the scaled indices as well
- static const int ordered_bwd[3] = { BWDREF_FRAME, ALTREF2_FRAME,
- EXTREF_FRAME };
-
- for (int i = 2; i > 0; --i) {
- // [0] is allocated to the current coded frame, i.e. bwdref
- memcpy(cpi->interp_filter_selected[ordered_bwd[i]],
- cpi->interp_filter_selected[ordered_bwd[i - 1]],
- sizeof(cpi->interp_filter_selected[ordered_bwd[i - 1]]));
-
- cpi->common.remapped_ref_idx[ordered_bwd[i] - LAST_FRAME] =
- cpi->common.remapped_ref_idx[ordered_bwd[i - 1] - LAST_FRAME];
- }
-}
-
-// This function is used to shift the virtual indices of bwd reference
-// frames as follows:
-// BWD_REF <- ALT2_REF <- EXT_REF
-// to update the bwd reference frame for coding the next frame.
-static INLINE void lshift_bwd_ref_frames(AV1_COMP *cpi) {
- // TODO(isbs): shift the scaled indices as well
- static const int ordered_bwd[3] = { BWDREF_FRAME, ALTREF2_FRAME,
- EXTREF_FRAME };
-
- for (int i = 0; i < 2; ++i) {
- // [0] is allocated to the current coded frame, i.e. bwdref
- memcpy(cpi->interp_filter_selected[ordered_bwd[i]],
- cpi->interp_filter_selected[ordered_bwd[i + 1]],
- sizeof(cpi->interp_filter_selected[ordered_bwd[i + 1]]));
-
- cpi->common.remapped_ref_idx[ordered_bwd[i] - LAST_FRAME] =
- cpi->common.remapped_ref_idx[ordered_bwd[i + 1] - LAST_FRAME];
- }
-}
-
-static void update_reference_frames(AV1_COMP *cpi) {
- AV1_COMMON *const cm = &cpi->common;
-
- // NOTE: Save the new show frame buffer index for --test-code=warn, i.e.,
- // for the purpose to verify no mismatch between encoder and decoder.
- if (cm->show_frame) cpi->last_show_frame_buf = cm->cur_frame;
-
- // 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) {
- // If we are not indicating to the decoder that this frame is
- // a show_existing_frame, which occurs in error_resilient mode,
- // we still want to refresh the LAST_FRAME when the current frame
- // was the source of an ext_arf.
- cpi->refresh_last_frame =
- !encode_show_existing_frame(cm) && cpi->rc.is_src_frame_ext_arf;
- 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;
- }
-
- // At this point the new frame has been encoded.
- // If any buffer copy / swapping is signaled it should be done here.
-
- // Only update all of the reference buffers if a KEY_FRAME is also a
- // show_frame. This ensures a fwd keyframe does not update all of the buffers
- if ((cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) ||
- frame_is_sframe(cm)) {
- for (int ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame) {
- assign_frame_buffer_p(&cm->ref_frame_map[cm->remapped_ref_idx[ref_frame]],
- cm->cur_frame);
- }
- return;
- }
-
- 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 in function
- // av1_bitstream.c::get_refresh_mask() we left it in the GF slot and, if
- // we're updating the GF with the current decoded frame, we save it to the
- // ARF slot instead.
- // We now have to update the ARF with the current frame and swap gld_fb_idx
- // and alt_fb_idx so that, overall, we've stored the old GF in the new ARF
- // slot and, if we're updating the GF, the current frame becomes the new GF.
- int tmp;
-
- // ARF in general is a better reference than overlay. We shouldkeep ARF as
- // reference instead of replacing it with overlay.
-
- if (!cpi->preserve_arf_as_gld) {
- assign_frame_buffer_p(
- &cm->ref_frame_map[get_ref_frame_map_idx(cm, ALTREF_FRAME)],
- cm->cur_frame);
- }
-
- tmp = get_ref_frame_map_idx(cm, ALTREF_FRAME);
- cm->remapped_ref_idx[ALTREF_FRAME - LAST_FRAME] =
- get_ref_frame_map_idx(cm, GOLDEN_FRAME);
- cm->remapped_ref_idx[GOLDEN_FRAME - LAST_FRAME] = tmp;
-
- // TODO(zoeliu): Do we need to copy cpi->interp_filter_selected[0] over to
- // cpi->interp_filter_selected[GOLDEN_FRAME]?
- } else if (cpi->rc.is_src_frame_ext_arf && encode_show_existing_frame(cm)) {
-#if CONFIG_DEBUG
- const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
- assert(gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE);
-#endif // CONFIG_DEBUG
- const int bwdref_to_show =
- (cpi->new_bwdref_update_rule == 1) ? BWDREF_FRAME : ALTREF2_FRAME;
- // Deal with the special case for showing existing internal ALTREF_FRAME
- // Refresh the LAST_FRAME with the ALTREF_FRAME and retire the LAST3_FRAME
- // by updating the virtual indices.
- const int last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME);
- shift_last_ref_frames(cpi);
-
- cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] =
- get_ref_frame_map_idx(cm, bwdref_to_show);
-
- memcpy(cpi->interp_filter_selected[LAST_FRAME],
- cpi->interp_filter_selected[bwdref_to_show],
- sizeof(cpi->interp_filter_selected[bwdref_to_show]));
- if (cpi->new_bwdref_update_rule == 1) {
- lshift_bwd_ref_frames(cpi);
- // pass outdated forward reference frame (previous LAST3) to the
- // spared space
- cm->remapped_ref_idx[EXTREF_FRAME - LAST_FRAME] = last3_remapped_idx;
- } else {
- cm->remapped_ref_idx[bwdref_to_show - LAST_FRAME] = last3_remapped_idx;
- }
- } else { /* For non key/golden frames */
- // === ALTREF_FRAME ===
- if (cpi->refresh_alt_ref_frame) {
- int arf_idx = get_ref_frame_map_idx(cm, ALTREF_FRAME);
- assign_frame_buffer_p(&cm->ref_frame_map[arf_idx], cm->cur_frame);
-
- memcpy(cpi->interp_filter_selected[ALTREF_FRAME],
- cpi->interp_filter_selected[0],
- sizeof(cpi->interp_filter_selected[0]));
- }
-
- // === GOLDEN_FRAME ===
- if (cpi->refresh_golden_frame) {
- assign_frame_buffer_p(
- &cm->ref_frame_map[get_ref_frame_map_idx(cm, GOLDEN_FRAME)],
- cm->cur_frame);
-
- memcpy(cpi->interp_filter_selected[GOLDEN_FRAME],
- cpi->interp_filter_selected[0],
- sizeof(cpi->interp_filter_selected[0]));
- }
-
- // === BWDREF_FRAME ===
- if (cpi->refresh_bwd_ref_frame) {
- if (cpi->new_bwdref_update_rule) {
- // We shift the backward reference frame as follows:
- // BWDREF -> ALTREF2 -> EXTREF
- // and assign the newly coded frame to BWDREF so that it always
- // keeps the nearest future frame
- const int tmp = get_ref_frame_map_idx(cm, EXTREF_FRAME);
- assign_frame_buffer_p(&cm->ref_frame_map[tmp], cm->cur_frame);
-
- rshift_bwd_ref_frames(cpi);
- cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = tmp;
- } else {
- assign_frame_buffer_p(
- &cm->ref_frame_map[get_ref_frame_map_idx(cm, BWDREF_FRAME)],
- cm->cur_frame);
- }
- memcpy(cpi->interp_filter_selected[BWDREF_FRAME],
- cpi->interp_filter_selected[0],
- sizeof(cpi->interp_filter_selected[0]));
- }
-
- // === ALTREF2_FRAME ===
- if (cpi->refresh_alt2_ref_frame) {
- assign_frame_buffer_p(
- &cm->ref_frame_map[get_ref_frame_map_idx(cm, ALTREF2_FRAME)],
- cm->cur_frame);
-
- memcpy(cpi->interp_filter_selected[ALTREF2_FRAME],
- cpi->interp_filter_selected[0],
- sizeof(cpi->interp_filter_selected[0]));
- }
- }
-
- if (cpi->refresh_last_frame) {
- // NOTE(zoeliu): We have two layers of mapping (1) from the per-frame
- // reference to the reference frame buffer virtual index; and then (2) from
- // the virtual index to the reference frame buffer (RefCntBuffer):
- //
- // LAST_FRAME, ..., EXTREF_FRAME
- // | |
- // v v
- // remapped_ref_idx[LAST_FRAME - 1], ..., remapped_ref_idx[EXTREF_FRAME - 1]
- // | |
- // v v
- // ref_frame_map[], ..., ref_frame_map[]
- //
- // When refresh_last_frame is set, it is intended to retire LAST3_FRAME,
- // have the other 2 LAST reference frames shifted as follows:
- // LAST_FRAME -> LAST2_FRAME -> LAST3_FRAME
- // , and then have LAST_FRAME refreshed by the newly coded frame.
- //
- // To fulfill it, the decoder will be notified to execute following 2 steps:
- //
- // (a) To change ref_frame_map[] and have the virtual index of LAST3_FRAME
- // to point to the newly coded frame, i.e.
- // ref_frame_map[lst_fb_idexes[2]] => cur_frame;
- //
- // (b) To change the 1st layer mapping to have LAST_FRAME mapped to the
- // original virtual index of LAST3_FRAME and have the other mappings
- // shifted as follows:
- // LAST_FRAME, LAST2_FRAME, LAST3_FRAME
- // | | |
- // v v v
- // remapped_ref_idx[2], remapped_ref_idx[0], remapped_ref_idx[1]
- assign_frame_buffer_p(
- &cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST3_FRAME)],
- cm->cur_frame);
-
- int last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME);
-
- shift_last_ref_frames(cpi);
- cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] = last3_remapped_idx;
-
- assert(!encode_show_existing_frame(cm));
- memcpy(cpi->interp_filter_selected[LAST_FRAME],
- cpi->interp_filter_selected[0],
- sizeof(cpi->interp_filter_selected[0]));
-
- // If the new structure is used, we will always have overlay frames coupled
- // with bwdref frames. Therefore, we won't have to perform this update
- // in advance (we do this update when the overlay frame shows up).
- if (cpi->new_bwdref_update_rule == 0 && cpi->rc.is_last_bipred_frame) {
- // Refresh the LAST_FRAME with the BWDREF_FRAME and retire the
- // LAST3_FRAME by updating the virtual indices.
- //
- // NOTE: The source frame for BWDREF does not have a holding position as
- // the OVERLAY frame for ALTREF's. Hence, to resolve the reference
- // virtual index reshuffling for BWDREF, the encoder always
- // specifies a LAST_BIPRED right before BWDREF and completes the
- // reshuffling job accordingly.
- last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME);
-
- shift_last_ref_frames(cpi);
- cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] =
- get_ref_frame_map_idx(cm, BWDREF_FRAME);
- cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = last3_remapped_idx;
-
- memcpy(cpi->interp_filter_selected[LAST_FRAME],
- cpi->interp_filter_selected[BWDREF_FRAME],
- sizeof(cpi->interp_filter_selected[BWDREF_FRAME]));
- }
- }
-
-#if DUMP_REF_FRAME_IMAGES == 1
- // Dump out all reference frame images.
- dump_ref_frame_images(cpi);
-#endif // DUMP_REF_FRAME_IMAGES
-}
-
static void scale_references(AV1_COMP *cpi) {
AV1_COMMON *cm = &cpi->common;
const int num_planes = av1_num_planes(cm);
@@ -4419,6 +4081,10 @@
frame_is_sframe(cm))
return 0xFF;
+ // show_existing_frames don't actually send refresh_frame_flags so set the
+ // flags to 0 to keep things consistent.
+ if (encode_show_existing_frame(cm)) return 0;
+
int refresh_mask = 0;
// NOTE(zoeliu): When LAST_FRAME is to get refreshed, the decoder will be
@@ -4440,7 +4106,7 @@
refresh_mask |=
(cpi->refresh_alt2_ref_frame << get_ref_frame_map_idx(cm, ALTREF2_FRAME));
- if (av1_preserve_existing_gf(cpi)) {
+ if (cpi->rc.is_src_frame_alt_ref && !cpi->rc.is_src_frame_ext_arf) {
// 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
@@ -5089,8 +4755,20 @@
return 0;
}
-static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest,
- unsigned int *frame_flags) {
+// Refresh reference frame buffers according to refresh_frame_flags.
+static void refresh_reference_frames(AV1_COMP *cpi) {
+ AV1_COMMON *const cm = &cpi->common;
+ // All buffers are refreshed for shown keyframes and S-frames.
+
+ for (int ref_frame = 0; ref_frame < REF_FRAMES; ref_frame++) {
+ if (((cm->current_frame.refresh_frame_flags >> ref_frame) & 1) == 1) {
+ assign_frame_buffer_p(&cm->ref_frame_map[ref_frame], cm->cur_frame);
+ }
+ }
+}
+
+static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
+ uint8_t *dest) {
AV1_COMMON *const cm = &cpi->common;
SequenceHeader *const seq_params = &cm->seq_params;
CurrentFrame *const current_frame = &cm->current_frame;
@@ -5117,10 +4795,6 @@
cpi->sf.interp_filter_search_mask = setup_interp_filter_search_mask(cpi);
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.
- cpi->frame_flags = *frame_flags;
-
restore_coding_context(cpi);
finalize_encoded_frame(cpi);
@@ -5144,26 +4818,11 @@
dump_filtered_recon_frames(cpi);
#endif // DUMP_RECON_FRAMES
- // Update the LAST_FRAME in the reference frame buffer.
- // NOTE:
- // (1) For BWDREF_FRAME as the show_existing_frame, the reference frame
- // update has been done previously when handling the LAST_BIPRED_FRAME
- // right before BWDREF_FRAME (in the display order);
- // (2) For INTNL_OVERLAY as the show_existing_frame, the reference frame
- // update will be done when the following is called, which will
- // exchange
- // the virtual indexes between LAST_FRAME and ALTREF2_FRAME, so that
- // LAST3 will get retired, LAST2 becomes LAST3, LAST becomes LAST2,
- // and
- // ALTREF2_FRAME will serve as the new LAST_FRAME.
- update_reference_frames(cpi);
+ // NOTE: Save the new show frame buffer index for --test-code=warn, i.e.,
+ // for the purpose to verify no mismatch between encoder and decoder.
+ if (cm->show_frame) cpi->last_show_frame_buf = cm->cur_frame;
- // Update frame flags
- cpi->frame_flags &= ~FRAMEFLAGS_GOLDEN;
- cpi->frame_flags &= ~FRAMEFLAGS_BWDREF;
- cpi->frame_flags &= ~FRAMEFLAGS_ALTREF;
-
- *frame_flags = cpi->frame_flags & ~FRAMEFLAGS_KEY;
+ refresh_reference_frames(cpi);
// Since we allocate a spot for the OVERLAY frame in the gf group, we need
// to do post-encoding update accordingly.
@@ -5380,7 +5039,11 @@
release_scaled_references(cpi);
}
- update_reference_frames(cpi);
+ // NOTE: Save the new show frame buffer index for --test-code=warn, i.e.,
+ // for the purpose to verify no mismatch between encoder and decoder.
+ if (cm->show_frame) cpi->last_show_frame_buf = cm->cur_frame;
+
+ refresh_reference_frames(cpi);
#if CONFIG_ENTROPY_STATS
av1_accumulate_frame_counts(&aggregate_fc, &cpi->counts);
@@ -5406,31 +5069,10 @@
#endif // EXT_TILE_DEBUG
#undef EXT_TILE_DEBUG
- if (cpi->refresh_golden_frame == 1)
- cpi->frame_flags |= FRAMEFLAGS_GOLDEN;
- else
- cpi->frame_flags &= ~FRAMEFLAGS_GOLDEN;
-
- if (cpi->refresh_alt_ref_frame == 1)
- cpi->frame_flags |= FRAMEFLAGS_ALTREF;
- else
- cpi->frame_flags &= ~FRAMEFLAGS_ALTREF;
-
- if (cpi->refresh_bwd_ref_frame == 1)
- cpi->frame_flags |= FRAMEFLAGS_BWDREF;
- else
- cpi->frame_flags &= ~FRAMEFLAGS_BWDREF;
cm->last_frame_type = current_frame->frame_type;
av1_rc_postencode_update(cpi, *size);
- if (current_frame->frame_type == KEY_FRAME) {
- // Tell the caller that the frame was coded as a key frame
- *frame_flags = cpi->frame_flags | FRAMEFLAGS_KEY;
- } else {
- *frame_flags = cpi->frame_flags & ~FRAMEFLAGS_KEY;
- }
-
// Store encoded frame's hash table for is_integer_mv() next time
if (oxcf->pass != 1 && cpi->common.allow_screen_content_tools) {
cpi->previous_hash_table = &cm->cur_frame->hash_table;
@@ -5478,6 +5120,9 @@
cpi->ref_frame_flags = frame_params->ref_frame_flags;
cpi->speed = frame_params->speed;
+ memcpy(cm->remapped_ref_idx, frame_params->remapped_ref_idx,
+ REF_FRAMES * sizeof(*cm->remapped_ref_idx));
+
cpi->refresh_last_frame = frame_params->refresh_last_frame;
cpi->refresh_golden_frame = frame_params->refresh_golden_frame;
cpi->refresh_bwd_ref_frame = frame_params->refresh_bwd_ref_frame;
@@ -5499,8 +5144,8 @@
if (cpi->oxcf.pass == 1) {
av1_first_pass(cpi, frame_input->ts_duration);
} else if (cpi->oxcf.pass == 0 || cpi->oxcf.pass == 2) {
- if (encode_frame_to_data_rate(cpi, &frame_results->size, dest,
- frame_params->frame_flags) != AOM_CODEC_OK) {
+ if (encode_frame_to_data_rate(cpi, &frame_results->size, dest) !=
+ AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
}
} else {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index f3b2bf8..5042f4f 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -862,8 +862,6 @@
int resize_pending_width;
int resize_pending_height;
- int frame_flags;
-
// ss_cfg[SS_CFG_LOOKAHEAD] : used only in temporal filtering
// ss_cfg[SS_CFG_SRC] : used everywhere except temporal filtering
search_site_config ss_cfg[SS_CFG_TOTAL];
@@ -976,6 +974,9 @@
// Bitmask of which reference buffers may be referenced by this frame
int ref_frame_flags;
+ // Reference buffer assignment for this frame.
+ int remapped_ref_idx[REF_FRAMES];
+
// Flags which determine which reference buffers are refreshed by this frame
int refresh_last_frame;
int refresh_golden_frame;
@@ -985,8 +986,6 @@
// Speed level to use for this frame: Bigger number means faster.
int speed;
-
- unsigned int *frame_flags;
};
typedef struct EncodeFrameParams EncodeFrameParams;
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index d5e8a36..5878803 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -1519,7 +1519,8 @@
#define DEFAULT_GRP_WEIGHT 1.0
void av1_get_second_pass_params(AV1_COMP *cpi,
- EncodeFrameParams *const frame_params) {
+ EncodeFrameParams *const frame_params,
+ unsigned int frame_flags) {
AV1_COMMON *const cm = &cpi->common;
CurrentFrame *const current_frame = &cm->current_frame;
RATE_CONTROL *const rc = &cpi->rc;
@@ -1599,7 +1600,7 @@
twopass->fr_content_type = FC_NORMAL;
// Keyframe and section processing.
- if (rc->frames_to_key == 0 || (cpi->frame_flags & FRAMEFLAGS_KEY)) {
+ if (rc->frames_to_key == 0 || (frame_flags & FRAMEFLAGS_KEY)) {
FIRSTPASS_STATS this_frame_copy;
this_frame_copy = this_frame;
frame_params->frame_type = KEY_FRAME;
diff --git a/av1/encoder/pass2_strategy.h b/av1/encoder/pass2_strategy.h
index dd2f80e..bf37746a 100644
--- a/av1/encoder/pass2_strategy.h
+++ b/av1/encoder/pass2_strategy.h
@@ -22,7 +22,8 @@
void av1_init_second_pass(struct AV1_COMP *cpi);
void av1_get_second_pass_params(struct AV1_COMP *cpi,
- struct EncodeFrameParams *const frame_params);
+ struct EncodeFrameParams *const frame_params,
+ unsigned int frame_flags);
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index f72a5db..f2b3813 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1515,7 +1515,8 @@
void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi,
FRAME_UPDATE_TYPE *const frame_update_type,
- EncodeFrameParams *const frame_params) {
+ EncodeFrameParams *const frame_params,
+ unsigned int frame_flags) {
AV1_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
CurrentFrame *const current_frame = &cm->current_frame;
@@ -1526,9 +1527,8 @@
int sframe_enabled = cpi->oxcf.sframe_enabled;
// TODO(yaowu): replace the "auto_key && 0" below with proper decision logic.
if (*frame_update_type != ARF_UPDATE &&
- (current_frame->frame_number == 0 ||
- (cpi->frame_flags & FRAMEFLAGS_KEY) || rc->frames_to_key == 0 ||
- (cpi->oxcf.auto_key && 0))) {
+ (current_frame->frame_number == 0 || (frame_flags & FRAMEFLAGS_KEY) ||
+ rc->frames_to_key == 0 || (cpi->oxcf.auto_key && 0))) {
frame_params->frame_type = KEY_FRAME;
rc->this_key_frame_forced =
current_frame->frame_number != 0 && rc->frames_to_key == 0;
@@ -1658,15 +1658,15 @@
void av1_rc_get_one_pass_cbr_params(AV1_COMP *cpi,
FRAME_UPDATE_TYPE *const frame_update_type,
- EncodeFrameParams *const frame_params) {
+ EncodeFrameParams *const frame_params,
+ unsigned int frame_flags) {
AV1_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
CurrentFrame *const current_frame = &cm->current_frame;
int target;
// TODO(yaowu): replace the "auto_key && 0" below with proper decision logic.
- if ((current_frame->frame_number == 0 ||
- (cpi->frame_flags & FRAMEFLAGS_KEY) || rc->frames_to_key == 0 ||
- (cpi->oxcf.auto_key && 0))) {
+ if ((current_frame->frame_number == 0 || (frame_flags & FRAMEFLAGS_KEY) ||
+ rc->frames_to_key == 0 || (cpi->oxcf.auto_key && 0))) {
frame_params->frame_type = KEY_FRAME;
rc->this_key_frame_forced =
current_frame->frame_number != 0 && rc->frames_to_key == 0;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 66faf25..5121c72 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -202,10 +202,10 @@
struct EncodeFrameParams;
void av1_rc_get_one_pass_vbr_params(
struct AV1_COMP *cpi, uint8_t *const frame_update_type,
- struct EncodeFrameParams *const frame_params);
+ struct EncodeFrameParams *const frame_params, unsigned int frame_flags);
void av1_rc_get_one_pass_cbr_params(
struct AV1_COMP *cpi, uint8_t *const frame_update_type,
- struct EncodeFrameParams *const frame_params);
+ struct EncodeFrameParams *const frame_params, unsigned int frame_flags);
// Post encode update of the rate control parameters based
// on bytes used