shithub: libvpx

Download patch

ref: 7b9984b38618d94e91f377634adf458b07a58f02
parent: 239511fad877863b7b8fdfba2c83449e753e679a
author: Marco Paniconi <marpan@google.com>
date: Mon Mar 26 16:25:57 EDT 2018

vp9-svc: Add logic to enable for constrained framedrop.

Add the logic for the constrained framdrop mode for SVC.

Add test case in datarate unittests.
Also lower target bitrates in the tests to better test
frame dropper.

Change-Id: I8ee1b8cb56d835c233ad1fbe0fc1456cb2e7291f

--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -1369,6 +1369,7 @@
     superframe_count_ = -1;
     key_frame_spacing_ = 9999;
     num_nonref_frames_ = 0;
+    constrained_framedrop_ = 0;
   }
   virtual void BeginPassHook(unsigned int /*pass*/) {}
 
@@ -1451,6 +1452,14 @@
       encoder->Control(VP9E_SET_ROW_MT, 1);
       encoder->Control(VP8E_SET_STATIC_THRESHOLD, 1);
       encoder->Control(VP9E_SET_TUNE_CONTENT, tune_content_);
+
+      if (constrained_framedrop_) {
+        vpx_svc_frame_drop_t svc_drop_frame;
+        svc_drop_frame.framedrop_mode = 1;
+        for (i = 0; i < number_spatial_layers_; i++)
+          svc_drop_frame.framedrop_thresh[i] = 30;
+        encoder->Control(VP9E_SET_SVC_FRAME_DROP_LAYER, &svc_drop_frame);
+      }
     }
 
     superframe_count_++;
@@ -1695,6 +1704,7 @@
   int superframe_count_;
   int key_frame_spacing_;
   unsigned int num_nonref_frames_;
+  int constrained_framedrop_;
 };
 
 // Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 1
@@ -1926,20 +1936,25 @@
   ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
   top_sl_width_ = 1280;
   top_sl_height_ = 720;
-  for (int i = 200; i <= 800; i += 300) {
-    cfg_.rc_target_bitrate = i;
-    ResetModel();
-    assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
-                          cfg_.ts_number_layers, cfg_.temporal_layering_mode,
-                          layer_target_avg_bandwidth_, bits_in_buffer_model_);
-    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
-    CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
-                            number_temporal_layers_, file_datarate_, 0.75, 1.2);
+  constrained_framedrop_ = 0;
+  for (int k = 0; k < 2; k++) {
+    for (int i = 200; i <= 600; i += 200) {
+      cfg_.rc_target_bitrate = i;
+      ResetModel();
+      constrained_framedrop_ = k;
+      assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
+                            cfg_.ts_number_layers, cfg_.temporal_layering_mode,
+                            layer_target_avg_bandwidth_, bits_in_buffer_model_);
+      ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+      CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
+                              number_temporal_layers_, file_datarate_, 0.75,
+                              1.2);
 #if CONFIG_VP9_DECODER
-    // The non-reference frames are expected to be mismatched frames as the
-    // encoder will avoid loopfilter on these frames.
-    EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+      // The non-reference frames are expected to be mismatched frames as the
+      // encoder will avoid loopfilter on these frames.
+      EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
 #endif
+    }
   }
 }
 
@@ -2222,20 +2237,25 @@
   ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
   top_sl_width_ = 1280;
   top_sl_height_ = 720;
-  for (int i = 200; i <= 800; i += 300) {
-    cfg_.rc_target_bitrate = i;
-    ResetModel();
-    assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
-                          cfg_.ts_number_layers, cfg_.temporal_layering_mode,
-                          layer_target_avg_bandwidth_, bits_in_buffer_model_);
-    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
-    CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
-                            number_temporal_layers_, file_datarate_, 0.73, 1.2);
+  constrained_framedrop_ = 0;
+  for (int k = 0; k < 2; k++) {
+    for (int i = 200; i <= 600; i += 200) {
+      cfg_.rc_target_bitrate = i;
+      ResetModel();
+      constrained_framedrop_ = k;
+      assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
+                            cfg_.ts_number_layers, cfg_.temporal_layering_mode,
+                            layer_target_avg_bandwidth_, bits_in_buffer_model_);
+      ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+      CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
+                              number_temporal_layers_, file_datarate_, 0.73,
+                              1.2);
 #if CONFIG_VP9_DECODER
-    // The non-reference frames are expected to be mismatched frames as the
-    // encoder will avoid loopfilter on these frames.
-    EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+      // The non-reference frames are expected to be mismatched frames as the
+      // encoder will avoid loopfilter on these frames.
+      EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
 #endif
+    }
   }
 }
 
--- a/test/encode_test_driver.h
+++ b/test/encode_test_driver.h
@@ -137,6 +137,11 @@
     const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
     ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
   }
+
+  void Control(int ctrl_id, struct vpx_svc_frame_drop *arg) {
+    const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
+    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
+  }
 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
   void Control(int ctrl_id, vpx_active_map_t *arg) {
     const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -4618,17 +4618,24 @@
   }
 
   // For 1 pass CBR, check if we are dropping this frame.
-  // Never drop on key frame, of if base layer is key for svc.
+  // Never drop on key frame, or if base layer is key for svc.
   if (oxcf->pass == 0 && oxcf->rc_mode == VPX_CBR &&
       cm->frame_type != KEY_FRAME &&
       (!cpi->use_svc ||
        !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame)) {
-    if (vp9_rc_drop_frame(cpi)) {
+    int svc_prev_layer_dropped = 0;
+    // In the contrained framedrop mode for svc (framedrop_mode = 1), if the
+    // previous spatial layer was dropped, drop the current spatial layer.
+    if (cpi->use_svc && cpi->svc.spatial_layer_id > 0 &&
+        cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id - 1])
+      svc_prev_layer_dropped = 1;
+    if ((svc_prev_layer_dropped && cpi->svc.framedrop_mode) ||
+        vp9_rc_drop_frame(cpi)) {
       vp9_rc_postencode_update_drop_frame(cpi);
       cpi->ext_refresh_frame_flags_pending = 0;
       cpi->last_frame_dropped = 1;
-      cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1;
       if (cpi->use_svc) {
+        cpi->svc.last_layer_dropped[cpi->svc.spatial_layer_id] = 1;
         cpi->svc.drop_spatial_layer[cpi->svc.spatial_layer_id] = 1;
         vp9_inc_frame_in_layer(cpi);
         cpi->svc.skip_enhancement_layer = 1;
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -771,7 +771,7 @@
  * spatial layers to drop.
  */
 typedef struct vpx_svc_frame_drop {
-  int framedrop_thresh[VPX_SS_MAX_LAYERS]; /**< Frame flags. */
+  int framedrop_thresh[VPX_SS_MAX_LAYERS]; /**< Frame drop thresholds */
   int framedrop_mode; /**< Layer-based or constrained dropping. */
 } vpx_svc_frame_drop_t;