Set up explicit reference frame maps in GF_GROUP
- Add two arrays ref_frame_disp_idx and ref_frame_gop_idx, holding
gop indices and display order indices of reference frames of frames
in the current gop.
- Rename 'frame_gop_index' as 'frame_disp_idx' because the values
are indices in display order
- If a reference frame, other than the golden frame, is not in the
current gop, the index is set as -1
- TODO: need to figure out how to handle (1) S frame (2) no show
key frame (3) error resilient mode (4) INTNL_OVERLAY_UPDATE frame
with show_existing_frame off.
Change-Id: Ica311c800052784acc8f3aa70405ab66ee7e8ece
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index a6c5336..7897015 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -119,8 +119,10 @@
unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char arf_update_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char arf_pos_in_gf[MAX_STATIC_GF_GROUP_LENGTH + 1];
- unsigned char frame_gop_index[MAX_STATIC_GF_GROUP_LENGTH + 1];
+ unsigned char frame_disp_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char pyramid_level[MAX_STATIC_GF_GROUP_LENGTH + 1];
+ int ref_frame_disp_idx[MAX_STATIC_GF_GROUP_LENGTH + 1][REF_FRAMES];
+ int ref_frame_gop_idx[MAX_STATIC_GF_GROUP_LENGTH + 1][REF_FRAMES];
unsigned char pyramid_height;
unsigned char pyramid_lvl_nodes[MAX_PYRAMID_LVL];
int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH + 1];
diff --git a/av1/encoder/gop_structure.c b/av1/encoder/gop_structure.c
index 66f96b3..af9da59 100644
--- a/av1/encoder/gop_structure.c
+++ b/av1/encoder/gop_structure.c
@@ -42,7 +42,7 @@
gf_group->arf_src_offset[*frame_ind] = 0;
gf_group->arf_pos_in_gf[*frame_ind] = 0;
gf_group->arf_update_idx[*frame_ind] = arf_ind;
- gf_group->frame_gop_index[*frame_ind] = start;
+ gf_group->frame_disp_idx[*frame_ind] = start;
gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL;
++gf_group->pyramid_lvl_nodes[MIN_PYRAMID_LVL];
++(*frame_ind);
@@ -56,7 +56,7 @@
gf_group->arf_src_offset[*frame_ind] = m - start - 1;
gf_group->arf_pos_in_gf[*frame_ind] = 0;
gf_group->arf_update_idx[*frame_ind] = 1; // mark all internal ARF 1
- gf_group->frame_gop_index[*frame_ind] = m;
+ gf_group->frame_disp_idx[*frame_ind] = m;
gf_group->pyramid_level[*frame_ind] = level;
++gf_group->pyramid_lvl_nodes[level];
++(*frame_ind);
@@ -69,7 +69,7 @@
gf_group->arf_src_offset[*frame_ind] = 0;
gf_group->arf_pos_in_gf[*frame_ind] = arf_pos_in_gf; // For bit allocation.
gf_group->arf_update_idx[*frame_ind] = 1;
- gf_group->frame_gop_index[*frame_ind] = m;
+ gf_group->frame_disp_idx[*frame_ind] = m;
gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL;
++(*frame_ind);
@@ -104,7 +104,7 @@
gf_group->arf_src_offset[frame_index] = gf_interval - 1;
gf_group->arf_pos_in_gf[frame_index] = 0;
gf_group->arf_update_idx[frame_index] = 0;
- gf_group->frame_gop_index[frame_index] = gf_interval;
+ gf_group->frame_disp_idx[frame_index] = gf_interval;
gf_group->pyramid_level[frame_index] = gf_group->pyramid_height;
++frame_index;
}
@@ -169,6 +169,136 @@
cpi->oxcf.gf_max_pyr_height);
}
+#define REF_IDX(ref) ((ref)-LAST_FRAME)
+
+static INLINE void reset_ref_frame_idx(int *ref_idx, int reset_value) {
+ for (int i = 0; i < REF_FRAMES; ++i) ref_idx[i] = reset_value;
+}
+
+static INLINE void set_ref_frame_disp_idx(GF_GROUP *const gf_group) {
+ for (int i = 0; i <= gf_group->size; ++i) {
+ for (int ref = 0; ref < INTER_REFS_PER_FRAME + 1; ++ref) {
+ int ref_gop_idx = gf_group->ref_frame_gop_idx[i][ref];
+ if (ref_gop_idx == -1) {
+ gf_group->ref_frame_disp_idx[i][ref] = -1;
+ } else {
+ gf_group->ref_frame_disp_idx[i][ref] =
+ gf_group->frame_disp_idx[ref_gop_idx];
+ }
+ }
+ }
+}
+
+static void set_gop_ref_frame_map(GF_GROUP *const gf_group) {
+ // Initialize the reference slots as all -1.
+ for (int frame_idx = 0; frame_idx <= gf_group->size; ++frame_idx)
+ reset_ref_frame_idx(gf_group->ref_frame_gop_idx[frame_idx], -1);
+
+ // Set the map for frames in the current gop
+ for (int frame_idx = 0; frame_idx < gf_group->size; ++frame_idx) {
+ const FRAME_UPDATE_TYPE update_type = gf_group->update_type[frame_idx];
+ // TODO(yuec): need to figure out how to determine
+ // (1) whether a KEY_FRAME has show_frame on
+ // (2) whether a frame with INTNL_OVERLAY_UPDATE type has
+ // show_existing_frame on
+ const int show_frame =
+ update_type != ARF_UPDATE && update_type != INTNL_ARF_UPDATE;
+ const int show_existing_frame =
+ update_type == OVERLAY_UPDATE || update_type == INTNL_OVERLAY_UPDATE;
+
+ int this_ref_map[INTER_REFS_PER_FRAME + 1];
+ memcpy(this_ref_map, gf_group->ref_frame_gop_idx[frame_idx],
+ sizeof(this_ref_map));
+ int *next_ref_map = &gf_group->ref_frame_gop_idx[frame_idx + 1][0];
+
+ switch (update_type) {
+ case KF_UPDATE:
+ if (show_frame) {
+ reset_ref_frame_idx(this_ref_map, frame_idx);
+ } else {
+ this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(EXTREF_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(ALTREF2_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(GOLDEN_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx;
+ }
+ break;
+ case LF_UPDATE: this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx; break;
+ case GF_UPDATE:
+ this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(GOLDEN_FRAME)] = frame_idx;
+ break;
+ case OVERLAY_UPDATE:
+ this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx;
+ break;
+ case ARF_UPDATE: this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx; break;
+ case INTNL_OVERLAY_UPDATE:
+ if (!show_existing_frame)
+ this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+ break;
+ case INTNL_ARF_UPDATE:
+ this_ref_map[REF_IDX(EXTREF_FRAME)] = frame_idx;
+ break;
+ default: assert(0); break;
+ }
+
+ memcpy(next_ref_map, this_ref_map, sizeof(this_ref_map));
+
+ switch (update_type) {
+ case LF_UPDATE:
+ case GF_UPDATE:
+ next_ref_map[REF_IDX(LAST3_FRAME)] = this_ref_map[REF_IDX(LAST2_FRAME)];
+ next_ref_map[REF_IDX(LAST2_FRAME)] = this_ref_map[REF_IDX(LAST_FRAME)];
+ next_ref_map[REF_IDX(LAST_FRAME)] = this_ref_map[REF_IDX(LAST3_FRAME)];
+ break;
+ case INTNL_OVERLAY_UPDATE:
+ if (!show_existing_frame) {
+ next_ref_map[REF_IDX(LAST3_FRAME)] =
+ this_ref_map[REF_IDX(LAST2_FRAME)];
+ next_ref_map[REF_IDX(LAST2_FRAME)] =
+ this_ref_map[REF_IDX(LAST_FRAME)];
+ next_ref_map[REF_IDX(LAST_FRAME)] =
+ this_ref_map[REF_IDX(LAST3_FRAME)];
+ } else {
+ next_ref_map[REF_IDX(LAST_FRAME)] =
+ this_ref_map[REF_IDX(BWDREF_FRAME)];
+ next_ref_map[REF_IDX(LAST2_FRAME)] =
+ this_ref_map[REF_IDX(LAST_FRAME)];
+ next_ref_map[REF_IDX(LAST3_FRAME)] =
+ this_ref_map[REF_IDX(LAST2_FRAME)];
+ next_ref_map[REF_IDX(BWDREF_FRAME)] =
+ this_ref_map[REF_IDX(ALTREF2_FRAME)];
+ next_ref_map[REF_IDX(ALTREF2_FRAME)] =
+ this_ref_map[REF_IDX(EXTREF_FRAME)];
+ next_ref_map[REF_IDX(EXTREF_FRAME)] =
+ this_ref_map[REF_IDX(LAST3_FRAME)];
+ }
+ break;
+ case INTNL_ARF_UPDATE:
+ if (!show_existing_frame) {
+ next_ref_map[REF_IDX(BWDREF_FRAME)] =
+ this_ref_map[REF_IDX(EXTREF_FRAME)];
+ next_ref_map[REF_IDX(ALTREF2_FRAME)] =
+ this_ref_map[REF_IDX(BWDREF_FRAME)];
+ next_ref_map[REF_IDX(EXTREF_FRAME)] =
+ this_ref_map[REF_IDX(ALTREF2_FRAME)];
+ }
+ break;
+ case OVERLAY_UPDATE:
+ next_ref_map[REF_IDX(ALTREF_FRAME)] =
+ this_ref_map[REF_IDX(GOLDEN_FRAME)];
+ next_ref_map[REF_IDX(GOLDEN_FRAME)] =
+ this_ref_map[REF_IDX(ALTREF_FRAME)];
+ break;
+ default: break;
+ }
+ }
+
+ // Set the map in display order index by converting from gop indices in the
+ // above map
+ set_ref_frame_disp_idx(gf_group);
+}
+
void av1_gop_setup_structure(AV1_COMP *cpi,
const EncodeFrameParams *const frame_params) {
RATE_CONTROL *const rc = &cpi->rc;
@@ -190,6 +320,8 @@
gf_group->arf_update_idx[gf_group->size] = 0;
gf_group->arf_pos_in_gf[gf_group->size] = 0;
+ set_gop_ref_frame_map(gf_group);
+
#if CHECK_GF_PARAMETER
check_frame_params(gf_group, rc->baseline_gf_interval);
#endif
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 2381a3c..4b2075c 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -517,7 +517,7 @@
// Initialize P frames
for (frame_idx = 2; frame_idx < MAX_LAG_BUFFERS; ++frame_idx) {
struct lookahead_entry *buf;
- frame_gop_offset = gf_group->frame_gop_index[frame_idx];
+ frame_gop_offset = gf_group->frame_disp_idx[frame_idx];
buf = av1_lookahead_peek(cpi->lookahead, frame_gop_offset - 1);
if (buf == NULL) break;