Make sure we observe enough frames before scaling.

If the encoder takes a long time to start up and emit frames the polling
interval of the quality scaler would get out of sync. This causes it to
sometimes make scaling decisions based on only a handful of frames.
This CL ensures that we have observed some minimum number of frames
before deciding to scale up or down.

BUG=b/36734056

Review-Url: https://codereview.webrtc.org/2789483002
Cr-Commit-Position: refs/heads/master@{#17523}
diff --git a/webrtc/modules/video_coding/utility/quality_scaler.cc b/webrtc/modules/video_coding/utility/quality_scaler.cc
index ff22862..f1623cb 100644
--- a/webrtc/modules/video_coding/utility/quality_scaler.cc
+++ b/webrtc/modules/video_coding/utility/quality_scaler.cc
@@ -39,6 +39,7 @@
 // bitstream range of [0, 127] and not the user-level range of [0,63].
 static const int kLowVp8QpThreshold = 29;
 static const int kHighVp8QpThreshold = 95;
+static const int kMinFramesNeededToScale = 2 * 30;
 
 static VideoEncoder::QpThresholds CodecTypeToDefaultThresholds(
     VideoCodecType codec_type) {
@@ -142,6 +143,12 @@
   RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
   // Should be set through InitEncode -> Should be set by now.
   RTC_DCHECK_GE(thresholds_.low, 0);
+
+  // If we have not observed at least this many frames we can't
+  // make a good scaling decision.
+  if (framedrop_percent_.size() < kMinFramesNeededToScale)
+    return;
+
   // Check if we should scale down due to high frame drop.
   const rtc::Optional<int> drop_rate = framedrop_percent_.GetAverage();
   if (drop_rate && *drop_rate >= kFramedropPercentThreshold) {
diff --git a/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc b/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc
index 32d0aa9..93b5fcd 100644
--- a/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc
+++ b/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc
@@ -131,9 +131,11 @@
 
 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
   DO_SYNC(q_, {
-    qs_->ReportDroppedFrame();
-    qs_->ReportDroppedFrame();
-    qs_->ReportQP(kHighQp);
+    for (int i = 0; i < kFramerate * 5; ++i) {
+      qs_->ReportDroppedFrame();
+      qs_->ReportDroppedFrame();
+      qs_->ReportQP(kHighQp);
+    }
   });
   EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
   EXPECT_EQ(1, observer_->adapt_down_events_);
@@ -149,8 +151,10 @@
 
 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
   DO_SYNC(q_, {
-    qs_->ReportDroppedFrame();
-    qs_->ReportQP(kHighQp);
+    for (int i = 0; i < kFramerate * 5; ++i) {
+      qs_->ReportDroppedFrame();
+      qs_->ReportQP(kHighQp);
+    }
   });
   EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
   EXPECT_EQ(0, observer_->adapt_down_events_);
@@ -174,5 +178,25 @@
   EXPECT_EQ(1, observer_->adapt_down_events_);
   EXPECT_EQ(1, observer_->adapt_up_events_);
 }
+
+TEST_F(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
+  DO_SYNC(q_, {
+      // Send 30 frames. This should not be enough to make a decision.
+      for (int i = 0; i < kFramerate; ++i) {
+        qs_->ReportQP(kLowQp);
+      }
+    });
+  EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
+  DO_SYNC(q_, {
+      // Send 30 more. This should result in an adapt request as
+      // enough frames have now been observed.
+      for (int i = 0; i < kFramerate; ++i) {
+        qs_->ReportQP(kLowQp);
+      }
+    });
+  EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
+  EXPECT_EQ(0, observer_->adapt_down_events_);
+  EXPECT_EQ(1, observer_->adapt_up_events_);
+}
 }  // namespace webrtc
 #undef DO_SYNC