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 |
(...skipping 13 matching lines...) Expand all Loading... |
24 static const int kMaxQp = 56; | 24 static const int kMaxQp = 56; |
25 } // namespace | 25 } // namespace |
26 | 26 |
27 class QualityScalerTest : public ::testing::Test { | 27 class QualityScalerTest : public ::testing::Test { |
28 protected: | 28 protected: |
29 enum ScaleDirection { kScaleDown, kScaleUp }; | 29 enum ScaleDirection { kScaleDown, kScaleUp }; |
30 | 30 |
31 QualityScalerTest() { | 31 QualityScalerTest() { |
32 input_frame_.CreateEmptyFrame( | 32 input_frame_.CreateEmptyFrame( |
33 kWidth, kHeight, kWidth, kHalfWidth, kHalfWidth); | 33 kWidth, kHeight, kWidth, kHalfWidth, kHalfWidth); |
34 qs_.Init(kMaxQp / kDefaultLowQpDenominator); | 34 qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator); |
35 qs_.ReportFramerate(kFramerate); | 35 qs_.ReportFramerate(kFramerate); |
36 } | 36 } |
37 | 37 |
38 void TriggerScale(ScaleDirection scale_direction) { | 38 bool TriggerScale(ScaleDirection scale_direction) { |
39 int initial_width = qs_.GetScaledResolution(input_frame_).width; | 39 int initial_width = qs_.GetScaledResolution(input_frame_).width; |
40 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 40 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
41 switch (scale_direction) { | 41 switch (scale_direction) { |
42 case kScaleUp: | 42 case kScaleUp: |
43 qs_.ReportQP(kLowQp); | 43 qs_.ReportQP(kLowQp); |
44 break; | 44 break; |
45 case kScaleDown: | 45 case kScaleDown: |
46 qs_.ReportDroppedFrame(); | 46 qs_.ReportDroppedFrame(); |
47 break; | 47 break; |
48 } | 48 } |
49 | 49 |
50 if (qs_.GetScaledResolution(input_frame_).width != initial_width) | 50 if (qs_.GetScaledResolution(input_frame_).width != initial_width) |
51 return; | 51 return true; |
52 } | 52 } |
53 | 53 |
54 FAIL() << "No downscale within " << kNumSeconds << " seconds."; | 54 return false; |
55 } | 55 } |
56 | 56 |
57 void ExpectOriginalFrame() { | 57 void ExpectOriginalFrame() { |
58 EXPECT_EQ(&input_frame_, &qs_.GetScaledFrame(input_frame_)) | 58 EXPECT_EQ(&input_frame_, &qs_.GetScaledFrame(input_frame_)) |
59 << "Using scaled frame instead of original input."; | 59 << "Using scaled frame instead of original input."; |
60 } | 60 } |
61 | 61 |
62 void ExpectScaleUsingReportedResolution() { | 62 void ExpectScaleUsingReportedResolution() { |
63 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); | 63 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); |
64 const VideoFrame& scaled_frame = qs_.GetScaledFrame(input_frame_); | 64 const VideoFrame& scaled_frame = qs_.GetScaledFrame(input_frame_); |
65 EXPECT_EQ(res.width, scaled_frame.width()); | 65 EXPECT_EQ(res.width, scaled_frame.width()); |
66 EXPECT_EQ(res.height, scaled_frame.height()); | 66 EXPECT_EQ(res.height, scaled_frame.height()); |
67 } | 67 } |
68 | 68 |
69 void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); | 69 void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); |
70 | 70 |
71 void DoesNotDownscaleFrameDimensions(int width, int height); | 71 void DoesNotDownscaleFrameDimensions(int width, int height); |
72 | 72 |
| 73 void DownscaleEndsAt(int input_width, |
| 74 int input_height, |
| 75 int end_width, |
| 76 int end_height); |
| 77 |
73 QualityScaler qs_; | 78 QualityScaler qs_; |
74 VideoFrame input_frame_; | 79 VideoFrame input_frame_; |
75 }; | 80 }; |
76 | 81 |
77 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { | 82 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { |
78 ExpectOriginalFrame(); | 83 ExpectOriginalFrame(); |
79 } | 84 } |
80 | 85 |
81 TEST_F(QualityScalerTest, ReportsOriginalResolutionInitially) { | 86 TEST_F(QualityScalerTest, ReportsOriginalResolutionInitially) { |
82 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); | 87 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); |
83 EXPECT_EQ(input_frame_.width(), res.width); | 88 EXPECT_EQ(input_frame_.width(), res.width); |
84 EXPECT_EQ(input_frame_.height(), res.height); | 89 EXPECT_EQ(input_frame_.height(), res.height); |
85 } | 90 } |
86 | 91 |
87 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { | 92 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { |
88 TriggerScale(kScaleDown); | 93 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds |
| 94 << " seconds."; |
89 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); | 95 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); |
90 EXPECT_LT(res.width, input_frame_.width()); | 96 EXPECT_LT(res.width, input_frame_.width()); |
91 EXPECT_LT(res.height, input_frame_.height()); | 97 EXPECT_LT(res.height, input_frame_.height()); |
92 } | 98 } |
93 | 99 |
94 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { | 100 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { |
95 for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { | 101 for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { |
96 qs_.ReportQP(kNormalQp); | 102 qs_.ReportQP(kNormalQp); |
97 qs_.ReportDroppedFrame(); | 103 qs_.ReportDroppedFrame(); |
98 qs_.ReportDroppedFrame(); | 104 qs_.ReportDroppedFrame(); |
(...skipping 24 matching lines...) Expand all Loading... |
123 } | 129 } |
124 } | 130 } |
125 | 131 |
126 void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() { | 132 void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() { |
127 const int initial_min_dimension = input_frame_.width() < input_frame_.height() | 133 const int initial_min_dimension = input_frame_.width() < input_frame_.height() |
128 ? input_frame_.width() | 134 ? input_frame_.width() |
129 : input_frame_.height(); | 135 : input_frame_.height(); |
130 int min_dimension = initial_min_dimension; | 136 int min_dimension = initial_min_dimension; |
131 int current_shift = 0; | 137 int current_shift = 0; |
132 // Drop all frames to force-trigger downscaling. | 138 // Drop all frames to force-trigger downscaling. |
133 while (min_dimension > 16) { | 139 while (min_dimension >= 2 * QualityScaler::kDefaultMinDownscaleDimension) { |
134 TriggerScale(kScaleDown); | 140 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " |
| 141 << kNumSeconds << " seconds."; |
135 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); | 142 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); |
136 min_dimension = res.width < res.height ? res.width : res.height; | 143 min_dimension = res.width < res.height ? res.width : res.height; |
137 ++current_shift; | 144 ++current_shift; |
138 ASSERT_EQ(input_frame_.width() >> current_shift, res.width); | 145 ASSERT_EQ(input_frame_.width() >> current_shift, res.width); |
139 ASSERT_EQ(input_frame_.height() >> current_shift, res.height); | 146 ASSERT_EQ(input_frame_.height() >> current_shift, res.height); |
140 ExpectScaleUsingReportedResolution(); | 147 ExpectScaleUsingReportedResolution(); |
141 } | 148 } |
142 | 149 |
143 // Make sure we can scale back with good-quality frames. | 150 // Make sure we can scale back with good-quality frames. |
144 while (min_dimension < initial_min_dimension) { | 151 while (min_dimension < initial_min_dimension) { |
145 TriggerScale(kScaleUp); | 152 EXPECT_TRUE(TriggerScale(kScaleUp)) << "No upscale within " << kNumSeconds |
| 153 << " seconds."; |
146 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); | 154 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); |
147 min_dimension = res.width < res.height ? res.width : res.height; | 155 min_dimension = res.width < res.height ? res.width : res.height; |
148 --current_shift; | 156 --current_shift; |
149 ASSERT_EQ(input_frame_.width() >> current_shift, res.width); | 157 ASSERT_EQ(input_frame_.width() >> current_shift, res.width); |
150 ASSERT_EQ(input_frame_.height() >> current_shift, res.height); | 158 ASSERT_EQ(input_frame_.height() >> current_shift, res.height); |
151 ExpectScaleUsingReportedResolution(); | 159 ExpectScaleUsingReportedResolution(); |
152 } | 160 } |
153 | 161 |
154 // Verify we don't start upscaling after further low use. | 162 // Verify we don't start upscaling after further low use. |
155 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 163 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 } | 196 } |
189 | 197 |
190 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) { | 198 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) { |
191 DoesNotDownscaleFrameDimensions(kWidth, 1); | 199 DoesNotDownscaleFrameDimensions(kWidth, 1); |
192 } | 200 } |
193 | 201 |
194 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) { | 202 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) { |
195 DoesNotDownscaleFrameDimensions(1, 1); | 203 DoesNotDownscaleFrameDimensions(1, 1); |
196 } | 204 } |
197 | 205 |
| 206 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) { |
| 207 DoesNotDownscaleFrameDimensions( |
| 208 2 * QualityScaler::kDefaultMinDownscaleDimension - 1, 1000); |
| 209 } |
| 210 |
| 211 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { |
| 212 DoesNotDownscaleFrameDimensions( |
| 213 1000, 2 * QualityScaler::kDefaultMinDownscaleDimension - 1); |
| 214 } |
| 215 |
| 216 void QualityScalerTest::DownscaleEndsAt(int input_width, |
| 217 int input_height, |
| 218 int end_width, |
| 219 int end_height) { |
| 220 // Create a frame with 2x expected end width/height to verify that we can |
| 221 // scale down to expected end width/height. |
| 222 input_frame_.CreateEmptyFrame(input_width, input_height, input_width, |
| 223 (input_width + 1) / 2, (input_width + 1) / 2); |
| 224 |
| 225 int last_width = input_width; |
| 226 int last_height = input_height; |
| 227 // Drop all frames to force-trigger downscaling. |
| 228 while (true) { |
| 229 TriggerScale(kScaleDown); |
| 230 QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_); |
| 231 if (last_width == res.width) { |
| 232 EXPECT_EQ(last_height, res.height); |
| 233 EXPECT_EQ(end_width, res.width); |
| 234 EXPECT_EQ(end_height, res.height); |
| 235 break; |
| 236 } |
| 237 last_width = res.width; |
| 238 last_height = res.height; |
| 239 } |
| 240 } |
| 241 |
| 242 TEST_F(QualityScalerTest, DefaultDownscalesTo160x90) { |
| 243 DownscaleEndsAt(320, 180, 160, 90); |
| 244 } |
| 245 |
| 246 TEST_F(QualityScalerTest, DefaultDownscalesTo90x160) { |
| 247 DownscaleEndsAt(180, 320, 90, 160); |
| 248 } |
| 249 |
| 250 TEST_F(QualityScalerTest, DefaultDownscalesFrom1280x720To160x90) { |
| 251 DownscaleEndsAt(1280, 720, 160, 90); |
| 252 } |
| 253 |
| 254 TEST_F(QualityScalerTest, DefaultDoesntDownscaleBelow160x90) { |
| 255 DownscaleEndsAt(320 - 1, 180 - 1, 320 - 1, 180 - 1); |
| 256 } |
| 257 |
| 258 TEST_F(QualityScalerTest, DefaultDoesntDownscaleBelow90x160) { |
| 259 DownscaleEndsAt(180 - 1, 320 - 1, 180 - 1, 320 - 1); |
| 260 } |
| 261 |
| 262 TEST_F(QualityScalerTest, RespectsMinResolutionWidth) { |
| 263 // Should end at 200x100, as width can't go lower. |
| 264 qs_.SetMinResolution(200, 10); |
| 265 DownscaleEndsAt(1600, 800, 200, 100); |
| 266 } |
| 267 |
| 268 TEST_F(QualityScalerTest, RespectsMinResolutionHeight) { |
| 269 // Should end at 100x200, as height can't go lower. |
| 270 qs_.SetMinResolution(10, 200); |
| 271 DownscaleEndsAt(800, 1600, 100, 200); |
| 272 } |
| 273 |
198 } // namespace webrtc | 274 } // namespace webrtc |
OLD | NEW |