shithub: libvpx

Download patch

ref: 26bd81b955c0f20edc9ffad0a03f99edf485d0be
parent: 4b65837bc6d7d341e7c4be078d5a26e0bb717eeb
author: John Koleszar <jkoleszar@google.com>
date: Wed Jan 16 07:19:42 EST 2013

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

--- a/vp9/common/vp9_alloccommon.c
+++ b/vp9/common/vp9_alloccommon.c
@@ -87,14 +87,16 @@
     }
   }
 
-  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) {
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -38,6 +38,7 @@
 #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 @@
 
   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;
 
--- a/vp9/decoder/vp9_decodframe.c
+++ b/vp9/decoder/vp9_decodframe.c
@@ -1634,9 +1634,20 @@
    * 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);
--- a/vp9/decoder/vp9_onyxd_if.c
+++ b/vp9/decoder/vp9_onyxd_if.c
@@ -171,11 +171,7 @@
    * 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 @@
   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 @@
 
   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,
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -1772,10 +1772,30 @@
 
   // 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]);
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -2573,13 +2573,30 @@
 
   // 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);