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}
This commit is contained in:
parent
e62a588314
commit
80f53b785b
@ -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",
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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<webrtc::VideoStream> 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;
|
||||
|
||||
@ -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<size_t> GetVp9TemporalLayersFromFieldTrial() {
|
||||
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 @@ std::vector<webrtc::VideoStream> EncoderStreamFactory::CreateEncoderStreams(
|
||||
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 @@ std::vector<webrtc::VideoStream> 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<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 @@ std::vector<webrtc::VideoStream> 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<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;
|
||||
|
||||
@ -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<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 {
|
||||
|
||||
@ -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<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 @@ 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;
|
||||
|
||||
@ -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",
|
||||
|
||||
110
rtc_base/experiments/min_video_bitrate_experiment.cc
Normal file
110
rtc_base/experiments/min_video_bitrate_experiment.cc
Normal file
@ -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
|
||||
28
rtc_base/experiments/min_video_bitrate_experiment.h
Normal file
28
rtc_base/experiments/min_video_bitrate_experiment.h
Normal file
@ -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_
|
||||
161
rtc_base/experiments/min_video_bitrate_experiment_unittest.cc
Normal file
161
rtc_base/experiments/min_video_bitrate_experiment_unittest.cc
Normal file
@ -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
|
||||
@ -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",
|
||||
|
||||
@ -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<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 @@ 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<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 @@ 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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user