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 |