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)