| 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/include/quality_scaler.h" | 11 #include "webrtc/modules/video_coding/utility/include/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 kHalfWidth = kWidth / 2; | 19 static const int kHalfWidth = kWidth / 2; |
| 20 static const int kHeight = 1080; | 20 static const int kHeight = 1080; |
| 21 static const int kFramerate = 30; | 21 static const int kFramerate = 30; |
| 22 static const int kLowQp = 15; | 22 static const int kLowQp = 15; |
| 23 static const int kNormalQp = 30; | 23 static const int kNormalQp = 30; |
| 24 static const int kHighQp = 40; |
| 24 static const int kMaxQp = 56; | 25 static const int kMaxQp = 56; |
| 25 } // namespace | 26 } // namespace |
| 26 | 27 |
| 27 class QualityScalerTest : public ::testing::Test { | 28 class QualityScalerTest : public ::testing::Test { |
| 28 public: | 29 public: |
| 29 // Temporal and spatial resolution. | 30 // Temporal and spatial resolution. |
| 30 struct Resolution { | 31 struct Resolution { |
| 31 int framerate; | 32 int framerate; |
| 32 int width; | 33 int width; |
| 33 int height; | 34 int height; |
| 34 }; | 35 }; |
| 35 protected: | 36 protected: |
| 36 enum ScaleDirection { kScaleDown, kScaleUp }; | 37 enum ScaleDirection { |
| 38 kKeepScaleAtHighQp, |
| 39 kScaleDown, |
| 40 kScaleDownAboveHighQp, |
| 41 kScaleUp |
| 42 }; |
| 37 enum BadQualityMetric { kDropFrame, kReportLowQP }; | 43 enum BadQualityMetric { kDropFrame, kReportLowQP }; |
| 38 | 44 |
| 39 QualityScalerTest() { | 45 QualityScalerTest() { |
| 40 input_frame_.CreateEmptyFrame( | 46 input_frame_.CreateEmptyFrame( |
| 41 kWidth, kHeight, kWidth, kHalfWidth, kHalfWidth); | 47 kWidth, kHeight, kWidth, kHalfWidth, kHalfWidth); |
| 42 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, false); | 48 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false); |
| 43 qs_.ReportFramerate(kFramerate); | 49 qs_.ReportFramerate(kFramerate); |
| 44 qs_.OnEncodeFrame(input_frame_); | 50 qs_.OnEncodeFrame(input_frame_); |
| 45 } | 51 } |
| 46 | 52 |
| 47 bool TriggerScale(ScaleDirection scale_direction) { | 53 bool TriggerScale(ScaleDirection scale_direction) { |
| 48 qs_.OnEncodeFrame(input_frame_); | 54 qs_.OnEncodeFrame(input_frame_); |
| 49 int initial_width = qs_.GetScaledResolution().width; | 55 int initial_width = qs_.GetScaledResolution().width; |
| 50 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 56 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
| 51 switch (scale_direction) { | 57 switch (scale_direction) { |
| 52 case kScaleUp: | 58 case kScaleUp: |
| 53 qs_.ReportQP(kLowQp); | 59 qs_.ReportQP(kLowQp); |
| 54 break; | 60 break; |
| 55 case kScaleDown: | 61 case kScaleDown: |
| 56 qs_.ReportDroppedFrame(); | 62 qs_.ReportDroppedFrame(); |
| 57 break; | 63 break; |
| 64 case kKeepScaleAtHighQp: |
| 65 qs_.ReportQP(kHighQp); |
| 66 break; |
| 67 case kScaleDownAboveHighQp: |
| 68 qs_.ReportQP(kHighQp + 1); |
| 69 break; |
| 58 } | 70 } |
| 59 qs_.OnEncodeFrame(input_frame_); | 71 qs_.OnEncodeFrame(input_frame_); |
| 60 if (qs_.GetScaledResolution().width != initial_width) | 72 if (qs_.GetScaledResolution().width != initial_width) |
| 61 return true; | 73 return true; |
| 62 } | 74 } |
| 63 | 75 |
| 64 return false; | 76 return false; |
| 65 } | 77 } |
| 66 | 78 |
| 67 void ExpectOriginalFrame() { | 79 void ExpectOriginalFrame() { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 } | 122 } |
| 111 | 123 |
| 112 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { | 124 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { |
| 113 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds | 125 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds |
| 114 << " seconds."; | 126 << " seconds."; |
| 115 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 127 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 116 EXPECT_LT(res.width, input_frame_.width()); | 128 EXPECT_LT(res.width, input_frame_.width()); |
| 117 EXPECT_LT(res.height, input_frame_.height()); | 129 EXPECT_LT(res.height, input_frame_.height()); |
| 118 } | 130 } |
| 119 | 131 |
| 132 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) { |
| 133 EXPECT_FALSE(TriggerScale(kKeepScaleAtHighQp)) |
| 134 << "Downscale at high threshold which should keep scale."; |
| 135 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 136 EXPECT_EQ(res.width, input_frame_.width()); |
| 137 EXPECT_EQ(res.height, input_frame_.height()); |
| 138 } |
| 139 |
| 140 TEST_F(QualityScalerTest, DownscalesAboveHighQp) { |
| 141 EXPECT_TRUE(TriggerScale(kScaleDownAboveHighQp)) |
| 142 << "No downscale within " << kNumSeconds << " seconds."; |
| 143 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 144 EXPECT_LT(res.width, input_frame_.width()); |
| 145 EXPECT_LT(res.height, input_frame_.height()); |
| 146 } |
| 147 |
| 120 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { | 148 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { |
| 121 for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { | 149 for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { |
| 122 qs_.ReportQP(kNormalQp); | 150 qs_.ReportQP(kNormalQp); |
| 123 qs_.ReportDroppedFrame(); | 151 qs_.ReportDroppedFrame(); |
| 124 qs_.ReportDroppedFrame(); | 152 qs_.ReportDroppedFrame(); |
| 125 qs_.OnEncodeFrame(input_frame_); | 153 qs_.OnEncodeFrame(input_frame_); |
| 126 if (qs_.GetScaledResolution().width < input_frame_.width()) | 154 if (qs_.GetScaledResolution().width < input_frame_.width()) |
| 127 return; | 155 return; |
| 128 } | 156 } |
| 129 | 157 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 qs_.ReportFramerate(res.framerate); | 283 qs_.ReportFramerate(res.framerate); |
| 256 res.width = qs_.GetScaledResolution().width; | 284 res.width = qs_.GetScaledResolution().width; |
| 257 res.height = qs_.GetScaledResolution().height; | 285 res.height = qs_.GetScaledResolution().height; |
| 258 } | 286 } |
| 259 return res; | 287 return res; |
| 260 } | 288 } |
| 261 | 289 |
| 262 void QualityScalerTest::VerifyQualityAdaptation( | 290 void QualityScalerTest::VerifyQualityAdaptation( |
| 263 int initial_framerate, int seconds, bool expect_spatial_resize, | 291 int initial_framerate, int seconds, bool expect_spatial_resize, |
| 264 bool expect_framerate_reduction) { | 292 bool expect_framerate_reduction) { |
| 265 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, true); | 293 const int kDisabledBadQpThreshold = kMaxQp + 1; |
| 294 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, |
| 295 kDisabledBadQpThreshold, true); |
| 266 qs_.OnEncodeFrame(input_frame_); | 296 qs_.OnEncodeFrame(input_frame_); |
| 267 int init_width = qs_.GetScaledResolution().width; | 297 int init_width = qs_.GetScaledResolution().width; |
| 268 int init_height = qs_.GetScaledResolution().height; | 298 int init_height = qs_.GetScaledResolution().height; |
| 269 | 299 |
| 270 // Test reducing framerate by dropping frame continuously. | 300 // Test reducing framerate by dropping frame continuously. |
| 271 QualityScalerTest::Resolution res = TriggerResolutionChange( | 301 QualityScalerTest::Resolution res = TriggerResolutionChange( |
| 272 kDropFrame, seconds, initial_framerate); | 302 kDropFrame, seconds, initial_framerate); |
| 273 | 303 |
| 274 if (expect_framerate_reduction) { | 304 if (expect_framerate_reduction) { |
| 275 EXPECT_LT(res.framerate, initial_framerate); | 305 EXPECT_LT(res.framerate, initial_framerate); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 DownscaleEndsAt(1600, 800, 200, 100); | 410 DownscaleEndsAt(1600, 800, 200, 100); |
| 381 } | 411 } |
| 382 | 412 |
| 383 TEST_F(QualityScalerTest, RespectsMinResolutionHeight) { | 413 TEST_F(QualityScalerTest, RespectsMinResolutionHeight) { |
| 384 // Should end at 100x200, as height can't go lower. | 414 // Should end at 100x200, as height can't go lower. |
| 385 qs_.SetMinResolution(10, 200); | 415 qs_.SetMinResolution(10, 200); |
| 386 DownscaleEndsAt(800, 1600, 100, 200); | 416 DownscaleEndsAt(800, 1600, 100, 200); |
| 387 } | 417 } |
| 388 | 418 |
| 389 } // namespace webrtc | 419 } // namespace webrtc |
| OLD | NEW |