OLD | NEW |
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 kLowQpThreshold = 18; |
26 static const int kHighQp = 40; | 27 static const int kHighQp = 40; |
27 static const int kMaxQp = 56; | 28 static const int kDisabledBadQpThreshold = 64; |
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 | 30 // These values need to be in sync with corresponding constants |
31 // in quality_scaler.cc | 31 // in quality_scaler.cc |
32 static const int kMeasureSecondsDownscale = 3; | 32 static const int kMeasureSecondsDownscale = 3; |
33 static const int kMeasureSecondsFastUpscale = 2; | 33 static const int kMeasureSecondsFastUpscale = 2; |
34 static const int kMeasureSecondsUpscale = 5; | 34 static const int kMeasureSecondsUpscale = 5; |
35 static const int kMinDownscaleDimension = 140; | 35 static const int kMinDownscaleDimension = 140; |
36 } // namespace | 36 } // namespace |
37 | 37 |
38 class QualityScalerTest : public ::testing::Test { | 38 class QualityScalerTest : public ::testing::Test { |
(...skipping 10 matching lines...) Expand all Loading... |
49 kKeepScaleAtHighQp, | 49 kKeepScaleAtHighQp, |
50 kScaleDown, | 50 kScaleDown, |
51 kScaleDownAboveHighQp, | 51 kScaleDownAboveHighQp, |
52 kScaleUp | 52 kScaleUp |
53 }; | 53 }; |
54 enum BadQualityMetric { kDropFrame, kReportLowQP }; | 54 enum BadQualityMetric { kDropFrame, kReportLowQP }; |
55 | 55 |
56 QualityScalerTest() { | 56 QualityScalerTest() { |
57 input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth, | 57 input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth, |
58 kHalfWidth); | 58 kHalfWidth); |
59 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, | 59 qs_.Init(kLowQpThreshold, kHighQp, false, 0, 0, 0, kFramerate); |
60 0, 0, 0, kFramerate); | |
61 qs_.OnEncodeFrame(input_frame_); | 60 qs_.OnEncodeFrame(input_frame_); |
62 } | 61 } |
63 | 62 |
64 bool TriggerScale(ScaleDirection scale_direction) { | 63 bool TriggerScale(ScaleDirection scale_direction) { |
65 qs_.OnEncodeFrame(input_frame_); | 64 qs_.OnEncodeFrame(input_frame_); |
66 int initial_width = qs_.GetScaledResolution().width; | 65 int initial_width = qs_.GetScaledResolution().width; |
67 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 66 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
68 switch (scale_direction) { | 67 switch (scale_direction) { |
69 case kScaleUp: | 68 case kScaleUp: |
70 qs_.ReportQP(kLowQp); | 69 qs_.ReportQP(kLowQp); |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 } | 300 } |
302 return res; | 301 return res; |
303 } | 302 } |
304 | 303 |
305 void QualityScalerTest::VerifyQualityAdaptation( | 304 void QualityScalerTest::VerifyQualityAdaptation( |
306 int initial_framerate, | 305 int initial_framerate, |
307 int seconds_downscale, | 306 int seconds_downscale, |
308 int seconds_upscale, | 307 int seconds_upscale, |
309 bool expect_spatial_resize, | 308 bool expect_spatial_resize, |
310 bool expect_framerate_reduction) { | 309 bool expect_framerate_reduction) { |
311 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, | 310 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, true, 0, 0, 0, |
312 kDisabledBadQpThreshold, true, 0, 0, 0, initial_framerate); | 311 initial_framerate); |
313 qs_.OnEncodeFrame(input_frame_); | 312 qs_.OnEncodeFrame(input_frame_); |
314 int init_width = qs_.GetScaledResolution().width; | 313 int init_width = qs_.GetScaledResolution().width; |
315 int init_height = qs_.GetScaledResolution().height; | 314 int init_height = qs_.GetScaledResolution().height; |
316 | 315 |
317 // Test reducing framerate by dropping frame continuously. | 316 // Test reducing framerate by dropping frame continuously. |
318 QualityScalerTest::Resolution res = | 317 QualityScalerTest::Resolution res = |
319 TriggerResolutionChange(kDropFrame, seconds_downscale, initial_framerate); | 318 TriggerResolutionChange(kDropFrame, seconds_downscale, initial_framerate); |
320 | 319 |
321 if (expect_framerate_reduction) { | 320 if (expect_framerate_reduction) { |
322 EXPECT_LT(res.framerate, initial_framerate); | 321 EXPECT_LT(res.framerate, initial_framerate); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 DoesNotDownscaleFrameDimensions( | 373 DoesNotDownscaleFrameDimensions( |
375 2 * kMinDownscaleDimension - 1, 1000); | 374 2 * kMinDownscaleDimension - 1, 1000); |
376 } | 375 } |
377 | 376 |
378 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { | 377 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { |
379 DoesNotDownscaleFrameDimensions( | 378 DoesNotDownscaleFrameDimensions( |
380 1000, 2 * kMinDownscaleDimension - 1); | 379 1000, 2 * kMinDownscaleDimension - 1); |
381 } | 380 } |
382 | 381 |
383 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { | 382 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { |
384 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, | 383 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, true, |
385 kDisabledBadQpThreshold, true, | |
386 kLowInitialBitrateKbps, kWidth, kHeight, kFramerate); | 384 kLowInitialBitrateKbps, kWidth, kHeight, kFramerate); |
387 qs_.OnEncodeFrame(input_frame_); | 385 qs_.OnEncodeFrame(input_frame_); |
388 int init_width = qs_.GetScaledResolution().width; | 386 int init_width = qs_.GetScaledResolution().width; |
389 int init_height = qs_.GetScaledResolution().height; | 387 int init_height = qs_.GetScaledResolution().height; |
390 EXPECT_LE(init_width, kWidthVga); | 388 EXPECT_LE(init_width, kWidthVga); |
391 EXPECT_LE(init_height, kHeightVga); | 389 EXPECT_LE(init_height, kHeightVga); |
392 } | 390 } |
393 | 391 |
394 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { | 392 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { |
395 QualityScalerTest::Resolution initial_res; | 393 QualityScalerTest::Resolution initial_res; |
396 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, 0, | 394 qs_.Init(kLowQpThreshold, kHighQp, false, 0, kWidth, kHeight, kFramerate); |
397 kWidth, kHeight, kFramerate); | |
398 qs_.OnEncodeFrame(input_frame_); | 395 qs_.OnEncodeFrame(input_frame_); |
399 initial_res.width = qs_.GetScaledResolution().width; | 396 initial_res.width = qs_.GetScaledResolution().width; |
400 initial_res.height = qs_.GetScaledResolution().height; | 397 initial_res.height = qs_.GetScaledResolution().height; |
401 | 398 |
402 // Should not downscale if less than kMeasureSecondsDownscale seconds passed. | 399 // Should not downscale if less than kMeasureSecondsDownscale seconds passed. |
403 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { | 400 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { |
404 qs_.ReportQP(kHighQp + 1); | 401 qs_.ReportQP(kHighQp + 1); |
405 qs_.OnEncodeFrame(input_frame_); | 402 qs_.OnEncodeFrame(input_frame_); |
406 } | 403 } |
407 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 404 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
(...skipping 18 matching lines...) Expand all Loading... |
426 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed | 423 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed |
427 // (add last frame). | 424 // (add last frame). |
428 qs_.ReportQP(kLowQp); | 425 qs_.ReportQP(kLowQp); |
429 qs_.OnEncodeFrame(input_frame_); | 426 qs_.OnEncodeFrame(input_frame_); |
430 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 427 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
431 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); | 428 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
432 } | 429 } |
433 | 430 |
434 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { | 431 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { |
435 QualityScalerTest::Resolution initial_res; | 432 QualityScalerTest::Resolution initial_res; |
436 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, | 433 qs_.Init(kLowQpThreshold, kHighQp, false, kLowInitialBitrateKbps, kWidth, |
437 kLowInitialBitrateKbps, kWidth, kHeight, kFramerate); | 434 kHeight, kFramerate); |
438 qs_.OnEncodeFrame(input_frame_); | 435 qs_.OnEncodeFrame(input_frame_); |
439 initial_res.width = qs_.GetScaledResolution().width; | 436 initial_res.width = qs_.GetScaledResolution().width; |
440 initial_res.height = qs_.GetScaledResolution().height; | 437 initial_res.height = qs_.GetScaledResolution().height; |
441 | 438 |
442 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. | 439 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. |
443 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { | 440 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { |
444 qs_.ReportQP(kLowQp); | 441 qs_.ReportQP(kLowQp); |
445 qs_.OnEncodeFrame(input_frame_); | 442 qs_.OnEncodeFrame(input_frame_); |
446 } | 443 } |
447 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 444 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 | 488 |
492 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) { | 489 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) { |
493 DownscaleEndsAt(1280, 720, 320, 180); | 490 DownscaleEndsAt(1280, 720, 320, 180); |
494 } | 491 } |
495 | 492 |
496 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) { | 493 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) { |
497 DownscaleEndsAt(320, 180, 320, 180); | 494 DownscaleEndsAt(320, 180, 320, 180); |
498 } | 495 } |
499 | 496 |
500 } // namespace webrtc | 497 } // namespace webrtc |
OLD | NEW |