Use resolution bitrate limits if one spatial layer is configured via scalability mode.

Bug: webrtc:13960
Change-Id: Ie9238f3352b0d9d92fda97a250de0792e6bbfc9a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261721
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36948}
This commit is contained in:
Asa Persson 2022-05-20 14:22:27 +02:00 committed by WebRTC LUCI CQ
parent 6fb674ea5a
commit 2ee3e4db22
8 changed files with 432 additions and 128 deletions

View File

@ -47,6 +47,7 @@ rtc_library("video_adaptation") {
"../../api/video_codecs:video_codecs_api",
"../../call/adaptation:resource_adaptation",
"../../modules/video_coding:video_coding_utility",
"../../modules/video_coding/svc:scalability_mode_util",
"../../rtc_base:checks",
"../../rtc_base:event_tracer",
"../../rtc_base:logging",
@ -96,6 +97,7 @@ if (rtc_include_tests) {
"../../api/video:encoded_image",
"../../api/video:video_adaptation",
"../../api/video:video_frame",
"../../api/video_codecs:scalability_mode",
"../../api/video_codecs:video_codecs_api",
"../../call/adaptation:resource_adaptation",
"../../call/adaptation:resource_adaptation_test_utilities",

View File

@ -37,6 +37,10 @@ void BitrateConstraint::OnEncoderTargetBitrateUpdated(
encoder_target_bitrate_bps_ = std::move(encoder_target_bitrate_bps);
}
// Checks if resolution is allowed to adapt up based on the current bitrate and
// ResolutionBitrateLimits.min_start_bitrate_bps for the next higher resolution.
// Bitrate limits usage is restricted to a single active stream/layer (e.g. when
// quality scaling is enabled).
bool BitrateConstraint::IsAdaptationUpAllowed(
const VideoStreamInputState& input_state,
const VideoSourceRestrictions& restrictions_before,
@ -53,7 +57,7 @@ bool BitrateConstraint::IsAdaptationUpAllowed(
return true;
}
if (VideoStreamEncoderResourceManager::IsSimulcast(
if (VideoStreamEncoderResourceManager::IsSimulcastOrMultipleSpatialLayers(
encoder_settings_->encoder_config())) {
// Resolution bitrate limits usage is restricted to singlecast.
return true;

View File

@ -13,6 +13,7 @@
#include <utility>
#include <vector>
#include "api/video_codecs/scalability_mode.h"
#include "api/video_codecs/video_encoder.h"
#include "call/adaptation/encoder_settings.h"
#include "call/adaptation/test/fake_frame_rate_provider.h"
@ -23,6 +24,9 @@
namespace webrtc {
namespace {
const VideoSourceRestrictions k180p{/*max_pixels_per_frame=*/320 * 180,
/*target_pixels_per_frame=*/320 * 180,
/*max_frame_rate=*/30};
const VideoSourceRestrictions k360p{/*max_pixels_per_frame=*/640 * 360,
/*target_pixels_per_frame=*/640 * 360,
/*max_frame_rate=*/30};
@ -30,39 +34,50 @@ const VideoSourceRestrictions k720p{/*max_pixels_per_frame=*/1280 * 720,
/*target_pixels_per_frame=*/1280 * 720,
/*max_frame_rate=*/30};
struct TestParams {
bool active;
absl::optional<ScalabilityMode> scalability_mode;
};
void FillCodecConfig(VideoCodec* video_codec,
VideoEncoderConfig* encoder_config,
int width_px,
int height_px,
std::vector<bool> active_flags) {
size_t num_layers = active_flags.size();
const std::vector<TestParams>& params,
bool svc) {
size_t num_layers = params.size();
video_codec->codecType = kVideoCodecVP8;
video_codec->numberOfSimulcastStreams = num_layers;
encoder_config->number_of_streams = num_layers;
encoder_config->number_of_streams = svc ? 1 : num_layers;
encoder_config->simulcast_layers.resize(num_layers);
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
int layer_width_px = width_px >> (num_layers - 1 - layer_idx);
int layer_height_px = height_px >> (num_layers - 1 - layer_idx);
video_codec->simulcastStream[layer_idx].active = active_flags[layer_idx];
if (params[layer_idx].scalability_mode)
video_codec->SetScalabilityMode(*params[layer_idx].scalability_mode);
video_codec->simulcastStream[layer_idx].active = params[layer_idx].active;
video_codec->simulcastStream[layer_idx].width = layer_width_px;
video_codec->simulcastStream[layer_idx].height = layer_height_px;
encoder_config->simulcast_layers[layer_idx].scalability_mode =
params[layer_idx].scalability_mode;
encoder_config->simulcast_layers[layer_idx].active =
active_flags[layer_idx];
params[layer_idx].active;
encoder_config->simulcast_layers[layer_idx].width = layer_width_px;
encoder_config->simulcast_layers[layer_idx].height = layer_height_px;
}
}
constexpr int kStartBitrateBps360p = 500000;
constexpr int kStartBitrateBps720p = 1000000;
VideoEncoder::EncoderInfo MakeEncoderInfo() {
VideoEncoder::EncoderInfo encoder_info;
encoder_info.resolution_bitrate_limits = {
{640 * 360, 500000, 0, 5000000},
{640 * 360, kStartBitrateBps360p, 0, 5000000},
{1280 * 720, kStartBitrateBps720p, 0, 5000000},
{1920 * 1080, 2000000, 0, 5000000}};
return encoder_info;
@ -78,11 +93,12 @@ class BitrateConstraintTest : public ::testing::Test {
protected:
void OnEncoderSettingsUpdated(int width_px,
int height_px,
std::vector<bool> active_flags) {
const std::vector<TestParams>& params,
bool svc = false) {
VideoCodec video_codec;
VideoEncoderConfig encoder_config;
FillCodecConfig(&video_codec, &encoder_config, width_px, height_px,
active_flags);
FillCodecConfig(&video_codec, &encoder_config, width_px, height_px, params,
svc);
EncoderSettings encoder_settings(MakeEncoderInfo(),
std::move(encoder_config), video_codec);
@ -97,7 +113,7 @@ class BitrateConstraintTest : public ::testing::Test {
TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSinglecastIfBitrateIsEnough) {
OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
/*active_flags=*/{true});
{{.active = true}});
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
@ -110,7 +126,7 @@ TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSinglecastIfBitrateIsEnough) {
TEST_F(BitrateConstraintTest,
AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnough) {
OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
/*active_flags=*/{true});
{{.active = true}});
// 1 bps less than needed for 720p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
@ -121,10 +137,56 @@ TEST_F(BitrateConstraintTest,
/*restrictions_after=*/k720p));
}
TEST_F(BitrateConstraintTest,
AdaptUpAllowedAtSinglecastIfBitrateIsEnoughForOneSpatialLayer) {
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = true, .scalability_mode = ScalabilityMode::kL1T1}});
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k360p,
/*restrictions_after=*/k720p));
}
TEST_F(BitrateConstraintTest,
AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnoughForOneSpatialLayer) {
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = true, .scalability_mode = ScalabilityMode::kL1T1}});
// 1 bps less than needed for 720p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k360p,
/*restrictions_after=*/k720p));
}
TEST_F(BitrateConstraintTest,
AdaptUpAllowedAtSinglecastIfBitrateIsNotEnoughForMultipleSpatialLayers) {
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = true, .scalability_mode = ScalabilityMode::kL2T1}});
// 1 bps less than needed for 720p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k360p,
/*restrictions_after=*/k720p));
}
TEST_F(BitrateConstraintTest,
AdaptUpAllowedAtSinglecastUpperLayerActiveIfBitrateIsEnough) {
OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
/*active_flags=*/{false, true});
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = false, .scalability_mode = ScalabilityMode::kL2T1},
{.active = true}});
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
@ -136,8 +198,10 @@ TEST_F(BitrateConstraintTest,
TEST_F(BitrateConstraintTest,
AdaptUpDisallowedAtSinglecastUpperLayerActiveIfBitrateIsNotEnough) {
OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
/*active_flags=*/{false, true});
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = false, .scalability_mode = ScalabilityMode::kL2T1},
{.active = true}});
// 1 bps less than needed for 720p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
@ -148,23 +212,88 @@ TEST_F(BitrateConstraintTest,
/*restrictions_after=*/k720p));
}
TEST_F(BitrateConstraintTest,
AdaptUpAllowedAtSinglecastLowestLayerActiveIfBitrateIsNotEnough) {
TEST_F(BitrateConstraintTest, AdaptUpAllowedLowestActiveIfBitrateIsNotEnough) {
OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
/*active_flags=*/{true, false});
{{.active = true}, {.active = false}});
// 1 bps less than needed for 720p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
// 1 bps less than needed for 360p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k360p,
/*restrictions_after=*/k720p));
/*restrictions_before=*/k180p,
/*restrictions_after=*/k360p));
}
TEST_F(BitrateConstraintTest,
AdaptUpAllowedLowestActiveIfBitrateIsNotEnoughForOneSpatialLayer) {
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = true, .scalability_mode = ScalabilityMode::kL1T2},
{.active = false}});
// 1 bps less than needed for 360p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k180p,
/*restrictions_after=*/k360p));
}
TEST_F(BitrateConstraintTest,
AdaptUpAllowedLowestActiveIfBitrateIsEnoughForOneSpatialLayerSvc) {
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = true, .scalability_mode = ScalabilityMode::kL1T1},
{.active = false}},
/*svc=*/true);
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p);
EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k180p,
/*restrictions_after=*/k360p));
}
TEST_F(BitrateConstraintTest,
AdaptUpDisallowedLowestActiveIfBitrateIsNotEnoughForOneSpatialLayerSvc) {
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = true, .scalability_mode = ScalabilityMode::kL1T1},
{.active = false}},
/*svc=*/true);
// 1 bps less than needed for 360p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k180p,
/*restrictions_after=*/k360p));
}
TEST_F(BitrateConstraintTest,
AdaptUpAllowedLowestActiveIfBitrateIsNotEnoughForTwoSpatialLayersSvc) {
OnEncoderSettingsUpdated(
/*width_px=*/640, /*height_px=*/360,
{{.active = true, .scalability_mode = ScalabilityMode::kL2T1},
{.active = false}},
/*svc=*/true);
// 1 bps less than needed for 360p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
input_state_provider_.InputState(),
/*restrictions_before=*/k180p,
/*restrictions_after=*/k360p));
}
TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSimulcastIfBitrateIsNotEnough) {
OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
/*active_flags=*/{true, true});
{{.active = true}, {.active = true}});
// 1 bps less than needed for 720p.
bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
@ -178,7 +307,7 @@ TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSimulcastIfBitrateIsNotEnough) {
TEST_F(BitrateConstraintTest,
AdaptUpInFpsAllowedAtNoResolutionIncreaseIfBitrateIsNotEnough) {
OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
/*active_flags=*/{true});
{{.active = true}});
bitrate_constraint_.OnEncoderTargetBitrateUpdated(1);

