From f18072e5565dcc5a96578be2af0af76357cce48b Mon Sep 17 00:00:00 2001 From: Sergey Silkin Date: Wed, 14 Mar 2018 10:35:35 +0100 Subject: [PATCH] Enable SVC based on number of SSRCs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Number of spatial layers is set equal to number of SSRCs. The maximum value is limited to 3. If spatial layering is enabled, i.e. number of spatial layers is greater than 1, then number of temporal layers is set to 3. Otherwise number of temporal layers is set to 1. Number of spatial and temporal layers can be overwritten through field trial. Bug: webrtc:8931 Change-Id: I37bd7fe053529683dc3e91b4e544fbdb44429340 Reviewed-on: https://webrtc-review.googlesource.com/59440 Commit-Queue: Sergey Silkin Reviewed-by: Stefan Holmer Reviewed-by: Erik Språng Cr-Commit-Position: refs/heads/master@{#22511} --- media/base/mediaconstants.cc | 4 ++ media/base/mediaconstants.h | 4 ++ media/engine/webrtcvideoengine.cc | 44 ++++++++++++++-------- media/engine/webrtcvideoengine_unittest.cc | 32 ++++++++++++++++ 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/media/base/mediaconstants.cc b/media/base/mediaconstants.cc index e3a1d9b1d4..abc4e0c1b9 100644 --- a/media/base/mediaconstants.cc +++ b/media/base/mediaconstants.cc @@ -112,4 +112,8 @@ const char kH264FmtpSpropParameterSets[] = "sprop-parameter-sets"; const char kH264ProfileLevelConstrainedBaseline[] = "42e01f"; const int kDefaultVideoMaxFramerate = 60; + +const size_t kConferenceMaxNumSpatialLayers = 3; +const size_t kConferenceMaxNumTemporalLayers = 3; +const size_t kConferenceDefaultNumTemporalLayers = 3; } // namespace cricket diff --git a/media/base/mediaconstants.h b/media/base/mediaconstants.h index 73bbb8d247..72edd89e20 100644 --- a/media/base/mediaconstants.h +++ b/media/base/mediaconstants.h @@ -134,6 +134,10 @@ extern const char kH264FmtpSpropParameterSets[]; extern const char kH264ProfileLevelConstrainedBaseline[]; extern const int kDefaultVideoMaxFramerate; + +extern const size_t kConferenceMaxNumSpatialLayers; +extern const size_t kConferenceMaxNumTemporalLayers; +extern const size_t kConferenceDefaultNumTemporalLayers; } // namespace cricket #endif // MEDIA_BASE_MEDIACONSTANTS_H_ diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc index bc90c8fcf1..7174524dd7 100644 --- a/media/engine/webrtcvideoengine.cc +++ b/media/engine/webrtcvideoengine.cc @@ -340,43 +340,43 @@ static int GetMaxDefaultVideoBitrateKbps(int width, int height) { } } -bool GetVp9LayersFromFieldTrialGroup(int* num_spatial_layers, - int* num_temporal_layers) { +bool GetVp9LayersFromFieldTrialGroup(size_t* num_spatial_layers, + size_t* num_temporal_layers) { std::string group = webrtc::field_trial::FindFullName("WebRTC-SupportVP9SVC"); if (group.empty()) return false; - if (sscanf(group.c_str(), "EnabledByFlag_%dSL%dTL", num_spatial_layers, + if (sscanf(group.c_str(), "EnabledByFlag_%zuSL%zuTL", num_spatial_layers, num_temporal_layers) != 2) { return false; } - const int kMaxSpatialLayers = 2; + const size_t kMaxSpatialLayers = 3; if (*num_spatial_layers > kMaxSpatialLayers || *num_spatial_layers < 1) return false; - const int kMaxTemporalLayers = 3; + const size_t kMaxTemporalLayers = 3; if (*num_temporal_layers > kMaxTemporalLayers || *num_temporal_layers < 1) return false; return true; } -int GetDefaultVp9SpatialLayers() { - int num_sl; - int num_tl; +rtc::Optional GetVp9SpatialLayersFromFieldTrial() { + size_t num_sl; + size_t num_tl; if (GetVp9LayersFromFieldTrialGroup(&num_sl, &num_tl)) { return num_sl; } - return 1; + return rtc::nullopt; } -int GetDefaultVp9TemporalLayers() { - int num_sl; - int num_tl; +rtc::Optional GetVp9TemporalLayersFromFieldTrial() { + size_t num_sl; + size_t num_tl; if (GetVp9LayersFromFieldTrialGroup(&num_sl, &num_tl)) { return num_tl; } - return 1; + return rtc::nullopt; } const char kForcedFallbackFieldTrial[] = @@ -464,8 +464,22 @@ WebRtcVideoChannel::WebRtcVideoSendStream::ConfigureVideoEncoderSettings( vp9_settings.numberOfSpatialLayers = 2; vp9_settings.numberOfTemporalLayers = 1; } else { - vp9_settings.numberOfSpatialLayers = GetDefaultVp9SpatialLayers(); - vp9_settings.numberOfTemporalLayers = GetDefaultVp9TemporalLayers(); + const size_t default_num_spatial_layers = + parameters_.config.rtp.ssrcs.size(); + const size_t num_spatial_layers = + GetVp9SpatialLayersFromFieldTrial().value_or( + default_num_spatial_layers); + + const size_t default_num_temporal_layers = + num_spatial_layers > 1 ? kConferenceDefaultNumTemporalLayers : 1; + const size_t num_temporal_layers = + GetVp9TemporalLayersFromFieldTrial().value_or( + default_num_temporal_layers); + + vp9_settings.numberOfSpatialLayers = std::min( + num_spatial_layers, kConferenceMaxNumSpatialLayers); + vp9_settings.numberOfTemporalLayers = std::min( + num_temporal_layers, kConferenceMaxNumTemporalLayers); } // VP9 denoising is disabled by default. diff --git a/media/engine/webrtcvideoengine_unittest.cc b/media/engine/webrtcvideoengine_unittest.cc index e994d8d747..d0b570725a 100644 --- a/media/engine/webrtcvideoengine_unittest.cc +++ b/media/engine/webrtcvideoengine_unittest.cc @@ -2223,6 +2223,38 @@ TEST_F(Vp9SettingsTest, VerifyVp9SpecificSettings) { EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, true, nullptr, nullptr)); } +TEST_F(Vp9SettingsTest, MultipleSsrcsEnablesSvc) { + cricket::VideoSendParameters parameters; + parameters.codecs.push_back(GetEngineCodec("VP9")); + ASSERT_TRUE(channel_->SetSendParameters(parameters)); + + std::vector ssrcs = MAKE_VECTOR(kSsrcs3); + + FakeVideoSendStream* stream = + AddSendStream(CreateSimStreamParams("cname", ssrcs)); + + webrtc::VideoSendStream::Config config = stream->GetConfig().Copy(); + EXPECT_EQ(ssrcs.size(), config.rtp.ssrcs.size()); + + FakeVideoCapturerWithTaskQueue capturer; + EXPECT_EQ(cricket::CS_RUNNING, + capturer.Start(capturer.GetSupportedFormats()->front())); + EXPECT_TRUE(channel_->SetVideoSend(ssrcs[0], true, nullptr, &capturer)); + channel_->SetSend(true); + + EXPECT_TRUE(capturer.CaptureFrame()); + + webrtc::VideoCodecVP9 vp9_settings; + ASSERT_TRUE(stream->GetVp9Settings(&vp9_settings)) << "No VP9 config set."; + + const size_t kNumSpatialLayers = ssrcs.size(); + const size_t kNumTemporalLayers = 3; + EXPECT_EQ(vp9_settings.numberOfSpatialLayers, kNumSpatialLayers); + EXPECT_EQ(vp9_settings.numberOfTemporalLayers, kNumTemporalLayers); + + EXPECT_TRUE(channel_->SetVideoSend(ssrcs[0], true, nullptr, nullptr)); +} + class Vp9SettingsTestWithFieldTrial : public Vp9SettingsTest { public: explicit Vp9SettingsTestWithFieldTrial(const char* field_trials)