Add some unit tests to vie_encoder.

BUG=none

Review-Url: https://codereview.webrtc.org/2801293002
Cr-Commit-Position: refs/heads/master@{#17609}
diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc
index 704f90d..79a08b3 100644
--- a/webrtc/video/vie_encoder_unittest.cc
+++ b/webrtc/video/vie_encoder_unittest.cc
@@ -284,6 +284,19 @@
     return frame;
   }
 
+  void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
+    EXPECT_FALSE(wants.target_pixel_count);
+    EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
+    EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
+  }
+
+  void VerifyResolutionLimitationLessThan(const rtc::VideoSinkWants& wants,
+                                          int pixel_count) {
+    EXPECT_LT(wants.max_pixel_count, pixel_count);
+    EXPECT_GT(wants.max_pixel_count, 0);
+    EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
+  }
+
   class TestEncoder : public test::FakeEncoder {
    public:
     TestEncoder()
@@ -715,9 +728,7 @@
 TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
   vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
 
-  EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            video_source_.sink_wants().max_pixel_count);
+  VerifyNoLimitation(video_source_.sink_wants());
 
   int frame_width = 1280;
   int frame_height = 720;
@@ -763,12 +774,7 @@
 
 TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
   vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
-
-  EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            video_source_.sink_wants().max_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            video_source_.sink_wants().max_framerate_fps);
+  VerifyNoLimitation(video_source_.sink_wants());
 
   const int kFrameWidth = 1280;
   const int kFrameHeight = 720;
@@ -803,16 +809,13 @@
       VideoSendStream::DegradationPreference::kMaintainResolution);
 
   // Initially no degradation registered.
-  EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            new_video_source.sink_wants().max_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            new_video_source.sink_wants().max_framerate_fps);
+  VerifyNoLimitation(new_video_source.sink_wants());
 
   // Force an input frame rate to be available, or the adaptation call won't
   // know what framerate to adapt form.
+  const int kInputFps = 30;
   VideoSendStream::Stats stats = stats_proxy_->GetStats();
-  stats.input_frame_rate = 30;
+  stats.input_frame_rate = kInputFps;
   stats_proxy_->SetMockStats(stats);
 
   vie_encoder_->TriggerCpuOveruse();
@@ -825,19 +828,13 @@
   EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
   EXPECT_EQ(std::numeric_limits<int>::max(),
             new_video_source.sink_wants().max_pixel_count);
-  EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
+  EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
 
-  // Turn of degradation completely.
+  // Turn off degradation completely.
   vie_encoder_->SetSource(
       &new_video_source,
       VideoSendStream::DegradationPreference::kDegradationDisabled);
-
-  // Initially no degradation registered.
-  EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            new_video_source.sink_wants().max_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            new_video_source.sink_wants().max_framerate_fps);
+  VerifyNoLimitation(new_video_source.sink_wants());
 
   vie_encoder_->TriggerCpuOveruse();
   new_video_source.IncomingCapturedFrame(
@@ -846,11 +843,7 @@
   frame_timestamp += kFrameIntervalMs;
 
   // Still no degradation.
-  EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            new_video_source.sink_wants().max_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            new_video_source.sink_wants().max_framerate_fps);
+  VerifyNoLimitation(new_video_source.sink_wants());
 
   // Calling SetSource with resolution scaling enabled apply the old SinkWants.
   vie_encoder_->SetSource(
@@ -869,7 +862,7 @@
   EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
   EXPECT_EQ(std::numeric_limits<int>::max(),
             new_video_source.sink_wants().max_pixel_count);
-  EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
+  EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
 
   vie_encoder_->Stop();
 }
@@ -879,7 +872,6 @@
 
   const int kWidth = 1280;
   const int kHeight = 720;
-
   video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
   sink_.WaitForEncodedFrame(1);
   VideoSendStream::Stats stats = stats_proxy_->GetStats();
@@ -913,7 +905,6 @@
 
   const int kWidth = 1280;
   const int kHeight = 720;
-
   video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
   sink_.WaitForEncodedFrame(1);
   VideoSendStream::Stats stats = stats_proxy_->GetStats();
@@ -1002,6 +993,7 @@
   stats = stats_proxy_->GetStats();
   EXPECT_FALSE(stats.cpu_limited_resolution);
   EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
+  EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
 
   vie_encoder_->Stop();
 }
@@ -1050,7 +1042,7 @@
   EXPECT_TRUE(stats.bw_limited_resolution);
   EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
 
-  // Set adaptation disabled.
+  // Disable resolution scaling.
   vie_encoder_->SetSource(
       &new_video_source,
       VideoSendStream::DegradationPreference::kMaintainResolution);
@@ -1109,7 +1101,7 @@
   vie_encoder_->Stop();
 }
 
-TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) {
+TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
   vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
 
   const int kWidth = 1280;
@@ -1118,16 +1110,14 @@
 
   video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
   sink_.WaitForEncodedFrame(sequence++);
-
   VideoSendStream::Stats stats = stats_proxy_->GetStats();
   EXPECT_FALSE(stats.cpu_limited_resolution);
   EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
 
-  // Trigger CPU overuse again, should now adapt down.
+  // Trigger CPU overuse, should now adapt down.
   vie_encoder_->TriggerCpuOveruse();
   video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
   sink_.WaitForEncodedFrame(sequence++);
-
   stats = stats_proxy_->GetStats();
   EXPECT_TRUE(stats.cpu_limited_resolution);
   EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
@@ -1233,6 +1223,7 @@
   stats = stats_proxy_->GetStats();
   EXPECT_FALSE(stats.cpu_limited_resolution);
   EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
+  EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
 
   vie_encoder_->Stop();
 }