View File

@ -26,6 +26,7 @@
#include "api/video/video_adaptation_reason.h"
#include "api/video/video_source_interface.h"
#include "call/adaptation/video_source_restrictions.h"
#include "modules/video_coding/svc/scalability_mode_util.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
@ -815,15 +816,29 @@ void VideoStreamEncoderResourceManager::OnQualityRampUp() {
quality_rampup_experiment_.reset();
}
bool VideoStreamEncoderResourceManager::IsSimulcast(
bool VideoStreamEncoderResourceManager::IsSimulcastOrMultipleSpatialLayers(
const VideoEncoderConfig& encoder_config) {
const std::vector<VideoStream>& simulcast_layers =
encoder_config.simulcast_layers;
if (simulcast_layers.size() <= 1) {
if (simulcast_layers.empty()) {
return false;
}
if (simulcast_layers[0].active) {
absl::optional<int> num_spatial_layers;
if (simulcast_layers[0].scalability_mode.has_value() &&
encoder_config.number_of_streams == 1) {
num_spatial_layers = ScalabilityModeToNumSpatialLayers(
*simulcast_layers[0].scalability_mode);
}
if (simulcast_layers.size() == 1) {
// Check if multiple spatial layers are used.
return num_spatial_layers && *num_spatial_layers > 1;
}
bool svc_with_one_spatial_layer =
num_spatial_layers && *num_spatial_layers == 1;
if (simulcast_layers[0].active && !svc_with_one_spatial_layer) {
// We can't distinguish between simulcast and singlecast when only the
// lowest spatial layer is active. Treat this case as simulcast.
return true;

View File

@ -153,7 +153,8 @@ class VideoStreamEncoderResourceManager
// QualityRampUpExperimentListener implementation.
void OnQualityRampUp() override;
static bool IsSimulcast(const VideoEncoderConfig& encoder_config);
static bool IsSimulcastOrMultipleSpatialLayers(
const VideoEncoderConfig& encoder_config);
private:
class InitialFrameDropper;

View File

@ -11,6 +11,7 @@
#include <algorithm>
#include "media/engine/webrtc_video_engine.h"
#include "modules/video_coding/svc/scalability_mode_util.h"
#include "rtc_base/experiments/encoder_info_settings.h"
#include "test/call_test.h"
#include "test/fake_encoder.h"
@ -62,6 +63,8 @@ BitrateLimits GetLayerBitrateLimits(int pixels, const VideoCodec& codec) {
} // namespace
class ResolutionBitrateLimitsWithScalabilityModeTest : public test::CallTest {};
class ResolutionBitrateLimitsTest
: public test::CallTest,
public ::testing::WithParamInterface<std::string> {
@ -73,7 +76,10 @@ class ResolutionBitrateLimitsTest
INSTANTIATE_TEST_SUITE_P(PayloadName,
ResolutionBitrateLimitsTest,
::testing::Values("VP8", "VP9"));
::testing::Values("VP8", "VP9"),
[](const ::testing::TestParamInfo<std::string>& info) {
return info.param;
});
class InitEncodeTest : public test::EndToEndTest,
public test::FrameGeneratorCapturer::SinkWantsObserver,
@ -86,6 +92,7 @@ class InitEncodeTest : public test::EndToEndTest,
struct TestConfig {
const bool active;
const Bitrate bitrate;
const absl::optional<ScalabilityMode> scalability_mode;
};
struct Expectation {
const uint32_t pixels = 0;
@ -141,6 +148,7 @@ class InitEncodeTest : public test::EndToEndTest,
for (int i = configs_.size() - 1; i >= 0; --i) {
VideoStream& stream = encoder_config->simulcast_layers[i];
stream.active = configs_[i].active;
stream.scalability_mode = configs_[i].scalability_mode;
if (configs_[i].bitrate.min)
stream.min_bitrate_bps = configs_[i].bitrate.min->bps();
if (configs_[i].bitrate.max)
@ -203,6 +211,45 @@ TEST_P(ResolutionBitrateLimitsTest, LimitsApplied) {
RunBaseTest(&test);
}
TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
OneStreamLimitsAppliedForOneSpatialLayer) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-GetEncoderInfoOverride/"
"frame_size_pixels:921600,"
"min_start_bitrate_bps:0,"
"min_bitrate_bps:32000,"
"max_bitrate_bps:3333000/");
InitEncodeTest test(
"VP9", {{.active = true, .scalability_mode = ScalabilityMode::kL1T1}},
// Expectations:
{{.pixels = 1280 * 720,
.eq_bitrate = {DataRate::KilobitsPerSec(32),
DataRate::KilobitsPerSec(3333)}}});
RunBaseTest(&test);
}
TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
OneStreamLimitsNotAppliedForMultipleSpatialLayers) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-GetEncoderInfoOverride/"
"frame_size_pixels:230400|921600,"
"min_start_bitrate_bps:0|0,"
"min_bitrate_bps:21000|32000,"
"max_bitrate_bps:2222000|3333000/");
InitEncodeTest test(
"VP9", {{.active = true, .scalability_mode = ScalabilityMode::kL2T1}},
// Expectations:
{{.pixels = 640 * 360,
.ne_bitrate = {DataRate::KilobitsPerSec(31),
DataRate::KilobitsPerSec(2222)}},
{.pixels = 1280 * 720,
.ne_bitrate = {DataRate::KilobitsPerSec(32),
DataRate::KilobitsPerSec(3333)}}});
RunBaseTest(&test);
}
TEST_P(ResolutionBitrateLimitsTest, EncodingsApplied) {
InitEncodeTest test(payload_name_,
{{.active = true,
@ -248,7 +295,6 @@ TEST_P(ResolutionBitrateLimitsTest, LimitsAppliedMiddleActive) {
{{.pixels = 640 * 360,
.eq_bitrate = {DataRate::KilobitsPerSec(21),
DataRate::KilobitsPerSec(2222)}}});
RunBaseTest(&test);
}
@ -287,7 +333,26 @@ TEST_P(ResolutionBitrateLimitsTest, DefaultLimitsAppliedMiddleActive) {
DataRate::BitsPerSec(kDefaultSinglecastLimits360p->min_bitrate_bps),
DataRate::BitsPerSec(
kDefaultSinglecastLimits360p->max_bitrate_bps)}}});
RunBaseTest(&test);
}
TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
DefaultLimitsAppliedForOneSpatialLayer) {
const absl::optional<VideoEncoder::ResolutionBitrateLimits>
kDefaultSinglecastLimits720p =
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution(
PayloadStringToCodecType("VP9"), 1280 * 720);
InitEncodeTest test(
"VP9",
{{.active = true, .scalability_mode = ScalabilityMode::kL1T3},
{.active = false}},
// Expectations:
{{.pixels = 1280 * 720,
.eq_bitrate = {
DataRate::BitsPerSec(kDefaultSinglecastLimits720p->min_bitrate_bps),
DataRate::BitsPerSec(
kDefaultSinglecastLimits720p->max_bitrate_bps)}}});
RunBaseTest(&test);
}
@ -348,6 +413,49 @@ TEST_P(ResolutionBitrateLimitsTest, LimitsNotAppliedLowestActive) {
RunBaseTest(&test);
}
TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
LimitsAppliedForVp9OneSpatialLayer) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-GetEncoderInfoOverride/"
"frame_size_pixels:230400|921600,"
"min_start_bitrate_bps:0|0,"
"min_bitrate_bps:31000|32000,"
"max_bitrate_bps:2222000|3333000/");
InitEncodeTest test(
"VP9",
{{.active = true, .scalability_mode = ScalabilityMode::kL1T1},
{.active = false}},
// Expectations:
{{.pixels = 1280 * 720,
.eq_bitrate = {DataRate::KilobitsPerSec(32),
DataRate::KilobitsPerSec(3333)}}});
RunBaseTest(&test);
}
TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest,
LimitsNotAppliedForVp9MultipleSpatialLayers) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-GetEncoderInfoOverride/"
"frame_size_pixels:230400|921600,"
"min_start_bitrate_bps:0|0,"
"min_bitrate_bps:31000|32000,"
"max_bitrate_bps:2222000|3333000/");
InitEncodeTest test(
"VP9",
{{.active = true, .scalability_mode = ScalabilityMode::kL2T1},
{.active = false}},
// Expectations:
{{.pixels = 640 * 360,
.ne_bitrate = {DataRate::KilobitsPerSec(31),
DataRate::KilobitsPerSec(2222)}},
{.pixels = 1280 * 720,
.ne_bitrate = {DataRate::KilobitsPerSec(32),
DataRate::KilobitsPerSec(3333)}}});
RunBaseTest(&test);
}
TEST_P(ResolutionBitrateLimitsTest, LimitsNotAppliedSimulcast) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-GetEncoderInfoOverride/"

