blob: 618439c8a766620cce58866a3140098a5b9e6bc6 [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"
18#include "rtc_base/task_queue.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
Niels Möllerc572ff32018-11-07 08:43:50 +010031#define DO_SYNC(q, block) \
32 do { \
33 rtc::Event event; \
34 q->PostTask([this, &event] { \
35 block; \
36 event.Set(); \
37 }); \
38 RTC_CHECK(event.Wait(1000)); \
kthelgasonb12a3e32017-03-30 01:04:55 -070039 } while (0)
40
sprangb1ca0732017-02-01 08:38:12 -080041class MockAdaptationObserver : public AdaptationObserverInterface {
kthelgason876222f2016-11-29 01:44:11 -080042 public:
sprangb1ca0732017-02-01 08:38:12 -080043 virtual ~MockAdaptationObserver() {}
kthelgason876222f2016-11-29 01:44:11 -080044
sprangb1ca0732017-02-01 08:38:12 -080045 void AdaptUp(AdaptReason r) override {
46 adapt_up_events_++;
kthelgason876222f2016-11-29 01:44:11 -080047 event.Set();
48 }
sprangb1ca0732017-02-01 08:38:12 -080049 void AdaptDown(AdaptReason r) override {
50 adapt_down_events_++;
kthelgason876222f2016-11-29 01:44:11 -080051 event.Set();
52 }
53
54 rtc::Event event;
sprangb1ca0732017-02-01 08:38:12 -080055 int adapt_up_events_ = 0;
56 int adapt_down_events_ = 0;
kthelgason876222f2016-11-29 01:44:11 -080057};
58
59// Pass a lower sampling period to speed up the tests.
60class QualityScalerUnderTest : public QualityScaler {
61 public:
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010062 explicit QualityScalerUnderTest(rtc::TaskQueue* task_queue,
63 AdaptationObserverInterface* observer,
kthelgason876222f2016-11-29 01:44:11 -080064 VideoEncoder::QpThresholds thresholds)
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010065 : QualityScaler(task_queue, observer, thresholds, 5) {}
kthelgason876222f2016-11-29 01:44:11 -080066};
67
Åsa Perssona945aee2018-04-24 16:53:25 +020068class QualityScalerTest : public ::testing::Test,
69 public ::testing::WithParamInterface<std::string> {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000070 protected:
Peter Boström17417702015-09-25 17:03:26 +020071 enum ScaleDirection {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020072 kKeepScaleAboveLowQp,
Peter Boström17417702015-09-25 17:03:26 +020073 kKeepScaleAtHighQp,
74 kScaleDown,
75 kScaleDownAboveHighQp,
76 kScaleUp
77 };
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000078
kthelgason876222f2016-11-29 01:44:11 -080079 QualityScalerTest()
Åsa Perssona945aee2018-04-24 16:53:25 +020080 : scoped_field_trial_(GetParam()),
81 q_(new rtc::TaskQueue("QualityScalerTestQueue")),
sprangb1ca0732017-02-01 08:38:12 -080082 observer_(new MockAdaptationObserver()) {
kthelgasonb12a3e32017-03-30 01:04:55 -070083 DO_SYNC(q_, {
kthelgason876222f2016-11-29 01:44:11 -080084 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010085 q_.get(), observer_.get(),
86 VideoEncoder::QpThresholds(kLowQp, kHighQp)));
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020087 });
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000088 }
89
kthelgason876222f2016-11-29 01:44:11 -080090 ~QualityScalerTest() {
Yves Gerey665174f2018-06-19 15:03:05 +020091 DO_SYNC(q_, { qs_.reset(nullptr); });
kthelgason876222f2016-11-29 01:44:11 -080092 }
93
94 void TriggerScale(ScaleDirection scale_direction) {
95 for (int i = 0; i < kFramerate * 5; ++i) {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000096 switch (scale_direction) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020097 case kKeepScaleAboveLowQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010098 qs_->ReportQp(kLowQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020099 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000100 case kScaleUp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100101 qs_->ReportQp(kLowQp, 0);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000102 break;
103 case kScaleDown:
Åsa Perssona945aee2018-04-24 16:53:25 +0200104 qs_->ReportDroppedFrameByMediaOpt();
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000105 break;
Peter Boström17417702015-09-25 17:03:26 +0200106 case kKeepScaleAtHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100107 qs_->ReportQp(kHighQp, 0);
Peter Boström17417702015-09-25 17:03:26 +0200108 break;
109 case kScaleDownAboveHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100110 qs_->ReportQp(kHighQp + 1, 0);
Peter Boström17417702015-09-25 17:03:26 +0200111 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000112 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000113 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000114 }
115
Åsa Perssona945aee2018-04-24 16:53:25 +0200116 test::ScopedFieldTrials scoped_field_trial_;
kthelgason876222f2016-11-29 01:44:11 -0800117 std::unique_ptr<rtc::TaskQueue> q_;
118 std::unique_ptr<QualityScaler> qs_;
sprangb1ca0732017-02-01 08:38:12 -0800119 std::unique_ptr<MockAdaptationObserver> observer_;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000120};
121
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100122INSTANTIATE_TEST_SUITE_P(
Åsa Perssona945aee2018-04-24 16:53:25 +0200123 FieldTrials,
124 QualityScalerTest,
125 ::testing::Values(
126 "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/",
127 ""));
128
129TEST_P(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700130 DO_SYNC(q_, { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800131 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800132 EXPECT_EQ(1, observer_->adapt_down_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200133 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000134}
135
Åsa Perssona945aee2018-04-24 16:53:25 +0200136TEST_P(QualityScalerTest, KeepsScaleAtHighQp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700137 DO_SYNC(q_, { TriggerScale(kKeepScaleAtHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800138 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800139 EXPECT_EQ(0, observer_->adapt_down_events_);
140 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200141}
142
Åsa Perssona945aee2018-04-24 16:53:25 +0200143TEST_P(QualityScalerTest, DownscalesAboveHighQp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700144 DO_SYNC(q_, { TriggerScale(kScaleDownAboveHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800145 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800146 EXPECT_EQ(1, observer_->adapt_down_events_);
147 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200148}
149
Åsa Perssona945aee2018-04-24 16:53:25 +0200150TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700151 DO_SYNC(q_, {
kthelgason55a01352017-04-04 02:31:42 -0700152 for (int i = 0; i < kFramerate * 5; ++i) {
Åsa Perssona945aee2018-04-24 16:53:25 +0200153 qs_->ReportDroppedFrameByMediaOpt();
154 qs_->ReportDroppedFrameByMediaOpt();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100155 qs_->ReportQp(kHighQp, 0);
kthelgason55a01352017-04-04 02:31:42 -0700156 }
kthelgason876222f2016-11-29 01:44:11 -0800157 });
kthelgason86cf9a22016-12-01 02:57:01 -0800158 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800159 EXPECT_EQ(1, observer_->adapt_down_events_);
160 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000161}
162
Åsa Perssona945aee2018-04-24 16:53:25 +0200163TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700164 DO_SYNC(q_, {
kthelgason55a01352017-04-04 02:31:42 -0700165 for (int i = 0; i < kFramerate * 5; ++i) {
Åsa Perssona945aee2018-04-24 16:53:25 +0200166 qs_->ReportDroppedFrameByMediaOpt();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100167 qs_->ReportQp(kHighQp, 0);
kthelgason55a01352017-04-04 02:31:42 -0700168 }
kthelgason876222f2016-11-29 01:44:11 -0800169 });
kthelgason86cf9a22016-12-01 02:57:01 -0800170 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800171 EXPECT_EQ(0, observer_->adapt_down_events_);
172 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000173}
174
Åsa Perssona945aee2018-04-24 16:53:25 +0200175TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
176 const bool kDownScaleExpected = !GetParam().empty();
177 DO_SYNC(q_, {
178 for (int i = 0; i < kFramerate * 5; ++i) {
179 qs_->ReportDroppedFrameByMediaOpt();
180 qs_->ReportDroppedFrameByEncoder();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100181 qs_->ReportQp(kHighQp, 0);
Åsa Perssona945aee2018-04-24 16:53:25 +0200182 }
183 });
184 EXPECT_EQ(kDownScaleExpected, observer_->event.Wait(kDefaultTimeoutMs));
185 EXPECT_EQ(kDownScaleExpected ? 1 : 0, observer_->adapt_down_events_);
186 EXPECT_EQ(0, observer_->adapt_up_events_);
187}
188
189TEST_P(QualityScalerTest, KeepsScaleOnNormalQp) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200190 DO_SYNC(q_, { TriggerScale(kKeepScaleAboveLowQp); });
191 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
192 EXPECT_EQ(0, observer_->adapt_down_events_);
193 EXPECT_EQ(0, observer_->adapt_up_events_);
194}
195
Åsa Perssona945aee2018-04-24 16:53:25 +0200196TEST_P(QualityScalerTest, UpscalesAfterLowQp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700197 DO_SYNC(q_, { TriggerScale(kScaleUp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800198 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800199 EXPECT_EQ(0, observer_->adapt_down_events_);
200 EXPECT_EQ(1, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000201}
202
Åsa Perssona945aee2018-04-24 16:53:25 +0200203TEST_P(QualityScalerTest, ScalesDownAndBackUp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700204 DO_SYNC(q_, { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800205 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800206 EXPECT_EQ(1, observer_->adapt_down_events_);
207 EXPECT_EQ(0, observer_->adapt_up_events_);
kthelgasonb12a3e32017-03-30 01:04:55 -0700208 DO_SYNC(q_, { TriggerScale(kScaleUp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800209 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800210 EXPECT_EQ(1, observer_->adapt_down_events_);
211 EXPECT_EQ(1, observer_->adapt_up_events_);
Peter Boström6a688f52015-06-22 08:02:58 +0200212}
kthelgason55a01352017-04-04 02:31:42 -0700213
Åsa Perssona945aee2018-04-24 16:53:25 +0200214TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
kthelgason55a01352017-04-04 02:31:42 -0700215 DO_SYNC(q_, {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200216 // Not enough frames to make a decision.
217 for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100218 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200219 }
220 });
kthelgason55a01352017-04-04 02:31:42 -0700221 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
222 DO_SYNC(q_, {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200223 // Send 1 more. Enough frames observed, should result in an adapt request.
Sebastian Janssonb6789402019-03-01 15:40:49 +0100224 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200225 });
kthelgason55a01352017-04-04 02:31:42 -0700226 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
227 EXPECT_EQ(0, observer_->adapt_down_events_);
228 EXPECT_EQ(1, observer_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200229
230 // Samples should be cleared after an adapt request.
231 DO_SYNC(q_, {
232 // Not enough frames to make a decision.
Sebastian Janssonb6789402019-03-01 15:40:49 +0100233 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200234 });
235 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
236 EXPECT_EQ(0, observer_->adapt_down_events_);
237 EXPECT_EQ(1, observer_->adapt_up_events_);
kthelgason55a01352017-04-04 02:31:42 -0700238}
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200239
Åsa Perssona945aee2018-04-24 16:53:25 +0200240TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200241 DO_SYNC(q_, {
242 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100243 qs_->ReportQp(kHighQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200244 }
245 });
246 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
247 EXPECT_EQ(1, observer_->adapt_down_events_);
248 EXPECT_EQ(0, observer_->adapt_up_events_);
249 // Samples cleared.
250 DO_SYNC(q_, {
251 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100252 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200253 }
254 });
255 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
256 EXPECT_EQ(1, observer_->adapt_down_events_);
257 EXPECT_EQ(1, observer_->adapt_up_events_);
258}
259
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000260} // namespace webrtc
kthelgasonb12a3e32017-03-30 01:04:55 -0700261#undef DO_SYNC