@@ -1258,9 +1249,7 @@
   vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
 
   // Expect no scaling to begin with.
-  EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            video_source_.sink_wants().max_pixel_count);
+  VerifyNoLimitation(video_source_.sink_wants());
 
   video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
   sink_.WaitForEncodedFrame(1);
@@ -1275,7 +1264,7 @@
   EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
   EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
 
-  // Set adaptation disabled.
+  // Set resolution scaling disabled.
   test::FrameForwarder new_video_source;
   vie_encoder_->SetSource(
       &new_video_source,
@@ -1295,13 +1284,130 @@
   new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
   sink_.WaitForEncodedFrame(4);
 
-  // Expect nothing to change, still no scaling
+  // Expect nothing to change, still no scaling.
   EXPECT_EQ(std::numeric_limits<int>::max(),
             new_video_source.sink_wants().max_pixel_count);
 
   vie_encoder_->Stop();
 }
 
+TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
+  const int kWidth = 1280;
+  const int kHeight = 720;
+  vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+  // Enable kMaintainFramerate preference, no initial limitation.
+  test::FrameForwarder source;
+  vie_encoder_->SetSource(
+      &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
+
+  source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
+  sink_.WaitForEncodedFrame(1);
+  VerifyNoLimitation(source.sink_wants());
+  EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
+  EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  // Trigger adapt down, expect scaled down resolution.
+  vie_encoder_->TriggerCpuOveruse();
+  VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
+  const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
+  EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
+  EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  // Trigger adapt down for same input resolution, expect no change.
+  vie_encoder_->TriggerCpuOveruse();
+  EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
+  EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
+  EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
+  const int kWidth = 1280;
+  const int kHeight = 720;
+  vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+  // Enable kMaintainFramerate preference, no initial limitation.
+  test::FrameForwarder source;
+  vie_encoder_->SetSource(
+      &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
+
+  source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
+  sink_.WaitForEncodedFrame(kWidth, kHeight);
+  VerifyNoLimitation(source.sink_wants());
+  EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
+  EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  // Trigger adapt up, expect no change.
+  vie_encoder_->TriggerCpuNormalUsage();
+  VerifyNoLimitation(source.sink_wants());
+  EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
+  EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
+  const int kWidth = 1280;
+  const int kHeight = 720;
+  vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+  // Enable kMaintainResolution preference, no initial limitation.
+  test::FrameForwarder source;
+  vie_encoder_->SetSource(
+      &source, VideoSendStream::DegradationPreference::kMaintainResolution);
+
+  source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
+  sink_.WaitForEncodedFrame(kWidth, kHeight);
+  VerifyNoLimitation(source.sink_wants());
+  EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
+  EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  // Trigger adapt up, expect no change.
+  vie_encoder_->TriggerCpuNormalUsage();
+  VerifyNoLimitation(source.sink_wants());
+  EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
+  EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
+  const int kWidth = 1280;
+  const int kHeight = 720;
+  vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+  // Enable kMaintainFramerate preference, no initial limitation.
+  AdaptingFrameForwarder source;
+  source.set_adaptation_enabled(true);
+  vie_encoder_->SetSource(
+      &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
+
+  source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
+  sink_.WaitForEncodedFrame(1);
+  VerifyNoLimitation(source.sink_wants());
+  EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
+  EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
+
+  // Trigger adapt down, expect scaled down resolution.
+  vie_encoder_->TriggerQualityLow();
+  source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
+  sink_.WaitForEncodedFrame(2);
+  VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
+  EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
+  EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
+
+  // Trigger adapt up, expect no restriction.
+  vie_encoder_->TriggerQualityHigh();
+  VerifyNoLimitation(source.sink_wants());
+  EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
+  EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
+  EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
+
+  vie_encoder_->Stop();
+}
+
 TEST_F(ViEEncoderTest, DoesNotScaleBelowSetLimit) {
   int frame_width = 1280;
   int frame_height = 720;
@@ -1476,6 +1582,18 @@
   fake_encoder_.SetQualityScaling(true);
 }
 
+TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
+  fake_encoder_.ForceInitEncodeFailure(true);
+  vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+  ResetEncoder("VP8", 2, 1, true);
+  const int kFrameWidth = 1280;
+  const int kFrameHeight = 720;
+  video_source_.IncomingCapturedFrame(
+      CreateFrame(1, kFrameWidth, kFrameHeight));
+  sink_.ExpectDroppedFrame();
+  vie_encoder_->Stop();
+}
+
 // TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
 TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) {
   vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
@@ -1505,19 +1623,7 @@
   vie_encoder_->Stop();
 }
 
-TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
-  fake_encoder_.ForceInitEncodeFailure(true);
-  vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
-  ResetEncoder("VP8", 2, 1, true);
-  const int kFrameWidth = 1280;
-  const int kFrameHeight = 720;
-  video_source_.IncomingCapturedFrame(
-      CreateFrame(1, kFrameWidth, kFrameHeight));
-  sink_.ExpectDroppedFrame();
-  vie_encoder_->Stop();
-}
-
-TEST_F(ViEEncoderTest, AdaptsFrameOnOveruseWithMaintainResolution) {
+TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
   const int kDefaultFramerateFps = 30;
   const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
   const int kFrameWidth = 1280;