View File

@ -64,12 +64,21 @@ class QualityScalingTest : public test::CallTest {
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution(
kVideoCodecVP9,
640 * 360);
const absl::optional<VideoEncoder::ResolutionBitrateLimits>
kSinglecastLimits720pVp9 =
EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution(
kVideoCodecVP9,
1280 * 720);
};
class ScalingObserver : public test::SendTest {
protected:
struct TestParams {
bool active;
absl::optional<ScalabilityMode> scalability_mode;
};
ScalingObserver(const std::string& payload_name,
const std::vector<bool>& streams_active,
const std::vector<TestParams>& test_params,
int start_bps,
bool automatic_resize,
bool expect_scaling)
@ -86,7 +95,7 @@ class ScalingObserver : public test::SendTest {
return nullptr;
}),
payload_name_(payload_name),
streams_active_(streams_active),
test_params_(test_params),
start_bps_(start_bps),
automatic_resize_(automatic_resize),
expect_scaling_(expect_scaling) {}
@ -105,7 +114,7 @@ class ScalingObserver : public test::SendTest {
}
size_t GetNumVideoStreams() const override {
return (payload_name_ == "VP9") ? 1 : streams_active_.size();
return (payload_name_ == "VP9") ? 1 : test_params_.size();
}
void ModifyVideoConfigs(
@ -122,27 +131,28 @@ class ScalingObserver : public test::SendTest {
std::max(start_bps_, encoder_config->max_bitrate_bps);
if (payload_name_ == "VP9") {
// Simulcast layers indicates which spatial layers are active.
encoder_config->simulcast_layers.resize(streams_active_.size());
encoder_config->simulcast_layers.resize(test_params_.size());
encoder_config->simulcast_layers[0].max_bitrate_bps =
encoder_config->max_bitrate_bps;
}
double scale_factor = 1.0;
for (int i = streams_active_.size() - 1; i >= 0; --i) {
for (int i = test_params_.size() - 1; i >= 0; --i) {
VideoStream& stream = encoder_config->simulcast_layers[i];
stream.active = streams_active_[i];
stream.active = test_params_[i].active;
stream.scalability_mode = test_params_[i].scalability_mode;
stream.scale_resolution_down_by = scale_factor;
scale_factor *= (payload_name_ == "VP9") ? 1.0 : 2.0;
}
encoder_config->frame_drop_enabled = true;
SetEncoderSpecific(encoder_config, codec_type, automatic_resize_,
streams_active_.size());
test_params_.size());
}
void PerformTest() override { EXPECT_EQ(expect_scaling_, Wait()); }
test::FunctionVideoEncoderFactory encoder_factory_;
const std::string payload_name_;
const std::vector<bool> streams_active_;
const std::vector<TestParams> test_params_;
const int start_bps_;
const bool automatic_resize_;
const bool expect_scaling_;
@ -153,12 +163,12 @@ class DownscalingObserver
public test::FrameGeneratorCapturer::SinkWantsObserver {
public:
DownscalingObserver(const std::string& payload_name,
const std::vector<bool>& streams_active,
const std::vector<TestParams>& test_params,
int start_bps,
bool automatic_resize,
bool expect_downscale)
: ScalingObserver(payload_name,
streams_active,
test_params,
start_bps,
automatic_resize,
expect_downscale) {}
@ -182,12 +192,12 @@ class UpscalingObserver
public test::FrameGeneratorCapturer::SinkWantsObserver {
public:
UpscalingObserver(const std::string& payload_name,
const std::vector<bool>& streams_active,
const std::vector<TestParams>& test_params,
int start_bps,
bool automatic_resize,
bool expect_upscale)
: ScalingObserver(payload_name,
streams_active,
test_params,
start_bps,
automatic_resize,
expect_upscale) {}
@ -220,7 +230,7 @@ TEST_F(QualityScalingTest, AdaptsDownForHighQp_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,1,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true}, kHighStartBps,
DownscalingObserver test("VP8", {{.active = true}}, kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
@ -231,7 +241,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForHighQpIfScalingOff_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,1,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true}, kHighStartBps,
DownscalingObserver test("VP8", {{.active = true}}, kHighStartBps,
/*automatic_resize=*/false,
/*expect_downscale=*/false);
RunBaseTest(&test);
@ -242,7 +252,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForNormalQp_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true}, kHighStartBps,
DownscalingObserver test("VP8", {{.active = true}}, kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
@ -253,7 +263,7 @@ TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrate_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true}, kLowStartBps,
DownscalingObserver test("VP8", {{.active = true}}, kLowStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
@ -267,8 +277,7 @@ TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrateAndThenUp) {
"WebRTC-Video-BalancedDegradationSettings/"
"pixels:230400|921600,fps:20|30,kbps:300|500/"); // should not affect
UpscalingObserver test("VP8", /*streams_active=*/{true},
kDefaultVgaMinStartBps - 1,
UpscalingObserver test("VP8", {{.active = true}}, kDefaultVgaMinStartBps - 1,
/*automatic_resize=*/true, /*expect_upscale=*/true);
RunBaseTest(&test);
}
@ -280,8 +289,7 @@ TEST_F(QualityScalingTest, AdaptsDownAndThenUpWithBalanced) {
"WebRTC-Video-BalancedDegradationSettings/"
"pixels:230400|921600,fps:20|30,kbps:300|499/");
UpscalingObserver test("VP8", /*streams_active=*/{true},
kDefaultVgaMinStartBps - 1,
UpscalingObserver test("VP8", {{.active = true}}, kDefaultVgaMinStartBps - 1,
/*automatic_resize=*/true, /*expect_upscale=*/true);
test.SetDegradationPreference(DegradationPreference::BALANCED);
RunBaseTest(&test);
@ -294,8 +302,7 @@ TEST_F(QualityScalingTest, AdaptsDownButNotUpWithBalancedIfBitrateNotEnough) {
"WebRTC-Video-BalancedDegradationSettings/"
"pixels:230400|921600,fps:20|30,kbps:300|500/");
UpscalingObserver test("VP8", /*streams_active=*/{true},
kDefaultVgaMinStartBps - 1,
UpscalingObserver test("VP8", {{.active = true}}, kDefaultVgaMinStartBps - 1,
/*automatic_resize=*/true, /*expect_upscale=*/false);
test.SetDegradationPreference(DegradationPreference::BALANCED);
RunBaseTest(&test);
@ -306,7 +313,8 @@ TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrate_Simulcast) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true, true}, kLowStartBps,
DownscalingObserver test("VP8", {{.active = true}, {.active = true}},
kLowStartBps,
/*automatic_resize=*/false,
/*expect_downscale=*/false);
RunBaseTest(&test);
@ -317,10 +325,11 @@ TEST_F(QualityScalingTest, AdaptsDownForHighQp_HighestStreamActive_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,1,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{false, false, true},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
DownscalingObserver test(
"VP8", {{.active = false}, {.active = false}, {.active = true}},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
}
@ -330,10 +339,11 @@ TEST_F(QualityScalingTest,
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{false, false, true},
kSinglecastLimits720pVp8->min_start_bitrate_bps - 1,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
DownscalingObserver test(
"VP8", {{.active = false}, {.active = false}, {.active = true}},
kSinglecastLimits720pVp8->min_start_bitrate_bps - 1,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
}
@ -342,7 +352,7 @@ TEST_F(QualityScalingTest, AdaptsDownButNotUpWithMinStartBitrateLimit) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "127,127,0,0,0,0" + kEnd);
UpscalingObserver test("VP8", /*streams_active=*/{false, true},
UpscalingObserver test("VP8", {{.active = false}, {.active = true}},
kSinglecastLimits720pVp8->min_start_bitrate_bps - 1,
/*automatic_resize=*/true, /*expect_upscale=*/false);
RunBaseTest(&test);
@ -353,10 +363,11 @@ TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateIfBitrateEnough_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{false, false, true},
kSinglecastLimits720pVp8->min_start_bitrate_bps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
DownscalingObserver test(
"VP8", {{.active = false}, {.active = false}, {.active = true}},
kSinglecastLimits720pVp8->min_start_bitrate_bps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
@ -367,10 +378,11 @@ TEST_F(QualityScalingTest,
field_trials_, kPrefix + "1,127,0,0,0,0" + kEnd +
"WebRTC-DefaultBitrateLimitsKillSwitch/Enabled/");
DownscalingObserver test("VP8", /*streams_active=*/{false, false, true},
kSinglecastLimits720pVp8->min_start_bitrate_bps - 1,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
DownscalingObserver test(
"VP8", {{.active = false}, {.active = false}, {.active = true}},
kSinglecastLimits720pVp8->min_start_bitrate_bps - 1,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
@ -380,7 +392,7 @@ TEST_F(QualityScalingTest,
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true},
DownscalingObserver test("VP8", {{.active = true}},
kSinglecastLimits720pVp8->min_start_bitrate_bps - 1,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
@ -392,10 +404,11 @@ TEST_F(QualityScalingTest, NoAdaptDownForHighQp_LowestStreamActive_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,1,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true, false, false},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
DownscalingObserver test(
"VP8", {{.active = true}, {.active = false}, {.active = false}},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
@ -405,10 +418,11 @@ TEST_F(QualityScalingTest,
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true, false, false},
kLowStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
DownscalingObserver test(
"VP8", {{.active = true}, {.active = false}, {.active = false}},
kLowStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
@ -417,7 +431,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateIfScalingOff_Vp8) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "1,127,0,0,0,0" + kEnd);
DownscalingObserver test("VP8", /*streams_active=*/{true}, kLowStartBps,
DownscalingObserver test("VP8", {{.active = true}}, kLowStartBps,
/*automatic_resize=*/false,
/*expect_downscale=*/false);
RunBaseTest(&test);
@ -425,11 +439,10 @@ TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateIfScalingOff_Vp8) {
TEST_F(QualityScalingTest, AdaptsDownForHighQp_Vp9) {
// qp_low:1, qp_high:1 -> kHighQp
test::ScopedKeyValueConfig field_trials(
field_trials_,
kPrefix + "0,0,1,1,0,0" + kEnd + "WebRTC-VP9QualityScaler/Enabled/");
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,1,0,0" + kEnd);
DownscalingObserver test("VP9", /*streams_active=*/{true}, kHighStartBps,
DownscalingObserver test("VP9", {{.active = true}}, kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
@ -441,7 +454,7 @@ TEST_F(QualityScalingTest, NoAdaptDownForHighQpIfScalingOff_Vp9) {
field_trials_,
kPrefix + "0,0,1,1,0,0" + kEnd + "WebRTC-VP9QualityScaler/Disabled/");
DownscalingObserver test("VP9", /*streams_active=*/{true}, kHighStartBps,
DownscalingObserver test("VP9", {{.active = true}}, kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
@ -449,11 +462,10 @@ TEST_F(QualityScalingTest, NoAdaptDownForHighQpIfScalingOff_Vp9) {
TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrate_Vp9) {
// qp_low:1, qp_high:255 -> kNormalQp
test::ScopedKeyValueConfig field_trials(
field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd + "WebRTC-VP9QualityScaler/Enabled/");
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd);
DownscalingObserver test("VP9", /*streams_active=*/{true}, kLowStartBps,
DownscalingObserver test("VP9", {{.active = true}}, kLowStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
@ -461,68 +473,100 @@ TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrate_Vp9) {
TEST_F(QualityScalingTest, NoAdaptDownForHighQp_LowestStreamActive_Vp9) {
// qp_low:1, qp_high:1 -> kHighQp
test::ScopedKeyValueConfig field_trials(
field_trials_,
kPrefix + "0,0,1,1,0,0" + kEnd + "WebRTC-VP9QualityScaler/Enabled/");
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,1,0,0" + kEnd);
DownscalingObserver test("VP9", /*streams_active=*/{true, false, false},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
DownscalingObserver test(
"VP9", {{.active = true}, {.active = false}, {.active = false}},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
TEST_F(QualityScalingTest,
NoAdaptDownForLowStartBitrate_LowestStreamActive_Vp9) {
// qp_low:1, qp_high:255 -> kNormalQp
test::ScopedKeyValueConfig field_trials(
field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd + "WebRTC-VP9QualityScaler/Enabled/");
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd);
DownscalingObserver test("VP9", /*streams_active=*/{true, false, false},
kLowStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
DownscalingObserver test(
"VP9", {{.active = true}, {.active = false}, {.active = false}},
kLowStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
TEST_F(QualityScalingTest, AdaptsDownForHighQp_MiddleStreamActive_Vp9) {
// qp_low:1, qp_high:1 -> kHighQp
test::ScopedKeyValueConfig field_trials(
field_trials_,
kPrefix + "0,0,1,1,0,0" + kEnd + "WebRTC-VP9QualityScaler/Enabled/");
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,1,0,0" + kEnd);
DownscalingObserver test("VP9", /*streams_active=*/{false, true, false},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
DownscalingObserver test(
"VP9", {{.active = false}, {.active = true}, {.active = false}},
kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
}
TEST_F(QualityScalingTest,
AdaptsDownForLowStartBitrate_MiddleStreamActive_Vp9) {
// qp_low:1, qp_high:255 -> kNormalQp
test::ScopedKeyValueConfig field_trials(
field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd + "WebRTC-VP9QualityScaler/Enabled/");
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd);
DownscalingObserver test("VP9", /*streams_active=*/{false, true, false},
kSinglecastLimits360pVp9->min_start_bitrate_bps - 1,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
DownscalingObserver test(
"VP9", {{.active = false}, {.active = true}, {.active = false}},
kSinglecastLimits360pVp9->min_start_bitrate_bps - 1,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
}
TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateIfBitrateEnough_Vp9) {
// qp_low:1, qp_high:255 -> kNormalQp
test::ScopedKeyValueConfig field_trials(
field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd + "WebRTC-VP9QualityScaler/Enabled/");
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd);
DownscalingObserver test("VP9", /*streams_active=*/{false, true, false},
kSinglecastLimits360pVp9->min_start_bitrate_bps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
DownscalingObserver test(
"VP9", {{.active = false}, {.active = true}, {.active = false}},
kSinglecastLimits360pVp9->min_start_bitrate_bps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
TEST_F(QualityScalingTest,
AdaptsDownButNotUpWithMinStartBitrateLimitWithScalabilityMode_VP9) {
// qp_low:255, qp_high:255 -> kLowQp
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,255,255,0,0" + kEnd);
UpscalingObserver test(
"VP9",
{{.active = true, .scalability_mode = ScalabilityMode::kL1T3},
{.active = false}},
kSinglecastLimits720pVp9->min_start_bitrate_bps - 1,
/*automatic_resize=*/true, /*expect_upscale=*/false);
RunBaseTest(&test);
}
TEST_F(QualityScalingTest,
NoAdaptDownForLowStartBitrateIfBitrateEnoughWithScalabilityMode_Vp9) {
// qp_low:1, qp_high:255 -> kNormalQp
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,1,255,0,0" + kEnd);
DownscalingObserver test(
"VP9",
{{.active = true, .scalability_mode = ScalabilityMode::kL1T3},
{.active = false},
{.active = false}},
kSinglecastLimits720pVp9->min_start_bitrate_bps,
/*automatic_resize=*/true,
/*expect_downscale=*/false);
RunBaseTest(&test);
}
@ -532,7 +576,7 @@ TEST_F(QualityScalingTest, AdaptsDownForHighQp_H264) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,0,0,1,1" + kEnd);
DownscalingObserver test("H264", /*streams_active=*/{true}, kHighStartBps,
DownscalingObserver test("H264", {{.active = true}}, kHighStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);
@ -543,7 +587,7 @@ TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrate_H264) {
test::ScopedKeyValueConfig field_trials(field_trials_,
kPrefix + "0,0,0,0,1,51" + kEnd);
DownscalingObserver test("H264", /*streams_active=*/{true}, kLowStartBps,
DownscalingObserver test("H264", {{.active = true}}, kLowStartBps,
/*automatic_resize=*/true,
/*expect_downscale=*/true);
RunBaseTest(&test);

View File

@ -381,7 +381,8 @@ void ApplyVp9BitrateLimits(const VideoEncoder::EncoderInfo& encoder_info,
VideoCodec* codec) {
if (codec->codecType != VideoCodecType::kVideoCodecVP9 ||
encoder_config.simulcast_layers.size() <= 1 ||
VideoStreamEncoderResourceManager::IsSimulcast(encoder_config)) {
VideoStreamEncoderResourceManager::IsSimulcastOrMultipleSpatialLayers(
encoder_config)) {
// Resolution bitrate limits usage is restricted to singlecast.
return;
}