1 /*
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
11 #include "modules/video_coding/utility/quality_scaler.h"
12
13 #include <memory>
14
15 #include "rtc_base/event.h"
16 #include "rtc_base/task_queue.h"
17 #include "test/gmock.h"
18 #include "test/gtest.h"
19
20 namespace webrtc {
21 namespace {
22 static const int kFramerate = 30;
23 static const int kLowQp = 15;
24 static const int kLowQpThreshold = 18;
25 static const int kHighQp = 40;
26 static const size_t kDefaultTimeoutMs = 150;
27 } // namespace
28
29 #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
39 class MockAdaptationObserver : public AdaptationObserverInterface {
40 public:
MockAdaptationObserver()41 MockAdaptationObserver() : event(false, false) {}
~MockAdaptationObserver()42 virtual ~MockAdaptationObserver() {}
43
AdaptUp(AdaptReason r)44 void AdaptUp(AdaptReason r) override {
45 adapt_up_events_++;
46 event.Set();
47 }
AdaptDown(AdaptReason r)48 void AdaptDown(AdaptReason r) override {
49 adapt_down_events_++;
50 event.Set();
51 }
52
53 rtc::Event event;
54 int adapt_up_events_ = 0;
55 int adapt_down_events_ = 0;
56 };
57
58 // Pass a lower sampling period to speed up the tests.
59 class QualityScalerUnderTest : public QualityScaler {
60 public:
QualityScalerUnderTest(AdaptationObserverInterface * observer,VideoEncoder::QpThresholds thresholds)61 explicit QualityScalerUnderTest(AdaptationObserverInterface* observer,
62 VideoEncoder::QpThresholds thresholds)
63 : QualityScaler(observer, thresholds, 5) {}
64 };
65
66 class QualityScalerTest : public ::testing::Test {
67 protected:
68 enum ScaleDirection {
69 kKeepScaleAtHighQp,
70 kScaleDown,
71 kScaleDownAboveHighQp,
72 kScaleUp
73 };
74
QualityScalerTest()75 QualityScalerTest()
76 : q_(new rtc::TaskQueue("QualityScalerTestQueue")),
77 observer_(new MockAdaptationObserver()) {
78 DO_SYNC(q_, {
79 qs_ = std::unique_ptr<QualityScaler>(new QualityScalerUnderTest(
80 observer_.get(),
81 VideoEncoder::QpThresholds(kLowQpThreshold, kHighQp)));});
82 }
83
~QualityScalerTest()84 ~QualityScalerTest() {
85 DO_SYNC(q_, {qs_.reset(nullptr);});
86 }
87
TriggerScale(ScaleDirection scale_direction)88 void TriggerScale(ScaleDirection scale_direction) {
89 for (int i = 0; i < kFramerate * 5; ++i) {
90 switch (scale_direction) {
91 case kScaleUp:
92 qs_->ReportQP(kLowQp);
93 break;
94 case kScaleDown:
95 qs_->ReportDroppedFrame();
96 break;
97 case kKeepScaleAtHighQp:
98 qs_->ReportQP(kHighQp);
99 break;
100 case kScaleDownAboveHighQp:
101 qs_->ReportQP(kHighQp + 1);
102 break;
103 }
104 }
105 }
106
107 std::unique_ptr<rtc::TaskQueue> q_;
108 std::unique_ptr<QualityScaler> qs_;
109 std::unique_ptr<MockAdaptationObserver> observer_;
110 };
111
TEST_F(QualityScalerTest,DownscalesAfterContinuousFramedrop)112 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
113 DO_SYNC(q_, { TriggerScale(kScaleDown); });
114 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
115 EXPECT_EQ(1, observer_->adapt_down_events_);
116 }
117
TEST_F(QualityScalerTest,KeepsScaleAtHighQp)118 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) {
119 DO_SYNC(q_, { TriggerScale(kKeepScaleAtHighQp); });
120 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
121 EXPECT_EQ(0, observer_->adapt_down_events_);
122 EXPECT_EQ(0, observer_->adapt_up_events_);
123 }
124
TEST_F(QualityScalerTest,DownscalesAboveHighQp)125 TEST_F(QualityScalerTest, DownscalesAboveHighQp) {
126 DO_SYNC(q_, { TriggerScale(kScaleDownAboveHighQp); });
127 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
128 EXPECT_EQ(1, observer_->adapt_down_events_);
129 EXPECT_EQ(0, observer_->adapt_up_events_);
130 }
131
TEST_F(QualityScalerTest,DownscalesAfterTwoThirdsFramedrop)132 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
133 DO_SYNC(q_, {
134 for (int i = 0; i < kFramerate * 5; ++i) {
135 qs_->ReportDroppedFrame();
136 qs_->ReportDroppedFrame();
137 qs_->ReportQP(kHighQp);
138 }
139 });
140 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
141 EXPECT_EQ(1, observer_->adapt_down_events_);
142 EXPECT_EQ(0, observer_->adapt_up_events_);
143 }
144
TEST_F(QualityScalerTest,DoesNotDownscaleOnNormalQp)145 TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) {
146 DO_SYNC(q_, { TriggerScale(kScaleDownAboveHighQp); });
147 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
148 EXPECT_EQ(1, observer_->adapt_down_events_);
149 EXPECT_EQ(0, observer_->adapt_up_events_);
150 }
151
TEST_F(QualityScalerTest,DoesNotDownscaleAfterHalfFramedrop)152 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
153 DO_SYNC(q_, {
154 for (int i = 0; i < kFramerate * 5; ++i) {
155 qs_->ReportDroppedFrame();
156 qs_->ReportQP(kHighQp);
157 }
158 });
159 EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
160 EXPECT_EQ(0, observer_->adapt_down_events_);
161 EXPECT_EQ(0, observer_->adapt_up_events_);
162 }
163
TEST_F(QualityScalerTest,UpscalesAfterLowQp)164 TEST_F(QualityScalerTest, UpscalesAfterLowQp) {
165 DO_SYNC(q_, { TriggerScale(kScaleUp); });
166 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
167 EXPECT_EQ(0, observer_->adapt_down_events_);
168 EXPECT_EQ(1, observer_->adapt_up_events_);
169 }
170
TEST_F(QualityScalerTest,ScalesDownAndBackUp)171 TEST_F(QualityScalerTest, ScalesDownAndBackUp) {
172 DO_SYNC(q_, { TriggerScale(kScaleDown); });
173 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
174 EXPECT_EQ(1, observer_->adapt_down_events_);
175 EXPECT_EQ(0, observer_->adapt_up_events_);
176 DO_SYNC(q_, { TriggerScale(kScaleUp); });
177 EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
178 EXPECT_EQ(1, observer_->adapt_down_events_);
179 EXPECT_EQ(1, observer_->adapt_up_events_);
180 }
181
TEST_F(QualityScalerTest,DoesNotScaleUntilEnoughFramesObserved)182 TEST_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 }
201 } // namespace webrtc
202 #undef DO_SYNC
203