diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc index 3a32a43622..43def0f6f3 100644 --- a/modules/video_coding/codecs/vp9/svc_config.cc +++ b/modules/video_coding/codecs/vp9/svc_config.cc @@ -203,12 +203,7 @@ std::vector GetVp9SvcConfig(VideoCodec& codec) { codec.GetScalabilityMode() ? info : absl::nullopt); RTC_DCHECK(!spatial_layers.empty()); - // Use codec bitrate limits if spatial layering is not requested. - if (info->num_spatial_layers == 1) { - spatial_layers.back().minBitrate = codec.minBitrate; - spatial_layers.back().targetBitrate = codec.maxBitrate; - spatial_layers.back().maxBitrate = codec.maxBitrate; - } + spatial_layers[0].minBitrate = kMinVp9SvcBitrateKbps; return spatial_layers; } diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc index b0b16d06f4..c468e99638 100644 --- a/modules/video_coding/video_codec_initializer.cc +++ b/modules/video_coding/video_codec_initializer.cc @@ -237,6 +237,13 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec( spatial_layers = GetVp9SvcConfig(video_codec); if (spatial_layers.empty()) break; + // Use codec bitrate limits if spatial layering is not requested. + if (config.simulcast_layers.size() <= 1 && + ScalabilityModeToNumSpatialLayers(*scalability_mode) == 1) { + spatial_layers.back().minBitrate = video_codec.minBitrate; + spatial_layers.back().targetBitrate = video_codec.maxBitrate; + spatial_layers.back().maxBitrate = video_codec.maxBitrate; + } } else { size_t first_active_layer = 0; for (size_t spatial_idx = 0; diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc index e6286804d5..b9d8465aa8 100644 --- a/modules/video_coding/video_codec_initializer_unittest.cc +++ b/modules/video_coding/video_codec_initializer_unittest.cc @@ -331,6 +331,22 @@ TEST_F(VideoCodecInitializerTest, kDefaultMaxBitrateBps / 1000); } +TEST_F(VideoCodecInitializerTest, + Vp9SingleSpatialLayerMaxBitrateIsEqualToCodecMaxBitrateWithL1T1) { + SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 1, 1, false); + VideoStream stream = DefaultStream(); + stream.num_temporal_layers = 1; + stream.scalability_mode = ScalabilityMode::kL1T1; + streams_.push_back(stream); + + EXPECT_TRUE(InitializeCodec()); + EXPECT_EQ(1u, codec_out_.VP9()->numberOfSpatialLayers); + EXPECT_EQ(codec_out_.spatialLayers[0].minBitrate, + kDefaultMinBitrateBps / 1000); + EXPECT_EQ(codec_out_.spatialLayers[0].maxBitrate, + kDefaultMaxBitrateBps / 1000); +} + TEST_F(VideoCodecInitializerTest, Vp9SingleSpatialLayerTargetBitrateIsEqualToCodecMaxBitrate) { SetUpFor(VideoCodecType::kVideoCodecVP9, absl::nullopt, 1, 1, true); @@ -360,6 +376,27 @@ TEST_F(VideoCodecInitializerTest, kDefaultMaxBitrateBps / 1000); } +TEST_F(VideoCodecInitializerTest, + Vp9KeepBitrateLimitsIfNumberOfSpatialLayersIsReducedToOneWithL3T1) { + // Request 3 spatial layers for 320x180 input. Actual number of layers will be + // reduced to 1 due to low input resolution but SVC bitrate limits should be + // applied. + SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 3, 1, false); + VideoStream stream = DefaultStream(); + stream.width = 320; + stream.height = 180; + stream.num_temporal_layers = 1; + stream.scalability_mode = ScalabilityMode::kL3T1; + streams_.push_back(stream); + + EXPECT_TRUE(InitializeCodec()); + EXPECT_EQ(1u, codec_out_.VP9()->numberOfSpatialLayers); + EXPECT_LT(codec_out_.spatialLayers[0].minBitrate, + kDefaultMinBitrateBps / 1000); + EXPECT_LT(codec_out_.spatialLayers[0].maxBitrate, + kDefaultMaxBitrateBps / 1000); +} + TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) { SetUpFor(VideoCodecType::kVideoCodecVP9, absl::nullopt, 3, 1, false); VideoStream stream = DefaultStream(); @@ -537,4 +574,55 @@ TEST_F(VideoCodecInitializerTest, Av1TwoSpatialLayersOneDeactivated) { EXPECT_FALSE(codec.spatialLayers[1].active); } +TEST_F(VideoCodecInitializerTest, Vp9SingleSpatialLayerBitratesAreConsistent) { + VideoEncoderConfig config; + config.simulcast_layers.resize(3); + config.simulcast_layers[0].active = true; + config.simulcast_layers[1].active = false; + config.simulcast_layers[2].active = false; + + config.codec_type = VideoCodecType::kVideoCodecVP9; + std::vector streams = {DefaultStream()}; + streams[0].scalability_mode = ScalabilityMode::kL1T2; + + VideoCodec codec; + EXPECT_TRUE(VideoCodecInitializer::SetupCodec(config, streams, &codec)); + + EXPECT_EQ(1u, codec.VP9()->numberOfSpatialLayers); + EXPECT_GE(codec.spatialLayers[0].targetBitrate, + codec.spatialLayers[0].minBitrate); + EXPECT_LE(codec.spatialLayers[0].targetBitrate, + codec.spatialLayers[0].maxBitrate); + EXPECT_LT(codec.spatialLayers[0].minBitrate, kDefaultMinBitrateBps / 1000); +} + +TEST_F(VideoCodecInitializerTest, Vp9TwoSpatialLayersBitratesAreConsistent) { + VideoEncoderConfig config; + config.simulcast_layers.resize(3); + config.simulcast_layers[0].active = true; + config.simulcast_layers[1].active = false; + config.simulcast_layers[2].active = false; + + config.codec_type = VideoCodecType::kVideoCodecVP9; + std::vector streams = {DefaultStream()}; + streams[0].scalability_mode = ScalabilityMode::kL2T2; + + VideoCodec codec; + EXPECT_TRUE(VideoCodecInitializer::SetupCodec(config, streams, &codec)); + + EXPECT_EQ(2u, codec.VP9()->numberOfSpatialLayers); + EXPECT_GE(codec.spatialLayers[0].targetBitrate, + codec.spatialLayers[0].minBitrate); + EXPECT_LE(codec.spatialLayers[0].targetBitrate, + codec.spatialLayers[0].maxBitrate); + EXPECT_LT(codec.spatialLayers[0].minBitrate, kDefaultMinBitrateBps / 1000); + + EXPECT_GE(codec.spatialLayers[1].targetBitrate, + codec.spatialLayers[1].minBitrate); + EXPECT_LE(codec.spatialLayers[1].targetBitrate, + codec.spatialLayers[1].maxBitrate); + EXPECT_GT(codec.spatialLayers[1].minBitrate, + codec.spatialLayers[0].maxBitrate); +} + } // namespace webrtc 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 d5503391cd..86167ac75e 100644 --- a/video/end_to_end_tests/resolution_bitrate_limits_tests.cc +++ b/video/end_to_end_tests/resolution_bitrate_limits_tests.cc @@ -228,6 +228,33 @@ TEST_P(ResolutionBitrateLimitsTest, LimitsApplied) { RunBaseTest(&test); } +TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest, + OneStreamDefaultMaxBitrateAppliedForOneSpatialLayer) { + InitEncodeTest test("VP9", + {{.active = true, + .bitrate = {DataRate::KilobitsPerSec(30), + DataRate::KilobitsPerSec(3000)}, + .scalability_mode = ScalabilityMode::kL1T1}}, + // Expectations: + {{.pixels = 1280 * 720, + .eq_bitrate = {DataRate::KilobitsPerSec(30), + DataRate::KilobitsPerSec(3000)}}}); + RunBaseTest(&test); +} + +TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest, + OneStreamSvcMaxBitrateAppliedForTwoSpatialLayers) { + InitEncodeTest test( + "VP9", + {{.active = true, + .bitrate = {DataRate::KilobitsPerSec(30), + DataRate::KilobitsPerSec(3000)}, + .scalability_mode = ScalabilityMode::kL2T1}}, + // Expectations: + {{.pixels = 1280 * 720, + .ne_bitrate = {absl::nullopt, DataRate::KilobitsPerSec(3000)}}}); + RunBaseTest(&test); +} TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest, OneStreamLimitsAppliedForOneSpatialLayer) { webrtc::test::ScopedFieldTrials field_trials(