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

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

Issue 1830593003: Make QualityScaler more responsive to downgrades. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 9 months 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 "testing/gtest/include/gtest/gtest.h" 13 #include "testing/gtest/include/gtest/gtest.h"
14 14
15 namespace webrtc { 15 namespace webrtc {
16 namespace { 16 namespace {
17 static const int kNumSeconds = 10; 17 static const int kNumSeconds = 10;
18 static const int kWidth = 1920; 18 static const int kWidth = 1920;
19 static const int kWidthVga = 640; 19 static const int kWidthVga = 640;
20 static const int kHalfWidth = kWidth / 2; 20 static const int kHalfWidth = kWidth / 2;
21 static const int kHeight = 1080; 21 static const int kHeight = 1080;
22 static const int kHeightVga = 480; 22 static const int kHeightVga = 480;
23 static const int kFramerate = 30; 23 static const int kFramerate = 30;
24 static const int kLowQp = 15; 24 static const int kLowQp = 15;
25 static const int kNormalQp = 30; 25 static const int kNormalQp = 30;
26 static const int kHighQp = 40; 26 static const int kHighQp = 40;
27 static const int kMaxQp = 56; 27 static const int kMaxQp = 56;
28 static const int kDisabledBadQpThreshold = kMaxQp + 1; 28 static const int kDisabledBadQpThreshold = kMaxQp + 1;
29 static const int kLowInitialBitrateKbps = 300; 29 static const int kLowInitialBitrateKbps = 300;
30 // These values need to be in sync with corresponding constants
31 // in quality_scaler.cc
32 static const int kMeasureSecondsDownscale = 3;
33 static const int kMeasureSecondsFastUpscale = 2;
34 static const int kMeasureSecondsUpscale = 5;
30 } // namespace 35 } // namespace
31 36
32 class QualityScalerTest : public ::testing::Test { 37 class QualityScalerTest : public ::testing::Test {
33 public: 38 public:
34 // Temporal and spatial resolution. 39 // Temporal and spatial resolution.
35 struct Resolution { 40 struct Resolution {
36 int framerate; 41 int framerate;
37 int width; 42 int width;
38 int height; 43 int height;
39 }; 44 };
40 45
41 protected: 46 protected:
42 enum ScaleDirection { 47 enum ScaleDirection {
43 kKeepScaleAtHighQp, 48 kKeepScaleAtHighQp,
44 kScaleDown, 49 kScaleDown,
45 kScaleDownAboveHighQp, 50 kScaleDownAboveHighQp,
46 kScaleUp 51 kScaleUp
47 }; 52 };
48 enum BadQualityMetric { kDropFrame, kReportLowQP }; 53 enum BadQualityMetric { kDropFrame, kReportLowQP };
49 54
50 QualityScalerTest() { 55 QualityScalerTest() {
51 input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth, 56 input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth,
52 kHalfWidth); 57 kHalfWidth);
53 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, 58 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false,
54 0, 0, 0); 59 0, 0, 0, kFramerate);
55 qs_.ReportFramerate(kFramerate);
56 qs_.OnEncodeFrame(input_frame_); 60 qs_.OnEncodeFrame(input_frame_);
57 } 61 }
58 62
59 bool TriggerScale(ScaleDirection scale_direction) { 63 bool TriggerScale(ScaleDirection scale_direction) {
60 qs_.OnEncodeFrame(input_frame_); 64 qs_.OnEncodeFrame(input_frame_);
61 int initial_width = qs_.GetScaledResolution().width; 65 int initial_width = qs_.GetScaledResolution().width;
62 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { 66 for (int i = 0; i < kFramerate * kNumSeconds; ++i) {
63 switch (scale_direction) { 67 switch (scale_direction) {
64 case kScaleUp: 68 case kScaleUp:
65 qs_.ReportQP(kLowQp); 69 qs_.ReportQP(kLowQp);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 101
98 void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); 102 void ContinuouslyDownscalesByHalfDimensionsAndBackUp();
99 103
100 void DoesNotDownscaleFrameDimensions(int width, int height); 104 void DoesNotDownscaleFrameDimensions(int width, int height);
101 105
102 Resolution TriggerResolutionChange(BadQualityMetric dropframe_lowqp, 106 Resolution TriggerResolutionChange(BadQualityMetric dropframe_lowqp,
103 int num_second, 107 int num_second,
104 int initial_framerate); 108 int initial_framerate);
105 109
106 void VerifyQualityAdaptation(int initial_framerate, 110 void VerifyQualityAdaptation(int initial_framerate,
107 int seconds, 111 int seconds_downscale,
112 int seconds_upscale,
108 bool expect_spatial_resize, 113 bool expect_spatial_resize,
109 bool expect_framerate_reduction); 114 bool expect_framerate_reduction);
110 115
111 void DownscaleEndsAt(int input_width, 116 void DownscaleEndsAt(int input_width,
112 int input_height, 117 int input_height,
113 int end_width, 118 int end_width,
114 int end_height); 119 int end_height);
115 120
116 QualityScaler qs_; 121 QualityScaler qs_;
117 VideoFrame input_frame_; 122 VideoFrame input_frame_;
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 if (res.framerate != -1) 296 if (res.framerate != -1)
292 qs_.ReportFramerate(res.framerate); 297 qs_.ReportFramerate(res.framerate);
293 res.width = qs_.GetScaledResolution().width; 298 res.width = qs_.GetScaledResolution().width;
294 res.height = qs_.GetScaledResolution().height; 299 res.height = qs_.GetScaledResolution().height;
295 } 300 }
296 return res; 301 return res;
297 } 302 }
298 303
299 void QualityScalerTest::VerifyQualityAdaptation( 304 void QualityScalerTest::VerifyQualityAdaptation(
300 int initial_framerate, 305 int initial_framerate,
301 int seconds, 306 int seconds_downscale,
307 int seconds_upscale,
302 bool expect_spatial_resize, 308 bool expect_spatial_resize,
303 bool expect_framerate_reduction) { 309 bool expect_framerate_reduction) {
304 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, 310 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator,
305 kDisabledBadQpThreshold, true, 0, 0, 0); 311 kDisabledBadQpThreshold, true, 0, 0, 0, initial_framerate);
306 qs_.OnEncodeFrame(input_frame_); 312 qs_.OnEncodeFrame(input_frame_);
307 int init_width = qs_.GetScaledResolution().width; 313 int init_width = qs_.GetScaledResolution().width;
308 int init_height = qs_.GetScaledResolution().height; 314 int init_height = qs_.GetScaledResolution().height;
309 315
310 // Test reducing framerate by dropping frame continuously. 316 // Test reducing framerate by dropping frame continuously.
311 QualityScalerTest::Resolution res = 317 QualityScalerTest::Resolution res =
312 TriggerResolutionChange(kDropFrame, seconds, initial_framerate); 318 TriggerResolutionChange(kDropFrame, seconds_downscale, initial_framerate);
313 319
314 if (expect_framerate_reduction) { 320 if (expect_framerate_reduction) {
315 EXPECT_LT(res.framerate, initial_framerate); 321 EXPECT_LT(res.framerate, initial_framerate);
316 } else { 322 } else {
317 // No framerate reduction, video decimator should be disabled. 323 // No framerate reduction, video decimator should be disabled.
318 EXPECT_EQ(-1, res.framerate); 324 EXPECT_EQ(-1, res.framerate);
319 } 325 }
320 326
321 if (expect_spatial_resize) { 327 if (expect_spatial_resize) {
322 EXPECT_LT(res.width, init_width); 328 EXPECT_LT(res.width, init_width);
323 EXPECT_LT(res.height, init_height); 329 EXPECT_LT(res.height, init_height);
324 } else { 330 } else {
325 EXPECT_EQ(init_width, res.width); 331 EXPECT_EQ(init_width, res.width);
326 EXPECT_EQ(init_height, res.height); 332 EXPECT_EQ(init_height, res.height);
327 } 333 }
328 334
329 // The "seconds * 1.5" is to ensure spatial resolution to recover. 335 // The "seconds * 1.5" is to ensure spatial resolution to recover.
330 // For example, in 10 seconds test, framerate reduction happens in the first 336 // For example, in 6 seconds test, framerate reduction happens in the first
331 // 5 seconds from 30fps to 15fps and causes the buffer size to be half of the 337 // 3 seconds from 30fps to 15fps and causes the buffer size to be half of the
332 // original one. Then it will take only 75 samples to downscale (twice in 150 338 // original one. Then it will take only 45 samples to downscale (twice in 90
333 // samples). So to recover the resolution changes, we need more than 10 339 // samples). So to recover the resolution changes, we need more than 10
334 // seconds (i.e, seconds * 1.5). This is because the framerate increases 340 // seconds (i.e, seconds_upscale * 1.5). This is because the framerate
335 // before spatial size recovers, so it will take 150 samples to recover 341 // increases before spatial size recovers, so it will take 150 samples to
336 // spatial size (300 for twice). 342 // recover spatial size (300 for twice).
337 res = TriggerResolutionChange(kReportLowQP, seconds * 1.5, initial_framerate); 343 res = TriggerResolutionChange(kReportLowQP, seconds_upscale * 1.5,
344 initial_framerate);
338 EXPECT_EQ(-1, res.framerate); 345 EXPECT_EQ(-1, res.framerate);
339 EXPECT_EQ(init_width, res.width); 346 EXPECT_EQ(init_width, res.width);
340 EXPECT_EQ(init_height, res.height); 347 EXPECT_EQ(init_height, res.height);
341 } 348 }
342 349
343 // In 5 seconds test, only framerate adjusting should happen. 350 // In 3 seconds test, only framerate adjusting should happen and 5 second
351 // upscaling duration, only a framerate adjusting should happen.
344 TEST_F(QualityScalerTest, ChangeFramerateOnly) { 352 TEST_F(QualityScalerTest, ChangeFramerateOnly) {
345 VerifyQualityAdaptation(kFramerate, 5, false, true); 353 VerifyQualityAdaptation(kFramerate, kMeasureSecondsDownscale,
354 kMeasureSecondsUpscale, false, true);
346 } 355 }
347 356
348 // In 10 seconds test, framerate adjusting and scaling are both 357 // In 6 seconds test, framerate adjusting and scaling are both
349 // triggered, it shows that scaling would happen after framerate 358 // triggered, it shows that scaling would happen after framerate
350 // adjusting. 359 // adjusting.
351 TEST_F(QualityScalerTest, ChangeFramerateAndSpatialSize) { 360 TEST_F(QualityScalerTest, ChangeFramerateAndSpatialSize) {
352 VerifyQualityAdaptation(kFramerate, 10, true, true); 361 VerifyQualityAdaptation(kFramerate, kMeasureSecondsDownscale * 2,
362 kMeasureSecondsUpscale * 2, true, true);
353 } 363 }
354 364
355 // When starting from a low framerate, only spatial size will be changed. 365 // When starting from a low framerate, only spatial size will be changed.
356 TEST_F(QualityScalerTest, ChangeSpatialSizeOnly) { 366 TEST_F(QualityScalerTest, ChangeSpatialSizeOnly) {
357 qs_.ReportFramerate(kFramerate >> 1); 367 qs_.ReportFramerate(kFramerate >> 1);
358 VerifyQualityAdaptation(kFramerate >> 1, 10, true, false); 368 VerifyQualityAdaptation(kFramerate >> 1, kMeasureSecondsDownscale * 2,
369 kMeasureSecondsUpscale * 2, true, false);
359 } 370 }
360 371
361 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) { 372 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) {
362 DoesNotDownscaleFrameDimensions( 373 DoesNotDownscaleFrameDimensions(
363 2 * QualityScaler::kDefaultMinDownscaleDimension - 1, 1000); 374 2 * QualityScaler::kDefaultMinDownscaleDimension - 1, 1000);
364 } 375 }
365 376
366 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { 377 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) {
367 DoesNotDownscaleFrameDimensions( 378 DoesNotDownscaleFrameDimensions(
368 1000, 2 * QualityScaler::kDefaultMinDownscaleDimension - 1); 379 1000, 2 * QualityScaler::kDefaultMinDownscaleDimension - 1);
369 } 380 }
370 381
371 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { 382 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) {
372 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, 383 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator,
373 kDisabledBadQpThreshold, true, 384 kDisabledBadQpThreshold, true,
374 kLowInitialBitrateKbps, kWidth, kHeight); 385 kLowInitialBitrateKbps, kWidth, kHeight, kFramerate);
375 qs_.OnEncodeFrame(input_frame_); 386 qs_.OnEncodeFrame(input_frame_);
376 int init_width = qs_.GetScaledResolution().width; 387 int init_width = qs_.GetScaledResolution().width;
377 int init_height = qs_.GetScaledResolution().height; 388 int init_height = qs_.GetScaledResolution().height;
378 EXPECT_LE(init_width, kWidthVga); 389 EXPECT_LE(init_width, kWidthVga);
379 EXPECT_LE(init_height, kHeightVga); 390 EXPECT_LE(init_height, kHeightVga);
380 } 391 }
381 392
393 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) {
394 QualityScalerTest::Resolution initial_res;
395 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, 0,
396 kWidth, kHeight, kFramerate);
397 qs_.OnEncodeFrame(input_frame_);
398 initial_res.width = qs_.GetScaledResolution().width;
399 initial_res.height = qs_.GetScaledResolution().height;
400
401 // Should not downscale if less than kMeasureSecondsDownscale seconds passed.
402 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) {
403 qs_.ReportQP(kHighQp + 1);
404 qs_.OnEncodeFrame(input_frame_);
405 }
406 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width);
407 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height);
408
409 // Should downscale if more than kMeasureSecondsDownscale seconds passed (add
410 // last frame).
411 qs_.ReportQP(kHighQp + 1);
412 qs_.OnEncodeFrame(input_frame_);
413 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width);
414 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height);
415
416 // Should not upscale if less than kMeasureSecondsUpscale seconds passed since
417 // we saw issues initially (have already gone down).
418 for (int i = 0; i < kFramerate * kMeasureSecondsUpscale - 1; ++i) {
419 qs_.ReportQP(kLowQp);
420 qs_.OnEncodeFrame(input_frame_);
421 }
422 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width);
423 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height);
424
425 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed
426 // (add last frame).
427 qs_.ReportQP(kLowQp);
428 qs_.OnEncodeFrame(input_frame_);
429 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width);
430 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height);
431 }
432
433 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) {
434 QualityScalerTest::Resolution initial_res;
435 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false,
436 kLowInitialBitrateKbps, kWidth, kHeight, kFramerate);
437 qs_.OnEncodeFrame(input_frame_);
438 initial_res.width = qs_.GetScaledResolution().width;
439 initial_res.height = qs_.GetScaledResolution().height;
440
441 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed.
442 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) {
443 qs_.ReportQP(kLowQp);
444 qs_.OnEncodeFrame(input_frame_);
445 }
446 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width);
447 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height);
448
449 // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last
450 // frame).
451 qs_.ReportQP(kLowQp);
452 qs_.OnEncodeFrame(input_frame_);
453 EXPECT_LT(initial_res.width, qs_.GetScaledResolution().width);
454 EXPECT_LT(initial_res.height, qs_.GetScaledResolution().height);
455 }
456
382 void QualityScalerTest::DownscaleEndsAt(int input_width, 457 void QualityScalerTest::DownscaleEndsAt(int input_width,
383 int input_height, 458 int input_height,
384 int end_width, 459 int end_width,
385 int end_height) { 460 int end_height) {
386 // Create a frame with 2x expected end width/height to verify that we can 461 // Create a frame with 2x expected end width/height to verify that we can
387 // scale down to expected end width/height. 462 // scale down to expected end width/height.
388 input_frame_.CreateEmptyFrame(input_width, input_height, input_width, 463 input_frame_.CreateEmptyFrame(input_width, input_height, input_width,
389 (input_width + 1) / 2, (input_width + 1) / 2); 464 (input_width + 1) / 2, (input_width + 1) / 2);
390 465
391 int last_width = input_width; 466 int last_width = input_width;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 DownscaleEndsAt(1600, 800, 200, 100); 506 DownscaleEndsAt(1600, 800, 200, 100);
432 } 507 }
433 508
434 TEST_F(QualityScalerTest, RespectsMinResolutionHeight) { 509 TEST_F(QualityScalerTest, RespectsMinResolutionHeight) {
435 // Should end at 100x200, as height can't go lower. 510 // Should end at 100x200, as height can't go lower.
436 qs_.SetMinResolution(10, 200); 511 qs_.SetMinResolution(10, 200);
437 DownscaleEndsAt(800, 1600, 100, 200); 512 DownscaleEndsAt(800, 1600, 100, 200);
438 } 513 }
439 514
440 } // namespace webrtc 515 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698