BalancedDegradationSettings: add min bitrate configuration for resolution.
Add separate setting for configuring min bitrate that only applies when adapting up in resolution. Bug: none Change-Id: I83d33ac3110a22602065b8d83130e3f619cb1eba Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/150329 Commit-Queue: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Mirta Dvornicic <mirtad@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28970}
This commit is contained in:
@ -27,6 +27,7 @@ std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
|
||||
return {{320 * 240,
|
||||
7,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -35,6 +36,7 @@ std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
|
||||
{480 * 270,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -43,6 +45,7 @@ std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
|
||||
{640 * 480,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -221,6 +224,7 @@ BalancedDegradationSettings::Config::Config() = default;
|
||||
BalancedDegradationSettings::Config::Config(int pixels,
|
||||
int fps,
|
||||
int kbps,
|
||||
int kbps_res,
|
||||
int fps_diff,
|
||||
CodecTypeSpecific vp8,
|
||||
CodecTypeSpecific vp9,
|
||||
@ -229,6 +233,7 @@ BalancedDegradationSettings::Config::Config(int pixels,
|
||||
: pixels(pixels),
|
||||
fps(fps),
|
||||
kbps(kbps),
|
||||
kbps_res(kbps_res),
|
||||
fps_diff(fps_diff),
|
||||
vp8(vp8),
|
||||
vp9(vp9),
|
||||
@ -240,6 +245,8 @@ BalancedDegradationSettings::BalancedDegradationSettings() {
|
||||
{FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
|
||||
FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }),
|
||||
FieldTrialStructMember("kbps", [](Config* c) { return &c->kbps; }),
|
||||
FieldTrialStructMember("kbps_res",
|
||||
[](Config* c) { return &c->kbps_res; }),
|
||||
FieldTrialStructMember("fps_diff",
|
||||
[](Config* c) { return &c->fps_diff; }),
|
||||
FieldTrialStructMember("vp8_qp_low",
|
||||
@ -317,6 +324,18 @@ absl::optional<int> BalancedDegradationSettings::NextHigherBitrateKbps(
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<int>
|
||||
BalancedDegradationSettings::ResolutionNextHigherBitrateKbps(int pixels) const {
|
||||
for (size_t i = 0; i < configs_.size() - 1; ++i) {
|
||||
if (pixels <= configs_[i].pixels) {
|
||||
return (configs_[i + 1].kbps_res > 0)
|
||||
? absl::optional<int>(configs_[i + 1].kbps_res)
|
||||
: absl::nullopt;
|
||||
}
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
bool BalancedDegradationSettings::CanAdaptUp(int pixels,
|
||||
uint32_t bitrate_bps) const {
|
||||
absl::optional<int> next_layer_min_kbps = NextHigherBitrateKbps(pixels);
|
||||
@ -327,6 +346,18 @@ bool BalancedDegradationSettings::CanAdaptUp(int pixels,
|
||||
static_cast<uint32_t>(next_layer_min_kbps.value() * 1000);
|
||||
}
|
||||
|
||||
bool BalancedDegradationSettings::CanAdaptUpResolution(
|
||||
int pixels,
|
||||
uint32_t bitrate_bps) const {
|
||||
absl::optional<int> next_layer_min_kbps =
|
||||
ResolutionNextHigherBitrateKbps(pixels);
|
||||
if (!next_layer_min_kbps.has_value() || bitrate_bps == 0) {
|
||||
return true; // No limit configured or bitrate provided.
|
||||
}
|
||||
return bitrate_bps >=
|
||||
static_cast<uint32_t>(next_layer_min_kbps.value() * 1000);
|
||||
}
|
||||
|
||||
absl::optional<int> BalancedDegradationSettings::MinFpsDiff(int pixels) const {
|
||||
for (const auto& config : configs_) {
|
||||
if (pixels <= config.pixels) {
|
||||
|
@ -47,6 +47,7 @@ class BalancedDegradationSettings {
|
||||
Config(int pixels,
|
||||
int fps,
|
||||
int kbps,
|
||||
int kbps_res,
|
||||
int fps_diff,
|
||||
CodecTypeSpecific vp8,
|
||||
CodecTypeSpecific vp9,
|
||||
@ -55,14 +56,15 @@ class BalancedDegradationSettings {
|
||||
|
||||
bool operator==(const Config& o) const {
|
||||
return pixels == o.pixels && fps == o.fps && kbps == o.kbps &&
|
||||
fps_diff == o.fps_diff && vp8 == o.vp8 && vp9 == o.vp9 &&
|
||||
h264 == o.h264 && generic == o.generic;
|
||||
kbps_res == o.kbps_res && fps_diff == o.fps_diff && vp8 == o.vp8 &&
|
||||
vp9 == o.vp9 && h264 == o.h264 && generic == o.generic;
|
||||
}
|
||||
|
||||
int pixels = 0; // Video frame size.
|
||||
// If the frame size is less than or equal to |pixels|:
|
||||
int fps = 0; // Min framerate to be used.
|
||||
int kbps = 0; // Min bitrate needed to adapt up to this resolution.
|
||||
int kbps = 0; // Min bitrate needed to adapt up (resolution/fps).
|
||||
int kbps_res = 0; // Min bitrate needed to adapt up in resolution.
|
||||
int fps_diff = kNoFpsDiff; // Min fps reduction needed (input fps - |fps|)
|
||||
// w/o triggering a new subsequent downgrade
|
||||
// check.
|
||||
@ -81,9 +83,11 @@ class BalancedDegradationSettings {
|
||||
|
||||
// Gets the bitrate for the first resolution above |pixels|.
|
||||
absl::optional<int> NextHigherBitrateKbps(int pixels) const;
|
||||
absl::optional<int> ResolutionNextHigherBitrateKbps(int pixels) const;
|
||||
|
||||
// Checks if quality can be increased based on |pixels| and |bitrate_bps|.
|
||||
bool CanAdaptUp(int pixels, uint32_t bitrate_bps) const;
|
||||
bool CanAdaptUpResolution(int pixels, uint32_t bitrate_bps) const;
|
||||
|
||||
// Gets the min framerate diff from |configs_| based on |pixels|.
|
||||
absl::optional<int> MinFpsDiff(int pixels) const;
|
||||
|
@ -26,6 +26,7 @@ void VerifyIsDefault(
|
||||
320 * 240,
|
||||
7,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -35,6 +36,7 @@ void VerifyIsDefault(
|
||||
480 * 270,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -44,6 +46,7 @@ void VerifyIsDefault(
|
||||
640 * 480,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -57,6 +60,9 @@ TEST(BalancedDegradationSettings, GetsDefaultConfigIfNoList) {
|
||||
BalancedDegradationSettings settings;
|
||||
VerifyIsDefault(settings.GetConfigs());
|
||||
EXPECT_FALSE(settings.NextHigherBitrateKbps(1));
|
||||
EXPECT_FALSE(settings.ResolutionNextHigherBitrateKbps(1));
|
||||
EXPECT_TRUE(settings.CanAdaptUp(1, /*bitrate_bps*/ 1));
|
||||
EXPECT_TRUE(settings.CanAdaptUpResolution(1, /*bitrate_bps*/ 1));
|
||||
EXPECT_FALSE(settings.MinFpsDiff(1));
|
||||
EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP8, 1));
|
||||
EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP9, 1));
|
||||
@ -76,6 +82,7 @@ TEST(BalancedDegradationSettings, GetsConfig) {
|
||||
11,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -85,6 +92,7 @@ TEST(BalancedDegradationSettings, GetsConfig) {
|
||||
22,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -94,6 +102,7 @@ TEST(BalancedDegradationSettings, GetsConfig) {
|
||||
33,
|
||||
25,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -137,6 +146,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithSpecificFps) {
|
||||
1000,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 7},
|
||||
{0, 0, 9},
|
||||
@ -146,6 +156,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithSpecificFps) {
|
||||
2000,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 8},
|
||||
{0, 0, 10},
|
||||
@ -155,6 +166,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithSpecificFps) {
|
||||
3000,
|
||||
25,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 9},
|
||||
{0, 0, 11},
|
||||
@ -285,7 +297,7 @@ TEST(BalancedDegradationSettings, GetsUnlimitedForMaxValidFps) {
|
||||
TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Video-BalancedDegradationSettings/"
|
||||
"pixels:11|22|33,fps:5|15|25,kbps:44|88|99/");
|
||||
"pixels:11|22|33,fps:5|15|25,kbps:44|88|99,kbps_res:55|111|222/");
|
||||
BalancedDegradationSettings settings;
|
||||
EXPECT_THAT(settings.GetConfigs(),
|
||||
::testing::ElementsAre(
|
||||
@ -293,6 +305,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
||||
11,
|
||||
5,
|
||||
44,
|
||||
55,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -302,6 +315,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
||||
22,
|
||||
15,
|
||||
88,
|
||||
111,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -311,6 +325,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
||||
33,
|
||||
25,
|
||||
99,
|
||||
222,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{0, 0, 0},
|
||||
{0, 0, 0},
|
||||
@ -373,6 +388,46 @@ TEST(BalancedDegradationSettings, CanAdaptUpIfBitrateGeNextHigherKbpsLimit) {
|
||||
EXPECT_TRUE(settings.CanAdaptUp(3001, 1)); // No limit.
|
||||
}
|
||||
|
||||
TEST(BalancedDegradationSettings, GetsResolutionNextHigherBitrate) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Video-BalancedDegradationSettings/"
|
||||
"pixels:1000|2000|3000,fps:5|15|25,kbps_res:44|88|99/");
|
||||
BalancedDegradationSettings settings;
|
||||
EXPECT_EQ(88, settings.ResolutionNextHigherBitrateKbps(1));
|
||||
EXPECT_EQ(88, settings.ResolutionNextHigherBitrateKbps(1000));
|
||||
EXPECT_EQ(99, settings.ResolutionNextHigherBitrateKbps(1001));
|
||||
EXPECT_EQ(99, settings.ResolutionNextHigherBitrateKbps(2000));
|
||||
EXPECT_FALSE(settings.ResolutionNextHigherBitrateKbps(2001));
|
||||
}
|
||||
|
||||
TEST(BalancedDegradationSettings,
|
||||
GetsResolutionNextHigherBitrateWithUnsetValue) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Video-BalancedDegradationSettings/"
|
||||
"pixels:1000|2000|3000,fps:5|15|25,kbps_res:10|0|20/");
|
||||
BalancedDegradationSettings settings;
|
||||
EXPECT_FALSE(settings.ResolutionNextHigherBitrateKbps(1));
|
||||
EXPECT_FALSE(settings.ResolutionNextHigherBitrateKbps(1000));
|
||||
EXPECT_EQ(20, settings.ResolutionNextHigherBitrateKbps(1001));
|
||||
EXPECT_EQ(20, settings.ResolutionNextHigherBitrateKbps(2000));
|
||||
EXPECT_FALSE(settings.ResolutionNextHigherBitrateKbps(2001));
|
||||
}
|
||||
|
||||
TEST(BalancedDegradationSettings,
|
||||
CanAdaptUpResolutionIfBitrateGeNextHigherKbpsLimit) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Video-BalancedDegradationSettings/"
|
||||
"pixels:1000|2000|3000|4000,fps:5|15|25|30,kbps_res:0|80|0|90/");
|
||||
BalancedDegradationSettings settings;
|
||||
EXPECT_TRUE(settings.CanAdaptUpResolution(1000, 0)); // No bitrate provided.
|
||||
EXPECT_FALSE(settings.CanAdaptUpResolution(1000, 79000));
|
||||
EXPECT_TRUE(settings.CanAdaptUpResolution(1000, 80000));
|
||||
EXPECT_TRUE(settings.CanAdaptUpResolution(1001, 1)); // No limit configured.
|
||||
EXPECT_FALSE(settings.CanAdaptUpResolution(3000, 89000));
|
||||
EXPECT_TRUE(settings.CanAdaptUpResolution(3000, 90000));
|
||||
EXPECT_TRUE(settings.CanAdaptUpResolution(3001, 1)); // No limit.
|
||||
}
|
||||
|
||||
TEST(BalancedDegradationSettings, GetsFpsDiff) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Video-BalancedDegradationSettings/"
|
||||
@ -423,6 +478,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithQpThresholds) {
|
||||
1000,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{89, 90, 0},
|
||||
{27, 120, 0},
|
||||
@ -432,6 +488,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithQpThresholds) {
|
||||
2000,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{90, 91, 0},
|
||||
{28, 130, 0},
|
||||
@ -441,6 +498,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithQpThresholds) {
|
||||
3000,
|
||||
25,
|
||||
0,
|
||||
0,
|
||||
BalancedDegradationSettings::kNoFpsDiff,
|
||||
{88, 92, 0},
|
||||
{29, 140, 0},
|
||||
|
@ -1931,6 +1931,12 @@ void VideoStreamEncoder::AdaptUp(AdaptReason reason) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Check if resolution should be increased based on bitrate.
|
||||
if (reason == kQuality &&
|
||||
!balanced_settings_.CanAdaptUpResolution(
|
||||
last_frame_info_->pixel_count(), encoder_start_bitrate_bps_)) {
|
||||
return;
|
||||
}
|
||||
// Scale up resolution.
|
||||
RTC_FALLTHROUGH();
|
||||
}
|
||||
|
@ -2628,8 +2628,6 @@ TEST_F(VideoStreamEncoderTest, NoAdaptUpIfBwEstimateIsLessThanMinBitrate) {
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyFpsMaxResolutionMax(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
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 framerate (640x360@14fps).
|
||||
@ -2638,8 +2636,6 @@ TEST_F(VideoStreamEncoderTest, NoAdaptUpIfBwEstimateIsLessThanMinBitrate) {
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionMax(source.sink_wants(), 14);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution (480x270@14fps).
|
||||
@ -2648,31 +2644,212 @@ TEST_F(VideoStreamEncoderTest, NoAdaptUpIfBwEstimateIsLessThanMinBitrate) {
|
||||
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_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no upscale (target bitrate < min bitrate).
|
||||
// Trigger adapt down, expect scaled down framerate (480x270@10fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(source.sink_wants().max_framerate_fps, 10);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no upscale in fps (target bitrate < min bitrate).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled resolution (target bitrate == min
|
||||
// bitrate).
|
||||
// Trigger adapt up, expect upscaled fps (target bitrate == min bitrate).
|
||||
video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kMinBitrateBps),
|
||||
DataRate::bps(kMinBitrateBps), 0, 0);
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(source.sink_wants().max_framerate_fps, 14);
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest,
|
||||
NoAdaptUpInResolutionIfBwEstimateIsLessThanMinBitrate) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Video-BalancedDegradationSettings/"
|
||||
"pixels:57600|129600|230400,fps:7|10|14,kbps_res:0|0|435/");
|
||||
// Reset encoder for field trials to take effect.
|
||||
ConfigureEncoder(video_encoder_config_.Copy());
|
||||
|
||||
const int kWidth = 640; // pixels:640x360=230400
|
||||
const int kHeight = 360;
|
||||
const int64_t kFrameIntervalMs = 150;
|
||||
const int kResolutionMinBitrateBps = 435000;
|
||||
const int kTooLowMinResolutionBitrateBps = 434000;
|
||||
video_stream_encoder_->OnBitrateUpdated(
|
||||
DataRate::bps(kTooLowMinResolutionBitrateBps),
|
||||
DataRate::bps(kTooLowMinResolutionBitrateBps), 0, 0);
|
||||
|
||||
// Enable BALANCED preference, no initial limitation.
|
||||
AdaptingFrameForwarder source;
|
||||
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);
|
||||
VerifyFpsMaxResolutionMax(source.sink_wants());
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down framerate (640x360@14fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionMax(source.sink_wants(), 14);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution (480x270@14fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down framerate (480x270@10fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled fps (no bitrate limit) (480x270@14fps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no upscale in res (target bitrate < min bitrate).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled res (target bitrate == min bitrate).
|
||||
video_stream_encoder_->OnBitrateUpdated(
|
||||
DataRate::bps(kResolutionMinBitrateBps),
|
||||
DataRate::bps(kResolutionMinBitrateBps), 0, 0);
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest,
|
||||
NoAdaptUpInFpsAndResolutionIfBwEstimateIsLessThanMinBitrate) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Video-BalancedDegradationSettings/"
|
||||
"pixels:57600|129600|230400,fps:7|10|14,kbps:0|0|425,kbps_res:0|0|435/");
|
||||
// Reset encoder for field trials to take effect.
|
||||
ConfigureEncoder(video_encoder_config_.Copy());
|
||||
|
||||
const int kWidth = 640; // pixels:640x360=230400
|
||||
const int kHeight = 360;
|
||||
const int64_t kFrameIntervalMs = 150;
|
||||
const int kMinBitrateBps = 425000;
|
||||
const int kTooLowMinBitrateBps = 424000;
|
||||
const int kResolutionMinBitrateBps = 435000;
|
||||
const int kTooLowMinResolutionBitrateBps = 434000;
|
||||
video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTooLowMinBitrateBps),
|
||||
DataRate::bps(kTooLowMinBitrateBps),
|
||||
0, 0);
|
||||
|
||||
// Enable BALANCED preference, no initial limitation.
|
||||
AdaptingFrameForwarder source;
|
||||
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);
|
||||
VerifyFpsMaxResolutionMax(source.sink_wants());
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down framerate (640x360@14fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionMax(source.sink_wants(), 14);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution (480x270@14fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down framerate (480x270@10fps).
|
||||
video_stream_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no upscale (target bitrate < min bitrate).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled fps (target bitrate == min bitrate).
|
||||
video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kMinBitrateBps),
|
||||
DataRate::bps(kMinBitrateBps), 0, 0);
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no upscale in res (target bitrate < min bitrate).
|
||||
video_stream_encoder_->OnBitrateUpdated(
|
||||
DataRate::bps(kTooLowMinResolutionBitrateBps),
|
||||
DataRate::bps(kTooLowMinResolutionBitrateBps), 0, 0);
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled res (target bitrate == min bitrate).
|
||||
video_stream_encoder_->OnBitrateUpdated(
|
||||
DataRate::bps(kResolutionMinBitrateBps),
|
||||
DataRate::bps(kResolutionMinBitrateBps), 0, 0);
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
@ -3727,7 +3904,7 @@ TEST_F(VideoStreamEncoderTest,
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no restriction (1280x720fps@30fps).
|
||||
// Trigger adapt up, expect no restriction (1280x720fps@30fps).
|
||||
video_stream_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
|
Reference in New Issue
Block a user