| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 
| 3  * | 3  * | 
| 4  *  Use of this source code is governed by a BSD-style license | 4  *  Use of this source code is governed by a BSD-style license | 
| 5  *  that can be found in the LICENSE file in the root of the source | 5  *  that can be found in the LICENSE file in the root of the source | 
| 6  *  tree. An additional intellectual property rights grant can be found | 6  *  tree. An additional intellectual property rights grant can be found | 
| 7  *  in the file PATENTS.  All contributing project authors may | 7  *  in the file PATENTS.  All contributing project authors may | 
| 8  *  be found in the AUTHORS file in the root of the source tree. | 8  *  be found in the AUTHORS file in the root of the source tree. | 
| 9  */ | 9  */ | 
| 10 | 10 | 
| 11 #include "webrtc/modules/video_coding/utility/quality_scaler.h" | 11 #include "webrtc/modules/video_coding/utility/quality_scaler.h" | 
| 12 | 12 | 
|  | 13 #include <memory> | 
|  | 14 | 
|  | 15 #include "webrtc/base/event.h" | 
|  | 16 #include "webrtc/base/task_queue.h" | 
|  | 17 #include "webrtc/test/gmock.h" | 
| 13 #include "webrtc/test/gtest.h" | 18 #include "webrtc/test/gtest.h" | 
| 14 | 19 | 
| 15 namespace webrtc { | 20 namespace webrtc { | 
| 16 namespace { | 21 namespace { | 
| 17 static const int kNumSeconds = 10; |  | 
| 18 static const int kWidth = 1920; |  | 
| 19 static const int kHeight = 1080; |  | 
| 20 static const int kFramerate = 30; | 22 static const int kFramerate = 30; | 
| 21 static const int kLowQp = 15; | 23 static const int kLowQp = 15; | 
| 22 static const int kNormalQp = 30; |  | 
| 23 static const int kLowQpThreshold = 18; | 24 static const int kLowQpThreshold = 18; | 
| 24 static const int kHighQp = 40; | 25 static const int kHighQp = 40; | 
| 25 static const int kDisabledBadQpThreshold = 64; | 26 static const size_t kDefaultTimeoutMs = 1000; | 
| 26 static const int kLowInitialBitrateKbps = 300; |  | 
| 27 // These values need to be in sync with corresponding constants |  | 
| 28 // in quality_scaler.cc |  | 
| 29 static const int kMeasureSecondsFastUpscale = 2; |  | 
| 30 static const int kMeasureSecondsUpscale = 5; |  | 
| 31 static const int kMeasureSecondsDownscale = 5; |  | 
| 32 static const int kMinDownscaleDimension = 140; |  | 
| 33 }  // namespace | 27 }  // namespace | 
| 34 | 28 | 
|  | 29 class MockScaleObserver : public ScalingObserverInterface { | 
|  | 30  public: | 
|  | 31   MockScaleObserver() : event(false, false) {} | 
|  | 32   virtual ~MockScaleObserver() {} | 
|  | 33 | 
|  | 34   void ScaleUp(ScaleReason r) override { | 
|  | 35     scaled_up++; | 
|  | 36     event.Set(); | 
|  | 37   } | 
|  | 38   void ScaleDown(ScaleReason r) override { | 
|  | 39     scaled_down++; | 
|  | 40     event.Set(); | 
|  | 41   } | 
|  | 42 | 
|  | 43   rtc::Event event; | 
|  | 44   int scaled_up = 0; | 
|  | 45   int scaled_down = 0; | 
|  | 46 }; | 
|  | 47 | 
|  | 48 // Pass a lower sampling period to speed up the tests. | 
|  | 49 class QualityScalerUnderTest : public QualityScaler { | 
|  | 50  public: | 
|  | 51   explicit QualityScalerUnderTest(ScalingObserverInterface* observer, | 
|  | 52                                   VideoEncoder::QpThresholds thresholds) | 
|  | 53       : QualityScaler(observer, thresholds, 5) {} | 
|  | 54 }; | 
|  | 55 | 
| 35 class QualityScalerTest : public ::testing::Test { | 56 class QualityScalerTest : public ::testing::Test { | 
| 36  protected: | 57  protected: | 
| 37   enum ScaleDirection { | 58   enum ScaleDirection { | 
| 38     kKeepScaleAtHighQp, | 59     kKeepScaleAtHighQp, | 
| 39     kScaleDown, | 60     kScaleDown, | 
| 40     kScaleDownAboveHighQp, | 61     kScaleDownAboveHighQp, | 
| 41     kScaleUp | 62     kScaleUp | 
| 42   }; | 63   }; | 
| 43 | 64 | 
| 44   QualityScalerTest() { | 65   QualityScalerTest() | 
| 45     input_frame_ = I420Buffer::Create(kWidth, kHeight); | 66       : q_(new rtc::TaskQueue("QualityScalerTestQueue")), | 
| 46     qs_.Init(kLowQpThreshold, kHighQp, 0, kWidth, kHeight, kFramerate); | 67         observer_(new MockScaleObserver()) { | 
| 47     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); | 68     rtc::Event event(false, false); | 
|  | 69     q_->PostTask([this, &event] { | 
|  | 70       qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest( | 
|  | 71           observer_.get(), | 
|  | 72           VideoEncoder::QpThresholds(kLowQpThreshold, kHighQp))); | 
|  | 73       event.Set(); | 
|  | 74     }); | 
|  | 75     EXPECT_TRUE(event.Wait(kDefaultTimeoutMs)); | 
| 48   } | 76   } | 
| 49 | 77 | 
| 50   bool TriggerScale(ScaleDirection scale_direction) { | 78   ~QualityScalerTest() { | 
| 51     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); | 79     rtc::Event event(false, false); | 
| 52     int initial_width = qs_.GetScaledResolution().width; | 80     q_->PostTask([this, &event] { | 
| 53     for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 81       qs_.reset(nullptr); | 
|  | 82       event.Set(); | 
|  | 83     }); | 
|  | 84     EXPECT_TRUE(event.Wait(kDefaultTimeoutMs)); | 
|  | 85   } | 
|  | 86 | 
|  | 87   void TriggerScale(ScaleDirection scale_direction) { | 
|  | 88     for (int i = 0; i < kFramerate * 5; ++i) { | 
| 54       switch (scale_direction) { | 89       switch (scale_direction) { | 
| 55         case kScaleUp: | 90         case kScaleUp: | 
| 56           qs_.ReportQP(kLowQp); | 91           qs_->ReportQP(kLowQp); | 
| 57           break; | 92           break; | 
| 58         case kScaleDown: | 93         case kScaleDown: | 
| 59           qs_.ReportDroppedFrame(); | 94           qs_->ReportDroppedFrame(); | 
| 60           break; | 95           break; | 
| 61         case kKeepScaleAtHighQp: | 96         case kKeepScaleAtHighQp: | 
| 62           qs_.ReportQP(kHighQp); | 97           qs_->ReportQP(kHighQp); | 
| 63           break; | 98           break; | 
| 64         case kScaleDownAboveHighQp: | 99         case kScaleDownAboveHighQp: | 
| 65           qs_.ReportQP(kHighQp + 1); | 100           qs_->ReportQP(kHighQp + 1); | 
| 66           break; | 101           break; | 
| 67       } | 102       } | 
| 68       qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 69       if (qs_.GetScaledResolution().width != initial_width) |  | 
| 70         return true; |  | 
| 71     } | 103     } | 
| 72 |  | 
| 73     return false; |  | 
| 74   } | 104   } | 
| 75 | 105 | 
| 76   void ExpectOriginalFrame() { | 106   std::unique_ptr<rtc::TaskQueue> q_; | 
| 77     EXPECT_EQ(input_frame_, qs_.GetScaledBuffer(input_frame_)) | 107   std::unique_ptr<QualityScaler> qs_; | 
| 78         << "Using scaled frame instead of original input."; | 108   std::unique_ptr<MockScaleObserver> observer_; | 
| 79   } |  | 
| 80 |  | 
| 81   void ExpectScaleUsingReportedResolution() { |  | 
| 82     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 83     QualityScaler::Resolution res = qs_.GetScaledResolution(); |  | 
| 84     rtc::scoped_refptr<VideoFrameBuffer> scaled_frame = |  | 
| 85         qs_.GetScaledBuffer(input_frame_); |  | 
| 86     EXPECT_EQ(res.width, scaled_frame->width()); |  | 
| 87     EXPECT_EQ(res.height, scaled_frame->height()); |  | 
| 88   } |  | 
| 89 |  | 
| 90   void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); |  | 
| 91 |  | 
| 92   void DoesNotDownscaleFrameDimensions(int width, int height); |  | 
| 93 |  | 
| 94   void DownscaleEndsAt(int input_width, |  | 
| 95                        int input_height, |  | 
| 96                        int end_width, |  | 
| 97                        int end_height); |  | 
| 98 |  | 
| 99   QualityScaler qs_; |  | 
| 100   rtc::scoped_refptr<VideoFrameBuffer> input_frame_; |  | 
| 101 }; | 109 }; | 
| 102 | 110 | 
| 103 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { |  | 
| 104   ExpectOriginalFrame(); |  | 
| 105 } |  | 
| 106 |  | 
| 107 TEST_F(QualityScalerTest, ReportsOriginalResolutionInitially) { |  | 
| 108   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 109   QualityScaler::Resolution res = qs_.GetScaledResolution(); |  | 
| 110   EXPECT_EQ(input_frame_->width(), res.width); |  | 
| 111   EXPECT_EQ(input_frame_->height(), res.height); |  | 
| 112 } |  | 
| 113 |  | 
| 114 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { | 111 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { | 
| 115   EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds | 112   q_->PostTask([this] { TriggerScale(kScaleDown); }); | 
| 116                                         << " seconds."; | 113   EXPECT_TRUE(observer_->event.Wait(50)); | 
| 117   QualityScaler::Resolution res = qs_.GetScaledResolution(); | 114   EXPECT_EQ(1, observer_->scaled_down); | 
| 118   EXPECT_LT(res.width, input_frame_->width()); |  | 
| 119   EXPECT_LT(res.height, input_frame_->height()); |  | 
| 120 } | 115 } | 
| 121 | 116 | 
| 122 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) { | 117 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) { | 
| 123   EXPECT_FALSE(TriggerScale(kKeepScaleAtHighQp)) | 118   q_->PostTask([this] { TriggerScale(kKeepScaleAtHighQp); }); | 
| 124       << "Downscale at high threshold which should keep scale."; | 119   EXPECT_FALSE(observer_->event.Wait(50)); | 
| 125   QualityScaler::Resolution res = qs_.GetScaledResolution(); | 120   EXPECT_EQ(0, observer_->scaled_down); | 
| 126   EXPECT_EQ(res.width, input_frame_->width()); | 121   EXPECT_EQ(0, observer_->scaled_up); | 
| 127   EXPECT_EQ(res.height, input_frame_->height()); |  | 
| 128 } | 122 } | 
| 129 | 123 | 
| 130 TEST_F(QualityScalerTest, DownscalesAboveHighQp) { | 124 TEST_F(QualityScalerTest, DownscalesAboveHighQp) { | 
| 131   EXPECT_TRUE(TriggerScale(kScaleDownAboveHighQp)) | 125   q_->PostTask([this] { TriggerScale(kScaleDownAboveHighQp); }); | 
| 132       << "No downscale within " << kNumSeconds << " seconds."; | 126   EXPECT_TRUE(observer_->event.Wait(50)); | 
| 133   QualityScaler::Resolution res = qs_.GetScaledResolution(); | 127   EXPECT_EQ(1, observer_->scaled_down); | 
| 134   EXPECT_LT(res.width, input_frame_->width()); | 128   EXPECT_EQ(0, observer_->scaled_up); | 
| 135   EXPECT_LT(res.height, input_frame_->height()); |  | 
| 136 } | 129 } | 
| 137 | 130 | 
| 138 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { | 131 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { | 
| 139   for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { | 132   q_->PostTask([this] { | 
| 140     qs_.ReportQP(kNormalQp); | 133     qs_->ReportDroppedFrame(); | 
| 141     qs_.ReportDroppedFrame(); | 134     qs_->ReportDroppedFrame(); | 
| 142     qs_.ReportDroppedFrame(); | 135     qs_->ReportQP(kHighQp); | 
| 143     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); | 136   }); | 
| 144     if (qs_.GetScaledResolution().width < input_frame_->width()) | 137   EXPECT_TRUE(observer_->event.Wait(50)); | 
| 145       return; | 138   EXPECT_EQ(1, observer_->scaled_down); | 
| 146   } | 139   EXPECT_EQ(0, observer_->scaled_up); | 
| 147 |  | 
| 148   FAIL() << "No downscale within " << kNumSeconds << " seconds."; |  | 
| 149 } | 140 } | 
| 150 | 141 | 
| 151 TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) { | 142 TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) { | 
| 152   for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 143   q_->PostTask([this] { TriggerScale(kScaleDownAboveHighQp); }); | 
| 153     qs_.ReportQP(kNormalQp); | 144   EXPECT_TRUE(observer_->event.Wait(50)); | 
| 154     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); | 145   EXPECT_EQ(1, observer_->scaled_down); | 
| 155     ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) | 146   EXPECT_EQ(0, observer_->scaled_up); | 
| 156         << "Unexpected scale on half framedrop."; |  | 
| 157   } |  | 
| 158 } | 147 } | 
| 159 | 148 | 
| 160 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) { | 149 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) { | 
| 161   for (int i = 0; i < kFramerate * kNumSeconds / 2; ++i) { | 150   q_->PostTask([this] { | 
| 162     qs_.ReportQP(kNormalQp); | 151     qs_->ReportDroppedFrame(); | 
| 163     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); | 152     qs_->ReportQP(kHighQp); | 
| 164     ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) | 153   }); | 
| 165         << "Unexpected scale on half framedrop."; | 154   EXPECT_FALSE(observer_->event.Wait(50)); | 
| 166 | 155   EXPECT_EQ(0, observer_->scaled_down); | 
| 167     qs_.ReportDroppedFrame(); | 156   EXPECT_EQ(0, observer_->scaled_up); | 
| 168     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 169     ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) |  | 
| 170         << "Unexpected scale on half framedrop."; |  | 
| 171   } |  | 
| 172 } | 157 } | 
| 173 | 158 | 
| 174 void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() { | 159 TEST_F(QualityScalerTest, UpscalesAfterLowQp) { | 
| 175   const int initial_min_dimension = | 160   q_->PostTask([this] { TriggerScale(kScaleUp); }); | 
| 176       input_frame_->width() < input_frame_->height() ? input_frame_->width() | 161   EXPECT_TRUE(observer_->event.Wait(50)); | 
| 177                                                      : input_frame_->height(); | 162   EXPECT_EQ(0, observer_->scaled_down); | 
| 178   int min_dimension = initial_min_dimension; | 163   EXPECT_EQ(1, observer_->scaled_up); | 
| 179   int current_shift = 0; |  | 
| 180   // Drop all frames to force-trigger downscaling. |  | 
| 181   while (min_dimension >= 2 * kMinDownscaleDimension) { |  | 
| 182     EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " |  | 
| 183                                           << kNumSeconds << " seconds."; |  | 
| 184     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 185     QualityScaler::Resolution res = qs_.GetScaledResolution(); |  | 
| 186     min_dimension = res.width < res.height ? res.width : res.height; |  | 
| 187     ++current_shift; |  | 
| 188     ASSERT_EQ(input_frame_->width() >> current_shift, res.width); |  | 
| 189     ASSERT_EQ(input_frame_->height() >> current_shift, res.height); |  | 
| 190     ExpectScaleUsingReportedResolution(); |  | 
| 191   } |  | 
| 192 |  | 
| 193   // Make sure we can scale back with good-quality frames. |  | 
| 194   while (min_dimension < initial_min_dimension) { |  | 
| 195     EXPECT_TRUE(TriggerScale(kScaleUp)) << "No upscale within " << kNumSeconds |  | 
| 196                                         << " seconds."; |  | 
| 197     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 198     QualityScaler::Resolution res = qs_.GetScaledResolution(); |  | 
| 199     min_dimension = res.width < res.height ? res.width : res.height; |  | 
| 200     --current_shift; |  | 
| 201     ASSERT_EQ(input_frame_->width() >> current_shift, res.width); |  | 
| 202     ASSERT_EQ(input_frame_->height() >> current_shift, res.height); |  | 
| 203     ExpectScaleUsingReportedResolution(); |  | 
| 204   } |  | 
| 205 |  | 
| 206   // Verify we don't start upscaling after further low use. |  | 
| 207   for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |  | 
| 208     qs_.ReportQP(kLowQp); |  | 
| 209     ExpectOriginalFrame(); |  | 
| 210   } |  | 
| 211 } | 164 } | 
| 212 | 165 | 
| 213 TEST_F(QualityScalerTest, ContinuouslyDownscalesByHalfDimensionsAndBackUp) { | 166 TEST_F(QualityScalerTest, ScalesDownAndBackUp) { | 
| 214   ContinuouslyDownscalesByHalfDimensionsAndBackUp(); | 167   q_->PostTask([this] { TriggerScale(kScaleDown); }); | 
| 215 } | 168   EXPECT_TRUE(observer_->event.Wait(50)); | 
| 216 | 169   EXPECT_EQ(1, observer_->scaled_down); | 
| 217 TEST_F(QualityScalerTest, | 170   EXPECT_EQ(0, observer_->scaled_up); | 
| 218        ContinuouslyDownscalesOddResolutionsByHalfDimensionsAndBackUp) { | 171   q_->PostTask([this] { TriggerScale(kScaleUp); }); | 
| 219   const int kOddWidth = 517; | 172   EXPECT_TRUE(observer_->event.Wait(50)); | 
| 220   const int kOddHeight = 1239; | 173   EXPECT_EQ(1, observer_->scaled_down); | 
| 221   input_frame_ = I420Buffer::Create(kOddWidth, kOddHeight); | 174   EXPECT_EQ(1, observer_->scaled_up); | 
| 222   ContinuouslyDownscalesByHalfDimensionsAndBackUp(); |  | 
| 223 } |  | 
| 224 |  | 
| 225 void QualityScalerTest::DoesNotDownscaleFrameDimensions(int width, int height) { |  | 
| 226   input_frame_ = I420Buffer::Create(width, height); |  | 
| 227 |  | 
| 228   for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |  | 
| 229     qs_.ReportDroppedFrame(); |  | 
| 230     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 231     ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) |  | 
| 232         << "Unexpected scale of minimal-size frame."; |  | 
| 233   } |  | 
| 234 } |  | 
| 235 |  | 
| 236 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxWidth) { |  | 
| 237   DoesNotDownscaleFrameDimensions(1, kHeight); |  | 
| 238 } |  | 
| 239 |  | 
| 240 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) { |  | 
| 241   DoesNotDownscaleFrameDimensions(kWidth, 1); |  | 
| 242 } |  | 
| 243 |  | 
| 244 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) { |  | 
| 245   DoesNotDownscaleFrameDimensions(1, 1); |  | 
| 246 } |  | 
| 247 |  | 
| 248 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) { |  | 
| 249   DoesNotDownscaleFrameDimensions( |  | 
| 250       2 * kMinDownscaleDimension - 1, 1000); |  | 
| 251 } |  | 
| 252 |  | 
| 253 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { |  | 
| 254   DoesNotDownscaleFrameDimensions( |  | 
| 255       1000, 2 * kMinDownscaleDimension - 1); |  | 
| 256 } |  | 
| 257 |  | 
| 258 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { |  | 
| 259   static const int kWidth720p = 1280; |  | 
| 260   static const int kHeight720p = 720; |  | 
| 261   static const int kInitialBitrateKbps = 300; |  | 
| 262   input_frame_ = I420Buffer::Create(kWidth720p, kHeight720p); |  | 
| 263   qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, |  | 
| 264            kWidth720p, kHeight720p, kFramerate); |  | 
| 265   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 266   int init_width = qs_.GetScaledResolution().width; |  | 
| 267   int init_height = qs_.GetScaledResolution().height; |  | 
| 268   EXPECT_EQ(640, init_width); |  | 
| 269   EXPECT_EQ(360, init_height); |  | 
| 270 } |  | 
| 271 |  | 
| 272 TEST_F(QualityScalerTest, DownscaleToQvgaOnLowerInitialBitrate) { |  | 
| 273   static const int kWidth720p = 1280; |  | 
| 274   static const int kHeight720p = 720; |  | 
| 275   static const int kInitialBitrateKbps = 200; |  | 
| 276   input_frame_ = I420Buffer::Create(kWidth720p, kHeight720p); |  | 
| 277   qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, |  | 
| 278            kWidth720p, kHeight720p, kFramerate); |  | 
| 279   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 280   int init_width = qs_.GetScaledResolution().width; |  | 
| 281   int init_height = qs_.GetScaledResolution().height; |  | 
| 282   EXPECT_EQ(320, init_width); |  | 
| 283   EXPECT_EQ(180, init_height); |  | 
| 284 } |  | 
| 285 |  | 
| 286 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { |  | 
| 287   qs_.Init(kLowQpThreshold, kHighQp, 0, kWidth, kHeight, kFramerate); |  | 
| 288   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 289   QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); |  | 
| 290 |  | 
| 291   // Should not downscale if less than kMeasureSecondsDownscale seconds passed. |  | 
| 292   for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { |  | 
| 293     qs_.ReportQP(kHighQp + 1); |  | 
| 294     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 295   } |  | 
| 296   EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |  | 
| 297   EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |  | 
| 298 |  | 
| 299   // Should downscale if more than kMeasureSecondsDownscale seconds passed (add |  | 
| 300   // last frame). |  | 
| 301   qs_.ReportQP(kHighQp + 1); |  | 
| 302   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 303   EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); |  | 
| 304   EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); |  | 
| 305 |  | 
| 306   // Should not upscale if less than kMeasureSecondsUpscale seconds passed since |  | 
| 307   // we saw issues initially (have already gone down). |  | 
| 308   for (int i = 0; i < kFramerate * kMeasureSecondsUpscale - 1; ++i) { |  | 
| 309     qs_.ReportQP(kLowQp); |  | 
| 310     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 311   } |  | 
| 312   EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); |  | 
| 313   EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); |  | 
| 314 |  | 
| 315   // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed |  | 
| 316   // (add last frame). |  | 
| 317   qs_.ReportQP(kLowQp); |  | 
| 318   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 319   EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |  | 
| 320   EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |  | 
| 321 } |  | 
| 322 |  | 
| 323 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { |  | 
| 324   qs_.Init(kLowQpThreshold, kHighQp, kLowInitialBitrateKbps, kWidth, kHeight, |  | 
| 325            kFramerate); |  | 
| 326   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 327   QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); |  | 
| 328 |  | 
| 329   // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. |  | 
| 330   for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { |  | 
| 331     qs_.ReportQP(kLowQp); |  | 
| 332     qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 333   } |  | 
| 334   EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |  | 
| 335   EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |  | 
| 336 |  | 
| 337   // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last |  | 
| 338   // frame). |  | 
| 339   qs_.ReportQP(kLowQp); |  | 
| 340   qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |  | 
| 341   EXPECT_LT(initial_res.width, qs_.GetScaledResolution().width); |  | 
| 342   EXPECT_LT(initial_res.height, qs_.GetScaledResolution().height); |  | 
| 343 } |  | 
| 344 |  | 
| 345 void QualityScalerTest::DownscaleEndsAt(int input_width, |  | 
| 346                                         int input_height, |  | 
| 347                                         int end_width, |  | 
| 348                                         int end_height) { |  | 
| 349   // Create a frame with 2x expected end width/height to verify that we can |  | 
| 350   // scale down to expected end width/height. |  | 
| 351   input_frame_ = I420Buffer::Create(input_width, input_height); |  | 
| 352 |  | 
| 353   int last_width = input_width; |  | 
| 354   int last_height = input_height; |  | 
| 355   // Drop all frames to force-trigger downscaling. |  | 
| 356   while (true) { |  | 
| 357     TriggerScale(kScaleDown); |  | 
| 358     QualityScaler::Resolution res = qs_.GetScaledResolution(); |  | 
| 359     if (last_width == res.width) { |  | 
| 360       EXPECT_EQ(last_height, res.height); |  | 
| 361       EXPECT_EQ(end_width, res.width); |  | 
| 362       EXPECT_EQ(end_height, res.height); |  | 
| 363       break; |  | 
| 364     } |  | 
| 365     last_width = res.width; |  | 
| 366     last_height = res.height; |  | 
| 367   } |  | 
| 368 } |  | 
| 369 |  | 
| 370 TEST_F(QualityScalerTest, DownscalesTo320x180) { |  | 
| 371   DownscaleEndsAt(640, 360, 320, 180); |  | 
| 372 } |  | 
| 373 |  | 
| 374 TEST_F(QualityScalerTest, DownscalesTo180x320) { |  | 
| 375   DownscaleEndsAt(360, 640, 180, 320); |  | 
| 376 } |  | 
| 377 |  | 
| 378 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) { |  | 
| 379   DownscaleEndsAt(1280, 720, 320, 180); |  | 
| 380 } |  | 
| 381 |  | 
| 382 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) { |  | 
| 383   DownscaleEndsAt(320, 180, 320, 180); |  | 
| 384 } | 175 } | 
| 385 | 176 | 
| 386 }  // namespace webrtc | 177 }  // namespace webrtc | 
| OLD | NEW | 
|---|