From 55a01354841fa9ab2bcbb4623c1176dfc560fbdc Mon Sep 17 00:00:00 2001 From: kthelgason Date: Tue, 4 Apr 2017 02:31:42 -0700 Subject: [PATCH] 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} --- .../video_coding/utility/quality_scaler.cc | 7 ++++ .../utility/quality_scaler_unittest.cc | 34 ++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/webrtc/modules/video_coding/utility/quality_scaler.cc b/webrtc/modules/video_coding/utility/quality_scaler.cc index ff22862bb5..f1623cb6e9 100644 --- a/webrtc/modules/video_coding/utility/quality_scaler.cc +++ b/webrtc/modules/video_coding/utility/quality_scaler.cc @@ -39,6 +39,7 @@ static const int kHighH264QpThreshold = 37; // 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 @@ void QualityScaler::CheckQP() { 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 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 32d0aa9aea..93b5fcd431 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, DownscalesAboveHighQp) { 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, DoesNotDownscaleOnNormalQp) { 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 @@ TEST_F(QualityScalerTest, ScalesDownAndBackUp) { 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