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 |