diff --git a/rtc_base/experiments/encoder_info_settings.cc b/rtc_base/experiments/encoder_info_settings.cc index e643c70877..c5f544ee07 100644 --- a/rtc_base/experiments/encoder_info_settings.cc +++ b/rtc_base/experiments/encoder_info_settings.cc @@ -46,11 +46,10 @@ EncoderInfoSettings::GetDefaultSinglecastBitrateLimits( // The min bitrate limits are not used in singlecast (used in SVC/simulcast // to de-/activate spatial layers) and are set to zero. Send resolution in // singlecast is assumed to be regulated by QP-based quality scaler. - return {{320 * 180, 0, 0, 256000}, - {480 * 270, 176000, 0, 384000}, - {640 * 360, 256000, 0, 512000}, - {960 * 540, 384000, 0, 1024000}, - {1280 * 720, 576000, 0, 1536000}}; + return { + {320 * 180, 0, 0, 256000}, {480 * 270, 176000, 0, 384000}, + {640 * 360, 256000, 0, 512000}, {960 * 540, 384000, 0, 1024000}, + {1280 * 720, 576000, 0, 1536000}, {1920 * 1080, 1000000, 0, 3700000}}; } if (codec_type == kVideoCodecVP9 || codec_type == kVideoCodecH265) { @@ -64,7 +63,8 @@ EncoderInfoSettings::GetDefaultSinglecastBitrateLimits( {480 * 270, 120000, 30000, 300000}, {640 * 360, 190000, 30000, 420000}, {960 * 540, 350000, 30000, 1000000}, - {1280 * 720, 480000, 30000, 1500000}}; + {1280 * 720, 480000, 30000, 1500000}, + {1920 * 1080, 1000000, 30000, 3700000}}; } // VP8 and other codecs. @@ -72,7 +72,8 @@ EncoderInfoSettings::GetDefaultSinglecastBitrateLimits( {480 * 270, 200000, 30000, 500000}, {640 * 360, 300000, 30000, 800000}, {960 * 540, 500000, 30000, 1500000}, - {1280 * 720, 900000, 30000, 2500000}}; + {1280 * 720, 900000, 30000, 2500000}, + {1920 * 1080, 2000000, 30000, 5000000}}; } std::optional diff --git a/video/config/encoder_stream_factory.cc b/video/config/encoder_stream_factory.cc index cb7f9f269c..ff17c9cb1f 100644 --- a/video/config/encoder_stream_factory.cc +++ b/video/config/encoder_stream_factory.cc @@ -409,7 +409,8 @@ EncoderStreamFactory::CreateDefaultVideoStreams( RTC_DCHECK_GE(sum_max_bitrates_kbps, 0); if (!api_max_bitrate_bps.has_value()) { max_bitrate_bps = sum_max_bitrates_kbps * 1000; - } else { + } else if (encoder_config.simulcast_layers[0].max_bitrate_bps <= 0) { + // Encoding max bitrate is kept if configured. max_bitrate_bps = std::min(max_bitrate_bps, sum_max_bitrates_kbps * 1000); } diff --git a/video/config/encoder_stream_factory_unittest.cc b/video/config/encoder_stream_factory_unittest.cc index 25ba15a579..605d0d4eb9 100644 --- a/video/config/encoder_stream_factory_unittest.cc +++ b/video/config/encoder_stream_factory_unittest.cc @@ -488,4 +488,20 @@ TEST(EncoderStreamFactory, H265TemporalLayerCountTransferToStreamSettings) { } #endif +TEST(EncoderStreamFactory, VP9SetsMaxBitrateToConfiguredEncodingValue) { + VideoEncoderConfig encoder_config; + VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings(); + encoder_config.encoder_specific_settings = + rtc::make_ref_counted( + vp9_settings); + encoder_config.codec_type = VideoCodecType::kVideoCodecVP9; + encoder_config.number_of_streams = 1; + encoder_config.simulcast_layers.resize(3); + encoder_config.simulcast_layers[0].max_bitrate_bps = 5000000; + auto streams = CreateEncoderStreams(ExplicitKeyValueConfig(""), {1280, 720}, + encoder_config); + ASSERT_THAT(streams, SizeIs(1)); + EXPECT_EQ(streams[0].max_bitrate_bps, 5000000); +} + } // 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 06eb71e366..2a411f77d1 100644 --- a/video/end_to_end_tests/resolution_bitrate_limits_tests.cc +++ b/video/end_to_end_tests/resolution_bitrate_limits_tests.cc @@ -344,15 +344,14 @@ TEST_P(ResolutionBitrateLimitsTest, LimitsAppliedMiddleActive) { RunBaseTest(&test); } -TEST_P(ResolutionBitrateLimitsTest, EncodingMinBitrateAppliedMiddleActive) { +TEST_P(ResolutionBitrateLimitsTest, EncodingMinMaxBitrateAppliedMiddleActive) { 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/"); + "max_bitrate_bps:1111000|3333000/"); - // Max bitrate: min of encoding and bitrate limits used. InitEncodeTest test(env(), payload_name_, {{.active = false, .bitrate = {DataRate::KilobitsPerSec(28), @@ -368,6 +367,49 @@ TEST_P(ResolutionBitrateLimitsTest, EncodingMinBitrateAppliedMiddleActive) { RunBaseTest(&test); } +TEST_P(ResolutionBitrateLimitsTest, MinBitrateNotAboveEncodingMax) { + 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:1111000|3333000/"); + + InitEncodeTest test( + env(), payload_name_, + {{.active = false}, + {.active = true, + .bitrate = {std::nullopt, DataRate::KilobitsPerSec(25)}}, + {.active = false}}, + // Expectations: + {{.pixels = 640 * 360, + .eq_bitrate = {DataRate::KilobitsPerSec(25), + DataRate::KilobitsPerSec(25)}}}); + RunBaseTest(&test); +} + +TEST_P(ResolutionBitrateLimitsTest, MaxBitrateNotBelowEncodingMin) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-GetEncoderInfoOverride/" + "frame_size_pixels:230400|921600," + "min_start_bitrate_bps:0|0," + "min_bitrate_bps:21000|22000," + "max_bitrate_bps:31000|32000/"); + + InitEncodeTest test( + env(), payload_name_, + {{.active = false, + .bitrate = {DataRate::KilobitsPerSec(50), std::nullopt}}, + {.active = true, + .bitrate = {DataRate::KilobitsPerSec(50), std::nullopt}}, + {.active = false}}, + // Expectations: + {{.pixels = 640 * 360, + .eq_bitrate = {DataRate::KilobitsPerSec(50), + DataRate::KilobitsPerSec(50)}}}); + RunBaseTest(&test); +} + TEST_P(ResolutionBitrateLimitsTest, DefaultLimitsAppliedMiddleActive) { const std::optional kDefaultSinglecastLimits360p = @@ -423,15 +465,14 @@ TEST_P(ResolutionBitrateLimitsTest, LimitsAppliedHighestActive) { RunBaseTest(&test); } -TEST_P(ResolutionBitrateLimitsTest, EncodingMinBitrateAppliedHighestActive) { +TEST_P(ResolutionBitrateLimitsTest, EncodingMinMaxBitrateAppliedHighestActive) { 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/"); + "max_bitrate_bps:555000|1111000/"); - // Max bitrate: min of encoding and bitrate limits used. InitEncodeTest test(env(), payload_name_, {{.active = false, .bitrate = {DataRate::KilobitsPerSec(28), @@ -552,15 +593,14 @@ TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest, } TEST_F(ResolutionBitrateLimitsWithScalabilityModeTest, - EncodingMinBitrateAppliedForAv1SingleSpatialLayer) { + EncodingMinMaxBitrateAppliedForAv1SingleSpatialLayer) { webrtc::test::ScopedFieldTrials field_trials( "WebRTC-GetEncoderInfoOverride/" "frame_size_pixels:921600," "min_start_bitrate_bps:0," "min_bitrate_bps:32000," - "max_bitrate_bps:133000/"); + "max_bitrate_bps:99000/"); - // Max bitrate: min of encoding and bitrate limits used. InitEncodeTest test(env(), "AV1", {{.active = true, .bitrate = {DataRate::KilobitsPerSec(28), diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index a7df42116d..18b13ea6b0 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -468,15 +468,15 @@ void ApplySpatialLayerBitrateLimits( if (encoder_config.simulcast_layers[*index].max_bitrate_bps <= 0) { max_bitrate_bps = bitrate_limits->max_bitrate_bps; } else { - max_bitrate_bps = - std::min(bitrate_limits->max_bitrate_bps, - encoder_config.simulcast_layers[*index].max_bitrate_bps); + max_bitrate_bps = encoder_config.simulcast_layers[*index].max_bitrate_bps; } - if (min_bitrate_bps >= max_bitrate_bps) { - RTC_LOG(LS_WARNING) << "Bitrate limits not used, min_bitrate_bps " - << min_bitrate_bps << " >= max_bitrate_bps " - << max_bitrate_bps; - return; + + if (encoder_config.simulcast_layers[*index].min_bitrate_bps > 0) { + // Ensure max is not below configured min. + max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps); + } else { + // Ensure min is not above max. + min_bitrate_bps = std::min(min_bitrate_bps, max_bitrate_bps); } for (int i = 0; i < GetNumSpatialLayers(*codec); ++i) { @@ -484,8 +484,9 @@ void ApplySpatialLayerBitrateLimits( codec->spatialLayers[i].minBitrate = min_bitrate_bps / 1000; codec->spatialLayers[i].maxBitrate = max_bitrate_bps / 1000; codec->spatialLayers[i].targetBitrate = - std::min(codec->spatialLayers[i].targetBitrate, - codec->spatialLayers[i].maxBitrate); + std::clamp(codec->spatialLayers[i].targetBitrate, + codec->spatialLayers[i].minBitrate, + codec->spatialLayers[i].maxBitrate); break; } } @@ -531,25 +532,21 @@ void ApplyEncoderBitrateLimitsIfSingleActiveStream( if (encoder_config_layers[index].max_bitrate_bps <= 0) { max_bitrate_bps = encoder_bitrate_limits->max_bitrate_bps; } else { - max_bitrate_bps = std::min(encoder_bitrate_limits->max_bitrate_bps, - (*streams)[index].max_bitrate_bps); + max_bitrate_bps = (*streams)[index].max_bitrate_bps; } - if (min_bitrate_bps >= max_bitrate_bps) { - RTC_LOG(LS_WARNING) << "Encoder bitrate limits" - << " (min=" << encoder_bitrate_limits->min_bitrate_bps - << ", max=" << encoder_bitrate_limits->max_bitrate_bps - << ") do not intersect with stream limits" - << " (min=" << (*streams)[index].min_bitrate_bps - << ", max=" << (*streams)[index].max_bitrate_bps - << "). Encoder bitrate limits not used."; - return; + + if (encoder_config_layers[index].min_bitrate_bps > 0) { + // Ensure max is not below configured min. + max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps); + } else { + // Ensure min is not above max. + min_bitrate_bps = std::min(min_bitrate_bps, max_bitrate_bps); } (*streams)[index].min_bitrate_bps = min_bitrate_bps; (*streams)[index].max_bitrate_bps = max_bitrate_bps; - (*streams)[index].target_bitrate_bps = - std::min((*streams)[index].target_bitrate_bps, - encoder_bitrate_limits->max_bitrate_bps); + (*streams)[index].target_bitrate_bps = std::clamp( + (*streams)[index].target_bitrate_bps, min_bitrate_bps, max_bitrate_bps); } std::optional ParseVp9LowTierCoreCountThreshold( diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc index 08e3a45607..417a42486d 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -2685,16 +2685,18 @@ TEST_F(VideoStreamEncoderTest, config.video_stream_factory = nullptr; video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength); - // The encoder bitrate limits for 270p should be used. + // The max configured bitrate should be used. + // The encoder bitrate limits for 270p should be used for min bitrate video_source_.IncomingCapturedFrame(CreateFrame(1, 480, 270)); video_stream_encoder_->WaitUntilTaskQueueIsIdle(); EXPECT_EQ(fake_encoder_.config().numberOfSimulcastStreams, kNumStreams); EXPECT_EQ(static_cast(kEncoderLimits270p.min_bitrate_bps), fake_encoder_.config().simulcastStream[1].minBitrate * 1000); - EXPECT_EQ(static_cast(kEncoderLimits270p.max_bitrate_bps), + EXPECT_EQ(static_cast(kMaxBitrateBps), fake_encoder_.config().simulcastStream[1].maxBitrate * 1000); - // The max configured bitrate is less than the encoder limit for 360p. + // The max configured bitrate should be used. + // The encoder bitrate limits for 360p should be used for min bitrate video_source_.IncomingCapturedFrame(CreateFrame(2, 640, 360)); video_stream_encoder_->WaitUntilTaskQueueIsIdle(); EXPECT_EQ(static_cast(kEncoderLimits360p.min_bitrate_bps),