diff --git a/media/BUILD.gn b/media/BUILD.gn index b26be0635f..59b8c62944 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -331,6 +331,7 @@ rtc_library("rtc_audio_video") { "../rtc_base/third_party/base64", "../system_wrappers", "../system_wrappers:metrics", + "../video/config:streams_config", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", @@ -344,8 +345,6 @@ rtc_library("rtc_audio_video") { "engine/null_webrtc_video_engine.h", "engine/payload_type_mapper.cc", "engine/payload_type_mapper.h", - "engine/simulcast.cc", - "engine/simulcast.h", "engine/unhandled_packets_buffer.cc", "engine/unhandled_packets_buffer.h", "engine/webrtc_media_engine.cc", @@ -654,6 +653,7 @@ if (rtc_include_tests) { "../test:test_support", "../test:video_test_common", "../test/time_controller", + "../video/config:streams_config", ] if (enable_libaom) { @@ -683,7 +683,6 @@ if (rtc_include_tests) { "engine/null_webrtc_video_engine_unittest.cc", "engine/payload_type_mapper_unittest.cc", "engine/simulcast_encoder_adapter_unittest.cc", - "engine/simulcast_unittest.cc", "engine/unhandled_packets_buffer_unittest.cc", "engine/webrtc_media_engine_unittest.cc", "engine/webrtc_video_engine_unittest.cc", diff --git a/media/DEPS b/media/DEPS index a495631950..25b8c63723 100644 --- a/media/DEPS +++ b/media/DEPS @@ -22,4 +22,10 @@ specific_include_rules = { "win32devicemanager\.cc": [ "+third_party/logitech/files/logitechquickcam.h", ], + ".*webrtc_video_engine\.h": [ + "+video/config", + ], + ".*webrtc_video_engine_unittest\.cc": [ + "+video/config", + ], } diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index feaa78044a..f86ac97007 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -20,7 +20,6 @@ #include "absl/algorithm/container.h" #include "absl/strings/match.h" #include "api/media_stream_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" @@ -28,7 +27,6 @@ #include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder_factory.h" #include "call/call.h" -#include "media/engine/simulcast.h" #include "media/engine/webrtc_media_engine.h" #include "media/engine/webrtc_voice_engine.h" #include "modules/rtp_rtcp/source/rtp_util.h" @@ -37,8 +35,6 @@ #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/experiments/normalize_simulcast_size_experiment.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/strings/string_builder.h" @@ -52,25 +48,12 @@ namespace { using ::webrtc::ParseRtpPayloadType; using ::webrtc::ParseRtpSsrc; -const int kMinLayerSize = 16; constexpr int64_t kUnsignaledSsrcCooldownMs = rtc::kNumMillisecsPerSec / 2; // TODO(bugs.webrtc.org/13166): Remove AV1X when backwards compatibility is not // needed. constexpr char kAv1xCodecName[] = "AV1X"; -int ScaleDownResolution(int resolution, - double scale_down_by, - int min_resolution) { - // Resolution is never scalied down to smaller than min_resolution. - // If the input resolution is already smaller than min_resolution, - // no scaling should be done at all. - if (resolution <= min_resolution) - return resolution; - return std::max(static_cast(resolution / scale_down_by + 0.5), - min_resolution); -} - const char* StreamTypeToString( webrtc::VideoSendStream::StreamStats::StreamType type) { switch (type) { @@ -92,20 +75,6 @@ bool IsDisabled(const webrtc::FieldTrialsView& trials, absl::string_view name) { return absl::StartsWith(trials.Lookup(name), "Disabled"); } -bool PowerOfTwo(int value) { - return (value > 0) && ((value & (value - 1)) == 0); -} - -bool IsScaleFactorsPowerOfTwo(const webrtc::VideoEncoderConfig& config) { - for (const auto& layer : config.simulcast_layers) { - double scale = std::max(layer.scale_resolution_down_by, 1.0); - if (std::round(scale) != scale || !PowerOfTwo(scale)) { - return false; - } - } - return true; -} - void AddDefaultFeedbackParams(VideoCodec* codec, const webrtc::FieldTrialsView& trials) { // Don't add any feedback params for RED and ULPFEC. @@ -269,12 +238,6 @@ std::vector GetPayloadTypesAndDefaultCodecs( return output_codecs; } -bool IsTemporalLayersSupported(const std::string& codec_name) { - return absl::EqualsIgnoreCase(codec_name, kVp8CodecName) || - absl::EqualsIgnoreCase(codec_name, kVp9CodecName) || - absl::EqualsIgnoreCase(codec_name, kAv1CodecName); -} - static std::string CodecVectorToString(const std::vector& codecs) { rtc::StringBuilder out; out << "{"; @@ -356,26 +319,6 @@ bool IsCodecDisabledForSimulcast(const std::string& codec_name, return false; } -// The selected thresholds for QVGA and VGA corresponded to a QP around 10. -// The change in QP declined above the selected bitrates. -static int GetMaxDefaultVideoBitrateKbps(int width, - int height, - bool is_screenshare) { - int max_bitrate; - if (width * height <= 320 * 240) { - max_bitrate = 600; - } else if (width * height <= 640 * 480) { - max_bitrate = 1700; - } else if (width * height <= 960 * 540) { - max_bitrate = 2000; - } else { - max_bitrate = 2500; - } - if (is_screenshare) - max_bitrate = std::max(max_bitrate, 1200); - return max_bitrate; -} - // Returns its smallest positive argument. If neither argument is positive, // returns an arbitrary nonpositive value. int MinPositive(int a, int b) { @@ -394,17 +337,6 @@ bool IsLayerActive(const webrtc::RtpEncodingParameters& layer) { (!layer.max_framerate || *layer.max_framerate > 0); } -size_t FindRequiredActiveLayers( - const webrtc::VideoEncoderConfig& encoder_config) { - // Need enough layers so that at least the first active one is present. - for (size_t i = 0; i < encoder_config.number_of_streams; ++i) { - if (encoder_config.simulcast_layers[i].active) { - return i + 1; - } - } - return 0; -} - int NumActiveStreams(const webrtc::RtpParameters& rtp_parameters) { int res = 0; for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) { @@ -3636,309 +3568,4 @@ void WebRtcVideoChannel::SetDepacketizerToDecoderFrameTransformer( } } -// TODO(bugs.webrtc.org/8785): Consider removing max_qp as member of -// EncoderStreamFactory and instead set this value individually for each stream -// in the VideoEncoderConfig.simulcast_layers. -EncoderStreamFactory::EncoderStreamFactory( - std::string codec_name, - int max_qp, - bool is_screenshare, - bool conference_mode, - const webrtc::FieldTrialsView* trials) - - : codec_name_(codec_name), - max_qp_(max_qp), - is_screenshare_(is_screenshare), - conference_mode_(conference_mode), - trials_(trials ? *trials : fallback_trials_) {} - -std::vector EncoderStreamFactory::CreateEncoderStreams( - int width, - int height, - const webrtc::VideoEncoderConfig& encoder_config) { - RTC_DCHECK_GT(encoder_config.number_of_streams, 0); - RTC_DCHECK_GE(encoder_config.simulcast_layers.size(), - encoder_config.number_of_streams); - - 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)) && - is_screenshare_ && conference_mode_)) { - return CreateSimulcastOrConferenceModeScreenshareStreams( - width, height, encoder_config, experimental_min_bitrate); - } - - return CreateDefaultVideoStreams(width, height, encoder_config, - experimental_min_bitrate); -} - -std::vector -EncoderStreamFactory::CreateDefaultVideoStreams( - int width, - int height, - const webrtc::VideoEncoderConfig& encoder_config, - const absl::optional& experimental_min_bitrate) const { - std::vector layers; - - // For unset max bitrates set default bitrate for non-simulcast. - int max_bitrate_bps = - (encoder_config.max_bitrate_bps > 0) - ? encoder_config.max_bitrate_bps - : GetMaxDefaultVideoBitrateKbps(width, height, is_screenshare_) * - 1000; - - 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; - // If only min bitrate is configured, make sure max is above min. - if (encoder_config.max_bitrate_bps <= 0) - max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps); - } - int max_framerate = (encoder_config.simulcast_layers[0].max_framerate > 0) - ? encoder_config.simulcast_layers[0].max_framerate - : kDefaultVideoMaxFramerate; - - webrtc::VideoStream layer; - layer.width = width; - layer.height = height; - layer.max_framerate = max_framerate; - // Note: VP9 seems to have be sending if any layer is active, - // (see `UpdateSendState`) and still use parameters only from - // encoder_config.simulcast_layers[0]. - layer.active = absl::c_any_of(encoder_config.simulcast_layers, - [](const auto& layer) { return layer.active; }); - - if (encoder_config.simulcast_layers[0].scale_resolution_down_by > 1.) { - layer.width = ScaleDownResolution( - layer.width, - encoder_config.simulcast_layers[0].scale_resolution_down_by, - kMinLayerSize); - layer.height = ScaleDownResolution( - layer.height, - encoder_config.simulcast_layers[0].scale_resolution_down_by, - kMinLayerSize); - } - - if (absl::EqualsIgnoreCase(codec_name_, kVp9CodecName)) { - RTC_DCHECK(encoder_config.encoder_specific_settings); - // Use VP9 SVC layering from codec settings which might be initialized - // though field trial in ConfigureVideoEncoderSettings. - webrtc::VideoCodecVP9 vp9_settings; - encoder_config.encoder_specific_settings->FillVideoCodecVp9(&vp9_settings); - layer.num_temporal_layers = vp9_settings.numberOfTemporalLayers; - - // Number of spatial layers is signalled differently from different call - // sites (sigh), pick the max as we are interested in the upper bound. - int num_spatial_layers = - std::max({encoder_config.simulcast_layers.size(), - encoder_config.spatial_layers.size(), - size_t{vp9_settings.numberOfSpatialLayers}}); - - if (width * height > 0 && - (layer.num_temporal_layers > 1u || num_spatial_layers > 1)) { - // In SVC mode, the VP9 max bitrate is determined by SvcConfig, instead of - // GetMaxDefaultVideoBitrateKbps(). - std::vector svc_layers = - webrtc::GetSvcConfig(width, height, max_framerate, - /*first_active_layer=*/0, num_spatial_layers, - *layer.num_temporal_layers, is_screenshare_); - int sum_max_bitrates_kbps = 0; - for (const webrtc::SpatialLayer& spatial_layer : svc_layers) { - sum_max_bitrates_kbps += spatial_layer.maxBitrate; - } - RTC_DCHECK_GE(sum_max_bitrates_kbps, 0); - if (encoder_config.max_bitrate_bps <= 0) { - max_bitrate_bps = sum_max_bitrates_kbps * 1000; - } else { - max_bitrate_bps = - std::min(max_bitrate_bps, sum_max_bitrates_kbps * 1000); - } - max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps); - } - } - - // In the case that the application sets a max bitrate that's lower than the - // min bitrate, we adjust it down (see bugs.webrtc.org/9141). - layer.min_bitrate_bps = std::min(min_bitrate_bps, max_bitrate_bps); - if (encoder_config.simulcast_layers[0].target_bitrate_bps <= 0) { - layer.target_bitrate_bps = max_bitrate_bps; - } else { - layer.target_bitrate_bps = std::min( - encoder_config.simulcast_layers[0].target_bitrate_bps, max_bitrate_bps); - } - layer.max_bitrate_bps = max_bitrate_bps; - layer.max_qp = max_qp_; - layer.bitrate_priority = encoder_config.bitrate_priority; - - if (IsTemporalLayersSupported(codec_name_)) { - // Use configured number of temporal layers if set. - if (encoder_config.simulcast_layers[0].num_temporal_layers) { - layer.num_temporal_layers = - *encoder_config.simulcast_layers[0].num_temporal_layers; - } - } - layer.scalability_mode = encoder_config.simulcast_layers[0].scalability_mode; - layers.push_back(layer); - return layers; -} - -std::vector -EncoderStreamFactory::CreateSimulcastOrConferenceModeScreenshareStreams( - int width, - int height, - const webrtc::VideoEncoderConfig& encoder_config, - const absl::optional& experimental_min_bitrate) const { - std::vector layers; - - const bool temporal_layers_supported = - absl::EqualsIgnoreCase(codec_name_, kVp8CodecName) || - absl::EqualsIgnoreCase(codec_name_, kH264CodecName); - // Use legacy simulcast screenshare if conference mode is explicitly enabled - // or use the regular simulcast configuration path which is generic. - layers = GetSimulcastConfig(FindRequiredActiveLayers(encoder_config), - encoder_config.number_of_streams, width, height, - encoder_config.bitrate_priority, max_qp_, - is_screenshare_ && conference_mode_, - temporal_layers_supported, trials_); - // 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()); - } - // Update the active simulcast layers and configured bitrates. - bool is_highest_layer_max_bitrate_configured = false; - const bool has_scale_resolution_down_by = absl::c_any_of( - encoder_config.simulcast_layers, [](const webrtc::VideoStream& layer) { - return layer.scale_resolution_down_by != -1.; - }); - - bool default_scale_factors_used = true; - if (has_scale_resolution_down_by) { - default_scale_factors_used = IsScaleFactorsPowerOfTwo(encoder_config); - } - const bool norm_size_configured = - webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent().has_value(); - const int normalized_width = - (default_scale_factors_used || norm_size_configured) && - (width >= kMinLayerSize) - ? NormalizeSimulcastSize(width, encoder_config.number_of_streams) - : width; - const int normalized_height = - (default_scale_factors_used || norm_size_configured) && - (height >= kMinLayerSize) - ? NormalizeSimulcastSize(height, encoder_config.number_of_streams) - : height; - for (size_t i = 0; i < layers.size(); ++i) { - layers[i].active = encoder_config.simulcast_layers[i].active; - layers[i].scalability_mode = - encoder_config.simulcast_layers[i].scalability_mode; - // Update with configured num temporal layers if supported by codec. - if (encoder_config.simulcast_layers[i].num_temporal_layers && - IsTemporalLayersSupported(codec_name_)) { - layers[i].num_temporal_layers = - *encoder_config.simulcast_layers[i].num_temporal_layers; - } - if (encoder_config.simulcast_layers[i].max_framerate > 0) { - layers[i].max_framerate = - encoder_config.simulcast_layers[i].max_framerate; - } - if (has_scale_resolution_down_by) { - const double scale_resolution_down_by = std::max( - encoder_config.simulcast_layers[i].scale_resolution_down_by, 1.0); - layers[i].width = ScaleDownResolution( - normalized_width, scale_resolution_down_by, kMinLayerSize); - layers[i].height = ScaleDownResolution( - normalized_height, scale_resolution_down_by, kMinLayerSize); - } - // Update simulcast bitrates with configured min and max bitrate. - if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) { - layers[i].min_bitrate_bps = - encoder_config.simulcast_layers[i].min_bitrate_bps; - } - if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) { - layers[i].max_bitrate_bps = - encoder_config.simulcast_layers[i].max_bitrate_bps; - } - if (encoder_config.simulcast_layers[i].target_bitrate_bps > 0) { - layers[i].target_bitrate_bps = - encoder_config.simulcast_layers[i].target_bitrate_bps; - } - if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0 && - encoder_config.simulcast_layers[i].max_bitrate_bps > 0) { - // Min and max bitrate are configured. - // Set target to 3/4 of the max bitrate (or to max if below min). - if (encoder_config.simulcast_layers[i].target_bitrate_bps <= 0) - layers[i].target_bitrate_bps = layers[i].max_bitrate_bps * 3 / 4; - if (layers[i].target_bitrate_bps < layers[i].min_bitrate_bps) - layers[i].target_bitrate_bps = layers[i].max_bitrate_bps; - } else if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) { - // Only min bitrate is configured, make sure target/max are above min. - layers[i].target_bitrate_bps = - std::max(layers[i].target_bitrate_bps, layers[i].min_bitrate_bps); - layers[i].max_bitrate_bps = - std::max(layers[i].max_bitrate_bps, layers[i].min_bitrate_bps); - } else if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) { - // Only max bitrate is configured, make sure min/target are below max. - // Keep target bitrate if it is set explicitly in encoding config. - // Otherwise set target bitrate to 3/4 of the max bitrate - // or the one calculated from GetSimulcastConfig() which is larger. - layers[i].min_bitrate_bps = - std::min(layers[i].min_bitrate_bps, layers[i].max_bitrate_bps); - if (encoder_config.simulcast_layers[i].target_bitrate_bps <= 0) { - layers[i].target_bitrate_bps = std::max( - layers[i].target_bitrate_bps, layers[i].max_bitrate_bps * 3 / 4); - } - layers[i].target_bitrate_bps = std::max( - std::min(layers[i].target_bitrate_bps, layers[i].max_bitrate_bps), - layers[i].min_bitrate_bps); - } - if (i == layers.size() - 1) { - is_highest_layer_max_bitrate_configured = - encoder_config.simulcast_layers[i].max_bitrate_bps > 0; - } - } - if (!is_screenshare_ && !is_highest_layer_max_bitrate_configured && - encoder_config.max_bitrate_bps > 0) { - // No application-configured maximum for the largest layer. - // If there is bitrate leftover, give it to the largest layer. - BoostMaxSimulcastLayer( - webrtc::DataRate::BitsPerSec(encoder_config.max_bitrate_bps), &layers); - } - - // Sort the layers by max_bitrate_bps, they might not always be from - // smallest to biggest - std::vector index(layers.size()); - std::iota(index.begin(), index.end(), 0); - std::stable_sort(index.begin(), index.end(), [&layers](size_t a, size_t b) { - return layers[a].max_bitrate_bps < layers[b].max_bitrate_bps; - }); - - if (!layers[index[0]].active) { - // Adjust min bitrate of the first active layer to allow it to go as low as - // the lowest (now inactive) layer could. - // Otherwise, if e.g. a single HD stream is active, it would have 600kbps - // min bitrate, which would always be allocated to the stream. - // This would lead to congested network, dropped frames and overall bad - // experience. - - const int min_configured_bitrate = layers[index[0]].min_bitrate_bps; - for (size_t i = 0; i < layers.size(); ++i) { - if (layers[index[i]].active) { - layers[index[i]].min_bitrate_bps = min_configured_bitrate; - break; - } - } - } - - return layers; -} - } // namespace cricket diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h index 3993c6635b..ec31bf7ae7 100644 --- a/media/engine/webrtc_video_engine.h +++ b/media/engine/webrtc_video_engine.h @@ -37,6 +37,7 @@ #include "rtc_base/synchronization/mutex.h" #include "rtc_base/system/no_unique_address.h" #include "rtc_base/thread_annotations.h" +#include "video/config/encoder_stream_factory.h" namespace webrtc { class VideoDecoderFactory; @@ -683,54 +684,6 @@ class WebRtcVideoChannel : public VideoMediaChannel, bool allow_codec_switching_ = false; }; -class EncoderStreamFactory - : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface { - public: - EncoderStreamFactory(std::string codec_name, - int max_qp, - bool is_screenshare, - bool conference_mode) - : EncoderStreamFactory(codec_name, - max_qp, - is_screenshare, - conference_mode, - nullptr) {} - - EncoderStreamFactory(std::string codec_name, - int max_qp, - bool is_screenshare, - bool conference_mode, - const webrtc::FieldTrialsView* trials); - - private: - std::vector CreateEncoderStreams( - int width, - int height, - const webrtc::VideoEncoderConfig& encoder_config) override; - - std::vector CreateDefaultVideoStreams( - int width, - int height, - const webrtc::VideoEncoderConfig& encoder_config, - const absl::optional& experimental_min_bitrate) const; - - std::vector - CreateSimulcastOrConferenceModeScreenshareStreams( - int width, - int height, - const webrtc::VideoEncoderConfig& encoder_config, - const absl::optional& experimental_min_bitrate) const; - - const std::string codec_name_; - const int max_qp_; - const bool is_screenshare_; - // Allows a screenshare specific configuration, which enables temporal - // layering and various settings. - const bool conference_mode_; - const webrtc::FieldTrialBasedConfig fallback_trials_; - const webrtc::FieldTrialsView& trials_; -}; - } // namespace cricket #endif // MEDIA_ENGINE_WEBRTC_VIDEO_ENGINE_H_ diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc index d3c4211ee7..e7e43fcf3f 100644 --- a/media/engine/webrtc_video_engine_unittest.cc +++ b/media/engine/webrtc_video_engine_unittest.cc @@ -51,7 +51,6 @@ #include "media/base/test_utils.h" #include "media/engine/fake_webrtc_call.h" #include "media/engine/fake_webrtc_video_engine.h" -#include "media/engine/simulcast.h" #include "media/engine/webrtc_voice_engine.h" #include "modules/rtp_rtcp/source/rtp_packet.h" #include "rtc_base/arraysize.h" @@ -66,6 +65,7 @@ #include "test/gmock.h" #include "test/scoped_key_value_config.h" #include "test/time_controller/simulated_time_controller.h" +#include "video/config/simulcast.h" using ::testing::_; using ::testing::Contains; diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index da2a0a4979..b54b8bda91 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -989,6 +989,7 @@ if (rtc_include_tests) { "../../test:test_support", "../../test:video_test_common", "../../test:video_test_support", + "../../video/config:streams_config", ] absl_deps = [ "//third_party/abseil-cpp/absl/strings:strings", diff --git a/modules/video_coding/DEPS b/modules/video_coding/DEPS index 3a7629e84b..2aac37a1d4 100644 --- a/modules/video_coding/DEPS +++ b/modules/video_coding/DEPS @@ -19,5 +19,6 @@ specific_include_rules = { ".*test.*\.cc": [ "+media/base", "+media/engine", + "+video/config", ], } diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc index 9d203736ee..e30fe96800 100644 --- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc +++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc @@ -46,7 +46,6 @@ #include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h" #include "common_video/h264/h264_common.h" #include "media/base/media_constants.h" -#include "media/engine/simulcast.h" #include "modules/video_coding/codecs/h264/include/h264_globals.h" #include "modules/video_coding/codecs/vp9/svc_config.h" #include "modules/video_coding/utility/ivf_file_writer.h" @@ -61,6 +60,7 @@ #include "test/testsupport/file_utils.h" #include "test/testsupport/frame_writer.h" #include "test/video_codec_settings.h" +#include "video/config/simulcast.h" namespace webrtc { namespace test { diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn index 19b885d79f..9cf7790a08 100644 --- a/rtc_tools/BUILD.gn +++ b/rtc_tools/BUILD.gn @@ -218,6 +218,7 @@ if (!is_component_build) { "../test:fileutils", "../test:rtp_test_utils", "../test:video_test_common", + "../video/config:streams_config", "//third_party/abseil-cpp/absl/flags:flag", "//third_party/abseil-cpp/absl/flags:parse", "//third_party/abseil-cpp/absl/flags:usage", diff --git a/rtc_tools/DEPS b/rtc_tools/DEPS index 3cf6080c93..4d99061b8d 100644 --- a/rtc_tools/DEPS +++ b/rtc_tools/DEPS @@ -17,6 +17,7 @@ include_rules = [ "+system_wrappers", "+p2p", "+third_party/libyuv", + "+video/config", ] specific_include_rules = { diff --git a/rtc_tools/rtp_generator/rtp_generator.cc b/rtc_tools/rtp_generator/rtp_generator.cc index 8a3aceed75..d93655ac5c 100644 --- a/rtc_tools/rtp_generator/rtp_generator.cc +++ b/rtc_tools/rtp_generator/rtp_generator.cc @@ -25,6 +25,7 @@ #include "rtc_base/system/file_wrapper.h" #include "rtc_base/thread.h" #include "test/testsupport/file_utils.h" +#include "video/config/encoder_stream_factory.h" namespace webrtc { namespace { diff --git a/test/DEPS b/test/DEPS index ed994b7e79..a9e9a7b5f1 100644 --- a/test/DEPS +++ b/test/DEPS @@ -22,6 +22,7 @@ include_rules = [ "+sdk", "+system_wrappers", "+third_party/libyuv", + "+video/config", ] specific_include_rules = { diff --git a/test/scenario/BUILD.gn b/test/scenario/BUILD.gn index acd77b4508..e5c19012f9 100644 --- a/test/scenario/BUILD.gn +++ b/test/scenario/BUILD.gn @@ -142,7 +142,7 @@ if (rtc_include_tests && !build_with_chromium) { "../../rtc_base/task_utils:repeating_task", "../../system_wrappers", "../../system_wrappers:field_trial", - "../../video", + "../../video/config:streams_config", "../logging:log_writer", "../network:emulated_network", "../time_controller", diff --git a/test/scenario/video_stream.cc b/test/scenario/video_stream.cc index 3d1253ac92..60bf5ef27a 100644 --- a/test/scenario/video_stream.cc +++ b/test/scenario/video_stream.cc @@ -27,6 +27,7 @@ #include "test/fake_encoder.h" #include "test/scenario/hardware_codecs.h" #include "test/testsupport/file_utils.h" +#include "video/config/encoder_stream_factory.h" namespace webrtc { namespace test { diff --git a/video/BUILD.gn b/video/BUILD.gn index 76367fd53e..7dc15ff5f3 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -71,6 +71,8 @@ rtc_library("video") { "../api/crypto:options", "../api/task_queue", "../api/task_queue:pending_task_safety_flag", + "../api/transport:field_trial_based_config", + "../api/units:data_rate", "../api/units:frequency", "../api/units:time_delta", "../api/units:timestamp", @@ -102,6 +104,7 @@ rtc_library("video") { "../modules/video_coding:packet_buffer", "../modules/video_coding:video_codec_interface", "../modules/video_coding:video_coding_utility", + "../modules/video_coding:webrtc_vp9_helpers", "../modules/video_coding/timing:timing_module", "../rtc_base:checks", "../rtc_base:event_tracer", @@ -125,6 +128,7 @@ rtc_library("video") { "../rtc_base/experiments:field_trial_parser", "../rtc_base/experiments:keyframe_interval_settings_experiment", "../rtc_base/experiments:min_video_bitrate_experiment", + "../rtc_base/experiments:normalize_simulcast_size_experiment", "../rtc_base/experiments:rate_control_settings", "../rtc_base/synchronization:mutex", "../rtc_base/system:no_unique_address", @@ -530,6 +534,7 @@ if (rtc_include_tests) { "../test:test_support_test_artifacts", "../test:video_test_common", "../test:video_test_support", + "config:streams_config", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", @@ -799,6 +804,7 @@ if (rtc_include_tests) { "../api/test/metrics:global_metrics_logger_and_exporter", "../api/test/metrics:metric", "../api/test/video:function_video_factory", + "../api/transport:field_trial_based_config", "../api/units:data_rate", "../api/units:frequency", "../api/units:time_delta", @@ -899,6 +905,7 @@ if (rtc_include_tests) { "../test:video_test_common", "../test/time_controller", "adaptation:video_adaptation", + "config:streams_config", ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", diff --git a/video/config/BUILD.gn b/video/config/BUILD.gn new file mode 100644 index 0000000000..7902c0b9a6 --- /dev/null +++ b/video/config/BUILD.gn @@ -0,0 +1,68 @@ +# Copyright (c) 2022 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. + +import("../../webrtc.gni") + +rtc_library("streams_config") { + sources = [ + "encoder_stream_factory.cc", + "encoder_stream_factory.h", + "simulcast.cc", + "simulcast.h", + ] + + deps = [ + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + "../../api/units:data_rate", + "../../api/video:video_codec_constants", + "../../api/video_codecs:video_codecs_api", + "../../media:rtc_media_base", + "../../modules/video_coding:video_coding_utility", + "../../modules/video_coding:webrtc_vp9_helpers", + "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base/experiments:field_trial_parser", + "../../rtc_base/experiments:min_video_bitrate_experiment", + "../../rtc_base/experiments:normalize_simulcast_size_experiment", + "../../rtc_base/experiments:rate_control_settings", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +if (rtc_include_tests) { + rtc_library("video_config_tests") { + testonly = true + + defines = [] + sources = [ "simulcast_unittest.cc" ] + deps = [ + ":streams_config", + "../../api/transport:field_trial_based_config", + "../../test:field_trial", + "../../test:test_support", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/functional:bind_front", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + "//third_party/abseil-cpp/absl/types:variant", + ] + if (!build_with_mozilla) { + deps += [ "../../media:rtc_media_base" ] + } + } +} diff --git a/video/config/encoder_stream_factory.cc b/video/config/encoder_stream_factory.cc new file mode 100644 index 0000000000..f6156106fd --- /dev/null +++ b/video/config/encoder_stream_factory.cc @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2022 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 "video/config/encoder_stream_factory.h" + +#include +#include +#include +#include + +#include "absl/algorithm/container.h" +#include "absl/strings/match.h" +#include "api/video/video_codec_constants.h" +#include "media/base/media_constants.h" +#include "modules/video_coding/codecs/vp9/svc_config.h" +#include "rtc_base/experiments/min_video_bitrate_experiment.h" +#include "rtc_base/experiments/normalize_simulcast_size_experiment.h" +#include "video/config/simulcast.h" + +namespace cricket { +namespace { + +const int kMinLayerSize = 16; + +int ScaleDownResolution(int resolution, + double scale_down_by, + int min_resolution) { + // Resolution is never scalied down to smaller than min_resolution. + // If the input resolution is already smaller than min_resolution, + // no scaling should be done at all. + if (resolution <= min_resolution) + return resolution; + return std::max(static_cast(resolution / scale_down_by + 0.5), + min_resolution); +} + +bool PowerOfTwo(int value) { + return (value > 0) && ((value & (value - 1)) == 0); +} + +bool IsScaleFactorsPowerOfTwo(const webrtc::VideoEncoderConfig& config) { + for (const auto& layer : config.simulcast_layers) { + double scale = std::max(layer.scale_resolution_down_by, 1.0); + if (std::round(scale) != scale || !PowerOfTwo(scale)) { + return false; + } + } + return true; +} + +bool IsTemporalLayersSupported(const std::string& codec_name) { + return absl::EqualsIgnoreCase(codec_name, kVp8CodecName) || + absl::EqualsIgnoreCase(codec_name, kVp9CodecName) || + absl::EqualsIgnoreCase(codec_name, kAv1CodecName); +} + +size_t FindRequiredActiveLayers( + const webrtc::VideoEncoderConfig& encoder_config) { + // Need enough layers so that at least the first active one is present. + for (size_t i = 0; i < encoder_config.number_of_streams; ++i) { + if (encoder_config.simulcast_layers[i].active) { + return i + 1; + } + } + return 0; +} + +// The selected thresholds for QVGA and VGA corresponded to a QP around 10. +// The change in QP declined above the selected bitrates. +static int GetMaxDefaultVideoBitrateKbps(int width, + int height, + bool is_screenshare) { + int max_bitrate; + if (width * height <= 320 * 240) { + max_bitrate = 600; + } else if (width * height <= 640 * 480) { + max_bitrate = 1700; + } else if (width * height <= 960 * 540) { + max_bitrate = 2000; + } else { + max_bitrate = 2500; + } + if (is_screenshare) + max_bitrate = std::max(max_bitrate, 1200); + return max_bitrate; +} + +} // namespace + +// TODO(bugs.webrtc.org/8785): Consider removing max_qp as member of +// EncoderStreamFactory and instead set this value individually for each stream +// in the VideoEncoderConfig.simulcast_layers. +EncoderStreamFactory::EncoderStreamFactory( + std::string codec_name, + int max_qp, + bool is_screenshare, + bool conference_mode, + const webrtc::FieldTrialsView* trials) + + : codec_name_(codec_name), + max_qp_(max_qp), + is_screenshare_(is_screenshare), + conference_mode_(conference_mode), + trials_(trials ? *trials : fallback_trials_) {} + +std::vector EncoderStreamFactory::CreateEncoderStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config) { + RTC_DCHECK_GT(encoder_config.number_of_streams, 0); + RTC_DCHECK_GE(encoder_config.simulcast_layers.size(), + encoder_config.number_of_streams); + + 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)) && + is_screenshare_ && conference_mode_)) { + return CreateSimulcastOrConferenceModeScreenshareStreams( + width, height, encoder_config, experimental_min_bitrate); + } + + return CreateDefaultVideoStreams(width, height, encoder_config, + experimental_min_bitrate); +} + +std::vector +EncoderStreamFactory::CreateDefaultVideoStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config, + const absl::optional& experimental_min_bitrate) const { + std::vector layers; + + // For unset max bitrates set default bitrate for non-simulcast. + int max_bitrate_bps = + (encoder_config.max_bitrate_bps > 0) + ? encoder_config.max_bitrate_bps + : GetMaxDefaultVideoBitrateKbps(width, height, is_screenshare_) * + 1000; + + 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; + // If only min bitrate is configured, make sure max is above min. + if (encoder_config.max_bitrate_bps <= 0) + max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps); + } + int max_framerate = (encoder_config.simulcast_layers[0].max_framerate > 0) + ? encoder_config.simulcast_layers[0].max_framerate + : kDefaultVideoMaxFramerate; + + webrtc::VideoStream layer; + layer.width = width; + layer.height = height; + layer.max_framerate = max_framerate; + // Note: VP9 seems to have be sending if any layer is active, + // (see `UpdateSendState`) and still use parameters only from + // encoder_config.simulcast_layers[0]. + layer.active = absl::c_any_of(encoder_config.simulcast_layers, + [](const auto& layer) { return layer.active; }); + + if (encoder_config.simulcast_layers[0].scale_resolution_down_by > 1.) { + layer.width = ScaleDownResolution( + layer.width, + encoder_config.simulcast_layers[0].scale_resolution_down_by, + kMinLayerSize); + layer.height = ScaleDownResolution( + layer.height, + encoder_config.simulcast_layers[0].scale_resolution_down_by, + kMinLayerSize); + } + + if (absl::EqualsIgnoreCase(codec_name_, kVp9CodecName)) { + RTC_DCHECK(encoder_config.encoder_specific_settings); + // Use VP9 SVC layering from codec settings which might be initialized + // though field trial in ConfigureVideoEncoderSettings. + webrtc::VideoCodecVP9 vp9_settings; + encoder_config.encoder_specific_settings->FillVideoCodecVp9(&vp9_settings); + layer.num_temporal_layers = vp9_settings.numberOfTemporalLayers; + + // Number of spatial layers is signalled differently from different call + // sites (sigh), pick the max as we are interested in the upper bound. + int num_spatial_layers = + std::max({encoder_config.simulcast_layers.size(), + encoder_config.spatial_layers.size(), + size_t{vp9_settings.numberOfSpatialLayers}}); + + if (width * height > 0 && + (layer.num_temporal_layers > 1u || num_spatial_layers > 1)) { + // In SVC mode, the VP9 max bitrate is determined by SvcConfig, instead of + // GetMaxDefaultVideoBitrateKbps(). + std::vector svc_layers = + webrtc::GetSvcConfig(width, height, max_framerate, + /*first_active_layer=*/0, num_spatial_layers, + *layer.num_temporal_layers, is_screenshare_); + int sum_max_bitrates_kbps = 0; + for (const webrtc::SpatialLayer& spatial_layer : svc_layers) { + sum_max_bitrates_kbps += spatial_layer.maxBitrate; + } + RTC_DCHECK_GE(sum_max_bitrates_kbps, 0); + if (encoder_config.max_bitrate_bps <= 0) { + max_bitrate_bps = sum_max_bitrates_kbps * 1000; + } else { + max_bitrate_bps = + std::min(max_bitrate_bps, sum_max_bitrates_kbps * 1000); + } + max_bitrate_bps = std::max(min_bitrate_bps, max_bitrate_bps); + } + } + + // In the case that the application sets a max bitrate that's lower than the + // min bitrate, we adjust it down (see bugs.webrtc.org/9141). + layer.min_bitrate_bps = std::min(min_bitrate_bps, max_bitrate_bps); + if (encoder_config.simulcast_layers[0].target_bitrate_bps <= 0) { + layer.target_bitrate_bps = max_bitrate_bps; + } else { + layer.target_bitrate_bps = std::min( + encoder_config.simulcast_layers[0].target_bitrate_bps, max_bitrate_bps); + } + layer.max_bitrate_bps = max_bitrate_bps; + layer.max_qp = max_qp_; + layer.bitrate_priority = encoder_config.bitrate_priority; + + if (IsTemporalLayersSupported(codec_name_)) { + // Use configured number of temporal layers if set. + if (encoder_config.simulcast_layers[0].num_temporal_layers) { + layer.num_temporal_layers = + *encoder_config.simulcast_layers[0].num_temporal_layers; + } + } + layer.scalability_mode = encoder_config.simulcast_layers[0].scalability_mode; + layers.push_back(layer); + return layers; +} + +std::vector +EncoderStreamFactory::CreateSimulcastOrConferenceModeScreenshareStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config, + const absl::optional& experimental_min_bitrate) const { + std::vector layers; + + const bool temporal_layers_supported = + absl::EqualsIgnoreCase(codec_name_, kVp8CodecName) || + absl::EqualsIgnoreCase(codec_name_, kH264CodecName); + // Use legacy simulcast screenshare if conference mode is explicitly enabled + // or use the regular simulcast configuration path which is generic. + layers = GetSimulcastConfig(FindRequiredActiveLayers(encoder_config), + encoder_config.number_of_streams, width, height, + encoder_config.bitrate_priority, max_qp_, + is_screenshare_ && conference_mode_, + temporal_layers_supported, trials_); + // 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()); + } + // Update the active simulcast layers and configured bitrates. + bool is_highest_layer_max_bitrate_configured = false; + const bool has_scale_resolution_down_by = absl::c_any_of( + encoder_config.simulcast_layers, [](const webrtc::VideoStream& layer) { + return layer.scale_resolution_down_by != -1.; + }); + + bool default_scale_factors_used = true; + if (has_scale_resolution_down_by) { + default_scale_factors_used = IsScaleFactorsPowerOfTwo(encoder_config); + } + const bool norm_size_configured = + webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent().has_value(); + const int normalized_width = + (default_scale_factors_used || norm_size_configured) && + (width >= kMinLayerSize) + ? NormalizeSimulcastSize(width, encoder_config.number_of_streams) + : width; + const int normalized_height = + (default_scale_factors_used || norm_size_configured) && + (height >= kMinLayerSize) + ? NormalizeSimulcastSize(height, encoder_config.number_of_streams) + : height; + for (size_t i = 0; i < layers.size(); ++i) { + layers[i].active = encoder_config.simulcast_layers[i].active; + layers[i].scalability_mode = + encoder_config.simulcast_layers[i].scalability_mode; + // Update with configured num temporal layers if supported by codec. + if (encoder_config.simulcast_layers[i].num_temporal_layers && + IsTemporalLayersSupported(codec_name_)) { + layers[i].num_temporal_layers = + *encoder_config.simulcast_layers[i].num_temporal_layers; + } + if (encoder_config.simulcast_layers[i].max_framerate > 0) { + layers[i].max_framerate = + encoder_config.simulcast_layers[i].max_framerate; + } + if (has_scale_resolution_down_by) { + const double scale_resolution_down_by = std::max( + encoder_config.simulcast_layers[i].scale_resolution_down_by, 1.0); + layers[i].width = ScaleDownResolution( + normalized_width, scale_resolution_down_by, kMinLayerSize); + layers[i].height = ScaleDownResolution( + normalized_height, scale_resolution_down_by, kMinLayerSize); + } + // Update simulcast bitrates with configured min and max bitrate. + if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) { + layers[i].min_bitrate_bps = + encoder_config.simulcast_layers[i].min_bitrate_bps; + } + if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) { + layers[i].max_bitrate_bps = + encoder_config.simulcast_layers[i].max_bitrate_bps; + } + if (encoder_config.simulcast_layers[i].target_bitrate_bps > 0) { + layers[i].target_bitrate_bps = + encoder_config.simulcast_layers[i].target_bitrate_bps; + } + if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0 && + encoder_config.simulcast_layers[i].max_bitrate_bps > 0) { + // Min and max bitrate are configured. + // Set target to 3/4 of the max bitrate (or to max if below min). + if (encoder_config.simulcast_layers[i].target_bitrate_bps <= 0) + layers[i].target_bitrate_bps = layers[i].max_bitrate_bps * 3 / 4; + if (layers[i].target_bitrate_bps < layers[i].min_bitrate_bps) + layers[i].target_bitrate_bps = layers[i].max_bitrate_bps; + } else if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) { + // Only min bitrate is configured, make sure target/max are above min. + layers[i].target_bitrate_bps = + std::max(layers[i].target_bitrate_bps, layers[i].min_bitrate_bps); + layers[i].max_bitrate_bps = + std::max(layers[i].max_bitrate_bps, layers[i].min_bitrate_bps); + } else if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) { + // Only max bitrate is configured, make sure min/target are below max. + // Keep target bitrate if it is set explicitly in encoding config. + // Otherwise set target bitrate to 3/4 of the max bitrate + // or the one calculated from GetSimulcastConfig() which is larger. + layers[i].min_bitrate_bps = + std::min(layers[i].min_bitrate_bps, layers[i].max_bitrate_bps); + if (encoder_config.simulcast_layers[i].target_bitrate_bps <= 0) { + layers[i].target_bitrate_bps = std::max( + layers[i].target_bitrate_bps, layers[i].max_bitrate_bps * 3 / 4); + } + layers[i].target_bitrate_bps = std::max( + std::min(layers[i].target_bitrate_bps, layers[i].max_bitrate_bps), + layers[i].min_bitrate_bps); + } + if (i == layers.size() - 1) { + is_highest_layer_max_bitrate_configured = + encoder_config.simulcast_layers[i].max_bitrate_bps > 0; + } + } + if (!is_screenshare_ && !is_highest_layer_max_bitrate_configured && + encoder_config.max_bitrate_bps > 0) { + // No application-configured maximum for the largest layer. + // If there is bitrate leftover, give it to the largest layer. + BoostMaxSimulcastLayer( + webrtc::DataRate::BitsPerSec(encoder_config.max_bitrate_bps), &layers); + } + + // Sort the layers by max_bitrate_bps, they might not always be from + // smallest to biggest + std::vector index(layers.size()); + std::iota(index.begin(), index.end(), 0); + std::stable_sort(index.begin(), index.end(), [&layers](size_t a, size_t b) { + return layers[a].max_bitrate_bps < layers[b].max_bitrate_bps; + }); + + if (!layers[index[0]].active) { + // Adjust min bitrate of the first active layer to allow it to go as low as + // the lowest (now inactive) layer could. + // Otherwise, if e.g. a single HD stream is active, it would have 600kbps + // min bitrate, which would always be allocated to the stream. + // This would lead to congested network, dropped frames and overall bad + // experience. + + const int min_configured_bitrate = layers[index[0]].min_bitrate_bps; + for (size_t i = 0; i < layers.size(); ++i) { + if (layers[index[i]].active) { + layers[index[i]].min_bitrate_bps = min_configured_bitrate; + break; + } + } + } + + return layers; +} + +} // namespace cricket diff --git a/video/config/encoder_stream_factory.h b/video/config/encoder_stream_factory.h new file mode 100644 index 0000000000..971eed4983 --- /dev/null +++ b/video/config/encoder_stream_factory.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022 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 VIDEO_CONFIG_ENCODER_STREAM_FACTORY_H_ +#define VIDEO_CONFIG_ENCODER_STREAM_FACTORY_H_ + +#include +#include + +#include "api/transport/field_trial_based_config.h" +#include "api/units/data_rate.h" +#include "api/video_codecs/video_encoder_config.h" + +namespace cricket { + +class EncoderStreamFactory + : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface { + public: + EncoderStreamFactory(std::string codec_name, + int max_qp, + bool is_screenshare, + bool conference_mode) + : EncoderStreamFactory(codec_name, + max_qp, + is_screenshare, + conference_mode, + nullptr) {} + + EncoderStreamFactory(std::string codec_name, + int max_qp, + bool is_screenshare, + bool conference_mode, + const webrtc::FieldTrialsView* trials); + + private: + std::vector CreateEncoderStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config) override; + + std::vector CreateDefaultVideoStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config, + const absl::optional& experimental_min_bitrate) const; + + std::vector + CreateSimulcastOrConferenceModeScreenshareStreams( + int width, + int height, + const webrtc::VideoEncoderConfig& encoder_config, + const absl::optional& experimental_min_bitrate) const; + + const std::string codec_name_; + const int max_qp_; + const bool is_screenshare_; + // Allows a screenshare specific configuration, which enables temporal + // layering and various settings. + const bool conference_mode_; + const webrtc::FieldTrialBasedConfig fallback_trials_; + const webrtc::FieldTrialsView& trials_; +}; + +} // namespace cricket + +#endif // VIDEO_CONFIG_ENCODER_STREAM_FACTORY_H_ diff --git a/media/engine/simulcast.cc b/video/config/simulcast.cc similarity index 99% rename from media/engine/simulcast.cc rename to video/config/simulcast.cc index fb10c0f3e0..2bd4ac04c3 100644 --- a/media/engine/simulcast.cc +++ b/video/config/simulcast.cc @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "media/engine/simulcast.h" +#include "video/config/simulcast.h" #include #include diff --git a/media/engine/simulcast.h b/video/config/simulcast.h similarity index 95% rename from media/engine/simulcast.h rename to video/config/simulcast.h index e367830889..aa48058302 100644 --- a/media/engine/simulcast.h +++ b/video/config/simulcast.h @@ -8,8 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef MEDIA_ENGINE_SIMULCAST_H_ -#define MEDIA_ENGINE_SIMULCAST_H_ +#ifndef VIDEO_CONFIG_SIMULCAST_H_ +#define VIDEO_CONFIG_SIMULCAST_H_ #include @@ -69,4 +69,4 @@ std::vector GetScreenshareLayers( } // namespace cricket -#endif // MEDIA_ENGINE_SIMULCAST_H_ +#endif // VIDEO_CONFIG_SIMULCAST_H_ diff --git a/media/engine/simulcast_unittest.cc b/video/config/simulcast_unittest.cc similarity index 99% rename from media/engine/simulcast_unittest.cc rename to video/config/simulcast_unittest.cc index 47a9db75a1..152a0f9525 100644 --- a/media/engine/simulcast_unittest.cc +++ b/video/config/simulcast_unittest.cc @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "media/engine/simulcast.h" +#include "video/config/simulcast.h" #include "api/transport/field_trial_based_config.h" #include "media/base/media_constants.h" 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 8cdfaad4bf..5d905b850c 100644 --- a/video/end_to_end_tests/resolution_bitrate_limits_tests.cc +++ b/video/end_to_end_tests/resolution_bitrate_limits_tests.cc @@ -18,6 +18,7 @@ #include "test/field_trial.h" #include "test/gtest.h" #include "test/video_encoder_proxy_factory.h" +#include "video/config/encoder_stream_factory.h" namespace webrtc { namespace test { diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc index 1b5b3a85b3..d0554319f6 100644 --- a/video/video_quality_test.cc +++ b/video/video_quality_test.cc @@ -54,6 +54,7 @@ #ifdef WEBRTC_WIN #include "modules/audio_device/include/audio_device_factory.h" #endif +#include "video/config/encoder_stream_factory.h" namespace webrtc { diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc index 965073b264..33a607bd1a 100644 --- a/video/video_send_stream_tests.cc +++ b/video/video_send_stream_tests.cc @@ -69,6 +69,7 @@ #include "test/null_transport.h" #include "test/rtcp_packet_parser.h" #include "test/video_encoder_proxy_factory.h" +#include "video/config/encoder_stream_factory.h" #include "video/send_statistics_proxy.h" #include "video/transport_adapter.h" #include "video/video_send_stream.h" diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc index 3baa9c565d..961f592165 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -1,3 +1,4 @@ + /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -7,7 +8,6 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ - #include "video/video_stream_encoder.h" #include @@ -70,6 +70,7 @@ #include "test/time_controller/simulated_time_controller.h" #include "test/video_encoder_nullable_proxy_factory.h" #include "test/video_encoder_proxy_factory.h" +#include "video/config/encoder_stream_factory.h" #include "video/frame_cadence_adapter.h" #include "video/send_statistics_proxy.h"