| Index: webrtc/video/vie_encoder_unittest.cc
|
| diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc
|
| index 4d72a826f2241b22ff4d919877c2ef28bcbc0797..c7f4516a3152347a3e86d28db305f0ef98cf519b 100644
|
| --- a/webrtc/video/vie_encoder_unittest.cc
|
| +++ b/webrtc/video/vie_encoder_unittest.cc
|
| @@ -34,6 +34,9 @@ namespace {
|
| const int kMinPixelsPerFrame = 320 * 180;
|
| const int kMinFramerateFps = 2;
|
| const int64_t kFrameTimeoutMs = 100;
|
| +const int kBpsLimitFor15Fps = 500000;
|
| +const int kBpsLimitFor10Fps = 130000;
|
| +const int kBpsLimitFor7Fps = 60000;
|
| } // namespace
|
|
|
| namespace webrtc {
|
| @@ -326,6 +329,37 @@ class ViEEncoderTest : public ::testing::Test {
|
| EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
|
| }
|
|
|
| + void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
|
| + const rtc::VideoSinkWants& wants2) {
|
| + EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
|
| + EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
|
| + }
|
| +
|
| + void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
|
| + const rtc::VideoSinkWants& wants2) {
|
| + EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
| + EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
|
| + }
|
| +
|
| + void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
|
| + const rtc::VideoSinkWants& wants2) {
|
| + EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
| + EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
|
| + }
|
| +
|
| + void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
|
| + const rtc::VideoSinkWants& wants2) {
|
| + EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
| + EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
|
| + EXPECT_GT(wants1.max_pixel_count, 0);
|
| + }
|
| +
|
| + void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
|
| + const rtc::VideoSinkWants& wants2) {
|
| + EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
| + EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
|
| + }
|
| +
|
| void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
|
| int pixel_count) {
|
| EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
|
| @@ -339,6 +373,13 @@ class ViEEncoderTest : public ::testing::Test {
|
| EXPECT_FALSE(wants.target_pixel_count);
|
| }
|
|
|
| + void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
|
| + int expected_fps) {
|
| + EXPECT_EQ(expected_fps, wants.max_framerate_fps);
|
| + EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
|
| + EXPECT_FALSE(wants.target_pixel_count);
|
| + }
|
| +
|
| void WaitForEncodedFrame(int64_t expected_ntp_time) {
|
| sink_.WaitForEncodedFrame(expected_ntp_time);
|
| fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
|
| @@ -860,6 +901,59 @@ TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
|
| vie_encoder_->Stop();
|
| }
|
|
|
| +TEST_F(ViEEncoderTest, TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
|
| + const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
|
| + const int kWidth = 1280;
|
| + const int kHeight = 720;
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor15Fps + 1, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + AdaptingFrameForwarder source;
|
| + source.set_adaptation_enabled(true);
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| +
|
| + // Trigger adapt down kMaxCpuDowngrades times.
|
| + int t = 1;
|
| + for (int i = 1; i <= kMaxDowngrades; ++i) {
|
| + source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(t++);
|
| + vie_encoder_->TriggerCpuOveruse();
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + }
|
| +
|
| + // Trigger adapt down, max cpu downgrades reach, expect no change.
|
| + rtc::VideoSinkWants last_wants = source.sink_wants();
|
| + source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(t++);
|
| + vie_encoder_->TriggerCpuOveruse();
|
| + VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
|
| + EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_EQ(kMaxDowngrades,
|
| + stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| +
|
| + // Trigger adapt up kMaxCpuDowngrades times.
|
| + for (int i = 1; i <= kMaxDowngrades; ++i) {
|
| + source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(t++);
|
| + vie_encoder_->TriggerCpuNormalUsage();
|
| + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
| + EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
|
| + EXPECT_EQ(kMaxDowngrades + i,
|
| + stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + }
|
| +
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
|
| vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
| VerifyNoLimitation(video_source_.sink_wants());
|
| @@ -1428,6 +1522,45 @@ TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
|
| vie_encoder_->Stop();
|
| }
|
|
|
| +TEST_F(ViEEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
|
| + const int kWidth = 1280;
|
| + const int kHeight = 720;
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor15Fps + 1, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + test::FrameForwarder source;
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| + source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(1);
|
| + VerifyNoLimitation(source.sink_wants());
|
| +
|
| + // Trigger adapt down, expect scaled down resolution.
|
| + vie_encoder_->TriggerQualityLow();
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| + const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
|
| +
|
| + // Trigger adapt down for same input resolution, expect no change.
|
| + source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(2);
|
| + vie_encoder_->TriggerQualityLow();
|
| + EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down for larger input resolution, expect no change.
|
| + source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
|
| + sink_.WaitForEncodedFrame(3);
|
| + vie_encoder_->TriggerQualityLow();
|
| + EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| +
|
| TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
|
| const int kWidth = 1280;
|
| const int kHeight = 720;
|
| @@ -1478,6 +1611,33 @@ TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
|
| vie_encoder_->Stop();
|
| }
|
|
|
| +TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
|
| + const int kWidth = 1280;
|
| + const int kHeight = 720;
|
| + vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + test::FrameForwarder source;
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| +
|
| + source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect no change.
|
| + vie_encoder_->TriggerQualityHigh();
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| +
|
| TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
|
| const int kWidth = 1280;
|
| const int kHeight = 720;
|
| @@ -1669,6 +1829,59 @@ TEST_F(ViEEncoderTest,
|
| vie_encoder_->Stop();
|
| }
|
|
|
| +TEST_F(ViEEncoderTest,
|
| + AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
|
| + const int kWidth = 1280;
|
| + const int kHeight = 720;
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor15Fps + 1, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + AdaptingFrameForwarder source;
|
| + source.set_adaptation_enabled(true);
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| +
|
| + source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, expect scaled down resolution.
|
| + vie_encoder_->TriggerQualityLow();
|
| + source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(2);
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect no restriction.
|
| + vie_encoder_->TriggerQualityHigh();
|
| + source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, expect scaled down resolution.
|
| + vie_encoder_->TriggerQualityLow();
|
| + source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(4);
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect no restriction.
|
| + vie_encoder_->TriggerQualityHigh();
|
| + source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| +
|
| TEST_F(ViEEncoderTest,
|
| AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
|
| const int kWidth = 1280;
|
| @@ -1977,6 +2190,41 @@ TEST_F(ViEEncoderTest,
|
| vie_encoder_->Stop();
|
| }
|
|
|
| +TEST_F(ViEEncoderTest, ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
|
| + const int kTooSmallWidth = 10;
|
| + const int kTooSmallHeight = 10;
|
| + const int kFpsLimit = 7;
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor7Fps, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + test::FrameForwarder source;
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| +
|
| + // Trigger adapt down, expect limited framerate.
|
| + source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
|
| + sink_.WaitForEncodedFrame(1);
|
| + vie_encoder_->TriggerQualityLow();
|
| + VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, too small frame, expect no change.
|
| + source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
|
| + sink_.WaitForEncodedFrame(2);
|
| + vie_encoder_->TriggerQualityLow();
|
| + VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| +
|
| TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
|
| fake_encoder_.ForceInitEncodeFailure(true);
|
| vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
| @@ -2210,4 +2458,363 @@ TEST_F(ViEEncoderTest, PriodicallyUpdatesChannelParameters) {
|
|
|
| vie_encoder_->Stop();
|
| }
|
| +
|
| +TEST_F(ViEEncoderTest, AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
|
| + const int kWidth = 1280;
|
| + const int kHeight = 720;
|
| + const int64_t kFrameIntervalMs = 150;
|
| + int64_t timestamp_ms = kFrameIntervalMs;
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor15Fps, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + AdaptingFrameForwarder source;
|
| + source.set_adaptation_enabled(true);
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, expect scaled down resolution (960x540@30fps).
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, expect scaled down resolution (640x360@30fps).
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, expect reduced fps (640x360@15fps).
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, expect scaled down resolution (480x270@15fps).
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor10Fps, 0, 0);
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, expect scaled down resolution (320x180@10fps).
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
| + rtc::VideoSinkWants last_wants = source.sink_wants();
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt down, min resolution reached, expect no change.
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect upscaled resolution (480x270@10fps).
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor15Fps + 1, 0, 0);
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect upscaled resolution (640x360@15fps).
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect increased fps (640x360@30fps).
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect upscaled resolution (960x540@30fps).
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect no restriction (1280x720fps@30fps).
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect no change.
|
| + vie_encoder_->TriggerQualityHigh();
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| +
|
| +TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
|
| + const int kWidth = 1280;
|
| + const int kHeight = 720;
|
| + const int64_t kFrameIntervalMs = 150;
|
| + int64_t timestamp_ms = kFrameIntervalMs;
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor15Fps, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + AdaptingFrameForwarder source;
|
| + source.set_adaptation_enabled(true);
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
|
| + vie_encoder_->TriggerCpuOveruse();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
|
| + vie_encoder_->TriggerCpuOveruse();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger quality adapt down, expect reduced fps (640x360@15fps).
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger cpu adapt up, expect increased fps (640x360@30fps).
|
| + vie_encoder_->TriggerCpuNormalUsage();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
|
| + vie_encoder_->TriggerCpuNormalUsage();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect no change.
|
| + vie_encoder_->TriggerQualityHigh();
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| +
|
| +TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
|
| + const int kWidth = 640;
|
| + const int kHeight = 360;
|
| + const int kFpsLimit = 15;
|
| + const int64_t kFrameIntervalMs = 150;
|
| + int64_t timestamp_ms = kFrameIntervalMs;
|
| + vie_encoder_->OnBitrateUpdated(kBpsLimitFor15Fps, 0, 0);
|
| +
|
| + // Enable kBalanced preference, no initial limitation.
|
| + AdaptingFrameForwarder source;
|
| + source.set_adaptation_enabled(true);
|
| + vie_encoder_->SetSource(&source,
|
| + VideoSendStream::DegradationPreference::kBalanced);
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(kWidth, kHeight);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
|
| + vie_encoder_->TriggerCpuOveruse();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
|
| + vie_encoder_->TriggerQualityLow();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
|
| + vie_encoder_->TriggerCpuNormalUsage();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger quality adapt up, expect increased fps (640x360@30fps).
|
| + vie_encoder_->TriggerQualityHigh();
|
| + timestamp_ms += kFrameIntervalMs;
|
| + source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
| + sink_.WaitForEncodedFrame(timestamp_ms);
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
| + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + // Trigger adapt up, expect no change.
|
| + vie_encoder_->TriggerQualityHigh();
|
| + VerifyNoLimitation(source.sink_wants());
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
| + EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
| +
|
| + vie_encoder_->Stop();
|
| +}
|
| +
|
| } // namespace webrtc
|
|
|