]> granicus.if.org Git - libvpx/commitdiff
VP9 SVC: Add new level to constrain inter-layer pred.
authorJerome Jiang <jianj@google.com>
Wed, 25 Apr 2018 18:33:24 +0000 (11:33 -0700)
committerMarco Paniconi <marpan@google.com>
Fri, 27 Apr 2018 03:51:58 +0000 (20:51 -0700)
Add another level (INTER_LAYER_PRED_ON_CONSTRAINED) to the
inter-layer prediction control. This new level enforces the
condition that a given spatial layer S can only do inter-layer
prediction from the previous spatial layer (S - 1) from the same
time/superframe.

BUG=webm:1526

Change-Id: I0a1ec95b2c220c7b13a9a425d5fb0a8814c23c70

vp9/encoder/vp9_encoder.c
vp9/encoder/vp9_svc_layercontext.c
vp9/encoder/vp9_svc_layercontext.h

index 8cabe5723f43526267da1ec9013e9fc2647dbbb7..a936b0759560e866b1b398f873a7512c0ac07e1b 100644 (file)
@@ -3732,28 +3732,9 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
   suppress_active_map(cpi);
 
   // For SVC on non-zero spatial layer: check for disabling inter-layer
-  // (spatial) prediction, if svc.disable_inter_layer_pred is set.
-  // if the previous spatial layer was dropped then disable the prediction from
-  // this (scaled) reference.
-  if (cpi->use_svc && cpi->svc.spatial_layer_id > 0) {
-    if ((cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF_NONKEY &&
-         !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) ||
-        cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF ||
-        cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) {
-      MV_REFERENCE_FRAME ref_frame;
-      static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG,
-                                        VP9_ALT_FLAG };
-      for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
-        const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame);
-        if (yv12 != NULL && (cpi->ref_frame_flags & flag_list[ref_frame])) {
-          const struct scale_factors *const scale_fac =
-              &cm->frame_refs[ref_frame - 1].sf;
-          if (vp9_is_scaled(scale_fac))
-            cpi->ref_frame_flags &= (~flag_list[ref_frame]);
-        }
-      }
-    }
-  }
+  // prediction.
+  if (cpi->use_svc && cpi->svc.spatial_layer_id > 0)
+    vp9_svc_constrain_inter_layer_pred(cpi);
 
   // Variance adaptive and in frame q adjustment experiments are mutually
   // exclusive.
index e4caf9c7026a35d307e5d11f95ca7bd67bf3c505..c8196b718dd6cbf4f15ec8ec761c8a124ed8abec 100644 (file)
@@ -825,3 +825,63 @@ void vp9_svc_check_reset_layer_rc_flag(VP9_COMP *const cpi) {
     }
   }
 }
+
+void vp9_svc_constrain_inter_layer_pred(VP9_COMP *const cpi) {
+  VP9_COMMON *const cm = &cpi->common;
+  // Check for disabling inter-layer (spatial) prediction, if
+  // svc.disable_inter_layer_pred is set. If the previous spatial layer was
+  // dropped then disable the prediction from this (scaled) reference.
+  if ((cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF_NONKEY &&
+       !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) ||
+      cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_OFF ||
+      cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1]) {
+    MV_REFERENCE_FRAME ref_frame;
+    static const int flag_list[4] = { 0, VP9_LAST_FLAG, VP9_GOLD_FLAG,
+                                      VP9_ALT_FLAG };
+    for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+      const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame);
+      if (yv12 != NULL && (cpi->ref_frame_flags & flag_list[ref_frame])) {
+        const struct scale_factors *const scale_fac =
+            &cm->frame_refs[ref_frame - 1].sf;
+        if (vp9_is_scaled(scale_fac))
+          cpi->ref_frame_flags &= (~flag_list[ref_frame]);
+      }
+    }
+  }
+  // Check for disabling inter-layer prediction if
+  // INTER_LAYER_PRED_ON_CONSTRAINED is enabled.
+  // If the reference for inter-layer prediction (the reference that is scaled)
+  // is not the previous spatial layer from the same superframe, then we
+  // disable inter-layer prediction.
+  if (cpi->svc.disable_inter_layer_pred == INTER_LAYER_PRED_ON_CONSTRAINED) {
+    // We only use LAST and GOLDEN for prediction in real-time mode, so we
+    // check both here.
+    MV_REFERENCE_FRAME ref_frame;
+    for (ref_frame = LAST_FRAME; ref_frame <= GOLDEN_FRAME; ref_frame++) {
+      struct scale_factors *scale_fac = &cm->frame_refs[ref_frame - 1].sf;
+      if (vp9_is_scaled(scale_fac)) {
+        // If this reference  was updated on the previous spatial layer of the
+        // current superframe, then we keep this reference (don't disable).
+        // Otherwise we disable the inter-layer prediction.
+        // This condition is verified by checking if the current frame buffer
+        // index is equal to any of the slots for the previous spatial layer,
+        // and if so, check if that slot was updated/refreshed. If that is the
+        // case, then this reference is valid for inter-layer prediction under
+        // the mode INTER_LAYER_PRED_ON_CONSTRAINED.
+        int fb_idx =
+            ref_frame == LAST_FRAME ? cpi->lst_fb_idx : cpi->gld_fb_idx;
+        int ref_flag = ref_frame == LAST_FRAME ? VP9_LAST_FLAG : VP9_GOLD_FLAG;
+        int sl = cpi->svc.spatial_layer_id;
+        int disable = 1;
+        if ((fb_idx == cpi->svc.lst_fb_idx[sl - 1] &&
+             cpi->svc.update_last[sl - 1]) ||
+            (fb_idx == cpi->svc.gld_fb_idx[sl - 1] &&
+             cpi->svc.update_golden[sl - 1]) ||
+            (fb_idx == cpi->svc.alt_fb_idx[sl - 1] &&
+             cpi->svc.update_altref[sl - 1]))
+          disable = 0;
+        if (disable) cpi->ref_frame_flags &= (~ref_flag);
+      }
+    }
+  }
+}
index 48595302aabc48a52ae70a725b133370ec51496c..fb3127687f7ab30b23d8edcb09039d5db3216f34 100644 (file)
@@ -20,9 +20,16 @@ extern "C" {
 #endif
 
 typedef enum {
+  // Inter-layer prediction is on on all frames.
   INTER_LAYER_PRED_ON,
+  // Inter-layer prediction is off on all frames.
   INTER_LAYER_PRED_OFF,
-  INTER_LAYER_PRED_OFF_NONKEY
+  // Inter-layer prediction is off on non-key frames.
+  INTER_LAYER_PRED_OFF_NONKEY,
+  // Inter-layer prediction is on on all frames, but constrained such
+  // that any layer S (> 0) can only predict from previous spatial
+  // layer S-1, from the same superframe.
+  INTER_LAYER_PRED_ON_CONSTRAINED
 } INTER_LAYER_PRED;
 
 typedef struct {
@@ -188,6 +195,8 @@ void vp9_svc_reset_key_frame(struct VP9_COMP *const cpi);
 
 void vp9_svc_check_reset_layer_rc_flag(struct VP9_COMP *const cpi);
 
+void vp9_svc_constrain_inter_layer_pred(struct VP9_COMP *const cpi);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif