diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc index 48639c48dc..c5e4cdf67c 100644 --- a/media/engine/webrtcvideoengine.cc +++ b/media/engine/webrtcvideoengine.cc @@ -1989,7 +1989,9 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig( RTC_DCHECK_GE(rtp_parameters_.encodings.size(), encoder_config.number_of_streams); RTC_DCHECK_GT(encoder_config.number_of_streams, 0); - encoder_config.simulcast_layers.resize(encoder_config.number_of_streams); + + // Copy all provided constraints. + encoder_config.simulcast_layers.resize(rtp_parameters_.encodings.size()); for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i) { encoder_config.simulcast_layers[i].active = rtp_parameters_.encodings[i].active; @@ -2701,7 +2703,7 @@ std::vector EncoderStreamFactory::CreateEncoderStreams( RTC_DCHECK_EQ(1, encoder_config.number_of_streams); } RTC_DCHECK_GT(encoder_config.number_of_streams, 0); - RTC_DCHECK_EQ(encoder_config.simulcast_layers.size(), + RTC_DCHECK_GE(encoder_config.simulcast_layers.size(), encoder_config.number_of_streams); std::vector layers; diff --git a/media/engine/webrtcvideoengine_unittest.cc b/media/engine/webrtcvideoengine_unittest.cc index 4ba3c489dc..5e8183670a 100644 --- a/media/engine/webrtcvideoengine_unittest.cc +++ b/media/engine/webrtcvideoengine_unittest.cc @@ -3112,6 +3112,38 @@ TEST_F(Vp9SettingsTest, MultipleSsrcsEnablesSvc) { EXPECT_TRUE(channel_->SetVideoSend(ssrcs[0], nullptr, nullptr)); } +TEST_F(Vp9SettingsTest, AllEncodingParametersCopied) { + cricket::VideoSendParameters send_parameters; + send_parameters.codecs.push_back(GetEngineCodec("VP9")); + ASSERT_TRUE(channel_->SetSendParameters(send_parameters)); + + const size_t kNumSpatialLayers = 3; + std::vector ssrcs = MAKE_VECTOR(kSsrcs3); + + FakeVideoSendStream* stream = + AddSendStream(CreateSimStreamParams("cname", ssrcs)); + + webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(ssrcs[0]); + ASSERT_EQ(kNumSpatialLayers, parameters.encodings.size()); + ASSERT_TRUE(parameters.encodings[0].active); + ASSERT_TRUE(parameters.encodings[1].active); + ASSERT_TRUE(parameters.encodings[2].active); + // Invert value to verify copying. + parameters.encodings[1].active = false; + EXPECT_TRUE(channel_->SetRtpSendParameters(ssrcs[0], parameters).ok()); + + webrtc::VideoEncoderConfig encoder_config = stream->GetEncoderConfig().Copy(); + + // number_of_streams should be 1 since all spatial layers are sent on the + // same SSRC. But encoding parameters of all layers is supposed to be copied + // and stored in simulcast_layers[]. + EXPECT_EQ(1u, encoder_config.number_of_streams); + EXPECT_EQ(encoder_config.simulcast_layers.size(), kNumSpatialLayers); + EXPECT_TRUE(encoder_config.simulcast_layers[0].active); + EXPECT_FALSE(encoder_config.simulcast_layers[1].active); + EXPECT_TRUE(encoder_config.simulcast_layers[2].active); +} + class Vp9SettingsTestWithFieldTrial : public Vp9SettingsTest { public: explicit Vp9SettingsTestWithFieldTrial(const char* field_trials) diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc index 0e76b09d6b..1754195d5c 100644 --- a/modules/video_coding/codecs/vp9/svc_config.cc +++ b/modules/video_coding/codecs/vp9/svc_config.cc @@ -15,7 +15,6 @@ #include #include "modules/video_coding/codecs/vp9/include/vp9_globals.h" -#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h" #include "rtc_base/checks.h" namespace webrtc { @@ -47,6 +46,7 @@ std::vector ConfigureSvcScreenSharing(size_t input_width, spatial_layer.maxBitrate = static_cast(kMaxScreenSharingLayerBitrateKbps[sl_idx]); spatial_layer.targetBitrate = spatial_layer.maxBitrate; + spatial_layer.active = true; spatial_layers.push_back(spatial_layer); } @@ -70,13 +70,13 @@ std::vector ConfigureSvcNormalVideo(size_t input_width, num_spatial_layers = std::min({num_spatial_layers, num_layers_fit_horz, num_layers_fit_vert}); - float top_fraction = 0.; for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) { SpatialLayer spatial_layer = {0}; spatial_layer.width = input_width >> (num_spatial_layers - sl_idx - 1); spatial_layer.height = input_height >> (num_spatial_layers - sl_idx - 1); spatial_layer.maxFramerate = max_framerate_fps; spatial_layer.numberOfTemporalLayers = num_temporal_layers; + spatial_layer.active = true; // minBitrate and maxBitrate formulas were derived from // subjective-quality data to determing bit rates below which video @@ -96,14 +96,8 @@ std::vector ConfigureSvcNormalVideo(size_t input_width, spatial_layer.targetBitrate = (spatial_layer.minBitrate + spatial_layer.maxBitrate) / 2; spatial_layers.push_back(spatial_layer); - top_fraction += std::pow(kSpatialLayeringRateScalingFactor, sl_idx); } - // Compute spatial_layers[num_spatial_layers - 1].targetBitrate, which is - // used to set max_padding_bitrate_. Set max_padding_bitrate_ equal to the - // minimum total bit rate required to support all spatial layers. - spatial_layers[num_spatial_layers - 1].targetBitrate = - static_cast( - spatial_layers[num_spatial_layers - 1].minBitrate * top_fraction); + return spatial_layers; } diff --git a/modules/video_coding/codecs/vp9/svc_rate_allocator.cc b/modules/video_coding/codecs/vp9/svc_rate_allocator.cc index cf74e0887d..0535abda8a 100644 --- a/modules/video_coding/codecs/vp9/svc_rate_allocator.cc +++ b/modules/video_coding/codecs/vp9/svc_rate_allocator.cc @@ -23,8 +23,85 @@ namespace webrtc { const float kSpatialLayeringRateScalingFactor = 0.55f; const float kTemporalLayeringRateScalingFactor = 0.55f; +static size_t GetNumActiveSpatialLayers(const VideoCodec& codec) { + RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9); + RTC_DCHECK_GT(codec.VP9().numberOfSpatialLayers, 0u); + + size_t num_spatial_layers = 0; + for (; num_spatial_layers < codec.VP9().numberOfSpatialLayers; + ++num_spatial_layers) { + if (!codec.spatialLayers[num_spatial_layers].active) { + // TODO(bugs.webrtc.org/9350): Deactivation of middle layer is not + // implemented. For now deactivation of a VP9 layer deactivates all + // layers above the deactivated one. + break; + } + } + + return num_spatial_layers; +} + +static bool AdjustAndVerify(const VideoCodec& codec, + std::vector* spatial_layer_bitrate_bps) { + bool enough_bitrate = true; + size_t excess_rate = 0; + for (size_t sl_idx = 0; + sl_idx < spatial_layer_bitrate_bps->size() && enough_bitrate; ++sl_idx) { + RTC_DCHECK_GT(codec.spatialLayers[sl_idx].maxBitrate, 0); + RTC_DCHECK_GE(codec.spatialLayers[sl_idx].maxBitrate, + codec.spatialLayers[sl_idx].minBitrate); + + const size_t min_bitrate_bps = + codec.spatialLayers[sl_idx].minBitrate * 1000; + const size_t max_bitrate_bps = + codec.spatialLayers[sl_idx].maxBitrate * 1000; + + spatial_layer_bitrate_bps->at(sl_idx) += excess_rate; + if (spatial_layer_bitrate_bps->at(sl_idx) < max_bitrate_bps) { + excess_rate = 0; + } else { + excess_rate = spatial_layer_bitrate_bps->at(sl_idx) - max_bitrate_bps; + spatial_layer_bitrate_bps->at(sl_idx) = max_bitrate_bps; + } + + size_t bitrate_bps = spatial_layer_bitrate_bps->at(sl_idx); + enough_bitrate = (bitrate_bps >= min_bitrate_bps); + } + + return enough_bitrate; +} + +static std::vector SplitBitrate(size_t num_layers, + size_t total_bitrate, + float rate_scaling_factor) { + std::vector bitrates; + + double denominator = 0.0; + for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { + denominator += std::pow(rate_scaling_factor, layer_idx); + } + + double numerator = std::pow(rate_scaling_factor, num_layers - 1); + for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { + bitrates.push_back(numerator * total_bitrate / denominator); + numerator /= rate_scaling_factor; + } + + const size_t sum = std::accumulate(bitrates.begin(), bitrates.end(), 0); + // Ensure the sum of split bitrates doesn't exceed the total bitrate. + RTC_DCHECK_LE(sum, total_bitrate); + + // Keep the sum of split bitrates equal to the total bitrate by adding bits, + // which were lost due to rounding, to the latest layer. + bitrates.back() += total_bitrate - sum; + + return bitrates; +} + SvcRateAllocator::SvcRateAllocator(const VideoCodec& codec) : codec_(codec) { RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9); + RTC_DCHECK_GT(codec.VP9().numberOfSpatialLayers, 0u); + RTC_DCHECK_GT(codec.VP9().numberOfTemporalLayers, 0u); } VideoBitrateAllocation SvcRateAllocator::GetAllocation( @@ -36,24 +113,27 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocation( if (codec_.spatialLayers[0].targetBitrate == 0) { // Delegate rate distribution to VP9 encoder wrapper if bitrate thresholds - // are not initialized. + // are not set. VideoBitrateAllocation bitrate_allocation; bitrate_allocation.SetBitrate(0, 0, total_bitrate_bps); return bitrate_allocation; - } else if (codec_.mode == VideoCodecMode::kRealtimeVideo) { - return GetAllocationNormalVideo(total_bitrate_bps); + } + + size_t num_spatial_layers = GetNumActiveSpatialLayers(codec_); + if (num_spatial_layers == 0) { + return VideoBitrateAllocation(); // All layers are deactivated. + } + + if (codec_.mode == VideoCodecMode::kRealtimeVideo) { + return GetAllocationNormalVideo(total_bitrate_bps, num_spatial_layers); } else { - return GetAllocationScreenSharing(total_bitrate_bps); + return GetAllocationScreenSharing(total_bitrate_bps, num_spatial_layers); } } VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo( - uint32_t total_bitrate_bps) const { - size_t num_spatial_layers = codec_.VP9().numberOfSpatialLayers; - RTC_CHECK(num_spatial_layers > 0); - size_t num_temporal_layers = codec_.VP9().numberOfTemporalLayers; - RTC_CHECK(num_temporal_layers > 0); - + uint32_t total_bitrate_bps, + size_t num_spatial_layers) const { std::vector spatial_layer_bitrate_bps; // Distribute total bitrate across spatial layers. If there is not enough @@ -65,7 +145,8 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo( SplitBitrate(num_spatial_layers, total_bitrate_bps, kSpatialLayeringRateScalingFactor); - const bool enough_bitrate = AdjustAndVerify(&spatial_layer_bitrate_bps); + const bool enough_bitrate = + AdjustAndVerify(codec_, &spatial_layer_bitrate_bps); if (enough_bitrate || num_spatial_layers == 1) { break; } @@ -73,6 +154,7 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo( VideoBitrateAllocation bitrate_allocation; + const size_t num_temporal_layers = codec_.VP9().numberOfTemporalLayers; for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) { std::vector temporal_layer_bitrate_bps = SplitBitrate(num_temporal_layers, spatial_layer_bitrate_bps[sl_idx], @@ -102,41 +184,9 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo( return bitrate_allocation; } -bool SvcRateAllocator::AdjustAndVerify( - std::vector* spatial_layer_bitrate_bps) const { - bool enough_bitrate = true; - size_t excess_rate = 0; - for (size_t sl_idx = 0; - sl_idx < spatial_layer_bitrate_bps->size() && enough_bitrate; ++sl_idx) { - RTC_DCHECK_GT(codec_.spatialLayers[sl_idx].maxBitrate, 0); - RTC_DCHECK_GE(codec_.spatialLayers[sl_idx].maxBitrate, - codec_.spatialLayers[sl_idx].minBitrate); - - const size_t min_bitrate_bps = - codec_.spatialLayers[sl_idx].minBitrate * 1000; - const size_t max_bitrate_bps = - codec_.spatialLayers[sl_idx].maxBitrate * 1000; - - spatial_layer_bitrate_bps->at(sl_idx) += excess_rate; - if (spatial_layer_bitrate_bps->at(sl_idx) < max_bitrate_bps) { - excess_rate = 0; - } else { - excess_rate = spatial_layer_bitrate_bps->at(sl_idx) - max_bitrate_bps; - spatial_layer_bitrate_bps->at(sl_idx) = max_bitrate_bps; - } - - enough_bitrate = (spatial_layer_bitrate_bps->at(sl_idx) >= min_bitrate_bps); - } - - return enough_bitrate; -} - VideoBitrateAllocation SvcRateAllocator::GetAllocationScreenSharing( - uint32_t total_bitrate_bps) const { - const size_t num_spatial_layers = codec_.VP9().numberOfSpatialLayers; - RTC_CHECK(num_spatial_layers > 0); - RTC_CHECK_EQ(codec_.VP9().numberOfTemporalLayers, 1U); - + uint32_t total_bitrate_bps, + size_t num_spatial_layers) const { VideoBitrateAllocation bitrate_allocation; // Add next layer after bitrate of previous layer has reached its maximum. @@ -160,32 +210,43 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationScreenSharing( return bitrate_allocation; } -std::vector SvcRateAllocator::SplitBitrate( - size_t num_layers, - size_t total_bitrate, - float rate_scaling_factor) const { - std::vector bitrates; +uint32_t SvcRateAllocator::GetMaxBitrateBps(const VideoCodec& codec) { + const size_t num_spatial_layers = GetNumActiveSpatialLayers(codec); - double denominator = 0.0; - for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { - denominator += std::pow(rate_scaling_factor, layer_idx); + uint32_t max_bitrate_kbps = 0; + for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) { + max_bitrate_kbps += codec.spatialLayers[sl_idx].maxBitrate; } - double numerator = std::pow(rate_scaling_factor, num_layers - 1); - for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { - bitrates.push_back(numerator * total_bitrate / denominator); - numerator /= rate_scaling_factor; + if (codec.maxBitrate != 0) { + max_bitrate_kbps = std::min(max_bitrate_kbps, codec.maxBitrate); } - const size_t sum = std::accumulate(bitrates.begin(), bitrates.end(), 0); - // Ensure the sum of split bitrates doesn't exceed the total bitrate. - RTC_DCHECK_LE(sum, total_bitrate); + return max_bitrate_kbps * 1000; +} - // Keep the sum of split bitrates equal to the total bitrate by adding bits, - // which were lost due to rounding, to the latest layer. - bitrates.back() += total_bitrate - sum; +uint32_t SvcRateAllocator::GetPaddingBitrateBps(const VideoCodec& codec) { + const size_t num_spatial_layers = GetNumActiveSpatialLayers(codec); - return bitrates; + if (codec.mode == VideoCodecMode::kRealtimeVideo) { + float scale_factor = 0.0; + for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) { + scale_factor += std::pow(kSpatialLayeringRateScalingFactor, sl_idx); + } + uint32_t min_bitrate_bps = + codec.spatialLayers[num_spatial_layers - 1].minBitrate * 1000; + return static_cast(min_bitrate_bps * scale_factor); + } + + RTC_DCHECK(codec.mode == VideoCodecMode::kScreensharing); + + uint32_t min_bitrate_kbps = 0; + for (size_t sl_idx = 0; sl_idx < num_spatial_layers - 1; ++sl_idx) { + min_bitrate_kbps += codec.spatialLayers[sl_idx].maxBitrate; + } + min_bitrate_kbps += codec.spatialLayers[num_spatial_layers - 1].minBitrate; + + return min_bitrate_kbps * 1000; } } // namespace webrtc diff --git a/modules/video_coding/codecs/vp9/svc_rate_allocator.h b/modules/video_coding/codecs/vp9/svc_rate_allocator.h index 8aa60ff49b..fc4c67f5fa 100644 --- a/modules/video_coding/codecs/vp9/svc_rate_allocator.h +++ b/modules/video_coding/codecs/vp9/svc_rate_allocator.h @@ -21,9 +21,6 @@ namespace webrtc { -extern const float kSpatialLayeringRateScalingFactor; -extern const float kTemporalLayeringRateScalingFactor; - class SvcRateAllocator : public VideoBitrateAllocator { public: explicit SvcRateAllocator(const VideoCodec& codec); @@ -31,15 +28,17 @@ class SvcRateAllocator : public VideoBitrateAllocator { VideoBitrateAllocation GetAllocation(uint32_t total_bitrate_bps, uint32_t framerate_fps) override; + static uint32_t GetMaxBitrateBps(const VideoCodec& codec); + static uint32_t GetPaddingBitrateBps(const VideoCodec& codec); + private: VideoBitrateAllocation GetAllocationNormalVideo( - uint32_t total_bitrate_bps) const; + uint32_t total_bitrate_bps, + size_t num_spatial_layers) const; + VideoBitrateAllocation GetAllocationScreenSharing( - uint32_t total_bitrate_bps) const; - std::vector SplitBitrate(size_t num_layers, - size_t total_bitrate, - float rate_scaling_factor) const; - bool AdjustAndVerify(std::vector* spatial_layer_bitrate_bps) const; + uint32_t total_bitrate_bps, + size_t num_spatial_layers) const; const VideoCodec codec_; }; diff --git a/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc b/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc index e430123909..3c3f020349 100644 --- a/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc +++ b/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc @@ -164,4 +164,89 @@ TEST(SvcRateAllocatorTest, MinBitrateToGetQualityLayer) { EXPECT_EQ(allocation.GetSpatialLayerSum(1) / 1000, layers[1].minBitrate); } +TEST(SvcRateAllocatorTest, DeativateLayers) { + for (int deactivated_idx = 2; deactivated_idx >= 0; --deactivated_idx) { + VideoCodec codec = Configure(1280, 720, 3, 1, false); + EXPECT_LE(codec.VP9()->numberOfSpatialLayers, 3U); + + codec.spatialLayers[deactivated_idx].active = false; + + SvcRateAllocator allocator = SvcRateAllocator(codec); + + VideoBitrateAllocation allocation = + allocator.GetAllocation(10 * 1000 * 1000, 30); + + // Ensure layers spatial_idx < deactivated_idx are activated. + for (int spatial_idx = 0; spatial_idx < deactivated_idx; ++spatial_idx) { + EXPECT_GT(allocation.GetSpatialLayerSum(spatial_idx), 0UL); + } + + // Ensure layers spatial_idx >= deactivated_idx are deactivated. + for (int spatial_idx = deactivated_idx; spatial_idx < 3; ++spatial_idx) { + EXPECT_EQ(allocation.GetSpatialLayerSum(spatial_idx), 0UL); + } + } +} + +class SvcRateAllocatorTestParametrizedContentType + : public testing::Test, + public testing::WithParamInterface { + public: + SvcRateAllocatorTestParametrizedContentType() + : is_screen_sharing_(GetParam()) {} + + const bool is_screen_sharing_; +}; + +TEST_P(SvcRateAllocatorTestParametrizedContentType, MaxBitrate) { + VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_); + EXPECT_EQ( + SvcRateAllocator::GetMaxBitrateBps(codec), + (codec.spatialLayers[0].maxBitrate + codec.spatialLayers[1].maxBitrate + + codec.spatialLayers[2].maxBitrate) * + 1000); + + // Deactivate middle layer. This causes deactivation of top layer as well. + codec.spatialLayers[1].active = false; + EXPECT_EQ(SvcRateAllocator::GetMaxBitrateBps(codec), + codec.spatialLayers[0].maxBitrate * 1000); +} + +TEST_P(SvcRateAllocatorTestParametrizedContentType, PaddingBitrate) { + VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_); + SvcRateAllocator allocator = SvcRateAllocator(codec); + + uint32_t padding_bitrate_bps = SvcRateAllocator::GetPaddingBitrateBps(codec); + + VideoBitrateAllocation allocation = + allocator.GetAllocation(padding_bitrate_bps, 30); + EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL); + EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL); + EXPECT_GT(allocation.GetSpatialLayerSum(2), 0UL); + + // Allocate 90% of padding bitrate. Top layer should be disabled. + allocation = allocator.GetAllocation(9 * padding_bitrate_bps / 10, 30); + EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL); + EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL); + EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL); + + // Deactivate top layer. + codec.spatialLayers[2].active = false; + + padding_bitrate_bps = SvcRateAllocator::GetPaddingBitrateBps(codec); + allocation = allocator.GetAllocation(padding_bitrate_bps, 30); + EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL); + EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL); + EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL); + + allocation = allocator.GetAllocation(9 * padding_bitrate_bps / 10, 30); + EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL); + EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0UL); + EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL); +} + +INSTANTIATE_TEST_CASE_P(_, + SvcRateAllocatorTestParametrizedContentType, + ::testing::Bool()); + } // namespace webrtc diff --git a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc index 5386a8e285..9faeb5a431 100644 --- a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc +++ b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc @@ -336,12 +336,15 @@ TEST_F(TestVp9Impl, EncoderExplicitLayering) { (codec_settings_.spatialLayers[0].minBitrate + codec_settings_.spatialLayers[0].maxBitrate) / 2; + codec_settings_.spatialLayers[0].active = true; + codec_settings_.spatialLayers[1].minBitrate = 400; codec_settings_.spatialLayers[1].maxBitrate = 1500; codec_settings_.spatialLayers[1].targetBitrate = (codec_settings_.spatialLayers[1].minBitrate + codec_settings_.spatialLayers[1].maxBitrate) / 2; + codec_settings_.spatialLayers[1].active = true; codec_settings_.spatialLayers[0].width = codec_settings_.width / 2; codec_settings_.spatialLayers[0].height = codec_settings_.height / 2; @@ -1034,6 +1037,7 @@ TEST_F(TestVp9ImplFrameDropping, DifferentFrameratePerSpatialLayer) { codec_settings_.startBitrate; codec_settings_.spatialLayers[sl_idx].targetBitrate = codec_settings_.startBitrate; + codec_settings_.spatialLayers[sl_idx].active = true; bitrate_allocation.SetBitrate( sl_idx, 0, codec_settings_.spatialLayers[sl_idx].targetBitrate * 1000); @@ -1090,6 +1094,7 @@ TEST_F(TestVp9ImplFrameDropping, LayerMaxFramerateIsCappedByCodecMaxFramerate) { codec_settings_.spatialLayers[0].minBitrate = codec_settings_.startBitrate; codec_settings_.spatialLayers[0].maxBitrate = codec_settings_.startBitrate; codec_settings_.spatialLayers[0].targetBitrate = codec_settings_.startBitrate; + codec_settings_.spatialLayers[0].active = true; bitrate_allocation.SetBitrate( 0, 0, codec_settings_.spatialLayers[0].targetBitrate * 1000); diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc index cd3f1d7ffa..311fb868ef 100644 --- a/modules/video_coding/video_codec_initializer.cc +++ b/modules/video_coding/video_codec_initializer.cc @@ -192,6 +192,14 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec( spatial_layers.back().minBitrate = video_codec.minBitrate; spatial_layers.back().maxBitrate = video_codec.maxBitrate; } + + for (size_t spatial_idx = 0; + spatial_idx < config.simulcast_layers.size() && + spatial_idx < spatial_layers.size(); + ++spatial_idx) { + spatial_layers[spatial_layers.size() - spatial_idx - 1].active = + config.simulcast_layers[spatial_idx].active; + } } RTC_DCHECK(!spatial_layers.empty()); diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc index 8a0ed261b5..75be427226 100644 --- a/modules/video_coding/video_codec_initializer_unittest.cc +++ b/modules/video_coding/video_codec_initializer_unittest.cc @@ -313,4 +313,36 @@ TEST_F(VideoCodecInitializerTest, kDefaultMaxBitrateBps / 1000); } +TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) { + SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 1, false); + VideoStream stream = DefaultStream(); + streams_.push_back(stream); + + config_.simulcast_layers.resize(3); + + // Activate all layers. + config_.simulcast_layers[0].active = true; + config_.simulcast_layers[1].active = true; + config_.simulcast_layers[2].active = true; + EXPECT_TRUE(InitializeCodec()); + EXPECT_TRUE(codec_out_.spatialLayers[0].active); + EXPECT_TRUE(codec_out_.spatialLayers[1].active); + EXPECT_TRUE(codec_out_.spatialLayers[2].active); + + // Deactivate top layer. + config_.simulcast_layers[0].active = false; + EXPECT_TRUE(InitializeCodec()); + EXPECT_TRUE(codec_out_.spatialLayers[0].active); + EXPECT_TRUE(codec_out_.spatialLayers[1].active); + EXPECT_FALSE(codec_out_.spatialLayers[2].active); + + // Deactivate middle layer. + config_.simulcast_layers[0].active = true; + config_.simulcast_layers[1].active = false; + EXPECT_TRUE(InitializeCodec()); + EXPECT_TRUE(codec_out_.spatialLayers[0].active); + EXPECT_FALSE(codec_out_.spatialLayers[1].active); + EXPECT_TRUE(codec_out_.spatialLayers[2].active); +} + } // namespace webrtc diff --git a/video/BUILD.gn b/video/BUILD.gn index af08bb7827..a554213446 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -190,6 +190,7 @@ rtc_source_set("video_stream_encoder_impl") { "../common_video:common_video", "../modules/video_coding", "../modules/video_coding:video_coding_utility", + "../modules/video_coding:webrtc_vp9_helpers", "../rtc_base:checks", "../rtc_base:criticalsection", "../rtc_base:logging", diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc index 99f6888755..c6d19d0e26 100644 --- a/video/video_send_stream_impl.cc +++ b/video/video_send_stream_impl.cc @@ -555,7 +555,8 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged( const VideoCodecType codec_type = PayloadStringToCodecType(config_->rtp.payload_name); if (codec_type == kVideoCodecVP9) { - max_padding_bitrate_ = streams[0].target_bitrate_bps; + max_padding_bitrate_ = has_alr_probing_ ? streams[0].min_bitrate_bps + : streams[0].target_bitrate_bps; } else { max_padding_bitrate_ = CalculateMaxPadBitrateBps( streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate, diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index 410c331359..8cabc032b9 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -18,6 +18,7 @@ #include "api/video/encoded_image.h" #include "api/video/i420_buffer.h" #include "api/video/video_bitrate_allocator_factory.h" +#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h" #include "modules/video_coding/include/video_codec_initializer.h" #include "modules/video_coding/include/video_coding.h" #include "rtc_base/arraysize.h" @@ -550,24 +551,13 @@ void VideoStreamEncoder::ReconfigureEncoder() { // Set min_bitrate_bps, max_bitrate_bps, and max padding bit rate for VP9. if (encoder_config_.codec_type == kVideoCodecVP9) { - RTC_DCHECK_EQ(1U, streams.size()); - int max_encoder_bitrate_kbps = 0; - for (int i = 0; i < codec.VP9()->numberOfSpatialLayers; ++i) { - max_encoder_bitrate_kbps += codec.spatialLayers[i].maxBitrate; - } // Lower max bitrate to the level codec actually can produce. - streams[0].max_bitrate_bps = - std::min(streams[0].max_bitrate_bps, max_encoder_bitrate_kbps * 1000); + streams[0].max_bitrate_bps = std::min( + streams[0].max_bitrate_bps, SvcRateAllocator::GetMaxBitrateBps(codec)); streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000; - // Pass along the value of maximum padding bit rate from - // spatialLayers[].targetBitrate to streams[0].target_bitrate_bps. - // TODO(ssilkin): There should be some margin between max padding bitrate - // and max encoder bitrate. With the current logic they can be equal. + // target_bitrate_bps specifies the maximum padding bitrate. streams[0].target_bitrate_bps = - std::min(static_cast(streams[0].max_bitrate_bps), - codec.spatialLayers[codec.VP9()->numberOfSpatialLayers - 1] - .targetBitrate * - 1000); + SvcRateAllocator::GetPaddingBitrateBps(codec); } codec.startBitrate =