blob: d9da1b4b330c9e4763f2b1a84da0cc8cd1c5720d [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>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "rtc_base/event.h"
16#include "rtc_base/task_queue.h"
17#include "test/gmock.h"
18#include "test/gtest.h"
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000019
20namespace webrtc {
21namespace {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000022static const int kFramerate = 30;
23static const int kLowQp = 15;
Peter Boström00b62b02016-04-14 17:04:03 +020024static const int kLowQpThreshold = 18;
Peter Boström17417702015-09-25 17:03:26 +020025static const int kHighQp = 40;
kthelgason86cf9a22016-12-01 02:57:01 -080026static const size_t kDefaultTimeoutMs = 150;
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000027} // namespace
28
kthelgasonb12a3e32017-03-30 01:04:55 -070029#define DO_SYNC(q, block) do { \
30 rtc::Event event(false, false); \
31 q->PostTask([this, &event] { \
32 block; \
33 event.Set(); \
34 }); \
35 RTC_CHECK(event.Wait(1000)); \
36 } while (0)
37
38
sprangb1ca0732017-02-01 08:38:12 -080039class MockAdaptationObserver : public AdaptationObserverInterface {
kthelgason876222f2016-11-29 01:44:11 -080040 public:
sprangb1ca0732017-02-01 08:38:12 -080041 MockAdaptationObserver() : event(false, false) {}
42 virtual ~MockAdaptationObserver() {}
kthelgason876222f2016-11-29 01:44:11 -080043
sprangb1ca0732017-02-01 08:38:12 -080044 void AdaptUp(AdaptReason r) override {
45 adapt_up_events_++;
kthelgason876222f2016-11-29 01:44:11 -080046 event.Set();
47 }
sprangb1ca0732017-02-01 08:38:12 -080048 void AdaptDown(AdaptReason r) override {
49 adapt_down_events_++;
kthelgason876222f2016-11-29 01:44:11 -080050 event.Set();
51 }
52
53 rtc::Event event;
sprangb1ca0732017-02-01 08:38:12 -080054 int adapt_up_events_ = 0;
55 int adapt_down_events_ = 0;
kthelgason876222f2016-11-29 01:44:11 -080056};
57
58// Pass a lower sampling period to speed up the tests.
59class QualityScalerUnderTest : public QualityScaler {
60 public:
sprangb1ca0732017-02-01 08:38:12 -080061 explicit QualityScalerUnderTest(AdaptationObserverInterface* observer,
kthelgason876222f2016-11-29 01:44:11 -080062 VideoEncoder::QpThresholds thresholds)
63 : QualityScaler(observer, thresholds, 5) {}
64};
65
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000066class QualityScalerTest : public ::testing::Test {
67 protected:
Peter Boström17417702015-09-25 17:03:26 +020068 enum ScaleDirection {
69 kKeepScaleAtHighQp,
70 kScaleDown,
71 kScaleDownAboveHighQp,
72 kScaleUp
73 };
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000074
kthelgason876222f2016-11-29 01:44:11 -080075 QualityScalerTest()
76 : q_(new rtc::TaskQueue("QualityScalerTestQueue")),
sprangb1ca0732017-02-01 08:38:12 -080077 observer_(new MockAdaptationObserver()) {
kthelgasonb12a3e32017-03-30 01:04:55 -070078 DO_SYNC(q_, {
kthelgason876222f2016-11-29 01:44:11 -080079 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
80 observer_.get(),
kthelgasonb12a3e32017-03-30 01:04:55 -070081 VideoEncoder::QpThresholds(kLowQpThreshold, kHighQp)));});
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000082 }
83
kthelgason876222f2016-11-29 01:44:11 -080084 ~QualityScalerTest() {
kthelgasonb12a3e32017-03-30 01:04:55 -070085 DO_SYNC(q_, {qs_.reset(nullptr);});
kthelgason876222f2016-11-29 01:44:11 -080086 }
87
88 void TriggerScale(ScaleDirection scale_direction) {
89 for (int i = 0; i < kFramerate * 5; ++i) {
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000090 switch (scale_direction) {
91 case kScaleUp:
kthelgason876222f2016-11-29 01:44:11 -080092 qs_->ReportQP(kLowQp);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000093 break;
94 case kScaleDown:
kthelgason876222f2016-11-29 01:44:11 -080095 qs_->ReportDroppedFrame();
pbos@webrtc.orga0d78272014-09-12 11:51:47 +000096 break;
Peter Boström17417702015-09-25 17:03:26 +020097 case kKeepScaleAtHighQp:
kthelgason876222f2016-11-29 01:44:11 -080098 qs_->ReportQP(kHighQp);
Peter Boström17417702015-09-25 17:03:26 +020099 break;
100 case kScaleDownAboveHighQp:
kthelgason876222f2016-11-29 01:44:11 -0800101 qs_->ReportQP(kHighQp + 1);
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
kthelgason876222f2016-11-29 01:44:11 -0800107 std::unique_ptr<rtc::TaskQueue> q_;
108 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
kthelgasonb12a3e32017-03-30 01:04:55 -0700112TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
113 DO_SYNC(q_, { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800114 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800115 EXPECT_EQ(1, observer_->adapt_down_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000116}
117
kthelgasonb12a3e32017-03-30 01:04:55 -0700118TEST_F(QualityScalerTest, KeepsScaleAtHighQp) {
119 DO_SYNC(q_, { TriggerScale(kKeepScaleAtHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800120 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800121 EXPECT_EQ(0, observer_->adapt_down_events_);
122 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200123}
124
kthelgasonb12a3e32017-03-30 01:04:55 -0700125TEST_F(QualityScalerTest, DownscalesAboveHighQp) {
126 DO_SYNC(q_, { TriggerScale(kScaleDownAboveHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800127 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800128 EXPECT_EQ(1, observer_->adapt_down_events_);
129 EXPECT_EQ(0, observer_->adapt_up_events_);
Peter Boström17417702015-09-25 17:03:26 +0200130}
131
kthelgasonb12a3e32017-03-30 01:04:55 -0700132TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
133 DO_SYNC(q_, {
kthelgason55a01352017-04-04 02:31:42 -0700134 for (int i = 0; i < kFramerate * 5; ++i) {
135 qs_->ReportDroppedFrame();
136 qs_->ReportDroppedFrame();
137 qs_->ReportQP(kHighQp);
138 }
kthelgason876222f2016-11-29 01:44:11 -0800139 });
kthelgason86cf9a22016-12-01 02:57:01 -0800140 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800141 EXPECT_EQ(1, observer_->adapt_down_events_);
142 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000143}
144
kthelgasonb12a3e32017-03-30 01:04:55 -0700145TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) {
146 DO_SYNC(q_, { TriggerScale(kScaleDownAboveHighQp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800147 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800148 EXPECT_EQ(1, observer_->adapt_down_events_);
149 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000150}
151
kthelgasonb12a3e32017-03-30 01:04:55 -0700152TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
153 DO_SYNC(q_, {
kthelgason55a01352017-04-04 02:31:42 -0700154 for (int i = 0; i < kFramerate * 5; ++i) {
155 qs_->ReportDroppedFrame();
156 qs_->ReportQP(kHighQp);
157 }
kthelgason876222f2016-11-29 01:44:11 -0800158 });
kthelgason86cf9a22016-12-01 02:57:01 -0800159 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800160 EXPECT_EQ(0, observer_->adapt_down_events_);
161 EXPECT_EQ(0, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000162}
163
kthelgasonb12a3e32017-03-30 01:04:55 -0700164TEST_F(QualityScalerTest, UpscalesAfterLowQp) {
165 DO_SYNC(q_, { TriggerScale(kScaleUp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800166 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800167 EXPECT_EQ(0, observer_->adapt_down_events_);
168 EXPECT_EQ(1, observer_->adapt_up_events_);
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000169}
170
kthelgasonb12a3e32017-03-30 01:04:55 -0700171TEST_F(QualityScalerTest, ScalesDownAndBackUp) {
172 DO_SYNC(q_, { TriggerScale(kScaleDown); });
kthelgason86cf9a22016-12-01 02:57:01 -0800173 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800174 EXPECT_EQ(1, observer_->adapt_down_events_);
175 EXPECT_EQ(0, observer_->adapt_up_events_);
kthelgasonb12a3e32017-03-30 01:04:55 -0700176 DO_SYNC(q_, { TriggerScale(kScaleUp); });
kthelgason86cf9a22016-12-01 02:57:01 -0800177 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
sprangb1ca0732017-02-01 08:38:12 -0800178 EXPECT_EQ(1, observer_->adapt_down_events_);
179 EXPECT_EQ(1, observer_->adapt_up_events_);
Peter Boström6a688f52015-06-22 08:02:58 +0200180}
kthelgason55a01352017-04-04 02:31:42 -0700181
182TEST_F(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
183 DO_SYNC(q_, {
184 // Send 30 frames. This should not be enough to make a decision.
185 for (int i = 0; i < kFramerate; ++i) {
186 qs_->ReportQP(kLowQp);
187 }
188 });
189 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
190 DO_SYNC(q_, {
191 // Send 30 more. This should result in an adapt request as
192 // enough frames have now been observed.
193 for (int i = 0; i < kFramerate; ++i) {
194 qs_->ReportQP(kLowQp);
195 }
196 });
197 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
198 EXPECT_EQ(0, observer_->adapt_down_events_);
199 EXPECT_EQ(1, observer_->adapt_up_events_);
200}
pbos@webrtc.orga0d78272014-09-12 11:51:47 +0000201} // namespace webrtc
kthelgasonb12a3e32017-03-30 01:04:55 -0700202#undef DO_SYNC