From 2ee3e4db221d4b18529f8ad24be4c2c6466e3b11 Mon Sep 17 00:00:00 2001 From: Asa Persson Date: Fri, 20 May 2022 14:22:27 +0200 Subject: [PATCH] Use resolution bitrate limits if one spatial layer is configured via scalability mode. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:13960 Change-Id: Ie9238f3352b0d9d92fda97a250de0792e6bbfc9a Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261721 Commit-Queue: Åsa Persson Reviewed-by: Niels Moller Reviewed-by: Sergey Silkin Cr-Commit-Position: refs/heads/main@{#36948} --- video/adaptation/BUILD.gn | 2 + video/adaptation/bitrate_constraint.cc | 6 +- .../adaptation/bitrate_constraint_unittest.cc | 177 +++++++++++-- .../video_stream_encoder_resource_manager.cc | 21 +- .../video_stream_encoder_resource_manager.h | 3 +- .../resolution_bitrate_limits_tests.cc | 112 ++++++++- video/quality_scaling_tests.cc | 236 +++++++++++------- video/video_stream_encoder.cc | 3 +- 8 files changed, 432 insertions(+), 128 deletions(-) diff --git a/video/adaptation/BUILD.gn b/video/adaptation/BUILD.gn index b945142688..48e19c5894 100644 --- a/video/adaptation/BUILD.gn +++ b/video/adaptation/BUILD.gn @@ -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", diff --git a/video/adaptation/bitrate_constraint.cc b/video/adaptation/bitrate_constraint.cc index cd61e555cd..bc36723d48 100644 --- a/video/adaptation/bitrate_constraint.cc +++ b/video/adaptation/bitrate_constraint.cc @@ -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; diff --git a/video/adaptation/bitrate_constraint_unittest.cc b/video/adaptation/bitrate_constraint_unittest.cc index d7865a12ed..f9cb87e3c1 100644 --- a/video/adaptation/bitrate_constraint_unittest.cc +++ b/video/adaptation/bitrate_constraint_unittest.cc @@ -13,6 +13,7 @@ #include #include +#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 scalability_mode; +}; + void FillCodecConfig(VideoCodec* video_codec, VideoEncoderConfig* encoder_config, int width_px, int height_px, - std::vector active_flags) { - size_t num_layers = active_flags.size(); + const std::vector& 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 active_flags) { + const std::vector& 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); diff --git a/video/adaptation/video_stream_encoder_resource_manager.cc b/video/adaptation/video_stream_encoder_resource_manager.cc index 24bcd2c322..efca7ff77b 100644 --- a/video/adaptation/video_stream_encoder_resource_manager.cc +++ b/video/adaptation/video_stream_encoder_resource_manager.cc @@ -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& simulcast_layers = encoder_config.simulcast_layers; - if (simulcast_layers.size() <= 1) { + if (simulcast_layers.empty()) { return false; } - if (simulcast_layers[0].active) { + absl::optional 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; diff --git a/video/adaptation/video_stream_encoder_resource_manager.h b/video/adaptation/video_stream_encoder_resource_manager.h index 9e4b27140b..00c13e3663 100644 --- a/video/adaptation/video_stream_encoder_resource_manager.h +++ b/video/adaptation/video_stream_encoder_resource_manager.h @@ -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; diff --git a/video/end_to_end_tests/resolution_bitrate_limits_tests.cc b/video/end_to_end_tests/resolution_bitrate_limits_tests.cc index 1af69bf94b..591ddf9bb1 100644 --- a/video/end_to_end_tests/resolution_bitrate_limits_tests.cc +++ b/video/end_to_end_tests/resolution_bitrate_limits_tests.cc @@ -11,6 +11,7 @@ #include #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 { @@ -73,7 +76,10 @@ class ResolutionBitrateLimitsTest INSTANTIATE_TEST_SUITE_P(PayloadName, ResolutionBitrateLimitsTest, - ::testing::Values("VP8", "VP9")); + ::testing::Values("VP8", "VP9"), + [](const ::testing::TestParamInfo& 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 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 + 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/" diff --git a/video/quality_scaling_tests.cc b/video/quality_scaling_tests.cc index 966ba8f115..c8ac2f163e 100644 --- a/video/quality_scaling_tests.cc +++ b/video/quality_scaling_tests.cc @@ -64,12 +64,21 @@ class QualityScalingTest : public test::CallTest { EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution( kVideoCodecVP9, 640 * 360); + const absl::optional + kSinglecastLimits720pVp9 = + EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution( + kVideoCodecVP9, + 1280 * 720); }; class ScalingObserver : public test::SendTest { protected: + struct TestParams { + bool active; + absl::optional scalability_mode; + }; ScalingObserver(const std::string& payload_name, - const std::vector& streams_active, + const std::vector& 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 streams_active_; + const std::vector 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& streams_active, + const std::vector& 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& streams_active, + const std::vector& 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); diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index 68fc313739..1aa5f5e20e 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -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; }