Extend WebRTC-Video-MinVideoBitrate to experiment per-codec
The experiment was extended to support per-codec minimum bitrates
for the following codecs:
* VP8
* VP9
* H.264
The old semantic meaning for the field trial is retained, in that
specifying "br:" applies a minimum bitrate to all codecs. If "br:"
is not specified, the per-codec minimum config is consulted.
Bug: webrtc:11024
Change-Id: I89630262c7710771d5e25d039fe35f0bd217b58a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/156171
Commit-Queue: Elad Alon <eladalon@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Ying Wang <yinwa@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29450}
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 726a66d..3c8008a 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -274,6 +274,7 @@
"../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_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 @@
"../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 9adfa41..12d6ddd 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 d52505d..0abae3d 100644
--- a/media/engine/constants.h
+++ b/media/engine/constants.h
@@ -19,9 +19,6 @@
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 b8e7a6c..40135f4 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 @@
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 96a426d..7bce942 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 @@
return absl::nullopt;
}
-const char kForcedFallbackFieldTrial[] =
- "WebRTC-VP8-Forced-Fallback-Encoder-v2";
-
-absl::optional<int> 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 @@
encoder_config.number_of_streams);
std::vector<webrtc::VideoStream> layers;
+ const absl::optional<webrtc::DataRate> 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 @@
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<int>(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 @@
: 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<int>(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 b989e22..6e48304 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 @@
namespace cricket {
-struct MinVideoBitrateConfig {
- webrtc::FieldTrialParameter<webrtc::DataRate> 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 1ed3dc3..b4a0a61 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 @@
TEST_F(WebRtcVideoChannelTest, VerifyMinBitrate) {
std::vector<webrtc::VideoStream> 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 @@
// 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 @@
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 @@
// 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 @@
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 68afd8e..a167605 100644
--- a/rtc_base/experiments/BUILD.gn
+++ b/rtc_base/experiments/BUILD.gn
@@ -192,6 +192,22 @@
]
}
+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 @@
"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 @@
":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 @@
":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 0000000..c3cf937
--- /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 <string>
+
+#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<int> 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<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type) {
+ const absl::optional<int> 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<webrtc::DataRate> min_video_bitrate("br");
+
+ // New experiment - per-codec minimum bitrate.
+ webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp8("vp8_br");
+ webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp9("vp9_br");
+ webrtc::FieldTrialOptional<webrtc::DataRate> 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 0000000..9ea8783
--- /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<DataRate> 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 0000000..ca0550d
--- /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 06c0c49..b1d1b9d 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -106,6 +106,7 @@
"../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 e333091..4b65ea8 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 @@
});
}
-const char kForcedFallbackFieldTrial[] =
- "WebRTC-VP8-Forced-Fallback-Encoder-v2";
-
-const int kDefaultEncoderMinBitrateBps = 30000;
-const char kMinVideoBitrateExperiment[] = "WebRTC-Video-MinVideoBitrate";
-
-struct MinVideoBitrateConfig {
- webrtc::FieldTrialParameter<webrtc::DataRate> min_video_bitrate;
-
- MinVideoBitrateConfig()
- : min_video_bitrate("br",
- webrtc::DataRate::bps(kDefaultEncoderMinBitrateBps)) {
- webrtc::ParseFieldTrial(
- {&min_video_bitrate},
- webrtc::field_trial::FindFullName(kMinVideoBitrateExperiment));
- }
-};
-
-absl::optional<int> 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<VideoStream>& streams,
VideoEncoderConfig::ContentType content_type,
@@ -554,10 +501,18 @@
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<DataRate> experimental_min_bitrate =
+ GetExperimentalMinVideoBitrate(codec_type);
+ const int min_bitrate_bps =
+ experimental_min_bitrate
+ ? rtc::saturated_cast<int>(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 @@
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;