| 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 kHalfWidth = kWidth / 2; | |
| 20 static const int kHeight = 1080; | 19 static const int kHeight = 1080; |
| 21 static const int kFramerate = 30; | 20 static const int kFramerate = 30; |
| 22 static const int kLowQp = 15; | 21 static const int kLowQp = 15; |
| 23 static const int kNormalQp = 30; | 22 static const int kNormalQp = 30; |
| 24 static const int kLowQpThreshold = 18; | 23 static const int kLowQpThreshold = 18; |
| 25 static const int kHighQp = 40; | 24 static const int kHighQp = 40; |
| 26 static const int kDisabledBadQpThreshold = 64; | 25 static const int kDisabledBadQpThreshold = 64; |
| 27 static const int kLowInitialBitrateKbps = 300; | 26 static const int kLowInitialBitrateKbps = 300; |
| 28 // These values need to be in sync with corresponding constants | 27 // These values need to be in sync with corresponding constants |
| 29 // in quality_scaler.cc | 28 // in quality_scaler.cc |
| 30 static const int kMeasureSecondsFastUpscale = 2; | 29 static const int kMeasureSecondsFastUpscale = 2; |
| 31 static const int kMeasureSecondsUpscale = 5; | 30 static const int kMeasureSecondsUpscale = 5; |
| 32 static const int kMeasureSecondsDownscale = 5; | 31 static const int kMeasureSecondsDownscale = 5; |
| 33 static const int kMinDownscaleDimension = 140; | 32 static const int kMinDownscaleDimension = 140; |
| 34 } // namespace | 33 } // namespace |
| 35 | 34 |
| 36 class QualityScalerTest : public ::testing::Test { | 35 class QualityScalerTest : public ::testing::Test { |
| 37 protected: | 36 protected: |
| 38 enum ScaleDirection { | 37 enum ScaleDirection { |
| 39 kKeepScaleAtHighQp, | 38 kKeepScaleAtHighQp, |
| 40 kScaleDown, | 39 kScaleDown, |
| 41 kScaleDownAboveHighQp, | 40 kScaleDownAboveHighQp, |
| 42 kScaleUp | 41 kScaleUp |
| 43 }; | 42 }; |
| 44 | 43 |
| 45 QualityScalerTest() { | 44 QualityScalerTest() { |
| 46 input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth, | 45 input_frame_ = rtc::scoped_refptr<VideoFrameBuffer>( |
| 47 kHalfWidth); | 46 new rtc::RefCountedObject<I420Buffer>(kWidth, kHeight)); |
| 48 qs_.Init(kLowQpThreshold, kHighQp, 0, 0, 0, kFramerate); | 47 qs_.Init(kLowQpThreshold, kHighQp, 0, 0, 0, kFramerate); |
| 49 qs_.OnEncodeFrame(input_frame_); | 48 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 50 } | 49 } |
| 51 | 50 |
| 52 bool TriggerScale(ScaleDirection scale_direction) { | 51 bool TriggerScale(ScaleDirection scale_direction) { |
| 53 qs_.OnEncodeFrame(input_frame_); | 52 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 54 int initial_width = qs_.GetScaledResolution().width; | 53 int initial_width = qs_.GetScaledResolution().width; |
| 55 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 54 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
| 56 switch (scale_direction) { | 55 switch (scale_direction) { |
| 57 case kScaleUp: | 56 case kScaleUp: |
| 58 qs_.ReportQP(kLowQp); | 57 qs_.ReportQP(kLowQp); |
| 59 break; | 58 break; |
| 60 case kScaleDown: | 59 case kScaleDown: |
| 61 qs_.ReportDroppedFrame(); | 60 qs_.ReportDroppedFrame(); |
| 62 break; | 61 break; |
| 63 case kKeepScaleAtHighQp: | 62 case kKeepScaleAtHighQp: |
| 64 qs_.ReportQP(kHighQp); | 63 qs_.ReportQP(kHighQp); |
| 65 break; | 64 break; |
| 66 case kScaleDownAboveHighQp: | 65 case kScaleDownAboveHighQp: |
| 67 qs_.ReportQP(kHighQp + 1); | 66 qs_.ReportQP(kHighQp + 1); |
| 68 break; | 67 break; |
| 69 } | 68 } |
| 70 qs_.OnEncodeFrame(input_frame_); | 69 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 71 if (qs_.GetScaledResolution().width != initial_width) | 70 if (qs_.GetScaledResolution().width != initial_width) |
| 72 return true; | 71 return true; |
| 73 } | 72 } |
| 74 | 73 |
| 75 return false; | 74 return false; |
| 76 } | 75 } |
| 77 | 76 |
| 78 void ExpectOriginalFrame() { | 77 void ExpectOriginalFrame() { |
| 79 EXPECT_EQ(&input_frame_, &qs_.GetScaledFrame(input_frame_)) | 78 EXPECT_EQ(input_frame_, qs_.GetScaledBuffer(input_frame_)) |
| 80 << "Using scaled frame instead of original input."; | 79 << "Using scaled frame instead of original input."; |
| 81 } | 80 } |
| 82 | 81 |
| 83 void ExpectScaleUsingReportedResolution() { | 82 void ExpectScaleUsingReportedResolution() { |
| 84 qs_.OnEncodeFrame(input_frame_); | 83 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 85 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 84 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 86 const VideoFrame& scaled_frame = qs_.GetScaledFrame(input_frame_); | 85 rtc::scoped_refptr<VideoFrameBuffer> scaled_frame = |
| 87 EXPECT_EQ(res.width, scaled_frame.width()); | 86 qs_.GetScaledBuffer(input_frame_); |
| 88 EXPECT_EQ(res.height, scaled_frame.height()); | 87 EXPECT_EQ(res.width, scaled_frame->width()); |
| 88 EXPECT_EQ(res.height, scaled_frame->height()); |
| 89 } | 89 } |
| 90 | 90 |
| 91 void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); | 91 void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); |
| 92 | 92 |
| 93 void DoesNotDownscaleFrameDimensions(int width, int height); | 93 void DoesNotDownscaleFrameDimensions(int width, int height); |
| 94 | 94 |
| 95 void DownscaleEndsAt(int input_width, | 95 void DownscaleEndsAt(int input_width, |
| 96 int input_height, | 96 int input_height, |
| 97 int end_width, | 97 int end_width, |
| 98 int end_height); | 98 int end_height); |
| 99 | 99 |
| 100 QualityScaler qs_; | 100 QualityScaler qs_; |
| 101 VideoFrame input_frame_; | 101 rtc::scoped_refptr<VideoFrameBuffer> input_frame_; |
| 102 }; | 102 }; |
| 103 | 103 |
| 104 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { | 104 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { |
| 105 ExpectOriginalFrame(); | 105 ExpectOriginalFrame(); |
| 106 } | 106 } |
| 107 | 107 |
| 108 TEST_F(QualityScalerTest, ReportsOriginalResolutionInitially) { | 108 TEST_F(QualityScalerTest, ReportsOriginalResolutionInitially) { |
| 109 qs_.OnEncodeFrame(input_frame_); | 109 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 110 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 110 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 111 EXPECT_EQ(input_frame_.width(), res.width); | 111 EXPECT_EQ(input_frame_->width(), res.width); |
| 112 EXPECT_EQ(input_frame_.height(), res.height); | 112 EXPECT_EQ(input_frame_->height(), res.height); |
| 113 } | 113 } |
| 114 | 114 |
| 115 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { | 115 TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) { |
| 116 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds | 116 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds |
| 117 << " seconds."; | 117 << " seconds."; |
| 118 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 118 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 119 EXPECT_LT(res.width, input_frame_.width()); | 119 EXPECT_LT(res.width, input_frame_->width()); |
| 120 EXPECT_LT(res.height, input_frame_.height()); | 120 EXPECT_LT(res.height, input_frame_->height()); |
| 121 } | 121 } |
| 122 | 122 |
| 123 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) { | 123 TEST_F(QualityScalerTest, KeepsScaleAtHighQp) { |
| 124 EXPECT_FALSE(TriggerScale(kKeepScaleAtHighQp)) | 124 EXPECT_FALSE(TriggerScale(kKeepScaleAtHighQp)) |
| 125 << "Downscale at high threshold which should keep scale."; | 125 << "Downscale at high threshold which should keep scale."; |
| 126 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 126 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 127 EXPECT_EQ(res.width, input_frame_.width()); | 127 EXPECT_EQ(res.width, input_frame_->width()); |
| 128 EXPECT_EQ(res.height, input_frame_.height()); | 128 EXPECT_EQ(res.height, input_frame_->height()); |
| 129 } | 129 } |
| 130 | 130 |
| 131 TEST_F(QualityScalerTest, DownscalesAboveHighQp) { | 131 TEST_F(QualityScalerTest, DownscalesAboveHighQp) { |
| 132 EXPECT_TRUE(TriggerScale(kScaleDownAboveHighQp)) | 132 EXPECT_TRUE(TriggerScale(kScaleDownAboveHighQp)) |
| 133 << "No downscale within " << kNumSeconds << " seconds."; | 133 << "No downscale within " << kNumSeconds << " seconds."; |
| 134 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 134 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 135 EXPECT_LT(res.width, input_frame_.width()); | 135 EXPECT_LT(res.width, input_frame_->width()); |
| 136 EXPECT_LT(res.height, input_frame_.height()); | 136 EXPECT_LT(res.height, input_frame_->height()); |
| 137 } | 137 } |
| 138 | 138 |
| 139 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { | 139 TEST_F(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) { |
| 140 for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { | 140 for (int i = 0; i < kFramerate * kNumSeconds / 3; ++i) { |
| 141 qs_.ReportQP(kNormalQp); | 141 qs_.ReportQP(kNormalQp); |
| 142 qs_.ReportDroppedFrame(); | 142 qs_.ReportDroppedFrame(); |
| 143 qs_.ReportDroppedFrame(); | 143 qs_.ReportDroppedFrame(); |
| 144 qs_.OnEncodeFrame(input_frame_); | 144 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 145 if (qs_.GetScaledResolution().width < input_frame_.width()) | 145 if (qs_.GetScaledResolution().width < input_frame_->width()) |
| 146 return; | 146 return; |
| 147 } | 147 } |
| 148 | 148 |
| 149 FAIL() << "No downscale within " << kNumSeconds << " seconds."; | 149 FAIL() << "No downscale within " << kNumSeconds << " seconds."; |
| 150 } | 150 } |
| 151 | 151 |
| 152 TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) { | 152 TEST_F(QualityScalerTest, DoesNotDownscaleOnNormalQp) { |
| 153 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 153 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
| 154 qs_.ReportQP(kNormalQp); | 154 qs_.ReportQP(kNormalQp); |
| 155 qs_.OnEncodeFrame(input_frame_); | 155 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 156 ASSERT_EQ(input_frame_.width(), qs_.GetScaledResolution().width) | 156 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) |
| 157 << "Unexpected scale on half framedrop."; | 157 << "Unexpected scale on half framedrop."; |
| 158 } | 158 } |
| 159 } | 159 } |
| 160 | 160 |
| 161 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) { | 161 TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) { |
| 162 for (int i = 0; i < kFramerate * kNumSeconds / 2; ++i) { | 162 for (int i = 0; i < kFramerate * kNumSeconds / 2; ++i) { |
| 163 qs_.ReportQP(kNormalQp); | 163 qs_.ReportQP(kNormalQp); |
| 164 qs_.OnEncodeFrame(input_frame_); | 164 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 165 ASSERT_EQ(input_frame_.width(), qs_.GetScaledResolution().width) | 165 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) |
| 166 << "Unexpected scale on half framedrop."; | 166 << "Unexpected scale on half framedrop."; |
| 167 | 167 |
| 168 qs_.ReportDroppedFrame(); | 168 qs_.ReportDroppedFrame(); |
| 169 qs_.OnEncodeFrame(input_frame_); | 169 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 170 ASSERT_EQ(input_frame_.width(), qs_.GetScaledResolution().width) | 170 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) |
| 171 << "Unexpected scale on half framedrop."; | 171 << "Unexpected scale on half framedrop."; |
| 172 } | 172 } |
| 173 } | 173 } |
| 174 | 174 |
| 175 void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() { | 175 void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() { |
| 176 const int initial_min_dimension = input_frame_.width() < input_frame_.height() | 176 const int initial_min_dimension = |
| 177 ? input_frame_.width() | 177 input_frame_->width() < input_frame_->height() ? input_frame_->width() |
| 178 : input_frame_.height(); | 178 : input_frame_->height(); |
| 179 int min_dimension = initial_min_dimension; | 179 int min_dimension = initial_min_dimension; |
| 180 int current_shift = 0; | 180 int current_shift = 0; |
| 181 // Drop all frames to force-trigger downscaling. | 181 // Drop all frames to force-trigger downscaling. |
| 182 while (min_dimension >= 2 * kMinDownscaleDimension) { | 182 while (min_dimension >= 2 * kMinDownscaleDimension) { |
| 183 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " | 183 EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " |
| 184 << kNumSeconds << " seconds."; | 184 << kNumSeconds << " seconds."; |
| 185 qs_.OnEncodeFrame(input_frame_); | 185 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 186 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 186 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 187 min_dimension = res.width < res.height ? res.width : res.height; | 187 min_dimension = res.width < res.height ? res.width : res.height; |
| 188 ++current_shift; | 188 ++current_shift; |
| 189 ASSERT_EQ(input_frame_.width() >> current_shift, res.width); | 189 ASSERT_EQ(input_frame_->width() >> current_shift, res.width); |
| 190 ASSERT_EQ(input_frame_.height() >> current_shift, res.height); | 190 ASSERT_EQ(input_frame_->height() >> current_shift, res.height); |
| 191 ExpectScaleUsingReportedResolution(); | 191 ExpectScaleUsingReportedResolution(); |
| 192 } | 192 } |
| 193 | 193 |
| 194 // Make sure we can scale back with good-quality frames. | 194 // Make sure we can scale back with good-quality frames. |
| 195 while (min_dimension < initial_min_dimension) { | 195 while (min_dimension < initial_min_dimension) { |
| 196 EXPECT_TRUE(TriggerScale(kScaleUp)) << "No upscale within " << kNumSeconds | 196 EXPECT_TRUE(TriggerScale(kScaleUp)) << "No upscale within " << kNumSeconds |
| 197 << " seconds."; | 197 << " seconds."; |
| 198 qs_.OnEncodeFrame(input_frame_); | 198 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 199 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 199 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 200 min_dimension = res.width < res.height ? res.width : res.height; | 200 min_dimension = res.width < res.height ? res.width : res.height; |
| 201 --current_shift; | 201 --current_shift; |
| 202 ASSERT_EQ(input_frame_.width() >> current_shift, res.width); | 202 ASSERT_EQ(input_frame_->width() >> current_shift, res.width); |
| 203 ASSERT_EQ(input_frame_.height() >> current_shift, res.height); | 203 ASSERT_EQ(input_frame_->height() >> current_shift, res.height); |
| 204 ExpectScaleUsingReportedResolution(); | 204 ExpectScaleUsingReportedResolution(); |
| 205 } | 205 } |
| 206 | 206 |
| 207 // Verify we don't start upscaling after further low use. | 207 // Verify we don't start upscaling after further low use. |
| 208 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 208 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
| 209 qs_.ReportQP(kLowQp); | 209 qs_.ReportQP(kLowQp); |
| 210 ExpectOriginalFrame(); | 210 ExpectOriginalFrame(); |
| 211 } | 211 } |
| 212 } | 212 } |
| 213 | 213 |
| 214 TEST_F(QualityScalerTest, ContinuouslyDownscalesByHalfDimensionsAndBackUp) { | 214 TEST_F(QualityScalerTest, ContinuouslyDownscalesByHalfDimensionsAndBackUp) { |
| 215 ContinuouslyDownscalesByHalfDimensionsAndBackUp(); | 215 ContinuouslyDownscalesByHalfDimensionsAndBackUp(); |
| 216 } | 216 } |
| 217 | 217 |
| 218 TEST_F(QualityScalerTest, | 218 TEST_F(QualityScalerTest, |
| 219 ContinuouslyDownscalesOddResolutionsByHalfDimensionsAndBackUp) { | 219 ContinuouslyDownscalesOddResolutionsByHalfDimensionsAndBackUp) { |
| 220 const int kOddWidth = 517; | 220 const int kOddWidth = 517; |
| 221 const int kHalfOddWidth = (kOddWidth + 1) / 2; | |
| 222 const int kOddHeight = 1239; | 221 const int kOddHeight = 1239; |
| 223 input_frame_.CreateEmptyFrame(kOddWidth, kOddHeight, kOddWidth, kHalfOddWidth, | 222 input_frame_ = rtc::scoped_refptr<VideoFrameBuffer>( |
| 224 kHalfOddWidth); | 223 new rtc::RefCountedObject<I420Buffer>(kOddWidth, kOddHeight)); |
| 225 ContinuouslyDownscalesByHalfDimensionsAndBackUp(); | 224 ContinuouslyDownscalesByHalfDimensionsAndBackUp(); |
| 226 } | 225 } |
| 227 | 226 |
| 228 void QualityScalerTest::DoesNotDownscaleFrameDimensions(int width, int height) { | 227 void QualityScalerTest::DoesNotDownscaleFrameDimensions(int width, int height) { |
| 229 input_frame_.CreateEmptyFrame(width, height, width, (width + 1) / 2, | 228 input_frame_ = rtc::scoped_refptr<VideoFrameBuffer>( |
| 230 (width + 1) / 2); | 229 new rtc::RefCountedObject<I420Buffer>(width, height)); |
| 231 | 230 |
| 232 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 231 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
| 233 qs_.ReportDroppedFrame(); | 232 qs_.ReportDroppedFrame(); |
| 234 qs_.OnEncodeFrame(input_frame_); | 233 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 235 ASSERT_EQ(input_frame_.width(), qs_.GetScaledResolution().width) | 234 ASSERT_EQ(input_frame_->width(), qs_.GetScaledResolution().width) |
| 236 << "Unexpected scale of minimal-size frame."; | 235 << "Unexpected scale of minimal-size frame."; |
| 237 } | 236 } |
| 238 } | 237 } |
| 239 | 238 |
| 240 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxWidth) { | 239 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxWidth) { |
| 241 DoesNotDownscaleFrameDimensions(1, kHeight); | 240 DoesNotDownscaleFrameDimensions(1, kHeight); |
| 242 } | 241 } |
| 243 | 242 |
| 244 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) { | 243 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) { |
| 245 DoesNotDownscaleFrameDimensions(kWidth, 1); | 244 DoesNotDownscaleFrameDimensions(kWidth, 1); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 256 | 255 |
| 257 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { | 256 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { |
| 258 DoesNotDownscaleFrameDimensions( | 257 DoesNotDownscaleFrameDimensions( |
| 259 1000, 2 * kMinDownscaleDimension - 1); | 258 1000, 2 * kMinDownscaleDimension - 1); |
| 260 } | 259 } |
| 261 | 260 |
| 262 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { | 261 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { |
| 263 static const int kWidth720p = 1280; | 262 static const int kWidth720p = 1280; |
| 264 static const int kHeight720p = 720; | 263 static const int kHeight720p = 720; |
| 265 static const int kInitialBitrateKbps = 300; | 264 static const int kInitialBitrateKbps = 300; |
| 266 input_frame_.CreateEmptyFrame(kWidth720p, kHeight720p, kWidth720p, | 265 input_frame_ = rtc::scoped_refptr<VideoFrameBuffer>( |
| 267 kWidth720p / 2, kWidth720p / 2); | 266 new rtc::RefCountedObject<I420Buffer>(kWidth720p, kHeight720p)); |
| 268 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, | 267 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, |
| 269 kWidth720p, kHeight720p, kFramerate); | 268 kWidth720p, kHeight720p, kFramerate); |
| 270 qs_.OnEncodeFrame(input_frame_); | 269 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 271 int init_width = qs_.GetScaledResolution().width; | 270 int init_width = qs_.GetScaledResolution().width; |
| 272 int init_height = qs_.GetScaledResolution().height; | 271 int init_height = qs_.GetScaledResolution().height; |
| 273 EXPECT_EQ(640, init_width); | 272 EXPECT_EQ(640, init_width); |
| 274 EXPECT_EQ(360, init_height); | 273 EXPECT_EQ(360, init_height); |
| 275 } | 274 } |
| 276 | 275 |
| 277 TEST_F(QualityScalerTest, DownscaleToQvgaOnLowerInitialBitrate) { | 276 TEST_F(QualityScalerTest, DownscaleToQvgaOnLowerInitialBitrate) { |
| 278 static const int kWidth720p = 1280; | 277 static const int kWidth720p = 1280; |
| 279 static const int kHeight720p = 720; | 278 static const int kHeight720p = 720; |
| 280 static const int kInitialBitrateKbps = 200; | 279 static const int kInitialBitrateKbps = 200; |
| 281 input_frame_.CreateEmptyFrame(kWidth720p, kHeight720p, kWidth720p, | 280 input_frame_ = rtc::scoped_refptr<VideoFrameBuffer>( |
| 282 kWidth720p / 2, kWidth720p / 2); | 281 new rtc::RefCountedObject<I420Buffer>(kWidth720p, kHeight720p)); |
| 283 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, | 282 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, |
| 284 kWidth720p, kHeight720p, kFramerate); | 283 kWidth720p, kHeight720p, kFramerate); |
| 285 qs_.OnEncodeFrame(input_frame_); | 284 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 286 int init_width = qs_.GetScaledResolution().width; | 285 int init_width = qs_.GetScaledResolution().width; |
| 287 int init_height = qs_.GetScaledResolution().height; | 286 int init_height = qs_.GetScaledResolution().height; |
| 288 EXPECT_EQ(320, init_width); | 287 EXPECT_EQ(320, init_width); |
| 289 EXPECT_EQ(180, init_height); | 288 EXPECT_EQ(180, init_height); |
| 290 } | 289 } |
| 291 | 290 |
| 292 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { | 291 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { |
| 293 qs_.Init(kLowQpThreshold, kHighQp, 0, kWidth, kHeight, kFramerate); | 292 qs_.Init(kLowQpThreshold, kHighQp, 0, kWidth, kHeight, kFramerate); |
| 294 qs_.OnEncodeFrame(input_frame_); | 293 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 295 QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); | 294 QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); |
| 296 | 295 |
| 297 // Should not downscale if less than kMeasureSecondsDownscale seconds passed. | 296 // Should not downscale if less than kMeasureSecondsDownscale seconds passed. |
| 298 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { | 297 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { |
| 299 qs_.ReportQP(kHighQp + 1); | 298 qs_.ReportQP(kHighQp + 1); |
| 300 qs_.OnEncodeFrame(input_frame_); | 299 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 301 } | 300 } |
| 302 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 301 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
| 303 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); | 302 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
| 304 | 303 |
| 305 // Should downscale if more than kMeasureSecondsDownscale seconds passed (add | 304 // Should downscale if more than kMeasureSecondsDownscale seconds passed (add |
| 306 // last frame). | 305 // last frame). |
| 307 qs_.ReportQP(kHighQp + 1); | 306 qs_.ReportQP(kHighQp + 1); |
| 308 qs_.OnEncodeFrame(input_frame_); | 307 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 309 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); | 308 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); |
| 310 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); | 309 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); |
| 311 | 310 |
| 312 // Should not upscale if less than kMeasureSecondsUpscale seconds passed since | 311 // Should not upscale if less than kMeasureSecondsUpscale seconds passed since |
| 313 // we saw issues initially (have already gone down). | 312 // we saw issues initially (have already gone down). |
| 314 for (int i = 0; i < kFramerate * kMeasureSecondsUpscale - 1; ++i) { | 313 for (int i = 0; i < kFramerate * kMeasureSecondsUpscale - 1; ++i) { |
| 315 qs_.ReportQP(kLowQp); | 314 qs_.ReportQP(kLowQp); |
| 316 qs_.OnEncodeFrame(input_frame_); | 315 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 317 } | 316 } |
| 318 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); | 317 EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); |
| 319 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); | 318 EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); |
| 320 | 319 |
| 321 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed | 320 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed |
| 322 // (add last frame). | 321 // (add last frame). |
| 323 qs_.ReportQP(kLowQp); | 322 qs_.ReportQP(kLowQp); |
| 324 qs_.OnEncodeFrame(input_frame_); | 323 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 325 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 324 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
| 326 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); | 325 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
| 327 } | 326 } |
| 328 | 327 |
| 329 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { | 328 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { |
| 330 qs_.Init(kLowQpThreshold, kHighQp, kLowInitialBitrateKbps, kWidth, kHeight, | 329 qs_.Init(kLowQpThreshold, kHighQp, kLowInitialBitrateKbps, kWidth, kHeight, |
| 331 kFramerate); | 330 kFramerate); |
| 332 qs_.OnEncodeFrame(input_frame_); | 331 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 333 QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); | 332 QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); |
| 334 | 333 |
| 335 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. | 334 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. |
| 336 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { | 335 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { |
| 337 qs_.ReportQP(kLowQp); | 336 qs_.ReportQP(kLowQp); |
| 338 qs_.OnEncodeFrame(input_frame_); | 337 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 339 } | 338 } |
| 340 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 339 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
| 341 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); | 340 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
| 342 | 341 |
| 343 // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last | 342 // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last |
| 344 // frame). | 343 // frame). |
| 345 qs_.ReportQP(kLowQp); | 344 qs_.ReportQP(kLowQp); |
| 346 qs_.OnEncodeFrame(input_frame_); | 345 qs_.OnEncodeFrame(input_frame_->width(), input_frame_->height()); |
| 347 EXPECT_LT(initial_res.width, qs_.GetScaledResolution().width); | 346 EXPECT_LT(initial_res.width, qs_.GetScaledResolution().width); |
| 348 EXPECT_LT(initial_res.height, qs_.GetScaledResolution().height); | 347 EXPECT_LT(initial_res.height, qs_.GetScaledResolution().height); |
| 349 } | 348 } |
| 350 | 349 |
| 351 void QualityScalerTest::DownscaleEndsAt(int input_width, | 350 void QualityScalerTest::DownscaleEndsAt(int input_width, |
| 352 int input_height, | 351 int input_height, |
| 353 int end_width, | 352 int end_width, |
| 354 int end_height) { | 353 int end_height) { |
| 355 // Create a frame with 2x expected end width/height to verify that we can | 354 // Create a frame with 2x expected end width/height to verify that we can |
| 356 // scale down to expected end width/height. | 355 // scale down to expected end width/height. |
| 357 input_frame_.CreateEmptyFrame(input_width, input_height, input_width, | 356 input_frame_ = rtc::scoped_refptr<VideoFrameBuffer>( |
| 358 (input_width + 1) / 2, (input_width + 1) / 2); | 357 new rtc::RefCountedObject<I420Buffer>(input_width, input_height)); |
| 359 | 358 |
| 360 int last_width = input_width; | 359 int last_width = input_width; |
| 361 int last_height = input_height; | 360 int last_height = input_height; |
| 362 // Drop all frames to force-trigger downscaling. | 361 // Drop all frames to force-trigger downscaling. |
| 363 while (true) { | 362 while (true) { |
| 364 TriggerScale(kScaleDown); | 363 TriggerScale(kScaleDown); |
| 365 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 364 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 366 if (last_width == res.width) { | 365 if (last_width == res.width) { |
| 367 EXPECT_EQ(last_height, res.height); | 366 EXPECT_EQ(last_height, res.height); |
| 368 EXPECT_EQ(end_width, res.width); | 367 EXPECT_EQ(end_width, res.width); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 384 | 383 |
| 385 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) { | 384 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) { |
| 386 DownscaleEndsAt(1280, 720, 320, 180); | 385 DownscaleEndsAt(1280, 720, 320, 180); |
| 387 } | 386 } |
| 388 | 387 |
| 389 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) { | 388 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) { |
| 390 DownscaleEndsAt(320, 180, 320, 180); | 389 DownscaleEndsAt(320, 180, 320, 180); |
| 391 } | 390 } |
| 392 | 391 |
| 393 } // namespace webrtc | 392 } // namespace webrtc |
| OLD | NEW |