| 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 |