blob: 939865da35e63bf15440af05134135e016d56187 [file] [log] [blame]
pbos@webrtc.orga0d78272014-09-12 11:51:47 +00001/*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/video_coding/utility/quality_scaler.h"
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000012
kthelgason876222f2016-11-29 01:44:11 -080013#include <memory>
Åsa Perssona945aee2018-04-24 16:53:25 +020014#include <string>
kthelgason876222f2016-11-29 01:44:11 -080015
Yves Gerey3e707812018-11-28 16:47:49 +010016#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/event.h"
Danil Chapovalovb42165e2019-03-20 14:29:43 +010018#include "rtc_base/task_queue_for_test.h"
Åsa Perssona945aee2018-04-24 16:53:25 +020019#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "test/gtest.h"
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000021
22namespace webrtc {
23namespace {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000024static const int kFramerate = 30;
25static const int kLowQp = 15;
Peter Boström17417702015-09-25 17:03:26 +020026static const int kHighQp = 40;
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020027static const int kMinFramesNeededToScale = 60; // From quality_scaler.cc.
kthelgason86cf9a22016-12-01 02:57:01 -080028static const size_t kDefaultTimeoutMs = 150;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000029} // namespace
30
sprangb1ca0732017-02-01 08:38:12 -080031class MockAdaptationObserver : public AdaptationObserverInterface {
kthelgason876222f2016-11-29 01:44:11 -080032 public:
sprangb1ca0732017-02-01 08:38:12 -080033 virtual ~MockAdaptationObserver() {}
kthelgason876222f2016-11-29 01:44:11 -080034
sprangb1ca0732017-02-01 08:38:12 -080035 void AdaptUp(AdaptReason r) override {
36 adapt_up_events_++;
kthelgason876222f2016-11-29 01:44:11 -080037 event.Set();
38 }
Åsa Perssonf5e5d252019-08-16 17:24:59 +020039 bool AdaptDown(AdaptReason r) override {
sprangb1ca0732017-02-01 08:38:12 -080040 adapt_down_events_++;
kthelgason876222f2016-11-29 01:44:11 -080041 event.Set();
Åsa Perssonf5e5d252019-08-16 17:24:59 +020042 return true;
kthelgason876222f2016-11-29 01:44:11 -080043 }
44
45 rtc::Event event;
sprangb1ca0732017-02-01 08:38:12 -080046 int adapt_up_events_ = 0;
47 int adapt_down_events_ = 0;
kthelgason876222f2016-11-29 01:44:11 -080048};
49
50// Pass a lower sampling period to speed up the tests.
51class QualityScalerUnderTest : public QualityScaler {
52 public:
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010053 explicit QualityScalerUnderTest(rtc::TaskQueue* task_queue,
54 AdaptationObserverInterface* observer,
kthelgason876222f2016-11-29 01:44:11 -080055 VideoEncoder::QpThresholds thresholds)
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010056 : QualityScaler(task_queue, observer, thresholds, 5) {}
kthelgason876222f2016-11-29 01:44:11 -080057};
58
Åsa Perssona945aee2018-04-24 16:53:25 +020059class QualityScalerTest : public ::testing::Test,
60 public ::testing::WithParamInterface<std::string> {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000061 protected:
Peter Boström17417702015-09-25 17:03:26 +020062 enum ScaleDirection {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020063 kKeepScaleAboveLowQp,
Peter Boström17417702015-09-25 17:03:26 +020064 kKeepScaleAtHighQp,
65 kScaleDown,
66 kScaleDownAboveHighQp,
67 kScaleUp
68 };
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000069
kthelgason876222f2016-11-29 01:44:11 -080070 QualityScalerTest()
Åsa Perssona945aee2018-04-24 16:53:25 +020071 : scoped_field_trial_(GetParam()),
Danil Chapovalovb42165e2019-03-20 14:29:43 +010072 task_queue_("QualityScalerTestQueue"),
sprangb1ca0732017-02-01 08:38:12 -080073 observer_(new MockAdaptationObserver()) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020074 task_queue_.SendTask(
75 [this] {
76 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
77 &task_queue_, observer_.get(),
78 VideoEncoder::QpThresholds(kLowQp, kHighQp)));
79 },
80 RTC_FROM_HERE);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000081 }
82
kthelgason876222f2016-11-29 01:44:11 -080083 ~QualityScalerTest() {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020084 task_queue_.SendTask([this] { qs_ = nullptr; }, RTC_FROM_HERE);
kthelgason876222f2016-11-29 01:44:11 -080085 }
86
87 void TriggerScale(ScaleDirection scale_direction) {
88 for (int i = 0; i < kFramerate * 5; ++i) {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000089 switch (scale_direction) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020090 case kKeepScaleAboveLowQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010091 qs_->ReportQp(kLowQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020092 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000093 case kScaleUp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010094 qs_->ReportQp(kLowQp, 0);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000095 break;
96 case kScaleDown:
Åsa Perssona945aee2018-04-24 16:53:25 +020097 qs_->ReportDroppedFrameByMediaOpt();
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000098 break;
Peter Boström17417702015-09-25 17:03:26 +020099 case kKeepScaleAtHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100100 qs_->ReportQp(kHighQp, 0);
Peter Boström17417702015-09-25 17:03:26 +0200101 break;
102 case kScaleDownAboveHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100103 qs_->ReportQp(kHighQp + 1, 0);
Peter Boström17417702015-09-25 17:03:26 +0200104 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000105 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000106 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000107 }
108
Åsa Perssona945aee2018-04-24 16:53:25 +0200109 test::ScopedFieldTrials scoped_field_trial_;
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100110 TaskQueueForTest task_queue_;
kthelgason876222f2016-11-29 01:44:11 -0800111 std::unique_ptr<QualityScaler> qs_;
sprangb1ca0732017-02-01 08:38:12 -0800112 std::unique_ptr<MockAdaptationObserver> observer_;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000113};
114
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100115INSTANTIATE_TEST_SUITE_P(
Åsa Perssona945aee2018-04-24 16:53:25 +0200116 FieldTrials,
117 QualityScalerTest,
118 ::testing::Values(
119 "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/",
120 ""));
121
122TEST_P(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200123 task_queue_.SendTask([this] { TriggerScale(kScaleDown); }, RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800124 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800125 EXPECT_EQ(1, observer_->adapt_down_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200126 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000127}
128
Åsa Perssona945aee2018-04-24 16:53:25 +0200129TEST_P(QualityScalerTest, KeepsScaleAtHighQp) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200130 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAtHighQp); },
131 RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800132 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800133 EXPECT_EQ(0, observer_->adapt_down_events_);
134 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200135}
136
Åsa Perssona945aee2018-04-24 16:53:25 +0200137TEST_P(QualityScalerTest, DownscalesAboveHighQp) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200138 task_queue_.SendTask([this] { TriggerScale(kScaleDownAboveHighQp); },
139 RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800140 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800141 EXPECT_EQ(1, observer_->adapt_down_events_);
142 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200143}
144
Åsa Perssona945aee2018-04-24 16:53:25 +0200145TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200146 task_queue_.SendTask(
147 [this] {
148 for (int i = 0; i < kFramerate * 5; ++i) {
149 qs_->ReportDroppedFrameByMediaOpt();
150 qs_->ReportDroppedFrameByMediaOpt();
151 qs_->ReportQp(kHighQp, 0);
152 }
153 },
154 RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800155 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800156 EXPECT_EQ(1, observer_->adapt_down_events_);
157 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000158}
159
Åsa Perssona945aee2018-04-24 16:53:25 +0200160TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200161 task_queue_.SendTask(
162 [this] {
163 for (int i = 0; i < kFramerate * 5; ++i) {
164 qs_->ReportDroppedFrameByMediaOpt();
165 qs_->ReportQp(kHighQp, 0);
166 }
167 },
168 RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800169 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800170 EXPECT_EQ(0, observer_->adapt_down_events_);
171 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000172}
173
Åsa Perssona945aee2018-04-24 16:53:25 +0200174TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
175 const bool kDownScaleExpected = !GetParam().empty();
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200176 task_queue_.SendTask(
177 [this] {
178 for (int i = 0; i < kFramerate * 5; ++i) {
179 qs_->ReportDroppedFrameByMediaOpt();
180 qs_->ReportDroppedFrameByEncoder();
181 qs_->ReportQp(kHighQp, 0);
182 }
183 },
184 RTC_FROM_HERE);
Åsa Perssona945aee2018-04-24 16:53:25 +0200185 EXPECT_EQ(kDownScaleExpected, observer_->event.Wait(kDefaultTimeoutMs));
186 EXPECT_EQ(kDownScaleExpected ? 1 : 0, observer_->adapt_down_events_);
187 EXPECT_EQ(0, observer_->adapt_up_events_);
188}
189
190TEST_P(QualityScalerTest, KeepsScaleOnNormalQp) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200191 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAboveLowQp); },
192 RTC_FROM_HERE);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200193 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
194 EXPECT_EQ(0, observer_->adapt_down_events_);
195 EXPECT_EQ(0, observer_->adapt_up_events_);
196}
197
Åsa Perssona945aee2018-04-24 16:53:25 +0200198TEST_P(QualityScalerTest, UpscalesAfterLowQp) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200199 task_queue_.SendTask([this] { TriggerScale(kScaleUp); }, RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800200 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800201 EXPECT_EQ(0, observer_->adapt_down_events_);
202 EXPECT_EQ(1, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000203}
204
Åsa Perssona945aee2018-04-24 16:53:25 +0200205TEST_P(QualityScalerTest, ScalesDownAndBackUp) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200206 task_queue_.SendTask([this] { TriggerScale(kScaleDown); }, RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800207 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800208 EXPECT_EQ(1, observer_->adapt_down_events_);
209 EXPECT_EQ(0, observer_->adapt_up_events_);
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200210 task_queue_.SendTask([this] { TriggerScale(kScaleUp); }, RTC_FROM_HERE);
kthelgason86cf9a22016-12-01 02:57:01 -0800211 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800212 EXPECT_EQ(1, observer_->adapt_down_events_);
213 EXPECT_EQ(1, observer_->adapt_up_events_);
Peter Boström6a688f52015-06-22 08:02:58 +0200214}
kthelgason55a01352017-04-04 02:31:42 -0700215
Åsa Perssona945aee2018-04-24 16:53:25 +0200216TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200217 task_queue_.SendTask(
218 [this] {
219 // Not enough frames to make a decision.
220 for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
221 qs_->ReportQp(kLowQp, 0);
222 }
223 },
224 RTC_FROM_HERE);
kthelgason55a01352017-04-04 02:31:42 -0700225 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200226 task_queue_.SendTask(
227 [this] {
228 // Send 1 more. Enough frames observed, should result in an adapt
229 // request.
230 qs_->ReportQp(kLowQp, 0);
231 },
232 RTC_FROM_HERE);
kthelgason55a01352017-04-04 02:31:42 -0700233 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
234 EXPECT_EQ(0, observer_->adapt_down_events_);
235 EXPECT_EQ(1, observer_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200236
237 // Samples should be cleared after an adapt request.
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200238 task_queue_.SendTask(
239 [this] {
240 // Not enough frames to make a decision.
241 qs_->ReportQp(kLowQp, 0);
242 },
243 RTC_FROM_HERE);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200244 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
245 EXPECT_EQ(0, observer_->adapt_down_events_);
246 EXPECT_EQ(1, observer_->adapt_up_events_);
kthelgason55a01352017-04-04 02:31:42 -0700247}
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200248
Åsa Perssona945aee2018-04-24 16:53:25 +0200249TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200250 task_queue_.SendTask(
251 [this] {
252 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
253 qs_->ReportQp(kHighQp + 1, 0);
254 }
255 },
256 RTC_FROM_HERE);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200257 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
258 EXPECT_EQ(1, observer_->adapt_down_events_);
259 EXPECT_EQ(0, observer_->adapt_up_events_);
260 // Samples cleared.
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200261 task_queue_.SendTask(
262 [this] {
263 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
264 qs_->ReportQp(kLowQp, 0);
265 }
266 },
267 RTC_FROM_HERE);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200268 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
269 EXPECT_EQ(1, observer_->adapt_down_events_);
270 EXPECT_EQ(1, observer_->adapt_up_events_);
271}
272
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000273} // namespace webrtc