blob: 342431242ea9b792f95d151cc31df27538bfacef [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:
sprangb1ca0732017-02-01 08:38:12 -080062 explicit QualityScalerUnderTest(AdaptationObserverInterface* observer,
kthelgason876222f2016-11-29 01:44:11 -080063 VideoEncoder::QpThresholds thresholds)
64 : QualityScaler(observer, thresholds, 5) {}
65};
66
Åsa Perssona945aee2018-04-24 16:53:25 +020067class QualityScalerTest : public ::testing::Test,
68 public ::testing::WithParamInterface<std::string> {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000069 protected:
Peter Boström17417702015-09-25 17:03:26 +020070 enum ScaleDirection {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020071 kKeepScaleAboveLowQp,
Peter Boström17417702015-09-25 17:03:26 +020072 kKeepScaleAtHighQp,
73 kScaleDown,
74 kScaleDownAboveHighQp,
75 kScaleUp
76 };
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000077
kthelgason876222f2016-11-29 01:44:11 -080078 QualityScalerTest()
Åsa Perssona945aee2018-04-24 16:53:25 +020079 : scoped_field_trial_(GetParam()),
80 q_(new rtc::TaskQueue("QualityScalerTestQueue")),
sprangb1ca0732017-02-01 08:38:12 -080081 observer_(new MockAdaptationObserver()) {
kthelgasonb12a3e32017-03-30 01:04:55 -070082 DO_SYNC(q_, {
kthelgason876222f2016-11-29 01:44:11 -080083 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020084 observer_.get(), VideoEncoder::QpThresholds(kLowQp, kHighQp)));
85 });
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000086 }
87
kthelgason876222f2016-11-29 01:44:11 -080088 ~QualityScalerTest() {
Yves Gerey665174f2018-06-19 15:03:05 +020089 DO_SYNC(q_, { qs_.reset(nullptr); });
kthelgason876222f2016-11-29 01:44:11 -080090 }
91
92 void TriggerScale(ScaleDirection scale_direction) {
93 for (int i = 0; i < kFramerate * 5; ++i) {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000094 switch (scale_direction) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020095 case kKeepScaleAboveLowQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010096 qs_->ReportQp(kLowQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020097 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000098 case kScaleUp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010099 qs_->ReportQp(kLowQp, 0);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000100 break;
101 case kScaleDown:
Åsa Perssona945aee2018-04-24 16:53:25 +0200102 qs_->ReportDroppedFrameByMediaOpt();
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000103 break;
Peter Boström17417702015-09-25 17:03:26 +0200104 case kKeepScaleAtHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100105 qs_->ReportQp(kHighQp, 0);
Peter Boström17417702015-09-25 17:03:26 +0200106 break;
107 case kScaleDownAboveHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100108 qs_->ReportQp(kHighQp + 1, 0);
Peter Boström17417702015-09-25 17:03:26 +0200109 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000110 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000111 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000112 }
113
Åsa Perssona945aee2018-04-24 16:53:25 +0200114 test::ScopedFieldTrials scoped_field_trial_;
kthelgason876222f2016-11-29 01:44:11 -0800115 std::unique_ptr<rtc::TaskQueue> q_;
116 std::unique_ptr<QualityScaler> qs_;
sprangb1ca0732017-02-01 08:38:12 -0800117 std::unique_ptr<MockAdaptationObserver> observer_;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000118};
119
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100120INSTANTIATE_TEST_SUITE_P(
Åsa Perssona945aee2018-04-24 16:53:25 +0200121 FieldTrials,
122 QualityScalerTest,
123 ::testing::Values(
124 "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/",
125 ""));
126
127TEST_P(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700128 DO_SYNC(q_, { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800129 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800130 EXPECT_EQ(1, observer_->adapt_down_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200131 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000132}
133
Åsa Perssona945aee2018-04-24 16:53:25 +0200134TEST_P(QualityScalerTest, KeepsScaleAtHighQp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700135 DO_SYNC(q_, { TriggerScale(kKeepScaleAtHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800136 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800137 EXPECT_EQ(0, observer_->adapt_down_events_);
138 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200139}
140
Åsa Perssona945aee2018-04-24 16:53:25 +0200141TEST_P(QualityScalerTest, DownscalesAboveHighQp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700142 DO_SYNC(q_, { TriggerScale(kScaleDownAboveHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800143 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800144 EXPECT_EQ(1, observer_->adapt_down_events_);
145 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200146}
147
Åsa Perssona945aee2018-04-24 16:53:25 +0200148TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700149 DO_SYNC(q_, {
kthelgason55a01352017-04-04 02:31:42 -0700150 for (int i = 0; i < kFramerate * 5; ++i) {
Åsa Perssona945aee2018-04-24 16:53:25 +0200151 qs_->ReportDroppedFrameByMediaOpt();
152 qs_->ReportDroppedFrameByMediaOpt();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100153 qs_->ReportQp(kHighQp, 0);
kthelgason55a01352017-04-04 02:31:42 -0700154 }
kthelgason876222f2016-11-29 01:44:11 -0800155 });
kthelgason86cf9a22016-12-01 02:57:01 -0800156 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800157 EXPECT_EQ(1, observer_->adapt_down_events_);
158 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000159}
160
Åsa Perssona945aee2018-04-24 16:53:25 +0200161TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700162 DO_SYNC(q_, {
kthelgason55a01352017-04-04 02:31:42 -0700163 for (int i = 0; i < kFramerate * 5; ++i) {
Åsa Perssona945aee2018-04-24 16:53:25 +0200164 qs_->ReportDroppedFrameByMediaOpt();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100165 qs_->ReportQp(kHighQp, 0);
kthelgason55a01352017-04-04 02:31:42 -0700166 }
kthelgason876222f2016-11-29 01:44:11 -0800167 });
kthelgason86cf9a22016-12-01 02:57:01 -0800168 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800169 EXPECT_EQ(0, observer_->adapt_down_events_);
170 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000171}
172
Åsa Perssona945aee2018-04-24 16:53:25 +0200173TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
174 const bool kDownScaleExpected = !GetParam().empty();
175 DO_SYNC(q_, {
176 for (int i = 0; i < kFramerate * 5; ++i) {
177 qs_->ReportDroppedFrameByMediaOpt();
178 qs_->ReportDroppedFrameByEncoder();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100179 qs_->ReportQp(kHighQp, 0);
Åsa Perssona945aee2018-04-24 16:53:25 +0200180 }
181 });
182 EXPECT_EQ(kDownScaleExpected, observer_->event.Wait(kDefaultTimeoutMs));
183 EXPECT_EQ(kDownScaleExpected ? 1 : 0, observer_->adapt_down_events_);
184 EXPECT_EQ(0, observer_->adapt_up_events_);
185}
186
187TEST_P(QualityScalerTest, KeepsScaleOnNormalQp) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200188 DO_SYNC(q_, { TriggerScale(kKeepScaleAboveLowQp); });
189 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
190 EXPECT_EQ(0, observer_->adapt_down_events_);
191 EXPECT_EQ(0, observer_->adapt_up_events_);
192}
193
Åsa Perssona945aee2018-04-24 16:53:25 +0200194TEST_P(QualityScalerTest, UpscalesAfterLowQp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700195 DO_SYNC(q_, { TriggerScale(kScaleUp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800196 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800197 EXPECT_EQ(0, observer_->adapt_down_events_);
198 EXPECT_EQ(1, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000199}
200
Åsa Perssona945aee2018-04-24 16:53:25 +0200201TEST_P(QualityScalerTest, ScalesDownAndBackUp) {
kthelgasonb12a3e32017-03-30 01:04:55 -0700202 DO_SYNC(q_, { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800203 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800204 EXPECT_EQ(1, observer_->adapt_down_events_);
205 EXPECT_EQ(0, observer_->adapt_up_events_);
kthelgasonb12a3e32017-03-30 01:04:55 -0700206 DO_SYNC(q_, { TriggerScale(kScaleUp); });
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(1, observer_->adapt_up_events_);
Peter Boström6a688f52015-06-22 08:02:58 +0200210}
kthelgason55a01352017-04-04 02:31:42 -0700211
Åsa Perssona945aee2018-04-24 16:53:25 +0200212TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
kthelgason55a01352017-04-04 02:31:42 -0700213 DO_SYNC(q_, {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200214 // Not enough frames to make a decision.
215 for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100216 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200217 }
218 });
kthelgason55a01352017-04-04 02:31:42 -0700219 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
220 DO_SYNC(q_, {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200221 // Send 1 more. Enough frames observed, should result in an adapt request.
Sebastian Janssonb6789402019-03-01 15:40:49 +0100222 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200223 });
kthelgason55a01352017-04-04 02:31:42 -0700224 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
225 EXPECT_EQ(0, observer_->adapt_down_events_);
226 EXPECT_EQ(1, observer_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200227
228 // Samples should be cleared after an adapt request.
229 DO_SYNC(q_, {
230 // Not enough frames to make a decision.
Sebastian Janssonb6789402019-03-01 15:40:49 +0100231 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200232 });
233 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
234 EXPECT_EQ(0, observer_->adapt_down_events_);
235 EXPECT_EQ(1, observer_->adapt_up_events_);
kthelgason55a01352017-04-04 02:31:42 -0700236}
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200237
Åsa Perssona945aee2018-04-24 16:53:25 +0200238TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200239 DO_SYNC(q_, {
240 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100241 qs_->ReportQp(kHighQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200242 }
243 });
244 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
245 EXPECT_EQ(1, observer_->adapt_down_events_);
246 EXPECT_EQ(0, observer_->adapt_up_events_);
247 // Samples cleared.
248 DO_SYNC(q_, {
249 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100250 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200251 }
252 });
253 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
254 EXPECT_EQ(1, observer_->adapt_down_events_);
255 EXPECT_EQ(1, observer_->adapt_up_events_);
256}
257
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000258} // namespace webrtc
kthelgasonb12a3e32017-03-30 01:04:55 -0700259#undef DO_SYNC