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,
|
return {{320 * 240,
|
||||||
7,
|
7,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -35,6 +36,7 @@ std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
|
|||||||
{480 * 270,
|
{480 * 270,
|
||||||
10,
|
10,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -43,6 +45,7 @@ std::vector<BalancedDegradationSettings::Config> DefaultConfigs() {
|
|||||||
{640 * 480,
|
{640 * 480,
|
||||||
15,
|
15,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -221,6 +224,7 @@ BalancedDegradationSettings::Config::Config() = default;
|
|||||||
BalancedDegradationSettings::Config::Config(int pixels,
|
BalancedDegradationSettings::Config::Config(int pixels,
|
||||||
int fps,
|
int fps,
|
||||||
int kbps,
|
int kbps,
|
||||||
|
int kbps_res,
|
||||||
int fps_diff,
|
int fps_diff,
|
||||||
CodecTypeSpecific vp8,
|
CodecTypeSpecific vp8,
|
||||||
CodecTypeSpecific vp9,
|
CodecTypeSpecific vp9,
|
||||||
@ -229,6 +233,7 @@ BalancedDegradationSettings::Config::Config(int pixels,
|
|||||||
: pixels(pixels),
|
: pixels(pixels),
|
||||||
fps(fps),
|
fps(fps),
|
||||||
kbps(kbps),
|
kbps(kbps),
|
||||||
|
kbps_res(kbps_res),
|
||||||
fps_diff(fps_diff),
|
fps_diff(fps_diff),
|
||||||
vp8(vp8),
|
vp8(vp8),
|
||||||
vp9(vp9),
|
vp9(vp9),
|
||||||
@ -240,6 +245,8 @@ BalancedDegradationSettings::BalancedDegradationSettings() {
|
|||||||
{FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
|
{FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }),
|
||||||
FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }),
|
FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }),
|
||||||
FieldTrialStructMember("kbps", [](Config* c) { return &c->kbps; }),
|
FieldTrialStructMember("kbps", [](Config* c) { return &c->kbps; }),
|
||||||
|
FieldTrialStructMember("kbps_res",
|
||||||
|
[](Config* c) { return &c->kbps_res; }),
|
||||||
FieldTrialStructMember("fps_diff",
|
FieldTrialStructMember("fps_diff",
|
||||||
[](Config* c) { return &c->fps_diff; }),
|
[](Config* c) { return &c->fps_diff; }),
|
||||||
FieldTrialStructMember("vp8_qp_low",
|
FieldTrialStructMember("vp8_qp_low",
|
||||||
@ -317,6 +324,18 @@ absl::optional<int> BalancedDegradationSettings::NextHigherBitrateKbps(
|
|||||||
return absl::nullopt;
|
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,
|
bool BalancedDegradationSettings::CanAdaptUp(int pixels,
|
||||||
uint32_t bitrate_bps) const {
|
uint32_t bitrate_bps) const {
|
||||||
absl::optional<int> next_layer_min_kbps = NextHigherBitrateKbps(pixels);
|
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);
|
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 {
|
absl::optional<int> BalancedDegradationSettings::MinFpsDiff(int pixels) const {
|
||||||
for (const auto& config : configs_) {
|
for (const auto& config : configs_) {
|
||||||
if (pixels <= config.pixels) {
|
if (pixels <= config.pixels) {
|
||||||
|
@ -47,6 +47,7 @@ class BalancedDegradationSettings {
|
|||||||
Config(int pixels,
|
Config(int pixels,
|
||||||
int fps,
|
int fps,
|
||||||
int kbps,
|
int kbps,
|
||||||
|
int kbps_res,
|
||||||
int fps_diff,
|
int fps_diff,
|
||||||
CodecTypeSpecific vp8,
|
CodecTypeSpecific vp8,
|
||||||
CodecTypeSpecific vp9,
|
CodecTypeSpecific vp9,
|
||||||
@ -55,14 +56,15 @@ class BalancedDegradationSettings {
|
|||||||
|
|
||||||
bool operator==(const Config& o) const {
|
bool operator==(const Config& o) const {
|
||||||
return pixels == o.pixels && fps == o.fps && kbps == o.kbps &&
|
return pixels == o.pixels && fps == o.fps && kbps == o.kbps &&
|
||||||
fps_diff == o.fps_diff && vp8 == o.vp8 && vp9 == o.vp9 &&
|
kbps_res == o.kbps_res && fps_diff == o.fps_diff && vp8 == o.vp8 &&
|
||||||
h264 == o.h264 && generic == o.generic;
|
vp9 == o.vp9 && h264 == o.h264 && generic == o.generic;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pixels = 0; // Video frame size.
|
int pixels = 0; // Video frame size.
|
||||||
// If the frame size is less than or equal to |pixels|:
|
// If the frame size is less than or equal to |pixels|:
|
||||||
int fps = 0; // Min framerate to be used.
|
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|)
|
int fps_diff = kNoFpsDiff; // Min fps reduction needed (input fps - |fps|)
|
||||||
// w/o triggering a new subsequent downgrade
|
// w/o triggering a new subsequent downgrade
|
||||||
// check.
|
// check.
|
||||||
@ -81,9 +83,11 @@ class BalancedDegradationSettings {
|
|||||||
|
|
||||||
// Gets the bitrate for the first resolution above |pixels|.
|
// Gets the bitrate for the first resolution above |pixels|.
|
||||||
absl::optional<int> NextHigherBitrateKbps(int pixels) const;
|
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|.
|
// Checks if quality can be increased based on |pixels| and |bitrate_bps|.
|
||||||
bool CanAdaptUp(int pixels, uint32_t bitrate_bps) const;
|
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|.
|
// Gets the min framerate diff from |configs_| based on |pixels|.
|
||||||
absl::optional<int> MinFpsDiff(int pixels) const;
|
absl::optional<int> MinFpsDiff(int pixels) const;
|
||||||
|
@ -26,6 +26,7 @@ void VerifyIsDefault(
|
|||||||
320 * 240,
|
320 * 240,
|
||||||
7,
|
7,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -35,6 +36,7 @@ void VerifyIsDefault(
|
|||||||
480 * 270,
|
480 * 270,
|
||||||
10,
|
10,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -44,6 +46,7 @@ void VerifyIsDefault(
|
|||||||
640 * 480,
|
640 * 480,
|
||||||
15,
|
15,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -57,6 +60,9 @@ TEST(BalancedDegradationSettings, GetsDefaultConfigIfNoList) {
|
|||||||
BalancedDegradationSettings settings;
|
BalancedDegradationSettings settings;
|
||||||
VerifyIsDefault(settings.GetConfigs());
|
VerifyIsDefault(settings.GetConfigs());
|
||||||
EXPECT_FALSE(settings.NextHigherBitrateKbps(1));
|
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.MinFpsDiff(1));
|
||||||
EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP8, 1));
|
EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP8, 1));
|
||||||
EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP9, 1));
|
EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP9, 1));
|
||||||
@ -76,6 +82,7 @@ TEST(BalancedDegradationSettings, GetsConfig) {
|
|||||||
11,
|
11,
|
||||||
5,
|
5,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -85,6 +92,7 @@ TEST(BalancedDegradationSettings, GetsConfig) {
|
|||||||
22,
|
22,
|
||||||
15,
|
15,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -94,6 +102,7 @@ TEST(BalancedDegradationSettings, GetsConfig) {
|
|||||||
33,
|
33,
|
||||||
25,
|
25,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -137,6 +146,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithSpecificFps) {
|
|||||||
1000,
|
1000,
|
||||||
5,
|
5,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 7},
|
{0, 0, 7},
|
||||||
{0, 0, 9},
|
{0, 0, 9},
|
||||||
@ -146,6 +156,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithSpecificFps) {
|
|||||||
2000,
|
2000,
|
||||||
15,
|
15,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 8},
|
{0, 0, 8},
|
||||||
{0, 0, 10},
|
{0, 0, 10},
|
||||||
@ -155,6 +166,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithSpecificFps) {
|
|||||||
3000,
|
3000,
|
||||||
25,
|
25,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 9},
|
{0, 0, 9},
|
||||||
{0, 0, 11},
|
{0, 0, 11},
|
||||||
@ -285,7 +297,7 @@ TEST(BalancedDegradationSettings, GetsUnlimitedForMaxValidFps) {
|
|||||||
TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
||||||
webrtc::test::ScopedFieldTrials field_trials(
|
webrtc::test::ScopedFieldTrials field_trials(
|
||||||
"WebRTC-Video-BalancedDegradationSettings/"
|
"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;
|
BalancedDegradationSettings settings;
|
||||||
EXPECT_THAT(settings.GetConfigs(),
|
EXPECT_THAT(settings.GetConfigs(),
|
||||||
::testing::ElementsAre(
|
::testing::ElementsAre(
|
||||||
@ -293,6 +305,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
|||||||
11,
|
11,
|
||||||
5,
|
5,
|
||||||
44,
|
44,
|
||||||
|
55,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -302,6 +315,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
|||||||
22,
|
22,
|
||||||
15,
|
15,
|
||||||
88,
|
88,
|
||||||
|
111,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -311,6 +325,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithBitrate) {
|
|||||||
33,
|
33,
|
||||||
25,
|
25,
|
||||||
99,
|
99,
|
||||||
|
222,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
@ -373,6 +388,46 @@ TEST(BalancedDegradationSettings, CanAdaptUpIfBitrateGeNextHigherKbpsLimit) {
|
|||||||
EXPECT_TRUE(settings.CanAdaptUp(3001, 1)); // No limit.
|
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) {
|
TEST(BalancedDegradationSettings, GetsFpsDiff) {
|
||||||
webrtc::test::ScopedFieldTrials field_trials(
|
webrtc::test::ScopedFieldTrials field_trials(
|
||||||
"WebRTC-Video-BalancedDegradationSettings/"
|
"WebRTC-Video-BalancedDegradationSettings/"
|
||||||
@ -423,6 +478,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithQpThresholds) {
|
|||||||
1000,
|
1000,
|
||||||
5,
|
5,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{89, 90, 0},
|
{89, 90, 0},
|
||||||
{27, 120, 0},
|
{27, 120, 0},
|
||||||
@ -432,6 +488,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithQpThresholds) {
|
|||||||
2000,
|
2000,
|
||||||
15,
|
15,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{90, 91, 0},
|
{90, 91, 0},
|
||||||
{28, 130, 0},
|
{28, 130, 0},
|
||||||
@ -441,6 +498,7 @@ TEST(BalancedDegradationSettings, GetsConfigWithQpThresholds) {
|
|||||||
3000,
|
3000,
|
||||||
25,
|
25,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
BalancedDegradationSettings::kNoFpsDiff,
|
BalancedDegradationSettings::kNoFpsDiff,
|
||||||
{88, 92, 0},
|
{88, 92, 0},
|
||||||
{29, 140, 0},
|
{29, 140, 0},
|
||||||
|
@ -1931,6 +1931,12 @@ void VideoStreamEncoder::AdaptUp(AdaptReason reason) {
|
|||||||
}
|
}
|
||||||
break;
|
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.
|
// Scale up resolution.
|
||||||
RTC_FALLTHROUGH();
|
RTC_FALLTHROUGH();
|
||||||
}
|
}
|
||||||
|
@ -2628,8 +2628,6 @@ TEST_F(VideoStreamEncoderTest, NoAdaptUpIfBwEstimateIsLessThanMinBitrate) {
|
|||||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||||
VerifyFpsMaxResolutionMax(source.sink_wants());
|
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);
|
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||||
|
|
||||||
// Trigger adapt down, expect scaled down framerate (640x360@14fps).
|
// Trigger adapt down, expect scaled down framerate (640x360@14fps).
|
||||||
@ -2638,8 +2636,6 @@ TEST_F(VideoStreamEncoderTest, NoAdaptUpIfBwEstimateIsLessThanMinBitrate) {
|
|||||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||||
VerifyFpsEqResolutionMax(source.sink_wants(), 14);
|
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);
|
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||||
|
|
||||||
// Trigger adapt down, expect scaled down resolution (480x270@14fps).
|
// Trigger adapt down, expect scaled down resolution (480x270@14fps).
|
||||||
@ -2648,31 +2644,212 @@ TEST_F(VideoStreamEncoderTest, NoAdaptUpIfBwEstimateIsLessThanMinBitrate) {
|
|||||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||||
VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
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);
|
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();
|
video_stream_encoder_->TriggerQualityHigh();
|
||||||
timestamp_ms += kFrameIntervalMs;
|
timestamp_ms += kFrameIntervalMs;
|
||||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
|
||||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
|
||||||
|
|
||||||
// Trigger adapt up, expect upscaled resolution (target bitrate == min
|
// Trigger adapt up, expect upscaled fps (target bitrate == min bitrate).
|
||||||
// bitrate).
|
|
||||||
video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kMinBitrateBps),
|
video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kMinBitrateBps),
|
||||||
DataRate::bps(kMinBitrateBps), 0, 0);
|
DataRate::bps(kMinBitrateBps), 0, 0);
|
||||||
video_stream_encoder_->TriggerQualityHigh();
|
video_stream_encoder_->TriggerQualityHigh();
|
||||||
timestamp_ms += kFrameIntervalMs;
|
timestamp_ms += kFrameIntervalMs;
|
||||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
EXPECT_EQ(source.sink_wants().max_framerate_fps, 14);
|
||||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
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);
|
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();
|
video_stream_encoder_->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3727,7 +3904,7 @@ TEST_F(VideoStreamEncoderTest,
|
|||||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||||
EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
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();
|
video_stream_encoder_->TriggerQualityHigh();
|
||||||
timestamp_ms += kFrameIntervalMs;
|
timestamp_ms += kFrameIntervalMs;
|
||||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||||
|
Reference in New Issue
Block a user