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;