Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: webrtc/modules/video_coding/utility/quality_scaler_unittest.cc

Issue 2398963003: Move usage of QualityScaler to ViEEncoder. (Closed)
Patch Set: Code review Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/modules/video_coding/utility/quality_scaler.h" 11 #include "webrtc/modules/video_coding/utility/quality_scaler.h"
12 12
13 #include <memory>
14
15 #include "webrtc/base/event.h"
16 #include "webrtc/base/task_queue.h"
17 #include "webrtc/common_video/rotation.h"
magjed_webrtc 2016/10/27 11:45:58 This include looks unused.
kthelgason 2016/10/28 13:20:15 Acknowledged.
18 #include "webrtc/video_frame.h"
magjed_webrtc 2016/10/27 11:45:58 This include looks unused as well.
kthelgason 2016/10/28 13:20:16 Acknowledged.
19 #include "webrtc/test/gmock.h"
13 #include "webrtc/test/gtest.h" 20 #include "webrtc/test/gtest.h"
14 21
15 namespace webrtc { 22 namespace webrtc {
16 namespace { 23 namespace {
17 static const int kNumSeconds = 10;
18 static const int kWidth = 1920;
19 static const int kHeight = 1080;
20 static const int kFramerate = 30; 24 static const int kFramerate = 30;
21 static const int kLowQp = 15; 25 static const int kLowQp = 15;
22 static const int kNormalQp = 30;
23 static const int kLowQpThreshold = 18; 26 static const int kLowQpThreshold = 18;
24 static const int kHighQp = 40; 27 static const int kHighQp = 40;
25 static const int kDisabledBadQpThreshold = 64;
26 static const int kLowInitialBitrateKbps = 300;
27 // These values need to be in sync with corresponding constants
28 // in quality_scaler.cc
29 static const int kMeasureSecondsFastUpscale = 2;
30 static const int kMeasureSecondsUpscale = 5;
31 static const int kMeasureSecondsDownscale = 5;
32 static const int kMinDownscaleDimension = 140;
33 } // namespace 28 } // namespace
34 29
30 class MockScaleObserver : public ScalingObserverInterface {
31 public:
32 MockScaleObserver() {}
33 virtual ~MockScaleObserver() {}
34
35 MOCK_METHOD1(ScaleUp, void(ScaleReason));
36 MOCK_METHOD1(ScaleDown, void(ScaleReason));
37 };
38
39 // Override GetTimeoutMs to speed up the tests.
40 class QualityScalerUnderTest : public QualityScaler {
41 public:
42 explicit QualityScalerUnderTest(ScalingObserverInterface* observer)
43 : QualityScaler(observer) {}
44 int64_t GetTimeoutMs() { return 5; }
45 };
46
35 class QualityScalerTest : public ::testing::Test { 47 class QualityScalerTest : public ::testing::Test {
36 protected: 48 protected:
37 enum ScaleDirection { 49 enum ScaleDirection {
38 kKeepScaleAtHighQp, 50 kKeepScaleAtHighQp,
39 kScaleDown, 51 kScaleDown,
40 kScaleDownAboveHighQp, 52 kScaleDownAboveHighQp,
41 kScaleUp 53 kScaleUp
42 }; 54 };
43 55
44 QualityScalerTest() { 56 QualityScalerTest()
45 input_frame_ = I420Buffer::Create(kWidth, kHeight); 57 : q(new rtc::TaskQueue("QualityScalerTestQueue")),
46 qs_.Init(kLowQpThreshold, kHighQp, 0, kWidth, kHeight, kFramerate); 58 observer_(new MockScaleObserver()) {
47 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); 59 rtc::Event event(false, false);
60 qs_ = std::unique_ptr<QualityScaler>(
61 new QualityScalerUnderTest(observer_.get()));
62 q->PostTask([this, &event] {
63 qs_->Init(QualityScaler::QPThresholds(kLowQpThreshold, kHighQp));
64 event.Set();
65 });
66 EXPECT_TRUE(event.Wait(1000));
sprang_webrtc 2016/10/27 13:43:48 Perhaps a kDefaultTimeoutMs constant somewhere?
kthelgason 2016/10/28 13:20:15 Done.
48 } 67 }
49 68
50 bool TriggerScale(ScaleDirection scale_direction) { 69 ~QualityScalerTest() {
51 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); 70 rtc::Event event(false, false);
52 int initial_width = qs_.GetScaledResolution().width; 71 q->PostTask([this, &event] {
53 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { 72 qs_->Stop();
73 event.Set();
74 });
75 EXPECT_TRUE(event.Wait(1000));
76 }
77
78 void TriggerScale(ScaleDirection scale_direction) {
79 for (int i = 0; i < kFramerate * 5; ++i) {
54 switch (scale_direction) { 80 switch (scale_direction) {
55 case kScaleUp: 81 case kScaleUp:
56 qs_.ReportQP(kLowQp); 82 qs_->ReportQP(kLowQp);
57 break; 83 break;
58 case kScaleDown: 84 case kScaleDown:
59 qs_.ReportDroppedFrame(); 85 qs_->ReportDroppedFrame();
60 break; 86 break;
61 case kKeepScaleAtHighQp: 87 case kKeepScaleAtHighQp:
62 qs_.ReportQP(kHighQp); 88 qs_->ReportQP(kHighQp);
63 break; 89 break;
64 case kScaleDownAboveHighQp: 90 case kScaleDownAboveHighQp:
65 qs_.ReportQP(kHighQp + 1); 91 qs_->ReportQP(kHighQp + 1);
66 break; 92 break;
67 } 93 }
68 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
69 if (qs_.GetScaledResolution().width != initial_width)
70 return true;
71 } 94 }
72
73 return false;
74 } 95 }
75 96
76 void ExpectOriginalFrame() { 97 std::unique_ptr<rtc::TaskQueue> q;
77 EXPECT_EQ(input_frame_, qs_.GetScaledBuffer(input_frame_)) 98 std::unique_ptr<QualityScaler> qs_;
78 << "Using scaled frame instead of original input."; 99 std::unique_ptr<MockScaleObserver> observer_;
79 }
80 100
81 void ExpectScaleUsingReportedResolution() { 101 static const auto reason_ = ScalingObserverInterface::kQuality;
82 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
83 QualityScaler::Resolution res = qs_.GetScaledResolution();
84 rtc::scoped_refptr<VideoFrameBuffer> scaled_frame =
85 qs_.GetScaledBuffer(input_frame_);
86 EXPECT_EQ(res.width, scaled_frame->width());
87 EXPECT_EQ(res.height, scaled_frame->height());
88 }
89
90 void ContinuouslyDownscalesByHalfDimensionsAndBackUp();
91
92 void DoesNotDownscaleFrameDimensions(int width, int height);
93
94 void DownscaleEndsAt(int input_width,
95 int input_height,
96 int end_width,
97 int end_height);
98
99 QualityScaler qs_;
100 rtc::scoped_refptr<VideoFrameBuffer> input_frame_;
101 }; 102 };
102 103
103 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { 104 #define WAIT_FOR_MS(x) \
104 ExpectOriginalFrame(); 105 do { \
magjed_webrtc 2016/10/27 11:45:58 Why a do-while block and not just a block? { rtc
sprang_webrtc 2016/10/27 13:43:48 This is good practice. See for instance: http://st
kthelgason 2016/10/28 13:20:15 Sure, I would not use this in production code, but
105 } 106 rtc::Event ev(false, false); \
106 107 ev.Wait(x); \
107 TEST_F(QualityScalerTest, ReportsOriginalResolutionInitially) { 108 } while (0)
108 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
109 QualityScaler::Resolution res = qs_.GetScaledResolution();
110 EXPECT_EQ(input_frame_->width(), res.width);
111 EXPECT_EQ(input_frame_->height(), res.height);
112 }
113 109
114 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { 110 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
115 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds 111 EXPECT_CALL(*observer_, ScaleDown(reason_)).Times(1);
magjed_webrtc 2016/10/27 11:45:58 How do we know that it will be called exactly once
kthelgason 2016/10/28 13:20:16 After a scaledown event stats get flushed. If Scal
116 << " seconds."; 112 q->PostTask([this] { TriggerScale(kScaleDown); });
117 QualityScaler::Resolution res = qs_.GetScaledResolution(); 113 WAIT_FOR_MS(50);
magjed_webrtc 2016/10/27 11:45:58 Will this sleep for 50ms unconditionally? Can't we
kthelgason 2016/10/28 13:20:16 Yes, for now this is an unconditional wait. I don'
118 EXPECT_LT(res.width, input_frame_->width());
119 EXPECT_LT(res.height, input_frame_->height());
120 } 114 }
121 115
122 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) { 116 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) {
123 EXPECT_FALSE(TriggerScale(kKeepScaleAtHighQp)) 117 EXPECT_CALL(*observer_, ScaleDown(reason_)).Times(0);
124 << "Downscale at high threshold which should keep scale."; 118 EXPECT_CALL(*observer_, ScaleUp(reason_)).Times(0);
125 QualityScaler::Resolution res = qs_.GetScaledResolution(); 119 q->PostTask([this] { TriggerScale(kKeepScaleAtHighQp); });
126 EXPECT_EQ(res.width, input_frame_->width()); 120 WAIT_FOR_MS(50);
127 EXPECT_EQ(res.height, input_frame_->height());
128 } 121 }
129 122
130 TEST_F(QualityScalerTest, DownscalesAboveHighQp) { 123 TEST_F(QualityScalerTest, DownscalesAboveHighQp) {
131 EXPECT_TRUE(TriggerScale(kScaleDownAboveHighQp)) 124 EXPECT_CALL(*observer_, ScaleDown(reason_)).Times(1);
132 << "No downscale within " << kNumSeconds << " seconds."; 125 q->PostTask([this] { TriggerScale(kScaleDownAboveHighQp); });
133 QualityScaler::Resolution res = qs_.GetScaledResolution(); 126 WAIT_FOR_MS(50);
134 EXPECT_LT(res.width, input_frame_->width());
135 EXPECT_LT(res.height, input_frame_->height());
136 } 127 }
137 128
138 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { 129 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
139 for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { 130 EXPECT_CALL(*observer_, ScaleDown(reason_)).Times(1);
140 qs_.ReportQP(kNormalQp); 131 q->PostTask([this] {
141 qs_.ReportDroppedFrame(); 132 qs_->ReportDroppedFrame();
142 qs_.ReportDroppedFrame(); 133 qs_->ReportDroppedFrame();
143 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); 134 qs_->ReportQP(kHighQp);
144 if (qs_.GetScaledResolution().width < input_frame_->width()) 135 });
145 return; 136 WAIT_FOR_MS(50);
146 }
147
148 FAIL() << "No downscale within " << kNumSeconds << " seconds.";
149 } 137 }
150 138
151 TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) { 139 TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) {
152 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { 140 EXPECT_CALL(*observer_, ScaleDown(reason_)).Times(1);
153 qs_.ReportQP(kNormalQp); 141 q->PostTask([this] { TriggerScale(kScaleDownAboveHighQp); });
154 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); 142 WAIT_FOR_MS(50);
155 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width)
156 << "Unexpected scale on half framedrop.";
157 }
158 } 143 }
159 144
160 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) { 145 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
161 for (int i = 0; i < kFramerate * kNumSeconds / 2; ++i) { 146 EXPECT_CALL(*observer_, ScaleDown(reason_)).Times(0);
162 qs_.ReportQP(kNormalQp); 147 q->PostTask([this] {
163 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); 148 qs_->ReportDroppedFrame();
164 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) 149 qs_->ReportQP(kHighQp);
165 << "Unexpected scale on half framedrop."; 150 });
166 151 WAIT_FOR_MS(50);
167 qs_.ReportDroppedFrame();
168 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
169 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width)
170 << "Unexpected scale on half framedrop.";
171 }
172 } 152 }
173 153
174 void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() { 154 TEST_F(QualityScalerTest, UpscalesAfterLowQp) {
175 const int initial_min_dimension = 155 EXPECT_CALL(*observer_, ScaleUp(reason_)).Times(1);
176 input_frame_->width() < input_frame_->height() ? input_frame_->width() 156 q->PostTask([this] { TriggerScale(kScaleUp); });
177 : input_frame_->height(); 157 WAIT_FOR_MS(50);
178 int min_dimension = initial_min_dimension;
179 int current_shift = 0;
180 // Drop all frames to force-trigger downscaling.
181 while (min_dimension >= 2 * kMinDownscaleDimension) {
182 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within "
183 << kNumSeconds << " seconds.";
184 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
185 QualityScaler::Resolution res = qs_.GetScaledResolution();
186 min_dimension = res.width < res.height ? res.width : res.height;
187 ++current_shift;
188 ASSERT_EQ(input_frame_->width() >> current_shift, res.width);
189 ASSERT_EQ(input_frame_->height() >> current_shift, res.height);
190 ExpectScaleUsingReportedResolution();
191 }
192
193 // Make sure we can scale back with good-quality frames.
194 while (min_dimension < initial_min_dimension) {
195 EXPECT_TRUE(TriggerScale(kScaleUp)) << "No upscale within " << kNumSeconds
196 << " seconds.";
197 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
198 QualityScaler::Resolution res = qs_.GetScaledResolution();
199 min_dimension = res.width < res.height ? res.width : res.height;
200 --current_shift;
201 ASSERT_EQ(input_frame_->width() >> current_shift, res.width);
202 ASSERT_EQ(input_frame_->height() >> current_shift, res.height);
203 ExpectScaleUsingReportedResolution();
204 }
205
206 // Verify we don't start upscaling after further low use.
207 for (int i = 0; i < kFramerate * kNumSeconds; ++i) {
208 qs_.ReportQP(kLowQp);
209 ExpectOriginalFrame();
210 }
211 } 158 }
212 159
213 TEST_F(QualityScalerTest, ContinuouslyDownscalesByHalfDimensionsAndBackUp) { 160 TEST_F(QualityScalerTest, ScalesDownAndBackUp) {
214 ContinuouslyDownscalesByHalfDimensionsAndBackUp(); 161 {
162 testing::InSequence _;
163 EXPECT_CALL(*observer_, ScaleDown(reason_)).Times(1);
164 EXPECT_CALL(*observer_, ScaleUp(reason_)).Times(1);
165 }
166 q->PostTask([this] { TriggerScale(kScaleDown); });
167 WAIT_FOR_MS(50);
168 q->PostTask([this] { TriggerScale(kScaleUp); });
169 WAIT_FOR_MS(50);
215 } 170 }
216 171
217 TEST_F(QualityScalerTest, 172 #undef WAIT_FOR_MS
218 ContinuouslyDownscalesOddResolutionsByHalfDimensionsAndBackUp) {
219 const int kOddWidth = 517;
220 const int kOddHeight = 1239;
221 input_frame_ = I420Buffer::Create(kOddWidth, kOddHeight);
222 ContinuouslyDownscalesByHalfDimensionsAndBackUp();
223 }
224
225 void QualityScalerTest::DoesNotDownscaleFrameDimensions(int width, int height) {
226 input_frame_ = I420Buffer::Create(width, height);
227
228 for (int i = 0; i < kFramerate * kNumSeconds; ++i) {
229 qs_.ReportDroppedFrame();
230 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
231 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width)
232 << "Unexpected scale of minimal-size frame.";
233 }
234 }
235
236 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxWidth) {
237 DoesNotDownscaleFrameDimensions(1, kHeight);
238 }
239
240 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) {
241 DoesNotDownscaleFrameDimensions(kWidth, 1);
242 }
243
244 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) {
245 DoesNotDownscaleFrameDimensions(1, 1);
246 }
247
248 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) {
249 DoesNotDownscaleFrameDimensions(
250 2 * kMinDownscaleDimension - 1, 1000);
251 }
252
253 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) {
254 DoesNotDownscaleFrameDimensions(
255 1000, 2 * kMinDownscaleDimension - 1);
256 }
257
258 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) {
259 static const int kWidth720p = 1280;
260 static const int kHeight720p = 720;
261 static const int kInitialBitrateKbps = 300;
262 input_frame_ = I420Buffer::Create(kWidth720p, kHeight720p);
263 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps,
264 kWidth720p, kHeight720p, kFramerate);
265 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
266 int init_width = qs_.GetScaledResolution().width;
267 int init_height = qs_.GetScaledResolution().height;
268 EXPECT_EQ(640, init_width);
269 EXPECT_EQ(360, init_height);
270 }
271
272 TEST_F(QualityScalerTest, DownscaleToQvgaOnLowerInitialBitrate) {
273 static const int kWidth720p = 1280;
274 static const int kHeight720p = 720;
275 static const int kInitialBitrateKbps = 200;
276 input_frame_ = I420Buffer::Create(kWidth720p, kHeight720p);
277 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps,
278 kWidth720p, kHeight720p, kFramerate);
279 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
280 int init_width = qs_.GetScaledResolution().width;
281 int init_height = qs_.GetScaledResolution().height;
282 EXPECT_EQ(320, init_width);
283 EXPECT_EQ(180, init_height);
284 }
285
286 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) {
287 qs_.Init(kLowQpThreshold, kHighQp, 0, kWidth, kHeight, kFramerate);
288 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
289 QualityScaler::Resolution initial_res = qs_.GetScaledResolution();
290
291 // Should not downscale if less than kMeasureSecondsDownscale seconds passed.
292 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) {
293 qs_.ReportQP(kHighQp + 1);
294 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
295 }
296 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width);
297 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height);
298
299 // Should downscale if more than kMeasureSecondsDownscale seconds passed (add
300 // last frame).
301 qs_.ReportQP(kHighQp + 1);
302 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
303 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width);
304 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height);
305
306 // Should not upscale if less than kMeasureSecondsUpscale seconds passed since
307 // we saw issues initially (have already gone down).
308 for (int i = 0; i < kFramerate * kMeasureSecondsUpscale - 1; ++i) {
309 qs_.ReportQP(kLowQp);
310 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
311 }
312 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width);
313 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height);
314
315 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed
316 // (add last frame).
317 qs_.ReportQP(kLowQp);
318 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
319 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width);
320 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height);
321 }
322
323 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) {
324 qs_.Init(kLowQpThreshold, kHighQp, kLowInitialBitrateKbps, kWidth, kHeight,
325 kFramerate);
326 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
327 QualityScaler::Resolution initial_res = qs_.GetScaledResolution();
328
329 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed.
330 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) {
331 qs_.ReportQP(kLowQp);
332 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
333 }
334 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width);
335 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height);
336
337 // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last
338 // frame).
339 qs_.ReportQP(kLowQp);
340 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height());
341 EXPECT_LT(initial_res.width, qs_.GetScaledResolution().width);
342 EXPECT_LT(initial_res.height, qs_.GetScaledResolution().height);
343 }
344
345 void QualityScalerTest::DownscaleEndsAt(int input_width,
346 int input_height,
347 int end_width,
348 int end_height) {
349 // Create a frame with 2x expected end width/height to verify that we can
350 // scale down to expected end width/height.
351 input_frame_ = I420Buffer::Create(input_width, input_height);
352
353 int last_width = input_width;
354 int last_height = input_height;
355 // Drop all frames to force-trigger downscaling.
356 while (true) {
357 TriggerScale(kScaleDown);
358 QualityScaler::Resolution res = qs_.GetScaledResolution();
359 if (last_width == res.width) {
360 EXPECT_EQ(last_height, res.height);
361 EXPECT_EQ(end_width, res.width);
362 EXPECT_EQ(end_height, res.height);
363 break;
364 }
365 last_width = res.width;
366 last_height = res.height;
367 }
368 }
369
370 TEST_F(QualityScalerTest, DownscalesTo320x180) {
371 DownscaleEndsAt(640, 360, 320, 180);
372 }
373
374 TEST_F(QualityScalerTest, DownscalesTo180x320) {
375 DownscaleEndsAt(360, 640, 180, 320);
376 }
377
378 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) {
379 DownscaleEndsAt(1280, 720, 320, 180);
380 }
381
382 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) {
383 DownscaleEndsAt(320, 180, 320, 180);
384 }
385 173
386 } // namespace webrtc 174 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698