shithub: libvpx

Download patch

ref: 49785d3d0298ffc77915315bf1d37b26936128d1
parent: 87386826a95fda953162050a27f2506d8c1f3db5
author: Marco Paniconi <marpan@google.com>
date: Wed Jun 6 08:14:59 EDT 2018

vp9-svc: Add a buffer_idx is_used parameter for SVC.

For the case where a second (long term) temoral reference is
used in the SVC: this additional parameter is to make sure the
buffer slot selected for this reference is available for usage,
i.e., it is never used for any of the 3 references set for the
fixed SVC patterns.

And some code cleanup (replace cpi->svc).

No change in behavior.

Change-Id: Icba46edfbbefb94d5ea8e2d5c24cccd85a406ee6

--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -1837,24 +1837,23 @@
 void vp9_rc_get_svc_params(VP9_COMP *cpi) {
   VP9_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
+  SVC *const svc = &cpi->svc;
   int target = rc->avg_frame_bandwidth;
-  int layer =
-      LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id, cpi->svc.temporal_layer_id,
-                       cpi->svc.number_temporal_layers);
+  int layer = LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id,
+                               svc->number_temporal_layers);
   // Periodic key frames is based on the super-frame counter
   // (svc.current_superframe), also only base spatial layer is key frame.
   if ((cm->current_video_frame == 0) || (cpi->frame_flags & FRAMEFLAGS_KEY) ||
       (cpi->oxcf.auto_key &&
-       (cpi->svc.current_superframe % cpi->oxcf.key_freq == 0) &&
-       cpi->svc.spatial_layer_id == 0)) {
+       (svc->current_superframe % cpi->oxcf.key_freq == 0) &&
+       svc->spatial_layer_id == 0)) {
     cm->frame_type = KEY_FRAME;
     rc->source_alt_ref_active = 0;
     if (is_one_pass_cbr_svc(cpi)) {
       if (cm->current_video_frame > 0) vp9_svc_reset_key_frame(cpi);
-      layer = LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id,
-                               cpi->svc.temporal_layer_id,
-                               cpi->svc.number_temporal_layers);
-      cpi->svc.layer_context[layer].is_key_frame = 1;
+      layer = LAYER_IDS_TO_IDX(svc->spatial_layer_id, svc->temporal_layer_id,
+                               svc->number_temporal_layers);
+      svc->layer_context[layer].is_key_frame = 1;
       cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG);
       // Assumption here is that LAST_FRAME is being updated for a keyframe.
       // Thus no change in update flags.
