Updates for 1-pass CBR rate control.

Adjustments based on buffer level, frame dropper.

Change-Id: Iaa85b570493526a60c4b9fb7ded4c0226b1b3a33
diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index 2d46522..40a968c 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -193,7 +193,10 @@
 
   virtual void ResetModel() {
     last_pts_ = 0;
+    bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
     frame_number_ = 0;
+    first_drop_ = 0;
+    num_drops_ = 0;
     bits_total_ = 0;
     duration_ = 0.0;
   }
@@ -209,8 +212,29 @@
   }
 
   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
+    // Time since last timestamp = duration.
+    vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
+
+    // Add to the buffer the bits we'd expect from a constant bitrate server.
+    bits_in_buffer_model_ += duration * timebase_ * cfg_.rc_target_bitrate
+        * 1000;
+
+    // Buffer should not go negative.
+    ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame "
+        << pkt->data.frame.pts;
+
     const int frame_size_in_bits = pkt->data.frame.sz * 8;
     bits_total_ += frame_size_in_bits;
+
+    // If first drop not set and we have a drop set it to this time.
+    if (!first_drop_ && duration > 1)
+      first_drop_ = last_pts_ + 1;
+
+    // Update the number of frame drops.
+    if (duration > 1) {
+      num_drops_+= (duration - 1);
+    }
+
     // Update the most recent pts.
     last_pts_ = pkt->data.frame.pts;
     ++frame_number_;
@@ -231,13 +255,17 @@
   double duration_;
   double effective_datarate_;
   int set_cpu_used_;
+  int bits_in_buffer_model_;
+  int first_drop_;
+  int num_drops_;
 };
 
-// There is no buffer model/frame dropper in VP9 currently, so for now we
-// have separate test for VP9 rate targeting for 1-pass CBR. We only check
-// that effective datarate is within some range of target bitrate.
-// No frame dropper, so we can't go to low bitrates.
+// Check basic rate targeting,
 TEST_P(DatarateTestVP9, BasicRateTargeting) {
+  cfg_.rc_buf_initial_sz = 500;
+  cfg_.rc_buf_optimal_sz = 500;
+  cfg_.rc_buf_sz = 1000;
+  cfg_.rc_dropframe_thresh = 1;
   cfg_.rc_min_quantizer = 0;
   cfg_.rc_max_quantizer = 63;
   cfg_.rc_end_usage = VPX_CBR;
@@ -257,6 +285,49 @@
   }
 }
 
+// Check that (1) the first dropped frame gets earlier and earlier
+// as the drop frame threshold is increased, and (2) that the total number of
+// frame drops does not decrease as we increase frame drop threshold.
+// Use a lower qp-max to force some frame drops.
+TEST_P(DatarateTestVP9, ChangingDropFrameThresh) {
+  cfg_.rc_buf_initial_sz = 500;
+  cfg_.rc_buf_optimal_sz = 500;
+  cfg_.rc_buf_sz = 1000;
+  cfg_.rc_undershoot_pct = 20;
+  cfg_.rc_undershoot_pct = 20;
+  cfg_.rc_dropframe_thresh = 10;
+  cfg_.rc_min_quantizer = 0;
+  cfg_.rc_max_quantizer = 50;
+  cfg_.rc_end_usage = VPX_CBR;
+  cfg_.rc_target_bitrate = 200;
+
+  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+                                       30, 1, 0, 140);
+
+  const int kDropFrameThreshTestStep = 30;
+  int last_drop = 140;
+  int last_num_drops = 0;
+  for (int i = 10; i < 100; i += kDropFrameThreshTestStep) {
+    cfg_.rc_dropframe_thresh = i;
+    ResetModel();
+    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+    ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85)
+           << " The datarate for the file is lower than target by too much!";
+    ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15)
+           << " The datarate for the file is greater than target by too much!";
+    ASSERT_LE(first_drop_, last_drop)
+        << " The first dropped frame for drop_thresh " << i
+        << " > first dropped frame for drop_thresh "
+        << i - kDropFrameThreshTestStep;
+    ASSERT_GE(num_drops_, last_num_drops)
+        << " The number of dropped frames for drop_thresh " << i
+        << " < number of dropped frames for drop_thresh "
+        << i - kDropFrameThreshTestStep;
+    last_drop = first_drop_;
+    last_num_drops = num_drops_;
+  }
+}
+
 VP8_INSTANTIATE_TEST_CASE(DatarateTest, ALL_TEST_MODES);
 VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9,
                           ::testing::Values(::libvpx_test::kOnePassGood),