blob: c17159fb641c83f96935f31ab5a9f6aef8b60634 [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
Markus Handell2cfc1af2022-08-19 08:16:48 +000016#include "api/units/time_delta.h"
Yves Gerey3e707812018-11-28 16:47:49 +010017#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/event.h"
Danil Chapovalovb42165e2019-03-20 14:29:43 +010019#include "rtc_base/task_queue_for_test.h"
Åsa Perssona945aee2018-04-24 16:53:25 +020020#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "test/gtest.h"
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000022
23namespace webrtc {
24namespace {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000025static const int kFramerate = 30;
26static const int kLowQp = 15;
Peter Boström17417702015-09-25 17:03:26 +020027static const int kHighQp = 40;
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020028static const int kMinFramesNeededToScale = 60; // From quality_scaler.cc.
Markus Handell2cfc1af2022-08-19 08:16:48 +000029static constexpr TimeDelta kDefaultTimeout = TimeDelta::Millis(150);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000030} // namespace
31
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020032class FakeQpUsageHandler : public QualityScalerQpUsageHandlerInterface {
kthelgason876222f2016-11-29 01:44:11 -080033 public:
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020034 ~FakeQpUsageHandler() override = default;
kthelgason876222f2016-11-29 01:44:11 -080035
Henrik Boström012aa372020-04-27 17:40:55 +020036 // QualityScalerQpUsageHandlerInterface implementation.
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020037 void OnReportQpUsageHigh() override {
sprangb1ca0732017-02-01 08:38:12 -080038 adapt_down_events_++;
kthelgason876222f2016-11-29 01:44:11 -080039 event.Set();
Henrik Boström012aa372020-04-27 17:40:55 +020040 }
41
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020042 void OnReportQpUsageLow() override {
Henrik Boström012aa372020-04-27 17:40:55 +020043 adapt_up_events_++;
44 event.Set();
kthelgason876222f2016-11-29 01:44:11 -080045 }
46
47 rtc::Event event;
sprangb1ca0732017-02-01 08:38:12 -080048 int adapt_up_events_ = 0;
49 int adapt_down_events_ = 0;
kthelgason876222f2016-11-29 01:44:11 -080050};
51
52// Pass a lower sampling period to speed up the tests.
53class QualityScalerUnderTest : public QualityScaler {
54 public:
Henrik Boström012aa372020-04-27 17:40:55 +020055 explicit QualityScalerUnderTest(QualityScalerQpUsageHandlerInterface* handler,
kthelgason876222f2016-11-29 01:44:11 -080056 VideoEncoder::QpThresholds thresholds)
Henrik Boström012aa372020-04-27 17:40:55 +020057 : QualityScaler(handler, thresholds, 5) {}
kthelgason876222f2016-11-29 01:44:11 -080058};
59
Åsa Perssona945aee2018-04-24 16:53:25 +020060class QualityScalerTest : public ::testing::Test,
61 public ::testing::WithParamInterface<std::string> {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000062 protected:
Peter Boström17417702015-09-25 17:03:26 +020063 enum ScaleDirection {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020064 kKeepScaleAboveLowQp,
Peter Boström17417702015-09-25 17:03:26 +020065 kKeepScaleAtHighQp,
66 kScaleDown,
67 kScaleDownAboveHighQp,
68 kScaleUp
69 };
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000070
kthelgason876222f2016-11-29 01:44:11 -080071 QualityScalerTest()
Åsa Perssona945aee2018-04-24 16:53:25 +020072 : scoped_field_trial_(GetParam()),
Danil Chapovalovb42165e2019-03-20 14:29:43 +010073 task_queue_("QualityScalerTestQueue"),
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020074 handler_(std::make_unique<FakeQpUsageHandler>()) {
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020075 task_queue_.SendTask(
76 [this] {
77 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
Henrik Boström012aa372020-04-27 17:40:55 +020078 handler_.get(), VideoEncoder::QpThresholds(kLowQp, kHighQp)));
Danil Chapovalove519f382022-08-11 12:26:09 +020079 });
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000080 }
81
Evan Shrubsolea1c77f62020-08-10 11:01:06 +020082 ~QualityScalerTest() override {
Danil Chapovalove519f382022-08-11 12:26:09 +020083 task_queue_.SendTask([this] { qs_ = nullptr; });
kthelgason876222f2016-11-29 01:44:11 -080084 }
85
86 void TriggerScale(ScaleDirection scale_direction) {
87 for (int i = 0; i < kFramerate * 5; ++i) {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000088 switch (scale_direction) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020089 case kKeepScaleAboveLowQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010090 qs_->ReportQp(kLowQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020091 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000092 case kScaleUp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010093 qs_->ReportQp(kLowQp, 0);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000094 break;
95 case kScaleDown:
Åsa Perssona945aee2018-04-24 16:53:25 +020096 qs_->ReportDroppedFrameByMediaOpt();
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000097 break;
Peter Boström17417702015-09-25 17:03:26 +020098 case kKeepScaleAtHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010099 qs_->ReportQp(kHighQp, 0);
Peter Boström17417702015-09-25 17:03:26 +0200100 break;
101 case kScaleDownAboveHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100102 qs_->ReportQp(kHighQp + 1, 0);
Peter Boström17417702015-09-25 17:03:26 +0200103 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000104 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000105 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000106 }
107
Åsa Perssona945aee2018-04-24 16:53:25 +0200108 test::ScopedFieldTrials scoped_field_trial_;
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100109 TaskQueueForTest task_queue_;
kthelgason876222f2016-11-29 01:44:11 -0800110 std::unique_ptr<QualityScaler> qs_;
Evan Shrubsolea1c77f62020-08-10 11:01:06 +0200111 std::unique_ptr<FakeQpUsageHandler> handler_;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000112};
113
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100114INSTANTIATE_TEST_SUITE_P(
Åsa Perssona945aee2018-04-24 16:53:25 +0200115 FieldTrials,
116 QualityScalerTest,
117 ::testing::Values(
Ilya Nikolaevskiyd6604df2021-02-01 12:01:06 +0000118 "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/",
Ilya Nikolaevskiy483b31c2021-02-03 17:19:31 +0100119 "WebRTC-Video-QualityScaling/Disabled/"));
Åsa Perssona945aee2018-04-24 16:53:25 +0200120
121TEST_P(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200122 task_queue_.SendTask([this] { TriggerScale(kScaleDown); });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000123 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200124 EXPECT_EQ(1, handler_->adapt_down_events_);
125 EXPECT_EQ(0, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000126}
127
Åsa Perssona945aee2018-04-24 16:53:25 +0200128TEST_P(QualityScalerTest, KeepsScaleAtHighQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200129 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAtHighQp); });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000130 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200131 EXPECT_EQ(0, handler_->adapt_down_events_);
132 EXPECT_EQ(0, handler_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200133}
134
Åsa Perssona945aee2018-04-24 16:53:25 +0200135TEST_P(QualityScalerTest, DownscalesAboveHighQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200136 task_queue_.SendTask([this] { TriggerScale(kScaleDownAboveHighQp); });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000137 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200138 EXPECT_EQ(1, handler_->adapt_down_events_);
139 EXPECT_EQ(0, handler_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200140}
141
Åsa Perssona945aee2018-04-24 16:53:25 +0200142TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200143 task_queue_.SendTask([this] {
144 for (int i = 0; i < kFramerate * 5; ++i) {
145 qs_->ReportDroppedFrameByMediaOpt();
146 qs_->ReportDroppedFrameByMediaOpt();
147 qs_->ReportQp(kHighQp, 0);
148 }
149 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000150 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200151 EXPECT_EQ(1, handler_->adapt_down_events_);
152 EXPECT_EQ(0, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000153}
154
Åsa Perssona945aee2018-04-24 16:53:25 +0200155TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200156 task_queue_.SendTask([this] {
157 for (int i = 0; i < kFramerate * 5; ++i) {
158 qs_->ReportDroppedFrameByMediaOpt();
159 qs_->ReportQp(kHighQp, 0);
160 }
161 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000162 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200163 EXPECT_EQ(0, handler_->adapt_down_events_);
164 EXPECT_EQ(0, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000165}
166
Åsa Perssona945aee2018-04-24 16:53:25 +0200167TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
Ilya Nikolaevskiy483b31c2021-02-03 17:19:31 +0100168 const bool kDownScaleExpected =
169 GetParam().find("Enabled") != std::string::npos;
Danil Chapovalove519f382022-08-11 12:26:09 +0200170 task_queue_.SendTask([this] {
171 for (int i = 0; i < kFramerate * 5; ++i) {
172 qs_->ReportDroppedFrameByMediaOpt();
173 qs_->ReportDroppedFrameByEncoder();
174 qs_->ReportQp(kHighQp, 0);
175 }
176 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000177 EXPECT_EQ(kDownScaleExpected, handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200178 EXPECT_EQ(kDownScaleExpected ? 1 : 0, handler_->adapt_down_events_);
179 EXPECT_EQ(0, handler_->adapt_up_events_);
Åsa Perssona945aee2018-04-24 16:53:25 +0200180}
181
182TEST_P(QualityScalerTest, KeepsScaleOnNormalQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200183 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAboveLowQp); });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000184 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200185 EXPECT_EQ(0, handler_->adapt_down_events_);
186 EXPECT_EQ(0, handler_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200187}
188
Åsa Perssona945aee2018-04-24 16:53:25 +0200189TEST_P(QualityScalerTest, UpscalesAfterLowQp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200190 task_queue_.SendTask([this] { TriggerScale(kScaleUp); });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000191 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200192 EXPECT_EQ(0, handler_->adapt_down_events_);
193 EXPECT_EQ(1, handler_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000194}
195
Åsa Perssona945aee2018-04-24 16:53:25 +0200196TEST_P(QualityScalerTest, ScalesDownAndBackUp) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200197 task_queue_.SendTask([this] { TriggerScale(kScaleDown); });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000198 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200199 EXPECT_EQ(1, handler_->adapt_down_events_);
200 EXPECT_EQ(0, handler_->adapt_up_events_);
Danil Chapovalove519f382022-08-11 12:26:09 +0200201 task_queue_.SendTask([this] { TriggerScale(kScaleUp); });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000202 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200203 EXPECT_EQ(1, handler_->adapt_down_events_);
204 EXPECT_EQ(1, handler_->adapt_up_events_);
Peter Boström6a688f52015-06-22 08:02:58 +0200205}
kthelgason55a01352017-04-04 02:31:42 -0700206
Åsa Perssona945aee2018-04-24 16:53:25 +0200207TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200208 task_queue_.SendTask([this] {
209 // Not enough frames to make a decision.
210 for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
211 qs_->ReportQp(kLowQp, 0);
212 }
213 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000214 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeout));
Danil Chapovalove519f382022-08-11 12:26:09 +0200215 task_queue_.SendTask([this] {
216 // Send 1 more. Enough frames observed, should result in an adapt
217 // request.
218 qs_->ReportQp(kLowQp, 0);
219 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000220 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200221 EXPECT_EQ(0, handler_->adapt_down_events_);
222 EXPECT_EQ(1, handler_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200223
224 // Samples should be cleared after an adapt request.
Danil Chapovalove519f382022-08-11 12:26:09 +0200225 task_queue_.SendTask([this] {
226 // Not enough frames to make a decision.
227 qs_->ReportQp(kLowQp, 0);
228 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000229 EXPECT_FALSE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200230 EXPECT_EQ(0, handler_->adapt_down_events_);
231 EXPECT_EQ(1, handler_->adapt_up_events_);
kthelgason55a01352017-04-04 02:31:42 -0700232}
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200233
Åsa Perssona945aee2018-04-24 16:53:25 +0200234TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
Danil Chapovalove519f382022-08-11 12:26:09 +0200235 task_queue_.SendTask([this] {
236 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
237 qs_->ReportQp(kHighQp + 1, 0);
238 }
239 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000240 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200241 EXPECT_EQ(1, handler_->adapt_down_events_);
242 EXPECT_EQ(0, handler_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200243 // Samples cleared.
Danil Chapovalove519f382022-08-11 12:26:09 +0200244 task_queue_.SendTask([this] {
245 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
246 qs_->ReportQp(kLowQp, 0);
247 }
248 });
Markus Handell2cfc1af2022-08-19 08:16:48 +0000249 EXPECT_TRUE(handler_->event.Wait(kDefaultTimeout));
Henrik Boström012aa372020-04-27 17:40:55 +0200250 EXPECT_EQ(1, handler_->adapt_down_events_);
251 EXPECT_EQ(1, handler_->adapt_up_events_);
252}
253
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000254} // namespace webrtc