@@ -1863,12 +1862,12 @@
   } else {
     cm->frame_type = INTER_FRAME;
     if (is_one_pass_cbr_svc(cpi)) {
-      LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer];
-      if (cpi->svc.spatial_layer_id == cpi->svc.first_spatial_layer_to_encode) {
+      LAYER_CONTEXT *lc = &svc->layer_context[layer];
+      if (svc->spatial_layer_id == svc->first_spatial_layer_to_encode) {
         lc->is_key_frame = 0;
       } else {
         lc->is_key_frame =
-            cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame;
+            svc->layer_context[svc->temporal_layer_id].is_key_frame;
       }
       target = calc_pframe_target_size_one_pass_cbr(cpi);
     }
@@ -1876,13 +1875,12 @@
   // If long term termporal feature is enabled, set the period of the update.
   // The update/refresh of this reference frame  is always on base temporal
   // layer frame.
-  if (cpi->svc.use_longterm_ref_current_layer &&
-      cpi->svc.temporal_layer_id == 0) {
-    if (cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) {
+  if (svc->use_longterm_ref_current_layer && svc->temporal_layer_id == 0) {
+    if (svc->layer_context[svc->temporal_layer_id].is_key_frame) {
       // On key frame we update the buffer index used for long term reference.
       // Use the alt_ref since it is not used or updated on key frames.
       cpi->ext_refresh_alt_ref_frame = 1;
-      cpi->alt_fb_idx = cpi->svc.buffer_idx_longterm_ref;
+      cpi->alt_fb_idx = svc->buffer_longterm_ref.idx;
     } else if (rc->frames_till_gf_update_due == 0) {
       // Set perdiod of next update. Make it a multiple of 10, as the cyclic
       // refresh is typically ~10%, and we'd like the update to happen after
@@ -1894,7 +1892,7 @@
       cpi->ext_refresh_golden_frame = 1;
       rc->gfu_boost = DEFAULT_GF_BOOST;
     }
-  } else if (!cpi->svc.use_longterm_ref) {
+  } else if (!svc->use_longterm_ref) {
     rc->frames_till_gf_update_due = INT_MAX;
     rc->baseline_gf_interval = INT_MAX;
   }
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -62,6 +62,9 @@
   }
   svc->max_consec_drop = INT_MAX;
 
+  svc->buffer_longterm_ref.idx = 7;
+  svc->buffer_longterm_ref.is_used = 0;
+
   if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) {
     if (vpx_realloc_frame_buffer(&cpi->svc.empty_frame.img, SMALL_FRAME_WIDTH,
                                  SMALL_FRAME_HEIGHT, cpi->common.subsampling_x,
@@ -673,24 +676,24 @@
 
 int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) {
   int width = 0, height = 0;
+  SVC *const svc = &cpi->svc;
   LAYER_CONTEXT *lc = NULL;
-  cpi->svc.skip_enhancement_layer = 0;
-  if (cpi->svc.number_spatial_layers > 1) {
-    cpi->svc.use_base_mv = 1;
-    cpi->svc.use_partition_reuse = 1;
+  svc->skip_enhancement_layer = 0;
+  if (svc->number_spatial_layers > 1) {
+    svc->use_base_mv = 1;
+    svc->use_partition_reuse = 1;
   }
-  cpi->svc.force_zero_mode_spatial_ref = 1;
-  cpi->svc.mi_stride[cpi->svc.spatial_layer_id] = cpi->common.mi_stride;
+  svc->force_zero_mode_spatial_ref = 1;
+  svc->mi_stride[svc->spatial_layer_id] = cpi->common.mi_stride;
 
-  if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) {
+  if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) {
     set_flags_and_fb_idx_for_temporal_mode3(cpi);
-  } else if (cpi->svc.temporal_layering_mode ==
+  } else if (svc->temporal_layering_mode ==
              VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING) {
     set_flags_and_fb_idx_for_temporal_mode_noLayering(cpi);
-  } else if (cpi->svc.temporal_layering_mode ==
-             VP9E_TEMPORAL_LAYERING_MODE_0101) {
+  } else if (svc->temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0101) {
     set_flags_and_fb_idx_for_temporal_mode2(cpi);
-  } else if (cpi->svc.temporal_layering_mode ==
+  } else if (svc->temporal_layering_mode ==
              VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
     // In the BYPASS/flexible mode, the encoder is relying on the application
     // to specify, for each spatial layer, the flags and buffer indices for the
@@ -702,37 +705,41 @@
     // this case.
     if (cpi->ext_refresh_frame_flags_pending == 0) {
       int sl;
-      cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
-      sl = cpi->svc.spatial_layer_id;
-      vp9_apply_encoding_flags(cpi, cpi->svc.ext_frame_flags[sl]);
-      cpi->lst_fb_idx = cpi->svc.lst_fb_idx[sl];
-      cpi->gld_fb_idx = cpi->svc.gld_fb_idx[sl];
-      cpi->alt_fb_idx = cpi->svc.alt_fb_idx[sl];
+      svc->spatial_layer_id = svc->spatial_layer_to_encode;
+      sl = svc->spatial_layer_id;
+      vp9_apply_encoding_flags(cpi, svc->ext_frame_flags[sl]);
+      cpi->lst_fb_idx = svc->lst_fb_idx[sl];
+      cpi->gld_fb_idx = svc->gld_fb_idx[sl];
+      cpi->alt_fb_idx = svc->alt_fb_idx[sl];
     }
   }
 
+  if (cpi->lst_fb_idx == svc->buffer_longterm_ref.idx ||
+      cpi->gld_fb_idx == svc->buffer_longterm_ref.idx ||
+      cpi->alt_fb_idx == svc->buffer_longterm_ref.idx)
+    svc->buffer_longterm_ref.is_used = 1;
+
   // For the fixed (non-flexible/bypass) SVC mode:
   // If long term temporal reference is enabled at the sequence level
   // (use_longterm_ref == 1), and inter_layer is disabled (on inter-frames),
   // we can use golden as a second temporal reference
   // (since the spatial/inter-layer reference is disabled).
-  // To be safe we use fb_index 7 for this, since for 3-3 layer system slot 7
-  // should be free/un-used. For now usage of this second temporal reference
-  // will only be used for highest spatial layer.
-  cpi->svc.use_longterm_ref_current_layer = 0;
-  cpi->svc.buffer_idx_longterm_ref = 7;
-  if (cpi->svc.use_longterm_ref &&
-      cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS &&
-      cpi->svc.disable_inter_layer_pred != INTER_LAYER_PRED_ON &&
-      cpi->svc.number_spatial_layers <= 3 &&
-      cpi->svc.number_temporal_layers <= 3 &&
-      cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) {
+  // We check that the fb_idx for this reference (buffer_longterm_ref.idx) is
+  // unused (slot 7 should be available for 3-3 layer system).
+  // For now usage of this second temporal reference will only be used for
+  // highest spatial layer.
+  svc->use_longterm_ref_current_layer = 0;
+  if (svc->use_longterm_ref && !svc->buffer_longterm_ref.is_used &&
+      svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS &&
+      svc->disable_inter_layer_pred != INTER_LAYER_PRED_ON &&
+      svc->number_spatial_layers <= 3 && svc->number_temporal_layers <= 3 &&
+      svc->spatial_layer_id == svc->number_spatial_layers - 1) {
     // Enable the second (long-term) temporal reference at the frame-level.
-    cpi->svc.use_longterm_ref_current_layer = 1;
+    svc->use_longterm_ref_current_layer = 1;
     // Only used for prediction for on non-key superframes.
-    if (!cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) {
+    if (!svc->layer_context[svc->temporal_layer_id].is_key_frame) {
       // Use golden for this reference which will be used for prediction.
-      cpi->gld_fb_idx = cpi->svc.buffer_idx_longterm_ref;
+      cpi->gld_fb_idx = svc->buffer_longterm_ref.idx;
       // Enable prediction off LAST (last reference) and golden (which will
       // generally be further behind/long-term reference).
       cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
@@ -740,32 +747,31 @@
   }
 
   // Reset the drop flags for all spatial layers, on the base layer.
-  if (cpi->svc.spatial_layer_id == 0) {
-    vp9_zero(cpi->svc.drop_spatial_layer);
-    // TODO(jianj/marpan): Investigate why setting cpi->svc.lst/gld/alt_fb_idx
+  if (svc->spatial_layer_id == 0) {
+    vp9_zero(svc->drop_spatial_layer);
+    // TODO(jianj/marpan): Investigate why setting svc->lst/gld/alt_fb_idx
     // causes an issue with frame dropping and temporal layers, when the frame
     // flags are passed via the encode call (bypass mode). Issue is that we're
     // resetting ext_refresh_frame_flags_pending to 0 on frame drops.
-    if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
-      memset(&cpi->svc.lst_fb_idx, -1, sizeof(cpi->svc.lst_fb_idx));
-      memset(&cpi->svc.gld_fb_idx, -1, sizeof(cpi->svc.lst_fb_idx));
-      memset(&cpi->svc.alt_fb_idx, -1, sizeof(cpi->svc.lst_fb_idx));
+    if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
+      memset(&svc->lst_fb_idx, -1, sizeof(svc->lst_fb_idx));
+      memset(&svc->gld_fb_idx, -1, sizeof(svc->lst_fb_idx));
+      memset(&svc->alt_fb_idx, -1, sizeof(svc->lst_fb_idx));
     }
-    vp9_zero(cpi->svc.update_last);
-    vp9_zero(cpi->svc.update_golden);
-    vp9_zero(cpi->svc.update_altref);
-    vp9_zero(cpi->svc.reference_last);
-    vp9_zero(cpi->svc.reference_golden);
-    vp9_zero(cpi->svc.reference_altref);
+    vp9_zero(svc->update_last);
+    vp9_zero(svc->update_golden);
+    vp9_zero(svc->update_altref);
+    vp9_zero(svc->reference_last);
+    vp9_zero(svc->reference_golden);
+    vp9_zero(svc->reference_altref);
   }
 
-  lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
-                                   cpi->svc.number_temporal_layers +
-                               cpi->svc.temporal_layer_id];
+  lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers +
+                           svc->temporal_layer_id];
 
   // Setting the worst/best_quality via the encoder control: SET_SVC_PARAMETERS,
   // only for non-BYPASS mode for now.
-  if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
+  if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
     RATE_CONTROL *const lrc = &lc->rc;
     lrc->worst_quality = vp9_quantizer_to_qindex(lc->max_q);
     lrc->best_quality = vp9_quantizer_to_qindex(lc->min_q);
@@ -777,15 +783,13 @@
 
   // Use Eightap_smooth for low resolutions.
   if (width * height <= 320 * 240)
-    cpi->svc.downsample_filter_type[cpi->svc.spatial_layer_id] =
-        EIGHTTAP_SMOOTH;
+    svc->downsample_filter_type[svc->spatial_layer_id] = EIGHTTAP_SMOOTH;
   // For scale factors > 0.75, set the phase to 0 (aligns decimated pixel
   // to source pixel).
-  lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
-                                   cpi->svc.number_temporal_layers +
-                               cpi->svc.temporal_layer_id];
+  lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers +
+                           svc->temporal_layer_id];
   if (lc->scaling_factor_num > (3 * lc->scaling_factor_den) >> 2)
-    cpi->svc.downsample_filter_phase[cpi->svc.spatial_layer_id] = 0;
+    svc->downsample_filter_phase[svc->spatial_layer_id] = 0;
 
   // The usage of use_base_mv or partition_reuse assumes down-scale of 2x2.
   // For now, turn off use of base motion vectors and partition reuse if the
@@ -792,45 +796,45 @@
   // spatial scale factors for any layers are not 2,
   // keep the case of 3 spatial layers with scale factor of 4x4 for base layer.
   // TODO(marpan): Fix this to allow for use_base_mv for scale factors != 2.
-  if (cpi->svc.number_spatial_layers > 1) {
+  if (svc->number_spatial_layers > 1) {
     int sl;
-    for (sl = 0; sl < cpi->svc.number_spatial_layers - 1; ++sl) {
-      lc = &cpi->svc.layer_context[sl * cpi->svc.number_temporal_layers +
-                                   cpi->svc.temporal_layer_id];
+    for (sl = 0; sl < svc->number_spatial_layers - 1; ++sl) {
+      lc = &svc->layer_context[sl * svc->number_temporal_layers +
+                               svc->temporal_layer_id];
       if ((lc->scaling_factor_num != lc->scaling_factor_den >> 1) &&
           !(lc->scaling_factor_num == lc->scaling_factor_den >> 2 && sl == 0 &&
-            cpi->svc.number_spatial_layers == 3)) {
-        cpi->svc.use_base_mv = 0;
-        cpi->svc.use_partition_reuse = 0;
+            svc->number_spatial_layers == 3)) {
+        svc->use_base_mv = 0;
+        svc->use_partition_reuse = 0;
         break;
       }
     }
     // For non-zero spatial layers: if the previous spatial layer was dropped
     // disable the base_mv and partition_reuse features.
-    if (cpi->svc.spatial_layer_id > 0 &&
-        cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) {
-      cpi->svc.use_base_mv = 0;
-      cpi->svc.use_partition_reuse = 0;
+    if (svc->spatial_layer_id > 0 &&
+        svc->drop_spatial_layer[svc->spatial_layer_id - 1]) {
+      svc->use_base_mv = 0;
+      svc->use_partition_reuse = 0;
     }
   }
 
-  cpi->svc.non_reference_frame = 0;
+  svc->non_reference_frame = 0;
   if (cpi->common.frame_type != KEY_FRAME && !cpi->ext_refresh_last_frame &&
       !cpi->ext_refresh_golden_frame && !cpi->ext_refresh_alt_ref_frame) {
-    cpi->svc.non_reference_frame = 1;
+    svc->non_reference_frame = 1;
   }
 
-  if (cpi->svc.spatial_layer_id == 0) cpi->svc.high_source_sad_superframe = 0;
+  if (svc->spatial_layer_id == 0) svc->high_source_sad_superframe = 0;
 
-  if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS &&
-      cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] &&
-      cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id] != -1 &&
-      !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) {
+  if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS &&
+      svc->last_layer_dropped[svc->spatial_layer_id] &&
+      svc->fb_idx_upd_tl0[svc->spatial_layer_id] != -1 &&
+      !svc->layer_context[svc->temporal_layer_id].is_key_frame) {
     // For fixed/non-flexible mode, if the previous frame (same spatial layer
     // from previous superframe) was dropped, make sure the lst_fb_idx
     // for this frame corresponds to the buffer index updated on (last) encoded
     // TL0 frame (with same spatial layer).
-    cpi->lst_fb_idx = cpi->svc.fb_idx_upd_tl0[cpi->svc.spatial_layer_id];
+    cpi->lst_fb_idx = svc->fb_idx_upd_tl0[svc->spatial_layer_id];
   }
 
   if (vp9_set_size_literal(cpi, width, height) != 0)
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -32,6 +32,11 @@
   INTER_LAYER_PRED_ON_CONSTRAINED
 } INTER_LAYER_PRED;
 
+typedef struct BUFFER_LONGTERM_REF {
+  int idx;
+  int is_used;
+} BUFFER_LONGTERM_REF;
+
 typedef struct {
   RATE_CONTROL rc;
   int target_bandwidth;
@@ -101,7 +106,7 @@
   int use_longterm_ref;
   // Frame level flag to enable second (long term) temporal reference.
   int use_longterm_ref_current_layer;
-  int buffer_idx_longterm_ref;
+  BUFFER_LONGTERM_REF buffer_longterm_ref;
   int current_superframe;
   int non_reference_frame;
   int use_base_mv;