diff --git a/media/BUILD.gn b/media/BUILD.gn index 726a66df6b..3c8008a889 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -274,6 +274,7 @@ rtc_static_library("rtc_audio_video") { "../api/transport:datagram_transport_interface", "../api/transport/media:media_transport_interface", "../api/transport/rtp:rtp_source", + "../api/units:data_rate", "../api/video:video_bitrate_allocation", "../api/video:video_bitrate_allocator_factory", "../api/video:video_codec_constants", @@ -302,6 +303,7 @@ rtc_static_library("rtc_audio_video") { "../rtc_base:stringutils", "../rtc_base/experiments:experimental_screenshare_settings", "../rtc_base/experiments:field_trial_parser", + "../rtc_base/experiments:min_video_bitrate_experiment", "../rtc_base/experiments:normalize_simulcast_size_experiment", "../rtc_base/system:rtc_export", "../rtc_base/third_party/base64", @@ -565,6 +567,7 @@ if (rtc_include_tests) { "../rtc_base:rtc_base_tests_utils", "../rtc_base:rtc_task_queue", "../rtc_base:stringutils", + "../rtc_base/experiments:min_video_bitrate_experiment", "../rtc_base/third_party/sigslot", "../test:audio_codec_mocks", "../test:field_trial", diff --git a/media/engine/constants.cc b/media/engine/constants.cc index 9adfa41925..12d6ddde5a 100644 --- a/media/engine/constants.cc +++ b/media/engine/constants.cc @@ -12,9 +12,8 @@ namespace cricket { -const int kMinVideoBitrateBps = 30000; const int kVideoMtu = 1200; const int kVideoRtpSendBufferSize = 65536; const int kVideoRtpRecvBufferSize = 262144; -const char kMinVideoBitrateExperiment[] = "WebRTC-Video-MinVideoBitrate"; + } // namespace cricket diff --git a/media/engine/constants.h b/media/engine/constants.h index d52505db69..0abae3d407 100644 --- a/media/engine/constants.h +++ b/media/engine/constants.h @@ -19,9 +19,6 @@ extern const int kVideoRtpRecvBufferSize; extern const char kH264CodecName[]; -extern const int kMinVideoBitrateBps; -extern const char kMinVideoBitrateExperiment[]; - } // namespace cricket #endif // MEDIA_ENGINE_CONSTANTS_H_ diff --git a/media/engine/simulcast.cc b/media/engine/simulcast.cc index b8e7a6caa5..40135f4027 100644 --- a/media/engine/simulcast.cc +++ b/media/engine/simulcast.cc @@ -19,11 +19,11 @@ #include "absl/types/optional.h" #include "api/video/video_codec_constants.h" #include "media/base/media_constants.h" -#include "media/engine/constants.h" #include "modules/video_coding/utility/simulcast_rate_allocator.h" #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" #include "rtc_base/experiments/experimental_screenshare_settings.h" +#include "rtc_base/experiments/min_video_bitrate_experiment.h" #include "rtc_base/experiments/normalize_simulcast_size_experiment.h" #include "rtc_base/logging.h" #include "system_wrappers/include/field_trial.h" @@ -335,7 +335,7 @@ std::vector GetScreenshareLayers( layers[0].height = height; layers[0].max_qp = max_qp; layers[0].max_framerate = 5; - layers[0].min_bitrate_bps = kMinVideoBitrateBps; + layers[0].min_bitrate_bps = webrtc::kDefaultMinVideoBitrateBps; layers[0].target_bitrate_bps = kScreenshareDefaultTl0BitrateKbps * 1000; layers[0].max_bitrate_bps = kScreenshareDefaultTl1BitrateKbps * 1000; layers[0].num_temporal_layers = temporal_layers_supported ? 2 : 0; diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 96a426d88d..7bce942105 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -20,6 +20,7 @@ #include "absl/algorithm/container.h" #include "absl/strings/match.h" #include "api/transport/datagram_transport_interface.h" +#include "api/units/data_rate.h" #include "api/video/video_codec_constants.h" #include "api/video/video_codec_type.h" #include "api/video_codecs/sdp_video_format.h" @@ -33,7 +34,9 @@ #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/experiments/field_trial_units.h" +#include "rtc_base/experiments/min_video_bitrate_experiment.h" #include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/strings/string_builder.h" #include "rtc_base/time_utils.h" #include "rtc_base/trace_event.h" @@ -298,46 +301,6 @@ absl::optional GetVp9TemporalLayersFromFieldTrial() { return absl::nullopt; } -const char kForcedFallbackFieldTrial[] = - "WebRTC-VP8-Forced-Fallback-Encoder-v2"; - -absl::optional GetFallbackMinBpsFromFieldTrial( - webrtc::VideoCodecType type) { - if (type != webrtc::kVideoCodecVP8) - return absl::nullopt; - - if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) - return absl::nullopt; - - std::string group = - webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial); - if (group.empty()) - return absl::nullopt; - - int min_pixels; - int max_pixels; - int min_bps; - if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, - &min_bps) != 3) { - return absl::nullopt; - } - - if (min_bps <= 0) - return absl::nullopt; - - return min_bps; -} - -int GetMinVideoBitrateBps(webrtc::VideoCodecType type) { - if (GetFallbackMinBpsFromFieldTrial(type).has_value()) { - return GetFallbackMinBpsFromFieldTrial(type).value(); - } - if (webrtc::field_trial::IsEnabled(kMinVideoBitrateExperiment)) { - return MinVideoBitrateConfig().min_video_bitrate->bps(); - } - return kMinVideoBitrateBps; -} - // Returns its smallest positive argument. If neither argument is positive, // returns an arbitrary nonpositive value. int MinPositive(int a, int b) { @@ -3069,6 +3032,9 @@ std::vector EncoderStreamFactory::CreateEncoderStreams( encoder_config.number_of_streams); std::vector layers; + const absl::optional experimental_min_bitrate = + GetExperimentalMinVideoBitrate(encoder_config.codec_type); + if (encoder_config.number_of_streams > 1 || ((absl::EqualsIgnoreCase(codec_name_, kVp8CodecName) || absl::EqualsIgnoreCase(codec_name_, kH264CodecName)) && @@ -3082,6 +3048,12 @@ std::vector EncoderStreamFactory::CreateEncoderStreams( encoder_config.bitrate_priority, max_qp_, is_screenshare_ && conference_mode_, temporal_layers_supported); + // Allow an experiment to override the minimum bitrate for the lowest + // spatial layer. The experiment's configuration has the lowest priority. + if (experimental_min_bitrate) { + layers[0].min_bitrate_bps = + rtc::saturated_cast(experimental_min_bitrate->bps()); + } // The maximum |max_framerate| is currently used for video. const int max_framerate = GetMaxFramerate(encoder_config, layers.size()); // Update the active simulcast layers and configured bitrates. @@ -3170,7 +3142,10 @@ std::vector EncoderStreamFactory::CreateEncoderStreams( : GetMaxDefaultVideoBitrateKbps(width, height, is_screenshare_) * 1000; - int min_bitrate_bps = GetMinVideoBitrateBps(encoder_config.codec_type); + int min_bitrate_bps = + experimental_min_bitrate + ? rtc::saturated_cast(experimental_min_bitrate->bps()) + : webrtc::kDefaultMinVideoBitrateBps; if (encoder_config.simulcast_layers[0].min_bitrate_bps > 0) { // Use set min bitrate. min_bitrate_bps = encoder_config.simulcast_layers[0].min_bitrate_bps; diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h index b989e22f88..6e4830494a 100644 --- a/media/engine/webrtc_video_engine.h +++ b/media/engine/webrtc_video_engine.h @@ -33,11 +33,9 @@ #include "media/engine/unhandled_packets_buffer.h" #include "rtc_base/async_invoker.h" #include "rtc_base/critical_section.h" -#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/network_route.h" #include "rtc_base/thread_annotations.h" #include "rtc_base/thread_checker.h" -#include "system_wrappers/include/field_trial.h" namespace webrtc { class VideoDecoderFactory; @@ -51,17 +49,6 @@ class Thread; namespace cricket { -struct MinVideoBitrateConfig { - webrtc::FieldTrialParameter min_video_bitrate; - - MinVideoBitrateConfig() - : min_video_bitrate("br", webrtc::DataRate::bps(kMinVideoBitrateBps)) { - webrtc::ParseFieldTrial( - {&min_video_bitrate}, - webrtc::field_trial::FindFullName(kMinVideoBitrateExperiment)); - } -}; - class WebRtcVideoChannel; class UnsignalledSsrcHandler { diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc index 1ed3dc3f17..b4a0a6195a 100644 --- a/media/engine/webrtc_video_engine_unittest.cc +++ b/media/engine/webrtc_video_engine_unittest.cc @@ -52,6 +52,7 @@ #include "media/engine/simulcast.h" #include "media/engine/webrtc_voice_engine.h" #include "rtc_base/arraysize.h" +#include "rtc_base/experiments/min_video_bitrate_experiment.h" #include "rtc_base/fake_clock.h" #include "rtc_base/gunit.h" #include "rtc_base/numerics/safe_conversions.h" @@ -3489,7 +3490,7 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(WebRtcVideoChannelTest, VerifyMinBitrate) { std::vector streams = AddSendStream()->GetVideoStreams(); ASSERT_EQ(1u, streams.size()); - EXPECT_EQ(cricket::kMinVideoBitrateBps, streams[0].min_bitrate_bps); + EXPECT_EQ(webrtc::kDefaultMinVideoBitrateBps, streams[0].min_bitrate_bps); } TEST_F(WebRtcVideoChannelTest, VerifyMinBitrateWithForcedFallbackFieldTrial) { @@ -5862,12 +5863,13 @@ TEST_F(WebRtcVideoChannelTest, // we are just testing the behavior of // EncoderStreamFactory::CreateEncoderStreams. ASSERT_EQ(1UL, stream->GetVideoStreams().size()); - EXPECT_EQ(kMinVideoBitrateBps, stream->GetVideoStreams()[0].min_bitrate_bps); + EXPECT_EQ(webrtc::kDefaultMinVideoBitrateBps, + stream->GetVideoStreams()[0].min_bitrate_bps); // Set a low max bitrate & check that VideoStream.min_bitrate_bps is limited // by this amount. parameters = channel_->GetRtpSendParameters(last_ssrc_); - int low_max_bitrate_bps = kMinVideoBitrateBps - 1000; + int low_max_bitrate_bps = webrtc::kDefaultMinVideoBitrateBps - 1000; parameters.encodings[0].max_bitrate_bps = low_max_bitrate_bps; EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok()); @@ -5905,7 +5907,8 @@ TEST_F(WebRtcVideoChannelTest, ExpectSetMaxBitrate(send_parameters_.max_bandwidth_bps); ASSERT_TRUE(channel_->SetSendParameters(send_parameters_)); ASSERT_EQ(1UL, stream->GetVideoStreams().size()); - EXPECT_EQ(kMinVideoBitrateBps, stream->GetVideoStreams()[0].min_bitrate_bps); + EXPECT_EQ(webrtc::kDefaultMinVideoBitrateBps, + stream->GetVideoStreams()[0].min_bitrate_bps); EXPECT_EQ(send_parameters_.max_bandwidth_bps, stream->GetVideoStreams()[0].max_bitrate_bps); @@ -7070,7 +7073,7 @@ TEST_F(WebRtcVideoChannelTest, DefaultMinAndMaxBitratePropagatedToEncoder) { // FakeVideoSendStream calls CreateEncoderStreams, test that the vector of // VideoStreams are created appropriately. EXPECT_EQ(1u, stream->GetVideoStreams().size()); - EXPECT_EQ(cricket::kMinVideoBitrateBps, + EXPECT_EQ(webrtc::kDefaultMinVideoBitrateBps, stream->GetVideoStreams()[0].min_bitrate_bps); EXPECT_GT(stream->GetVideoStreams()[0].max_bitrate_bps, stream->GetVideoStreams()[0].min_bitrate_bps); @@ -7565,7 +7568,7 @@ class WebRtcVideoChannelSimulcastTest : public ::testing::Test { stream.width = capture_width; stream.height = capture_height; stream.max_framerate = kDefaultVideoMaxFramerate; - stream.min_bitrate_bps = cricket::kMinVideoBitrateBps; + stream.min_bitrate_bps = webrtc::kDefaultMinVideoBitrateBps; stream.target_bitrate_bps = stream.max_bitrate_bps = GetMaxDefaultBitrateBps(capture_width, capture_height); stream.max_qp = kDefaultQpMax; diff --git a/rtc_base/experiments/BUILD.gn b/rtc_base/experiments/BUILD.gn index 68afd8ed3d..a1676057b4 100644 --- a/rtc_base/experiments/BUILD.gn +++ b/rtc_base/experiments/BUILD.gn @@ -192,6 +192,22 @@ rtc_static_library("stable_target_rate_experiment") { ] } +rtc_static_library("min_video_bitrate_experiment") { + sources = [ + "min_video_bitrate_experiment.cc", + "min_video_bitrate_experiment.h", + ] + deps = [ + ":field_trial_parser", + "../../api/units:data_rate", + "../../api/video:video_frame", + "../../rtc_base:checks", + "../../rtc_base:logging", + "../../system_wrappers:field_trial", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + if (rtc_include_tests) { rtc_source_set("experiments_unittests") { testonly = true @@ -203,6 +219,7 @@ if (rtc_include_tests) { "field_trial_parser_unittest.cc", "field_trial_units_unittest.cc", "keyframe_interval_settings_unittest.cc", + "min_video_bitrate_experiment_unittest.cc", "normalize_simulcast_size_experiment_unittest.cc", "quality_scaler_settings_unittest.cc", "quality_scaling_experiment_unittest.cc", @@ -216,6 +233,7 @@ if (rtc_include_tests) { ":cpu_speed_experiment", ":field_trial_parser", ":keyframe_interval_settings_experiment", + ":min_video_bitrate_experiment", ":normalize_simulcast_size_experiment", ":quality_scaler_settings", ":quality_scaling_experiment", @@ -224,6 +242,8 @@ if (rtc_include_tests) { ":stable_target_rate_experiment", "..:gunit_helpers", "../:rtc_base_tests_utils", + "../../api/units:data_rate", + "../../api/video:video_frame", "../../api/video_codecs:video_codecs_api", "../../system_wrappers:field_trial", "../../test:field_trial", diff --git a/rtc_base/experiments/min_video_bitrate_experiment.cc b/rtc_base/experiments/min_video_bitrate_experiment.cc new file mode 100644 index 0000000000..c3cf9377e4 --- /dev/null +++ b/rtc_base/experiments/min_video_bitrate_experiment.cc @@ -0,0 +1,110 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/experiments/min_video_bitrate_experiment.h" + +#include + +#include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { + +const int kDefaultMinVideoBitrateBps = 30000; + +namespace { +const char kForcedFallbackFieldTrial[] = + "WebRTC-VP8-Forced-Fallback-Encoder-v2"; +const char kMinVideoBitrateExperiment[] = "WebRTC-Video-MinVideoBitrate"; + +absl::optional GetFallbackMinBpsFromFieldTrial(VideoCodecType type) { + if (type != kVideoCodecVP8) { + return absl::nullopt; + } + + if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) { + return absl::nullopt; + } + + const std::string group = + webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial); + if (group.empty()) { + return absl::nullopt; + } + + int min_pixels; // Ignored. + int max_pixels; // Ignored. + int min_bps; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, + &min_bps) != 3) { + return absl::nullopt; + } + + if (min_bps <= 0) { + return absl::nullopt; + } + + return min_bps; +} +} // namespace + +absl::optional GetExperimentalMinVideoBitrate(VideoCodecType type) { + const absl::optional fallback_min_bitrate_bps = + GetFallbackMinBpsFromFieldTrial(type); + if (fallback_min_bitrate_bps) { + return DataRate::bps(*fallback_min_bitrate_bps); + } + + if (webrtc::field_trial::IsEnabled(kMinVideoBitrateExperiment)) { + webrtc::FieldTrialFlag enabled("Enabled"); + + // Backwards-compatibility with an old experiment - a generic minimum which, + // if set, applies to all codecs. + webrtc::FieldTrialOptional min_video_bitrate("br"); + + // New experiment - per-codec minimum bitrate. + webrtc::FieldTrialOptional min_bitrate_vp8("vp8_br"); + webrtc::FieldTrialOptional min_bitrate_vp9("vp9_br"); + webrtc::FieldTrialOptional min_bitrate_h264("h264_br"); + + webrtc::ParseFieldTrial( + {&enabled, &min_video_bitrate, &min_bitrate_vp8, &min_bitrate_vp9, + &min_bitrate_h264}, + webrtc::field_trial::FindFullName(kMinVideoBitrateExperiment)); + + if (min_video_bitrate) { + if (min_bitrate_vp8 || min_bitrate_vp9 || min_bitrate_h264) { + // "br" is mutually-exclusive with the other configuration possibilites. + RTC_LOG(LS_WARNING) << "Self-contradictory experiment config."; + } + return *min_video_bitrate; + } + + switch (type) { + case kVideoCodecVP8: + return min_bitrate_vp8.GetOptional(); + case kVideoCodecVP9: + return min_bitrate_vp9.GetOptional(); + case kVideoCodecH264: + return min_bitrate_h264.GetOptional(); + case kVideoCodecGeneric: + case kVideoCodecMultiplex: + return absl::nullopt; + } + + RTC_NOTREACHED(); + } + + return absl::nullopt; +} + +} // namespace webrtc diff --git a/rtc_base/experiments/min_video_bitrate_experiment.h b/rtc_base/experiments/min_video_bitrate_experiment.h new file mode 100644 index 0000000000..9ea8783894 --- /dev/null +++ b/rtc_base/experiments/min_video_bitrate_experiment.h @@ -0,0 +1,28 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_ + +#include "absl/types/optional.h" +#include "api/units/data_rate.h" +#include "api/video/video_codec_type.h" + +namespace webrtc { + +extern const int kDefaultMinVideoBitrateBps; + +// Return the experiment-driven minimum video bitrate. +// If no experiment is effective, returns nullopt. +absl::optional GetExperimentalMinVideoBitrate(VideoCodecType type); + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_ diff --git a/rtc_base/experiments/min_video_bitrate_experiment_unittest.cc b/rtc_base/experiments/min_video_bitrate_experiment_unittest.cc new file mode 100644 index 0000000000..ca0550d65c --- /dev/null +++ b/rtc_base/experiments/min_video_bitrate_experiment_unittest.cc @@ -0,0 +1,161 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/experiments/min_video_bitrate_experiment.h" + +#include "absl/types/optional.h" +#include "api/units/data_rate.h" +#include "api/video/video_codec_type.h" +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +TEST(GetExperimentalMinVideoBitrateTest, + NulloptForAllCodecsIfFieldTrialUndefined) { + test::ScopedFieldTrials field_trials(""); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::nullopt); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, + NulloptForAllCodecsIfFieldTrialDisabled) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/Disabled,br:123kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::nullopt); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, BrForAllCodecsIfDefined) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/Enabled,br:123kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::make_optional(DataRate::kbps(123))); +} + +TEST(GetExperimentalMinVideoBitrateTest, BrTrumpsSpecificCodecConfigs) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,br:123kbps,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::kbps(123))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::make_optional(DataRate::kbps(123))); +} + +TEST(GetExperimentalMinVideoBitrateTest, + SpecificCodecConfigsIgnoredIfExpDisabled) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Disabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::nullopt); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, SpecificCodecConfigsUsedIfExpEnabled) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::kbps(100))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::kbps(200))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::kbps(300))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, + Vp8BitrateValueTakenFromFallbackIfAvailable) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/" + "WebRTC-VP8-Forced-Fallback-Encoder-v2/" + "Enabled-444444,555555,666666/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::bps(666666))); +} + +TEST(GetExperimentalMinVideoBitrateTest, + NonVp8BitrateValuesTakenFromMinVideoBitrate) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/" + "WebRTC-VP8-Forced-Fallback-Encoder-v2/" + "Enabled-444444,555555,666666/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::kbps(200))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::kbps(300))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +} // namespace +} // namespace webrtc diff --git a/video/BUILD.gn b/video/BUILD.gn index 06c0c49107..b1d1b9d794 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -106,6 +106,7 @@ rtc_static_library("video") { "../rtc_base/experiments:alr_experiment", "../rtc_base/experiments:field_trial_parser", "../rtc_base/experiments:keyframe_interval_settings_experiment", + "../rtc_base/experiments:min_video_bitrate_experiment", "../rtc_base/experiments:quality_scaling_experiment", "../rtc_base/experiments:rate_control_settings", "../rtc_base/synchronization:sequence_checker", diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc index e333091575..4b65ea884b 100644 --- a/video/video_send_stream_impl.cc +++ b/video/video_send_stream_impl.cc @@ -28,6 +28,7 @@ #include "rtc_base/checks.h" #include "rtc_base/experiments/alr_experiment.h" #include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/min_video_bitrate_experiment.h" #include "rtc_base/experiments/rate_control_settings.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" @@ -55,60 +56,6 @@ bool TransportSeqNumExtensionConfigured(const VideoSendStream::Config& config) { }); } -const char kForcedFallbackFieldTrial[] = - "WebRTC-VP8-Forced-Fallback-Encoder-v2"; - -const int kDefaultEncoderMinBitrateBps = 30000; -const char kMinVideoBitrateExperiment[] = "WebRTC-Video-MinVideoBitrate"; - -struct MinVideoBitrateConfig { - webrtc::FieldTrialParameter min_video_bitrate; - - MinVideoBitrateConfig() - : min_video_bitrate("br", - webrtc::DataRate::bps(kDefaultEncoderMinBitrateBps)) { - webrtc::ParseFieldTrial( - {&min_video_bitrate}, - webrtc::field_trial::FindFullName(kMinVideoBitrateExperiment)); - } -}; - -absl::optional GetFallbackMinBpsFromFieldTrial(VideoCodecType type) { - if (type != kVideoCodecVP8) - return absl::nullopt; - - if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) - return absl::nullopt; - - std::string group = - webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial); - if (group.empty()) - return absl::nullopt; - - int min_pixels; - int max_pixels; - int min_bps; - if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, - &min_bps) != 3) { - return absl::nullopt; - } - - if (min_bps <= 0) - return absl::nullopt; - - return min_bps; -} - -int GetEncoderMinBitrateBps(VideoCodecType type) { - if (GetFallbackMinBpsFromFieldTrial(type).has_value()) { - return GetFallbackMinBpsFromFieldTrial(type).value(); - } - if (webrtc::field_trial::IsEnabled(kMinVideoBitrateExperiment)) { - return MinVideoBitrateConfig().min_video_bitrate->bps(); - } - return kDefaultEncoderMinBitrateBps; -} - // Calculate max padding bitrate for a multi layer codec. int CalculateMaxPadBitrateBps(const std::vector& streams, VideoEncoderConfig::ContentType content_type, @@ -554,10 +501,18 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged( RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size()); RTC_DCHECK_RUN_ON(worker_queue_); + const VideoCodecType codec_type = + PayloadStringToCodecType(config_->rtp.payload_name); + + const absl::optional experimental_min_bitrate = + GetExperimentalMinVideoBitrate(codec_type); + const int min_bitrate_bps = + experimental_min_bitrate + ? rtc::saturated_cast(experimental_min_bitrate->bps()) + : kDefaultMinVideoBitrateBps; + encoder_min_bitrate_bps_ = - std::max(streams[0].min_bitrate_bps, - GetEncoderMinBitrateBps( - PayloadStringToCodecType(config_->rtp.payload_name))); + std::max(streams[0].min_bitrate_bps, min_bitrate_bps); encoder_max_bitrate_bps_ = 0; double stream_bitrate_priority_sum = 0; for (const auto& stream : streams) { @@ -575,8 +530,6 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged( encoder_max_bitrate_bps_); // TODO(bugs.webrtc.org/10266): Query the VideoBitrateAllocator instead. - const VideoCodecType codec_type = - PayloadStringToCodecType(config_->rtp.payload_name); if (codec_type == kVideoCodecVP9) { max_padding_bitrate_ = has_alr_probing_ ? streams[0].min_bitrate_bps : streams[0].target_bitrate_bps;