Ensure that fps adaptation count can go back to zero when framerate is unrestricted.
Bug: webrtc:12867 Change-Id: I1c11d1a1154ea3d802cdc01e260f72a7e9d17e99 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/221373 Commit-Queue: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Evan Shrubsole <eshr@google.com> Cr-Commit-Position: refs/heads/master@{#34265}
This commit is contained in:
parent
c63ae48871
commit
f5f7e8e806
@ -568,6 +568,14 @@ VideoStreamAdapter::RestrictionsOrState VideoStreamAdapter::IncreaseFramerate(
|
||||
input_state.frame_size_pixels().value());
|
||||
max_frame_rate = balanced_settings_.MaxFps(input_state.video_codec_type(),
|
||||
frame_size_pixels);
|
||||
// Temporary fix for cases when there are fewer framerate adaptation steps
|
||||
// up than down. Make number of down/up steps equal.
|
||||
if (max_frame_rate == std::numeric_limits<int>::max() &&
|
||||
current_restrictions.counters.fps_adaptations > 1) {
|
||||
// Do not unrestrict framerate to allow additional adaptation up steps.
|
||||
RTC_LOG(LS_INFO) << "Modifying framerate due to remaining fps count.";
|
||||
max_frame_rate -= current_restrictions.counters.fps_adaptations;
|
||||
}
|
||||
// In BALANCED, the max_frame_rate must be checked before proceeding. This
|
||||
// is because the MaxFps might be the current Fps and so the balanced
|
||||
// settings may want to scale up the resolution.
|
||||
|
||||
@ -546,6 +546,15 @@ class AdaptingFrameForwarder : public test::FrameForwarder {
|
||||
}
|
||||
}
|
||||
|
||||
void OnOutputFormatRequest(int width, int height) {
|
||||
absl::optional<std::pair<int, int>> target_aspect_ratio =
|
||||
std::make_pair(width, height);
|
||||
absl::optional<int> max_pixel_count = width * height;
|
||||
absl::optional<int> max_fps;
|
||||
adapter_.OnOutputFormatRequest(target_aspect_ratio, max_pixel_count,
|
||||
max_fps);
|
||||
}
|
||||
|
||||
void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
|
||||
const rtc::VideoSinkWants& wants) override {
|
||||
MutexLock lock(&mutex_);
|
||||
@ -3343,6 +3352,257 @@ TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest,
|
||||
FpsCountReturnsToZeroForFewerAdaptationsUpThanDown) {
|
||||
const int kWidth = 640;
|
||||
const int kHeight = 360;
|
||||
const int64_t kFrameIntervalMs = 150;
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps), 0, 0, 0);
|
||||
|
||||
// Enable BALANCED preference, no initial limitation.
|
||||
AdaptingFrameForwarder source(&time_controller_);
|
||||
source.set_adaptation_enabled(true);
|
||||
video_stream_encoder_->SetSource(&source,
|
||||
webrtc::DegradationPreference::BALANCED);
|
||||
|
||||
int64_t timestamp_ms = kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
EXPECT_THAT(source.sink_wants(), FpsMaxResolutionMax());
|
||||
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 reduced fps (640x360@15fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(),
|
||||
FpsMatchesResolutionMax(Lt(kDefaultFramerate)));
|
||||
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);
|
||||
|
||||
// Source requests 270p, expect reduced resolution (480x270@15fps).
|
||||
source.OnOutputFormatRequest(480, 270);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(480, 270);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect reduced fps (480x270@10fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsLtResolutionEq(source.last_wants()));
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Source requests QVGA, expect reduced resolution (320x180@10fps).
|
||||
source.OnOutputFormatRequest(320, 180);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(320, 180);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect reduced fps (320x180@7fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsLtResolutionEq(source.last_wants()));
|
||||
EXPECT_FALSE(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);
|
||||
|
||||
// Source requests VGA, expect increased resolution (640x360@7fps).
|
||||
source.OnOutputFormatRequest(640, 360);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect increased fps (640x360@(max-2)fps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsGtResolutionEq(source.last_wants()));
|
||||
EXPECT_FALSE(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);
|
||||
|
||||
// Trigger adapt up, expect increased fps (640x360@(max-1)fps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsGtResolutionEq(source.last_wants()));
|
||||
EXPECT_FALSE(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 up, expect increased fps (640x360@maxfps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsGtResolutionEq(source.last_wants()));
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest,
|
||||
FpsCountReturnsToZeroForFewerAdaptationsUpThanDownWithTwoResources) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
const int64_t kFrameIntervalMs = 150;
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||
DataRate::BitsPerSec(kTargetBitrateBps), 0, 0, 0);
|
||||
|
||||
// Enable BALANCED preference, no initial limitation.
|
||||
AdaptingFrameForwarder source(&time_controller_);
|
||||
source.set_adaptation_enabled(true);
|
||||
video_stream_encoder_->SetSource(&source,
|
||||
webrtc::DegradationPreference::BALANCED);
|
||||
|
||||
int64_t timestamp_ms = kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
EXPECT_THAT(source.sink_wants(), FpsMaxResolutionMax());
|
||||
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@maxfps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(),
|
||||
FpsMaxResolutionMatches(Lt(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@maxfps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsMaxResolutionLt(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).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsLtResolutionEq(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);
|
||||
|
||||
// Source requests QVGA, expect reduced resolution (320x180@15fps).
|
||||
source.OnOutputFormatRequest(320, 180);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(320, 180);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect reduced fps (320x180@7fps).
|
||||
video_stream_encoder_->TriggerCpuOveruse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsLtResolutionEq(source.last_wants()));
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Source requests HD, expect increased resolution (640x360@7fps).
|
||||
source.OnOutputFormatRequest(1280, 720);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect increased fps (640x360@(max-1)fps).
|
||||
video_stream_encoder_->TriggerCpuUnderuse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsGtResolutionEq(source.last_wants()));
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect increased fps (640x360@maxfps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
video_stream_encoder_->TriggerCpuUnderuse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsGtResolutionEq(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(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect increased resolution (960x570@maxfps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
video_stream_encoder_->TriggerCpuUnderuse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsEqResolutionGt(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(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect increased resolution (1280x720@maxfps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
video_stream_encoder_->TriggerCpuUnderuse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_THAT(source.sink_wants(), FpsEqResolutionGt(source.last_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(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest,
|
||||
NoChangeForInitialNormalUsage_MaintainFramerateMode) {
|
||||
const int kWidth = 1280;
|
||||
@ -6352,7 +6612,7 @@ TEST_F(VideoStreamEncoderTest,
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect expect increased fps (320x180@10fps).
|
||||
// Trigger adapt up, expect increased fps (320x180@10fps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user