| 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 16 matching lines...) Expand all Loading... |
| 27 static const int kLowInitialBitrateKbps = 300; | 27 static const int kLowInitialBitrateKbps = 300; |
| 28 // These values need to be in sync with corresponding constants | 28 // These values need to be in sync with corresponding constants |
| 29 // in quality_scaler.cc | 29 // in quality_scaler.cc |
| 30 static const int kMeasureSecondsFastUpscale = 2; | 30 static const int kMeasureSecondsFastUpscale = 2; |
| 31 static const int kMeasureSecondsUpscale = 5; | 31 static const int kMeasureSecondsUpscale = 5; |
| 32 static const int kMeasureSecondsDownscale = 5; | 32 static const int kMeasureSecondsDownscale = 5; |
| 33 static const int kMinDownscaleDimension = 140; | 33 static const int kMinDownscaleDimension = 140; |
| 34 } // namespace | 34 } // namespace |
| 35 | 35 |
| 36 class QualityScalerTest : public ::testing::Test { | 36 class QualityScalerTest : public ::testing::Test { |
| 37 public: | |
| 38 // Temporal and spatial resolution. | |
| 39 struct Resolution { | |
| 40 int framerate; | |
| 41 int width; | |
| 42 int height; | |
| 43 }; | |
| 44 | |
| 45 protected: | 37 protected: |
| 46 enum ScaleDirection { | 38 enum ScaleDirection { |
| 47 kKeepScaleAtHighQp, | 39 kKeepScaleAtHighQp, |
| 48 kScaleDown, | 40 kScaleDown, |
| 49 kScaleDownAboveHighQp, | 41 kScaleDownAboveHighQp, |
| 50 kScaleUp | 42 kScaleUp |
| 51 }; | 43 }; |
| 52 enum BadQualityMetric { kDropFrame, kReportLowQP }; | |
| 53 | 44 |
| 54 QualityScalerTest() { | 45 QualityScalerTest() { |
| 55 input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth, | 46 input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth, |
| 56 kHalfWidth); | 47 kHalfWidth); |
| 57 qs_.Init(kLowQpThreshold, kHighQp, false, 0, 0, 0, kFramerate); | 48 qs_.Init(kLowQpThreshold, kHighQp, 0, 0, 0, kFramerate); |
| 58 qs_.OnEncodeFrame(input_frame_); | 49 qs_.OnEncodeFrame(input_frame_); |
| 59 } | 50 } |
| 60 | 51 |
| 61 bool TriggerScale(ScaleDirection scale_direction) { | 52 bool TriggerScale(ScaleDirection scale_direction) { |
| 62 qs_.OnEncodeFrame(input_frame_); | 53 qs_.OnEncodeFrame(input_frame_); |
| 63 int initial_width = qs_.GetScaledResolution().width; | 54 int initial_width = qs_.GetScaledResolution().width; |
| 64 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { | 55 for (int i = 0; i < kFramerate * kNumSeconds; ++i) { |
| 65 switch (scale_direction) { | 56 switch (scale_direction) { |
| 66 case kScaleUp: | 57 case kScaleUp: |
| 67 qs_.ReportQP(kLowQp); | 58 qs_.ReportQP(kLowQp); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 94 QualityScaler::Resolution res = qs_.GetScaledResolution(); | 85 QualityScaler::Resolution res = qs_.GetScaledResolution(); |
| 95 const VideoFrame& scaled_frame = qs_.GetScaledFrame(input_frame_); | 86 const VideoFrame& scaled_frame = qs_.GetScaledFrame(input_frame_); |
| 96 EXPECT_EQ(res.width, scaled_frame.width()); | 87 EXPECT_EQ(res.width, scaled_frame.width()); |
| 97 EXPECT_EQ(res.height, scaled_frame.height()); | 88 EXPECT_EQ(res.height, scaled_frame.height()); |
| 98 } | 89 } |
| 99 | 90 |
| 100 void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); | 91 void ContinuouslyDownscalesByHalfDimensionsAndBackUp(); |
| 101 | 92 |
| 102 void DoesNotDownscaleFrameDimensions(int width, int height); | 93 void DoesNotDownscaleFrameDimensions(int width, int height); |
| 103 | 94 |
| 104 Resolution TriggerResolutionChange(BadQualityMetric dropframe_lowqp, | |
| 105 int num_second, | |
| 106 int initial_framerate); | |
| 107 | |
| 108 void VerifyQualityAdaptation(int initial_framerate, | |
| 109 int seconds_downscale, | |
| 110 int seconds_upscale, | |
| 111 bool expect_spatial_resize, | |
| 112 bool expect_framerate_reduction); | |
| 113 | |
| 114 void DownscaleEndsAt(int input_width, | 95 void DownscaleEndsAt(int input_width, |
| 115 int input_height, | 96 int input_height, |
| 116 int end_width, | 97 int end_width, |
| 117 int end_height); | 98 int end_height); |
| 118 | 99 |
| 119 QualityScaler qs_; | 100 QualityScaler qs_; |
| 120 VideoFrame input_frame_; | 101 VideoFrame input_frame_; |
| 121 }; | 102 }; |
| 122 | 103 |
| 123 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { | 104 TEST_F(QualityScalerTest, UsesOriginalFrameInitially) { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 } | 242 } |
| 262 | 243 |
| 263 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) { | 244 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1PxHeight) { |
| 264 DoesNotDownscaleFrameDimensions(kWidth, 1); | 245 DoesNotDownscaleFrameDimensions(kWidth, 1); |
| 265 } | 246 } |
| 266 | 247 |
| 267 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) { | 248 TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) { |
| 268 DoesNotDownscaleFrameDimensions(1, 1); | 249 DoesNotDownscaleFrameDimensions(1, 1); |
| 269 } | 250 } |
| 270 | 251 |
| 271 QualityScalerTest::Resolution QualityScalerTest::TriggerResolutionChange( | |
| 272 BadQualityMetric dropframe_lowqp, | |
| 273 int num_second, | |
| 274 int initial_framerate) { | |
| 275 QualityScalerTest::Resolution res; | |
| 276 res.framerate = initial_framerate; | |
| 277 qs_.OnEncodeFrame(input_frame_); | |
| 278 res.width = qs_.GetScaledResolution().width; | |
| 279 res.height = qs_.GetScaledResolution().height; | |
| 280 for (int i = 0; i < kFramerate * num_second; ++i) { | |
| 281 switch (dropframe_lowqp) { | |
| 282 case kReportLowQP: | |
| 283 qs_.ReportQP(kLowQp); | |
| 284 break; | |
| 285 case kDropFrame: | |
| 286 qs_.ReportDroppedFrame(); | |
| 287 break; | |
| 288 } | |
| 289 qs_.OnEncodeFrame(input_frame_); | |
| 290 // Simulate the case when SetRates is called right after reducing | |
| 291 // framerate. | |
| 292 qs_.ReportFramerate(initial_framerate); | |
| 293 res.framerate = qs_.GetTargetFramerate(); | |
| 294 if (res.framerate != -1) | |
| 295 qs_.ReportFramerate(res.framerate); | |
| 296 res.width = qs_.GetScaledResolution().width; | |
| 297 res.height = qs_.GetScaledResolution().height; | |
| 298 } | |
| 299 return res; | |
| 300 } | |
| 301 | |
| 302 void QualityScalerTest::VerifyQualityAdaptation( | |
| 303 int initial_framerate, | |
| 304 int seconds_downscale, | |
| 305 int seconds_upscale, | |
| 306 bool expect_spatial_resize, | |
| 307 bool expect_framerate_reduction) { | |
| 308 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, true, 0, 0, 0, | |
| 309 initial_framerate); | |
| 310 qs_.OnEncodeFrame(input_frame_); | |
| 311 int init_width = qs_.GetScaledResolution().width; | |
| 312 int init_height = qs_.GetScaledResolution().height; | |
| 313 | |
| 314 // Test reducing framerate by dropping frame continuously. | |
| 315 QualityScalerTest::Resolution res = | |
| 316 TriggerResolutionChange(kDropFrame, seconds_downscale, initial_framerate); | |
| 317 | |
| 318 if (expect_framerate_reduction) { | |
| 319 EXPECT_LT(res.framerate, initial_framerate); | |
| 320 } else { | |
| 321 // No framerate reduction, video decimator should be disabled. | |
| 322 EXPECT_EQ(-1, res.framerate); | |
| 323 } | |
| 324 | |
| 325 if (expect_spatial_resize) { | |
| 326 EXPECT_LT(res.width, init_width); | |
| 327 EXPECT_LT(res.height, init_height); | |
| 328 } else { | |
| 329 EXPECT_EQ(init_width, res.width); | |
| 330 EXPECT_EQ(init_height, res.height); | |
| 331 } | |
| 332 | |
| 333 // The "seconds * 1.5" is to ensure spatial resolution to recover. | |
| 334 // For example, in 6 seconds test, framerate reduction happens in the first | |
| 335 // 3 seconds from 30fps to 15fps and causes the buffer size to be half of the | |
| 336 // original one. Then it will take only 45 samples to downscale (twice in 90 | |
| 337 // samples). So to recover the resolution changes, we need more than 10 | |
| 338 // seconds (i.e, seconds_upscale * 1.5). This is because the framerate | |
| 339 // increases before spatial size recovers, so it will take 150 samples to | |
| 340 // recover spatial size (300 for twice). | |
| 341 res = TriggerResolutionChange(kReportLowQP, seconds_upscale * 1.5, | |
| 342 initial_framerate); | |
| 343 EXPECT_EQ(-1, res.framerate); | |
| 344 EXPECT_EQ(init_width, res.width); | |
| 345 EXPECT_EQ(init_height, res.height); | |
| 346 } | |
| 347 | |
| 348 // In 3 seconds test, only framerate adjusting should happen and 5 second | |
| 349 // upscaling duration, only a framerate adjusting should happen. | |
| 350 TEST_F(QualityScalerTest, ChangeFramerateOnly) { | |
| 351 VerifyQualityAdaptation(kFramerate, kMeasureSecondsDownscale, | |
| 352 kMeasureSecondsUpscale, false, true); | |
| 353 } | |
| 354 | |
| 355 // In 6 seconds test, framerate adjusting and scaling are both | |
| 356 // triggered, it shows that scaling would happen after framerate | |
| 357 // adjusting. | |
| 358 TEST_F(QualityScalerTest, ChangeFramerateAndSpatialSize) { | |
| 359 VerifyQualityAdaptation(kFramerate, kMeasureSecondsDownscale * 2, | |
| 360 kMeasureSecondsUpscale * 2, true, true); | |
| 361 } | |
| 362 | |
| 363 // When starting from a low framerate, only spatial size will be changed. | |
| 364 TEST_F(QualityScalerTest, ChangeSpatialSizeOnly) { | |
| 365 qs_.ReportFramerate(kFramerate >> 1); | |
| 366 VerifyQualityAdaptation(kFramerate >> 1, kMeasureSecondsDownscale * 2, | |
| 367 kMeasureSecondsUpscale * 2, true, false); | |
| 368 } | |
| 369 | |
| 370 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) { | 252 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) { |
| 371 DoesNotDownscaleFrameDimensions( | 253 DoesNotDownscaleFrameDimensions( |
| 372 2 * kMinDownscaleDimension - 1, 1000); | 254 2 * kMinDownscaleDimension - 1, 1000); |
| 373 } | 255 } |
| 374 | 256 |
| 375 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { | 257 TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { |
| 376 DoesNotDownscaleFrameDimensions( | 258 DoesNotDownscaleFrameDimensions( |
| 377 1000, 2 * kMinDownscaleDimension - 1); | 259 1000, 2 * kMinDownscaleDimension - 1); |
| 378 } | 260 } |
| 379 | 261 |
| 380 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { | 262 TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { |
| 381 static const int kWidth720p = 1280; | 263 static const int kWidth720p = 1280; |
| 382 static const int kHeight720p = 720; | 264 static const int kHeight720p = 720; |
| 383 static const int kInitialBitrateKbps = 300; | 265 static const int kInitialBitrateKbps = 300; |
| 384 input_frame_.CreateEmptyFrame(kWidth720p, kHeight720p, kWidth720p, | 266 input_frame_.CreateEmptyFrame(kWidth720p, kHeight720p, kWidth720p, |
| 385 kWidth720p / 2, kWidth720p / 2); | 267 kWidth720p / 2, kWidth720p / 2); |
| 386 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, true, kInitialBitrateKbps, | 268 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, |
| 387 kWidth720p, kHeight720p, kFramerate); | 269 kWidth720p, kHeight720p, kFramerate); |
| 388 qs_.OnEncodeFrame(input_frame_); | 270 qs_.OnEncodeFrame(input_frame_); |
| 389 int init_width = qs_.GetScaledResolution().width; | 271 int init_width = qs_.GetScaledResolution().width; |
| 390 int init_height = qs_.GetScaledResolution().height; | 272 int init_height = qs_.GetScaledResolution().height; |
| 391 EXPECT_EQ(640, init_width); | 273 EXPECT_EQ(640, init_width); |
| 392 EXPECT_EQ(360, init_height); | 274 EXPECT_EQ(360, init_height); |
| 393 } | 275 } |
| 394 | 276 |
| 395 TEST_F(QualityScalerTest, DownscaleToQvgaOnLowerInitialBitrate) { | 277 TEST_F(QualityScalerTest, DownscaleToQvgaOnLowerInitialBitrate) { |
| 396 static const int kWidth720p = 1280; | 278 static const int kWidth720p = 1280; |
| 397 static const int kHeight720p = 720; | 279 static const int kHeight720p = 720; |
| 398 static const int kInitialBitrateKbps = 200; | 280 static const int kInitialBitrateKbps = 200; |
| 399 input_frame_.CreateEmptyFrame(kWidth720p, kHeight720p, kWidth720p, | 281 input_frame_.CreateEmptyFrame(kWidth720p, kHeight720p, kWidth720p, |
| 400 kWidth720p / 2, kWidth720p / 2); | 282 kWidth720p / 2, kWidth720p / 2); |
| 401 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, true, kInitialBitrateKbps, | 283 qs_.Init(kLowQpThreshold, kDisabledBadQpThreshold, kInitialBitrateKbps, |
| 402 kWidth720p, kHeight720p, kFramerate); | 284 kWidth720p, kHeight720p, kFramerate); |
| 403 qs_.OnEncodeFrame(input_frame_); | 285 qs_.OnEncodeFrame(input_frame_); |
| 404 int init_width = qs_.GetScaledResolution().width; | 286 int init_width = qs_.GetScaledResolution().width; |
| 405 int init_height = qs_.GetScaledResolution().height; | 287 int init_height = qs_.GetScaledResolution().height; |
| 406 EXPECT_EQ(320, init_width); | 288 EXPECT_EQ(320, init_width); |
| 407 EXPECT_EQ(180, init_height); | 289 EXPECT_EQ(180, init_height); |
| 408 } | 290 } |
| 409 | 291 |
| 410 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { | 292 TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { |
| 411 QualityScalerTest::Resolution initial_res; | 293 qs_.Init(kLowQpThreshold, kHighQp, 0, kWidth, kHeight, kFramerate); |
| 412 qs_.Init(kLowQpThreshold, kHighQp, false, 0, kWidth, kHeight, kFramerate); | |
| 413 qs_.OnEncodeFrame(input_frame_); | 294 qs_.OnEncodeFrame(input_frame_); |
| 414 initial_res.width = qs_.GetScaledResolution().width; | 295 QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); |
| 415 initial_res.height = qs_.GetScaledResolution().height; | |
| 416 | 296 |
| 417 // Should not downscale if less than kMeasureSecondsDownscale seconds passed. | 297 // Should not downscale if less than kMeasureSecondsDownscale seconds passed. |
| 418 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { | 298 for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { |
| 419 qs_.ReportQP(kHighQp + 1); | 299 qs_.ReportQP(kHighQp + 1); |
| 420 qs_.OnEncodeFrame(input_frame_); | 300 qs_.OnEncodeFrame(input_frame_); |
| 421 } | 301 } |
| 422 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 302 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
| 423 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); | 303 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
| 424 | 304 |
| 425 // Should downscale if more than kMeasureSecondsDownscale seconds passed (add | 305 // Should downscale if more than kMeasureSecondsDownscale seconds passed (add |
| (...skipping 14 matching lines...) Expand all Loading... |
| 440 | 320 |
| 441 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed | 321 // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed |
| 442 // (add last frame). | 322 // (add last frame). |
| 443 qs_.ReportQP(kLowQp); | 323 qs_.ReportQP(kLowQp); |
| 444 qs_.OnEncodeFrame(input_frame_); | 324 qs_.OnEncodeFrame(input_frame_); |
| 445 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 325 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
| 446 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); | 326 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
| 447 } | 327 } |
| 448 | 328 |
| 449 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { | 329 TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { |
| 450 QualityScalerTest::Resolution initial_res; | 330 qs_.Init(kLowQpThreshold, kHighQp, kLowInitialBitrateKbps, kWidth, kHeight, |
| 451 qs_.Init(kLowQpThreshold, kHighQp, false, kLowInitialBitrateKbps, kWidth, | 331 kFramerate); |
| 452 kHeight, kFramerate); | |
| 453 qs_.OnEncodeFrame(input_frame_); | 332 qs_.OnEncodeFrame(input_frame_); |
| 454 initial_res.width = qs_.GetScaledResolution().width; | 333 QualityScaler::Resolution initial_res = qs_.GetScaledResolution(); |
| 455 initial_res.height = qs_.GetScaledResolution().height; | |
| 456 | 334 |
| 457 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. | 335 // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. |
| 458 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { | 336 for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { |
| 459 qs_.ReportQP(kLowQp); | 337 qs_.ReportQP(kLowQp); |
| 460 qs_.OnEncodeFrame(input_frame_); | 338 qs_.OnEncodeFrame(input_frame_); |
| 461 } | 339 } |
| 462 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); | 340 EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
| 463 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); | 341 EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
| 464 | 342 |
| 465 // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last | 343 // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 | 384 |
| 507 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) { | 385 TEST_F(QualityScalerTest, DownscalesFrom1280x720To320x180) { |
| 508 DownscaleEndsAt(1280, 720, 320, 180); | 386 DownscaleEndsAt(1280, 720, 320, 180); |
| 509 } | 387 } |
| 510 | 388 |
| 511 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) { | 389 TEST_F(QualityScalerTest, DoesntDownscaleInitialQvga) { |
| 512 DownscaleEndsAt(320, 180, 320, 180); | 390 DownscaleEndsAt(320, 180, 320, 180); |
| 513 } | 391 } |
| 514 | 392 |
| 515 } // namespace webrtc | 393 } // namespace webrtc |
| OLD | NEW |