From 26bd81b955c0f20edc9ffad0a03f99edf485d0be Mon Sep 17 00:00:00 2001 From: John Koleszar Date: Wed, 16 Jan 2013 12:19:42 -0800 Subject: [PATCH] Preserve the previous golden frame on golden updates This commit restores the quality lost when the buffer-to-buffer copy logic was removed. Note that this is specific to the current use of golden frames and will need rework when RTC functionality is added. Change-Id: I7324a75acd96eafd9e0f9b8633d782e390d5dc21 --- vp9/common/vp9_alloccommon.c | 14 ++++++++------ vp9/common/vp9_onyxc_int.h | 6 ++++++ vp9/decoder/vp9_decodframe.c | 13 ++++++++++++- vp9/decoder/vp9_onyxd_if.c | 12 ++++++------ vp9/encoder/vp9_bitstream.c | 26 +++++++++++++++++++++++--- vp9/encoder/vp9_onyx_if.c | 21 +++++++++++++++++++-- 6 files changed, 74 insertions(+), 18 deletions(-) diff --git a/vp9/common/vp9_alloccommon.c b/vp9/common/vp9_alloccommon.c index 895928b90..f2107d7aa 100644 --- a/vp9/common/vp9_alloccommon.c +++ b/vp9/common/vp9_alloccommon.c @@ -87,14 +87,16 @@ int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) { } } - oci->new_fb_idx = 0; + oci->new_fb_idx = NUM_YV12_BUFFERS - 1; + oci->fb_idx_ref_cnt[oci->new_fb_idx] = 1; + for (i = 0; i < 3; i++) - oci->active_ref_idx[i] = i + 1; + oci->active_ref_idx[i] = i; - oci->fb_idx_ref_cnt[0] = 1; - oci->fb_idx_ref_cnt[1] = 1; - oci->fb_idx_ref_cnt[2] = 1; - oci->fb_idx_ref_cnt[3] = 1; + for (i = 0; i < NUM_REF_FRAMES; i++) { + oci->ref_frame_map[i] = i; + oci->fb_idx_ref_cnt[i] = 1; + } if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, VP9BORDERINPIXELS) < 0) { diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index 46a9ff781..0f40e9faa 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -38,6 +38,7 @@ void vp9_initialize_common(void); #define QINDEX_RANGE (MAXQ + 1) #define NUM_REF_FRAMES 3 +#define NUM_REF_FRAMES_LG2 2 #define NUM_YV12_BUFFERS (NUM_REF_FRAMES + 1) #define NUM_FRAME_CONTEXTS_LG2 2 @@ -147,6 +148,11 @@ typedef struct VP9Common { YV12_BUFFER_CONFIG yv12_fb[NUM_YV12_BUFFERS]; int fb_idx_ref_cnt[NUM_YV12_BUFFERS]; /* reference counts */ + int ref_frame_map[NUM_REF_FRAMES]; /* maps fb_idx to reference slot */ + + /* TODO(jkoleszar): could expand active_ref_idx to 4, with 0 as intra, and + * roll new_fb_idx into it. + */ int active_ref_idx[3]; /* each frame can reference 3 buffers */ int new_fb_idx; diff --git a/vp9/decoder/vp9_decodframe.c b/vp9/decoder/vp9_decodframe.c index ca7b31f71..18e09e4c4 100644 --- a/vp9/decoder/vp9_decodframe.c +++ b/vp9/decoder/vp9_decodframe.c @@ -1634,10 +1634,21 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) { * For all non key frames the GF and ARF refresh flags and sign bias * flags must be set explicitly. */ - if (pc->frame_type != KEY_FRAME) { + if (pc->frame_type == KEY_FRAME) { + pc->active_ref_idx[0] = pc->new_fb_idx; + pc->active_ref_idx[1] = pc->new_fb_idx; + pc->active_ref_idx[2] = pc->new_fb_idx; + } else { /* Should the GF or ARF be updated from the current frame */ pbi->refresh_frame_flags = vp9_read_literal(&header_bc, NUM_REF_FRAMES); + /* Select active reference frames */ + for (i = 0; i < 3; i++) { + int ref_frame_num = vp9_read_literal(&header_bc, NUM_REF_FRAMES_LG2); + + pc->active_ref_idx[i] = pc->ref_frame_map[ref_frame_num]; + } + pc->ref_frame_sign_bias[GOLDEN_FRAME] = vp9_read_bit(&header_bc); pc->ref_frame_sign_bias[ALTREF_FRAME] = vp9_read_bit(&header_bc); diff --git a/vp9/decoder/vp9_onyxd_if.c b/vp9/decoder/vp9_onyxd_if.c index 1ab6fb23c..4fb610498 100644 --- a/vp9/decoder/vp9_onyxd_if.c +++ b/vp9/decoder/vp9_onyxd_if.c @@ -171,11 +171,7 @@ vpx_codec_err_t vp9_get_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag, * later commit that adds VP9-specific controls for this functionality. */ if (ref_frame_flag == VP9_LAST_FLAG) - ref_fb_idx = pbi->common.active_ref_idx[0]; - else if (ref_frame_flag == VP9_GOLD_FLAG) - ref_fb_idx = pbi->common.active_ref_idx[1]; - else if (ref_frame_flag == VP9_ALT_FLAG) - ref_fb_idx = pbi->common.active_ref_idx[2]; + ref_fb_idx = pbi->common.new_fb_idx; else { vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, "Invalid reference frame"); @@ -248,7 +244,7 @@ static void swap_frame_buffers(VP9D_COMP *pbi) { for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) { if (mask & 1) { ref_cnt_fb(pbi->common.fb_idx_ref_cnt, - &pbi->common.active_ref_idx[ref_index], + &pbi->common.ref_frame_map[ref_index], pbi->common.new_fb_idx); } ++ref_index; @@ -256,6 +252,10 @@ static void swap_frame_buffers(VP9D_COMP *pbi) { pbi->common.frame_to_show = &pbi->common.yv12_fb[pbi->common.new_fb_idx]; pbi->common.fb_idx_ref_cnt[pbi->common.new_fb_idx]--; + + /* Invalidate these references until the next frame starts. */ + for (ref_index = 0; ref_index < 3; ref_index++) + pbi->common.active_ref_idx[ref_index] = INT_MAX; } int vp9_receive_compressed_data(VP9D_PTR ptr, unsigned long size, diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index c02ae1b65..1a9d33dae 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -1772,10 +1772,30 @@ void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, // When there is a key frame all reference buffers are updated using the new key frame if (pc->frame_type != KEY_FRAME) { + int refresh_mask; + // Should the GF or ARF be updated using the transmitted frame or buffer - vp9_write_bit(&header_bc, cpi->refresh_alt_ref_frame); - vp9_write_bit(&header_bc, cpi->refresh_golden_frame); - vp9_write_bit(&header_bc, cpi->refresh_last_frame); + if (cpi->refresh_golden_frame && !cpi->refresh_alt_ref_frame) { + /* Preserve the previously existing golden frame and update the frame in + * the alt ref slot instead. This is highly specific to the use of + * alt-ref as a forward reference, and this needs to be generalized as + * other uses are implemented (like RTC/temporal scaling) + * + * gld_fb_idx and alt_fb_idx need to be swapped for future frames, but + * that happens in vp9_onyx_if.c:update_reference_frames() so that it can + * be done outside of the recode loop. + */ + refresh_mask = (cpi->refresh_last_frame << cpi->lst_fb_idx) | + (cpi->refresh_golden_frame << cpi->alt_fb_idx); + } else { + refresh_mask = (cpi->refresh_last_frame << cpi->lst_fb_idx) | + (cpi->refresh_golden_frame << cpi->gld_fb_idx) | + (cpi->refresh_alt_ref_frame << cpi->alt_fb_idx); + } + vp9_write_literal(&header_bc, refresh_mask, NUM_REF_FRAMES); + vp9_write_literal(&header_bc, cpi->lst_fb_idx, NUM_REF_FRAMES_LG2); + vp9_write_literal(&header_bc, cpi->gld_fb_idx, NUM_REF_FRAMES_LG2); + vp9_write_literal(&header_bc, cpi->alt_fb_idx, NUM_REF_FRAMES_LG2); // Indicate reference frame sign bias for Golden and ARF frames (always 0 for last frame buffer) vp9_write_bit(&header_bc, pc->ref_frame_sign_bias[GOLDEN_FRAME]); diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 0f087df1e..c288f93ef 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -2573,13 +2573,30 @@ static void update_reference_frames(VP9_COMP * const cpi) { // At this point the new frame has been encoded. // If any buffer copy / swapping is signaled it should be done here. - if (cm->frame_type == KEY_FRAME) { ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->active_ref_idx[cpi->gld_fb_idx], cm->new_fb_idx); ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->active_ref_idx[cpi->alt_fb_idx], cm->new_fb_idx); - } else { /* For non key frames */ + } else if (cpi->refresh_golden_frame && !cpi->refresh_alt_ref_frame) { + /* Preserve the previously existing golden frame and update the frame in + * the alt ref slot instead. This is highly specific to the current use of + * alt-ref as a forward reference, and this needs to be generalized as + * other uses are implemented (like RTC/temporal scaling) + * + * The update to the buffer in the alt ref slot was signalled in + * vp9_pack_bitstream(), now swap the buffer pointers so that it's treated + * as the golden frame next time. + */ + int tmp; + + ref_cnt_fb(cm->fb_idx_ref_cnt, + &cm->active_ref_idx[cpi->alt_fb_idx], cm->new_fb_idx); + + tmp = cpi->alt_fb_idx; + cpi->alt_fb_idx = cpi->gld_fb_idx; + cpi->gld_fb_idx = tmp; + } else { /* For non key/golden frames */ if (cpi->refresh_alt_ref_frame) { ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->active_ref_idx[cpi->alt_fb_idx], cm->new_fb_idx); -- 2.40.0