blob: 99eaed167380e4c89a0886ddced7e5c948aa361a [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 }
sprangb1ca0732017-02-01 08:38:12 -080039 void AdaptDown(AdaptReason r) override {
40 adapt_down_events_++;
kthelgason876222f2016-11-29 01:44:11 -080041 event.Set();
42 }
43
44 rtc::Event event;
sprangb1ca0732017-02-01 08:38:12 -080045 int adapt_up_events_ = 0;
46 int adapt_down_events_ = 0;
kthelgason876222f2016-11-29 01:44:11 -080047};
48
49// Pass a lower sampling period to speed up the tests.
50class QualityScalerUnderTest : public QualityScaler {
51 public:
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010052 explicit QualityScalerUnderTest(rtc::TaskQueue* task_queue,
53 AdaptationObserverInterface* observer,
kthelgason876222f2016-11-29 01:44:11 -080054 VideoEncoder::QpThresholds thresholds)
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010055 : QualityScaler(task_queue, observer, thresholds, 5) {}
kthelgason876222f2016-11-29 01:44:11 -080056};
57
Åsa Perssona945aee2018-04-24 16:53:25 +020058class QualityScalerTest : public ::testing::Test,
59 public ::testing::WithParamInterface<std::string> {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000060 protected:
Peter Boström17417702015-09-25 17:03:26 +020061 enum ScaleDirection {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020062 kKeepScaleAboveLowQp,
Peter Boström17417702015-09-25 17:03:26 +020063 kKeepScaleAtHighQp,
64 kScaleDown,
65 kScaleDownAboveHighQp,
66 kScaleUp
67 };
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000068
kthelgason876222f2016-11-29 01:44:11 -080069 QualityScalerTest()
Åsa Perssona945aee2018-04-24 16:53:25 +020070 : scoped_field_trial_(GetParam()),
Danil Chapovalovb42165e2019-03-20 14:29:43 +010071 task_queue_("QualityScalerTestQueue"),
sprangb1ca0732017-02-01 08:38:12 -080072 observer_(new MockAdaptationObserver()) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +010073 task_queue_.SendTask([this] {
kthelgason876222f2016-11-29 01:44:11 -080074 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
Danil Chapovalovb42165e2019-03-20 14:29:43 +010075 &task_queue_, observer_.get(),
Sebastian Janssoncda86dd2019-03-11 17:26:36 +010076 VideoEncoder::QpThresholds(kLowQp, kHighQp)));
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020077 });
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000078 }
79
kthelgason876222f2016-11-29 01:44:11 -080080 ~QualityScalerTest() {
Danil Chapovalovb42165e2019-03-20 14:29:43 +010081 task_queue_.SendTask([this] { qs_ = nullptr; });
kthelgason876222f2016-11-29 01:44:11 -080082 }
83
84 void TriggerScale(ScaleDirection scale_direction) {
85 for (int i = 0; i < kFramerate * 5; ++i) {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000086 switch (scale_direction) {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020087 case kKeepScaleAboveLowQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010088 qs_->ReportQp(kLowQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +020089 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000090 case kScaleUp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010091 qs_->ReportQp(kLowQp, 0);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000092 break;
93 case kScaleDown:
Åsa Perssona945aee2018-04-24 16:53:25 +020094 qs_->ReportDroppedFrameByMediaOpt();
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000095 break;
Peter Boström17417702015-09-25 17:03:26 +020096 case kKeepScaleAtHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +010097 qs_->ReportQp(kHighQp, 0);
Peter Boström17417702015-09-25 17:03:26 +020098 break;
99 case kScaleDownAboveHighQp:
Sebastian Janssonb6789402019-03-01 15:40:49 +0100100 qs_->ReportQp(kHighQp + 1, 0);
Peter Boström17417702015-09-25 17:03:26 +0200101 break;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000102 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000103 }
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000104 }
105
Åsa Perssona945aee2018-04-24 16:53:25 +0200106 test::ScopedFieldTrials scoped_field_trial_;
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100107 TaskQueueForTest task_queue_;
kthelgason876222f2016-11-29 01:44:11 -0800108 std::unique_ptr<QualityScaler> qs_;
sprangb1ca0732017-02-01 08:38:12 -0800109 std::unique_ptr<MockAdaptationObserver> observer_;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000110};
111
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100112INSTANTIATE_TEST_SUITE_P(
Åsa Perssona945aee2018-04-24 16:53:25 +0200113 FieldTrials,
114 QualityScalerTest,
115 ::testing::Values(
116 "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/",
117 ""));
118
119TEST_P(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100120 task_queue_.SendTask([this] { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800121 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800122 EXPECT_EQ(1, observer_->adapt_down_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200123 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000124}
125
Åsa Perssona945aee2018-04-24 16:53:25 +0200126TEST_P(QualityScalerTest, KeepsScaleAtHighQp) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100127 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAtHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800128 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800129 EXPECT_EQ(0, observer_->adapt_down_events_);
130 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200131}
132
Åsa Perssona945aee2018-04-24 16:53:25 +0200133TEST_P(QualityScalerTest, DownscalesAboveHighQp) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100134 task_queue_.SendTask([this] { TriggerScale(kScaleDownAboveHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800135 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800136 EXPECT_EQ(1, observer_->adapt_down_events_);
137 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200138}
139
Åsa Perssona945aee2018-04-24 16:53:25 +0200140TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100141 task_queue_.SendTask([this] {
kthelgason55a01352017-04-04 02:31:42 -0700142 for (int i = 0; i < kFramerate * 5; ++i) {
Åsa Perssona945aee2018-04-24 16:53:25 +0200143 qs_->ReportDroppedFrameByMediaOpt();
144 qs_->ReportDroppedFrameByMediaOpt();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100145 qs_->ReportQp(kHighQp, 0);
kthelgason55a01352017-04-04 02:31:42 -0700146 }
kthelgason876222f2016-11-29 01:44:11 -0800147 });
kthelgason86cf9a22016-12-01 02:57:01 -0800148 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800149 EXPECT_EQ(1, observer_->adapt_down_events_);
150 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000151}
152
Åsa Perssona945aee2018-04-24 16:53:25 +0200153TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100154 task_queue_.SendTask([this] {
kthelgason55a01352017-04-04 02:31:42 -0700155 for (int i = 0; i < kFramerate * 5; ++i) {
Åsa Perssona945aee2018-04-24 16:53:25 +0200156 qs_->ReportDroppedFrameByMediaOpt();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100157 qs_->ReportQp(kHighQp, 0);
kthelgason55a01352017-04-04 02:31:42 -0700158 }
kthelgason876222f2016-11-29 01:44:11 -0800159 });
kthelgason86cf9a22016-12-01 02:57:01 -0800160 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800161 EXPECT_EQ(0, observer_->adapt_down_events_);
162 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000163}
164
Åsa Perssona945aee2018-04-24 16:53:25 +0200165TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
166 const bool kDownScaleExpected = !GetParam().empty();
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100167 task_queue_.SendTask([this] {
Åsa Perssona945aee2018-04-24 16:53:25 +0200168 for (int i = 0; i < kFramerate * 5; ++i) {
169 qs_->ReportDroppedFrameByMediaOpt();
170 qs_->ReportDroppedFrameByEncoder();
Sebastian Janssonb6789402019-03-01 15:40:49 +0100171 qs_->ReportQp(kHighQp, 0);
Åsa Perssona945aee2018-04-24 16:53:25 +0200172 }
173 });
174 EXPECT_EQ(kDownScaleExpected, observer_->event.Wait(kDefaultTimeoutMs));
175 EXPECT_EQ(kDownScaleExpected ? 1 : 0, observer_->adapt_down_events_);
176 EXPECT_EQ(0, observer_->adapt_up_events_);
177}
178
179TEST_P(QualityScalerTest, KeepsScaleOnNormalQp) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100180 task_queue_.SendTask([this] { TriggerScale(kKeepScaleAboveLowQp); });
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200181 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
182 EXPECT_EQ(0, observer_->adapt_down_events_);
183 EXPECT_EQ(0, observer_->adapt_up_events_);
184}
185
Åsa Perssona945aee2018-04-24 16:53:25 +0200186TEST_P(QualityScalerTest, UpscalesAfterLowQp) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100187 task_queue_.SendTask([this] { TriggerScale(kScaleUp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800188 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800189 EXPECT_EQ(0, observer_->adapt_down_events_);
190 EXPECT_EQ(1, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000191}
192
Åsa Perssona945aee2018-04-24 16:53:25 +0200193TEST_P(QualityScalerTest, ScalesDownAndBackUp) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100194 task_queue_.SendTask([this] { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800195 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800196 EXPECT_EQ(1, observer_->adapt_down_events_);
197 EXPECT_EQ(0, observer_->adapt_up_events_);
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100198 task_queue_.SendTask([this] { TriggerScale(kScaleUp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800199 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800200 EXPECT_EQ(1, observer_->adapt_down_events_);
201 EXPECT_EQ(1, observer_->adapt_up_events_);
Peter Boström6a688f52015-06-22 08:02:58 +0200202}
kthelgason55a01352017-04-04 02:31:42 -0700203
Åsa Perssona945aee2018-04-24 16:53:25 +0200204TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100205 task_queue_.SendTask([this] {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200206 // Not enough frames to make a decision.
207 for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100208 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200209 }
210 });
kthelgason55a01352017-04-04 02:31:42 -0700211 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100212 task_queue_.SendTask([this] {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200213 // Send 1 more. Enough frames observed, should result in an adapt request.
Sebastian Janssonb6789402019-03-01 15:40:49 +0100214 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200215 });
kthelgason55a01352017-04-04 02:31:42 -0700216 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
217 EXPECT_EQ(0, observer_->adapt_down_events_);
218 EXPECT_EQ(1, observer_->adapt_up_events_);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200219
220 // Samples should be cleared after an adapt request.
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100221 task_queue_.SendTask([this] {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200222 // Not enough frames to make a decision.
Sebastian Janssonb6789402019-03-01 15:40:49 +0100223 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200224 });
225 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
226 EXPECT_EQ(0, observer_->adapt_down_events_);
227 EXPECT_EQ(1, observer_->adapt_up_events_);
kthelgason55a01352017-04-04 02:31:42 -0700228}
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200229
Åsa Perssona945aee2018-04-24 16:53:25 +0200230TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100231 task_queue_.SendTask([this] {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200232 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100233 qs_->ReportQp(kHighQp + 1, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200234 }
235 });
236 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
237 EXPECT_EQ(1, observer_->adapt_down_events_);
238 EXPECT_EQ(0, observer_->adapt_up_events_);
239 // Samples cleared.
Danil Chapovalovb42165e2019-03-20 14:29:43 +0100240 task_queue_.SendTask([this] {
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200241 for (int i = 0; i < kMinFramesNeededToScale; ++i) {
Sebastian Janssonb6789402019-03-01 15:40:49 +0100242 qs_->ReportQp(kLowQp, 0);
Åsa Persson0ad2d8a2018-04-19 11:06:11 +0200243 }
244 });
245 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
246 EXPECT_EQ(1, observer_->adapt_down_events_);
247 EXPECT_EQ(1, observer_->adapt_up_events_);
248}
249
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000250} // namespace webrtc