blob: 6202947a35c515c2de01a166e73f19c1dd9fad8a [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
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020031class FakeQpUsageHandler : public QualityScalerQpUsageHandlerInterface {
kthelgason876222f2016-11-29 01:44:11 -080032 public:
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020033 ~FakeQpUsageHandler() override = default;
kthelgason876222f2016-11-29 01:44:11 -080034
Henrik Boström012aa372020-04-27 17:40:55 +020035 // QualityScalerQpUsageHandlerInterface implementation.
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020036 void OnReportQpUsageHigh() override {
sprangb1ca0732017-02-01 08:38:12 -080037 adapt_down_events_++;
kthelgason876222f2016-11-29 01:44:11 -080038 event.Set();
Henrik Boström012aa372020-04-27 17:40:55 +020039 }
40
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020041 void OnReportQpUsageLow() override {
Henrik Boström012aa372020-04-27 17:40:55 +020042 adapt_up_events_++;
43 event.Set();
kthelgason876222f2016-11-29 01:44:11 -080044 }
45
46 rtc::Event event;
sprangb1ca0732017-02-01 08:38:12 -080047 int adapt_up_events_ = 0;
48 int adapt_down_events_ = 0;
kthelgason876222f2016-11-29 01:44:11 -080049};
50
51// Pass a lower sampling period to speed up the tests.
52class QualityScalerUnderTest : public QualityScaler {
53 public:
Henrik Boström012aa372020-04-27 17:40:55 +020054 explicit QualityScalerUnderTest(QualityScalerQpUsageHandlerInterface* handler,
kthelgason876222f2016-11-29 01:44:11 -080055 VideoEncoder::QpThresholds thresholds)
Henrik Boström012aa372020-04-27 17:40:55 +020056 : QualityScaler(handler, 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"),
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020073 handler_(std::make_unique<FakeQpUsageHandler>()) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020074 task_queue_.SendTask(
75 [this] {
76 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
Henrik Boström012aa372020-04-27 17:40:55 +020077 handler_.get(), VideoEncoder::QpThresholds(kLowQp, kHighQp)));
Danil Chapovalove519f382022-08-11 12:26:09 +020078 });
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000079 }
80
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020081 ~QualityScalerTest() override {
Danil Chapovalove519f382022-08-11 12:26:09 +020082 task_queue_.SendTask([this] { qs_ = nullptr; });
kthelgason876222f2016-11-29 01:44:11 -080083 }
84
85 void TriggerScale(ScaleDirection scale_direction) {
86 for (int i = 0; i < kFramerate * 5; ++i) {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000087 switch (scale_direction) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020088 case kKeepScaleAboveLowQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010089 qs_->ReportQp(kLowQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020090 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000091 case kScaleUp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010092 qs_->ReportQp(kLowQp, 0);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000093 break;
94 case kScaleDown:
Åsa Perssona945aee2018-04-24 16:53:25 +020095 qs_->ReportDroppedFrameByMediaOpt();
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000096 break;
Peter Boström17417702015-09-25 17:03:26 +020097 case kKeepScaleAtHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010098 qs_->ReportQp(kHighQp, 0);
Peter Boström17417702015-09-25 17:03:26 +020099 break;
100 case kScaleDownAboveHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100101 qs_->ReportQp(kHighQp + 1, 0);
Peter Boström17417702015-09-25 17:03:26 +0200102 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000103 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000104 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000105 }
106
Åsa Perssona945aee2018-04-24 16:53:25 +0200107 test::ScopedFieldTrials scoped_field_trial_;
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100108 TaskQueueForTest task_queue_;
kthelgason876222f2016-11-29 01:44:11 -0800109 std::unique_ptr<QualityScaler> qs_;
Evan Shrubsolea1c77f62020-08-10 11:01:06 +0200110 std::unique_ptr<FakeQpUsageHandler> handler_;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000111};
112
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100113INSTANTIATE_TEST_SUITE_P(
Åsa Perssona945aee2018-04-24 16:53:25 +0200114 FieldTrials,
115 QualityScalerTest,
116 ::testing::Values(
Ilya Nikolaevskiyd6604df2021-02-01 12:01:06 +0000117 "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/",
Ilya Nikolaevskiy483b31c2021-02-03 17:19:31 +0100118 "WebRTC-Video-QualityScaling/Disabled/"));
Åsa Perssona945aee2018-04-24 16:53:25 +0200119
120TEST_P(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200121 task_queue_.SendTask([this] { TriggerScale(kScaleDown); });
Henrik Boström012aa372020-04-27 17:40:55 +0200122 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
123 EXPECT_EQ(1, handler_->adapt_down_events_);
124 EXPECT_EQ(0, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000125}
126
Åsa Perssona945aee2018-04-24 16:53:25 +0200127TEST_P(QualityScalerTest, KeepsScaleAtHighQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200128 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAtHighQp); });
Henrik Boström012aa372020-04-27 17:40:55 +0200129 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeoutMs));
130 EXPECT_EQ(0, handler_->adapt_down_events_);
131 EXPECT_EQ(0, handler_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200132}
133
Åsa Perssona945aee2018-04-24 16:53:25 +0200134TEST_P(QualityScalerTest, DownscalesAboveHighQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200135 task_queue_.SendTask([this] { TriggerScale(kScaleDownAboveHighQp); });
Henrik Boström012aa372020-04-27 17:40:55 +0200136 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
137 EXPECT_EQ(1, handler_->adapt_down_events_);
138 EXPECT_EQ(0, handler_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200139}
140
Åsa Perssona945aee2018-04-24 16:53:25 +0200141TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200142 task_queue_.SendTask([this] {
143 for (int i = 0; i < kFramerate * 5; ++i) {
144 qs_->ReportDroppedFrameByMediaOpt();
145 qs_->ReportDroppedFrameByMediaOpt();
146 qs_->ReportQp(kHighQp, 0);
147 }
148 });
Henrik Boström012aa372020-04-27 17:40:55 +0200149 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
150 EXPECT_EQ(1, handler_->adapt_down_events_);
151 EXPECT_EQ(0, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000152}
153
Åsa Perssona945aee2018-04-24 16:53:25 +0200154TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200155 task_queue_.SendTask([this] {
156 for (int i = 0; i < kFramerate * 5; ++i) {
157 qs_->ReportDroppedFrameByMediaOpt();
158 qs_->ReportQp(kHighQp, 0);
159 }
160 });
Henrik Boström012aa372020-04-27 17:40:55 +0200161 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeoutMs));
162 EXPECT_EQ(0, handler_->adapt_down_events_);
163 EXPECT_EQ(0, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000164}
165
Åsa Perssona945aee2018-04-24 16:53:25 +0200166TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
Ilya Nikolaevskiy483b31c2021-02-03 17:19:31 +0100167 const bool kDownScaleExpected =
168 GetParam().find("Enabled") != std::string::npos;
Danil Chapovalove519f382022-08-11 12:26:09 +0200169 task_queue_.SendTask([this] {
170 for (int i = 0; i < kFramerate * 5; ++i) {
171 qs_->ReportDroppedFrameByMediaOpt();
172 qs_->ReportDroppedFrameByEncoder();
173 qs_->ReportQp(kHighQp, 0);
174 }
175 });
Henrik Boström012aa372020-04-27 17:40:55 +0200176 EXPECT_EQ(kDownScaleExpected, handler_->event.Wait(kDefaultTimeoutMs));
177 EXPECT_EQ(kDownScaleExpected ? 1 : 0, handler_->adapt_down_events_);
178 EXPECT_EQ(0, handler_->adapt_up_events_);
Åsa Perssona945aee2018-04-24 16:53:25 +0200179}
180
181TEST_P(QualityScalerTest, KeepsScaleOnNormalQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200182 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAboveLowQp); });
Henrik Boström012aa372020-04-27 17:40:55 +0200183 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeoutMs));
184 EXPECT_EQ(0, handler_->adapt_down_events_);
185 EXPECT_EQ(0, handler_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200186}
187
Åsa Perssona945aee2018-04-24 16:53:25 +0200188TEST_P(QualityScalerTest, UpscalesAfterLowQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200189 task_queue_.SendTask([this] { TriggerScale(kScaleUp); });
Henrik Boström012aa372020-04-27 17:40:55 +0200190 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
191 EXPECT_EQ(0, handler_->adapt_down_events_);
192 EXPECT_EQ(1, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000193}
194
Åsa Perssona945aee2018-04-24 16:53:25 +0200195TEST_P(QualityScalerTest, ScalesDownAndBackUp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200196 task_queue_.SendTask([this] { TriggerScale(kScaleDown); });
Henrik Boström012aa372020-04-27 17:40:55 +0200197 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
198 EXPECT_EQ(1, handler_->adapt_down_events_);
199 EXPECT_EQ(0, handler_->adapt_up_events_);
Danil Chapovalove519f382022-08-11 12:26:09 +0200200 task_queue_.SendTask([this] { TriggerScale(kScaleUp); });
Henrik Boström012aa372020-04-27 17:40:55 +0200201 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
202 EXPECT_EQ(1, handler_->adapt_down_events_);
203 EXPECT_EQ(1, handler_->adapt_up_events_);
Peter Boström6a688f52015-06-22 08:02:58 +0200204}
kthelgason55a01352017-04-04 02:31:42 -0700205
Åsa Perssona945aee2018-04-24 16:53:25 +0200206TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200207 task_queue_.SendTask([this] {
208 // Not enough frames to make a decision.
209 for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
210 qs_->ReportQp(kLowQp, 0);
211 }
212 });
Henrik Boström012aa372020-04-27 17:40:55 +0200213 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeoutMs));
Danil Chapovalove519f382022-08-11 12:26:09 +0200214 task_queue_.SendTask([this] {
215 // Send 1 more. Enough frames observed, should result in an adapt
216 // request.
217 qs_->ReportQp(kLowQp, 0);
218 });
Henrik Boström012aa372020-04-27 17:40:55 +0200219 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
220 EXPECT_EQ(0, handler_->adapt_down_events_);
221 EXPECT_EQ(1, handler_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200222
223 // Samples should be cleared after an adapt request.
Danil Chapovalove519f382022-08-11 12:26:09 +0200224 task_queue_.SendTask([this] {
225 // Not enough frames to make a decision.
226 qs_->ReportQp(kLowQp, 0);
227 });
Henrik Boström012aa372020-04-27 17:40:55 +0200228 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeoutMs));
229 EXPECT_EQ(0, handler_->adapt_down_events_);
230 EXPECT_EQ(1, handler_->adapt_up_events_);
kthelgason55a01352017-04-04 02:31:42 -0700231}
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200232
Åsa Perssona945aee2018-04-24 16:53:25 +0200233TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200234 task_queue_.SendTask([this] {
235 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
236 qs_->ReportQp(kHighQp + 1, 0);
237 }
238 });
Henrik Boström012aa372020-04-27 17:40:55 +0200239 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
240 EXPECT_EQ(1, handler_->adapt_down_events_);
241 EXPECT_EQ(0, handler_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200242 // Samples cleared.
Danil Chapovalove519f382022-08-11 12:26:09 +0200243 task_queue_.SendTask([this] {
244 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
245 qs_->ReportQp(kLowQp, 0);
246 }
247 });
Henrik Boström012aa372020-04-27 17:40:55 +0200248 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeoutMs));
249 EXPECT_EQ(1, handler_->adapt_down_events_);
250 EXPECT_EQ(1, handler_->adapt_up_events_);
251}
252
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000253} // namespace webrtc