Index: webrtc/modules/video_coding/utility/quality_scaler_unittest.cc |
diff --git a/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc b/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc |
index a5e3219f7059e283fe429fe4ea445009502c5323..72e9db405edf74ecc84b065db63d5fe7aade9993 100644 |
--- a/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc |
+++ b/webrtc/modules/video_coding/utility/quality_scaler_unittest.cc |
@@ -27,6 +27,11 @@ static const int kHighQp = 40; |
static const int kMaxQp = 56; |
static const int kDisabledBadQpThreshold = kMaxQp + 1; |
static const int kLowInitialBitrateKbps = 300; |
+// These values need to be in sync with corresponding constants |
+// in quality_scaler.cc |
+static const int kMeasureSecondsDownscale = 3; |
+static const int kMeasureSecondsFastUpscale = 2; |
+static const int kMeasureSecondsUpscale = 5; |
} // namespace |
class QualityScalerTest : public ::testing::Test { |
@@ -51,8 +56,7 @@ class QualityScalerTest : public ::testing::Test { |
input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth, |
kHalfWidth); |
qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, |
- 0, 0, 0); |
- qs_.ReportFramerate(kFramerate); |
+ 0, 0, 0, kFramerate); |
qs_.OnEncodeFrame(input_frame_); |
} |
@@ -104,7 +108,8 @@ class QualityScalerTest : public ::testing::Test { |
int initial_framerate); |
void VerifyQualityAdaptation(int initial_framerate, |
- int seconds, |
+ int seconds_downscale, |
+ int seconds_upscale, |
bool expect_spatial_resize, |
bool expect_framerate_reduction); |
@@ -298,18 +303,19 @@ QualityScalerTest::Resolution QualityScalerTest::TriggerResolutionChange( |
void QualityScalerTest::VerifyQualityAdaptation( |
int initial_framerate, |
- int seconds, |
+ int seconds_downscale, |
+ int seconds_upscale, |
bool expect_spatial_resize, |
bool expect_framerate_reduction) { |
qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, |
- kDisabledBadQpThreshold, true, 0, 0, 0); |
+ kDisabledBadQpThreshold, true, 0, 0, 0, initial_framerate); |
qs_.OnEncodeFrame(input_frame_); |
int init_width = qs_.GetScaledResolution().width; |
int init_height = qs_.GetScaledResolution().height; |
// Test reducing framerate by dropping frame continuously. |
QualityScalerTest::Resolution res = |
- TriggerResolutionChange(kDropFrame, seconds, initial_framerate); |
+ TriggerResolutionChange(kDropFrame, seconds_downscale, initial_framerate); |
if (expect_framerate_reduction) { |
EXPECT_LT(res.framerate, initial_framerate); |
@@ -327,35 +333,40 @@ void QualityScalerTest::VerifyQualityAdaptation( |
} |
// The "seconds * 1.5" is to ensure spatial resolution to recover. |
- // For example, in 10 seconds test, framerate reduction happens in the first |
- // 5 seconds from 30fps to 15fps and causes the buffer size to be half of the |
- // original one. Then it will take only 75 samples to downscale (twice in 150 |
+ // For example, in 6 seconds test, framerate reduction happens in the first |
+ // 3 seconds from 30fps to 15fps and causes the buffer size to be half of the |
+ // original one. Then it will take only 45 samples to downscale (twice in 90 |
// samples). So to recover the resolution changes, we need more than 10 |
- // seconds (i.e, seconds * 1.5). This is because the framerate increases |
- // before spatial size recovers, so it will take 150 samples to recover |
- // spatial size (300 for twice). |
- res = TriggerResolutionChange(kReportLowQP, seconds * 1.5, initial_framerate); |
+ // seconds (i.e, seconds_upscale * 1.5). This is because the framerate |
+ // increases before spatial size recovers, so it will take 150 samples to |
+ // recover spatial size (300 for twice). |
+ res = TriggerResolutionChange(kReportLowQP, seconds_upscale * 1.5, |
+ initial_framerate); |
EXPECT_EQ(-1, res.framerate); |
EXPECT_EQ(init_width, res.width); |
EXPECT_EQ(init_height, res.height); |
} |
-// In 5 seconds test, only framerate adjusting should happen. |
+// In 3 seconds test, only framerate adjusting should happen and 5 second |
+// upscaling duration, only a framerate adjusting should happen. |
TEST_F(QualityScalerTest, ChangeFramerateOnly) { |
- VerifyQualityAdaptation(kFramerate, 5, false, true); |
+ VerifyQualityAdaptation(kFramerate, kMeasureSecondsDownscale, |
+ kMeasureSecondsUpscale, false, true); |
} |
-// In 10 seconds test, framerate adjusting and scaling are both |
+// In 6 seconds test, framerate adjusting and scaling are both |
// triggered, it shows that scaling would happen after framerate |
// adjusting. |
TEST_F(QualityScalerTest, ChangeFramerateAndSpatialSize) { |
- VerifyQualityAdaptation(kFramerate, 10, true, true); |
+ VerifyQualityAdaptation(kFramerate, kMeasureSecondsDownscale * 2, |
+ kMeasureSecondsUpscale * 2, true, true); |
} |
// When starting from a low framerate, only spatial size will be changed. |
TEST_F(QualityScalerTest, ChangeSpatialSizeOnly) { |
qs_.ReportFramerate(kFramerate >> 1); |
- VerifyQualityAdaptation(kFramerate >> 1, 10, true, false); |
+ VerifyQualityAdaptation(kFramerate >> 1, kMeasureSecondsDownscale * 2, |
+ kMeasureSecondsUpscale * 2, true, false); |
} |
TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) { |
@@ -371,7 +382,7 @@ TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) { |
TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { |
qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, |
kDisabledBadQpThreshold, true, |
- kLowInitialBitrateKbps, kWidth, kHeight); |
+ kLowInitialBitrateKbps, kWidth, kHeight, kFramerate); |
qs_.OnEncodeFrame(input_frame_); |
int init_width = qs_.GetScaledResolution().width; |
int init_height = qs_.GetScaledResolution().height; |
@@ -379,6 +390,70 @@ TEST_F(QualityScalerTest, DownscaleToVgaOnLowInitialBitrate) { |
EXPECT_LE(init_height, kHeightVga); |
} |
+TEST_F(QualityScalerTest, DownscaleAfterMeasuredSecondsThenSlowerBackUp) { |
+ QualityScalerTest::Resolution initial_res; |
+ qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, 0, |
+ kWidth, kHeight, kFramerate); |
+ qs_.OnEncodeFrame(input_frame_); |
+ initial_res.width = qs_.GetScaledResolution().width; |
+ initial_res.height = qs_.GetScaledResolution().height; |
+ |
+ // Should not downscale if less than kMeasureSecondsDownscale seconds passed. |
+ for (int i = 0; i < kFramerate * kMeasureSecondsDownscale - 1; ++i) { |
+ qs_.ReportQP(kHighQp + 1); |
+ qs_.OnEncodeFrame(input_frame_); |
+ } |
+ EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
+ EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
+ |
+ // Should downscale if more than kMeasureSecondsDownscale seconds passed (add |
+ // last frame). |
+ qs_.ReportQP(kHighQp + 1); |
+ qs_.OnEncodeFrame(input_frame_); |
+ EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); |
+ EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); |
+ |
+ // Should not upscale if less than kMeasureSecondsUpscale seconds passed since |
+ // we saw issues initially (have already gone down). |
+ for (int i = 0; i < kFramerate * kMeasureSecondsUpscale - 1; ++i) { |
+ qs_.ReportQP(kLowQp); |
+ qs_.OnEncodeFrame(input_frame_); |
+ } |
+ EXPECT_GT(initial_res.width, qs_.GetScaledResolution().width); |
+ EXPECT_GT(initial_res.height, qs_.GetScaledResolution().height); |
+ |
+ // Should upscale (back to initial) if kMeasureSecondsUpscale seconds passed |
+ // (add last frame). |
+ qs_.ReportQP(kLowQp); |
+ qs_.OnEncodeFrame(input_frame_); |
+ EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
+ EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
+} |
+ |
+TEST_F(QualityScalerTest, UpscaleQuicklyInitiallyAfterMeasuredSeconds) { |
+ QualityScalerTest::Resolution initial_res; |
+ qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false, |
+ kLowInitialBitrateKbps, kWidth, kHeight, kFramerate); |
+ qs_.OnEncodeFrame(input_frame_); |
+ initial_res.width = qs_.GetScaledResolution().width; |
+ initial_res.height = qs_.GetScaledResolution().height; |
+ |
+ // Should not upscale if less than kMeasureSecondsFastUpscale seconds passed. |
+ for (int i = 0; i < kFramerate * kMeasureSecondsFastUpscale - 1; ++i) { |
+ qs_.ReportQP(kLowQp); |
+ qs_.OnEncodeFrame(input_frame_); |
+ } |
+ EXPECT_EQ(initial_res.width, qs_.GetScaledResolution().width); |
+ EXPECT_EQ(initial_res.height, qs_.GetScaledResolution().height); |
+ |
+ // Should upscale if kMeasureSecondsFastUpscale seconds passed (add last |
+ // frame). |
+ qs_.ReportQP(kLowQp); |
+ qs_.OnEncodeFrame(input_frame_); |
+ EXPECT_LT(initial_res.width, qs_.GetScaledResolution().width); |
+ EXPECT_LT(initial_res.height, qs_.GetScaledResolution().height); |
+} |
+ |
void QualityScalerTest::DownscaleEndsAt(int input_width, |
int input_height, |
int end_width, |