From 277a656263395f208588cae536fb395d8c475c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMichael?= Date: Fri, 1 Jun 2018 14:09:19 -0500 Subject: [PATCH] Unstable BWE due to improper bit rate padding for VP9. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:9345 Change-Id: I5b1e0b4ed7a8c1d0b942b09433017cac6d53c64b Reviewed-on: https://webrtc-review.googlesource.com/79000 Commit-Queue: Michael Horowitz Reviewed-by: Erik Språng Cr-Commit-Position: refs/heads/master@{#23496} --- modules/video_coding/codecs/vp9/svc_config.cc | 19 +++++++++++----- .../codecs/vp9/svc_rate_allocator.cc | 2 -- .../codecs/vp9/svc_rate_allocator.h | 3 +++ video/full_stack_tests.cc | 14 ++++++++++++ video/video_send_stream_impl.cc | 11 ++++++++-- video/video_stream_encoder.cc | 22 +++++++++++++++++++ 6 files changed, 62 insertions(+), 9 deletions(-) diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc index ed60a0d9fd..c4ec288ccd 100644 --- a/modules/video_coding/codecs/vp9/svc_config.cc +++ b/modules/video_coding/codecs/vp9/svc_config.cc @@ -14,6 +14,7 @@ #include #include +#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h" #include "modules/video_coding/include/video_codec_interface.h" namespace webrtc { @@ -63,6 +64,7 @@ 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); @@ -77,17 +79,24 @@ std::vector ConfigureSvcNormalVideo(size_t input_width, // TODO(ssilkin): Add to the comment PSNR/SSIM we get at encoding certain // video to min/max bitrate specified by those formulas. const size_t num_pixels = spatial_layer.width * spatial_layer.height; - const size_t min_bitrate = + int min_bitrate = static_cast((600. * std::sqrt(num_pixels) - 95000.) / 1000.); - spatial_layer.minBitrate = std::max(min_bitrate, kMinVp9SvcBitrateKbps); + min_bitrate = std::max(min_bitrate, 0); + spatial_layer.minBitrate = + std::max(static_cast(min_bitrate), kMinVp9SvcBitrateKbps); spatial_layer.maxBitrate = static_cast((1.6 * num_pixels + 50 * 1000) / 1000); spatial_layer.targetBitrate = - (spatial_layer.maxBitrate + spatial_layer.minBitrate) / 2; - + (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 61505c0883..87c8fb819a 100644 --- a/modules/video_coding/codecs/vp9/svc_rate_allocator.cc +++ b/modules/video_coding/codecs/vp9/svc_rate_allocator.cc @@ -18,10 +18,8 @@ namespace webrtc { -namespace { const float kSpatialLayeringRateScalingFactor = 0.55f; const float kTemporalLayeringRateScalingFactor = 0.55f; -} // namespace SvcRateAllocator::SvcRateAllocator(const VideoCodec& codec) : codec_(codec) { RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9); diff --git a/modules/video_coding/codecs/vp9/svc_rate_allocator.h b/modules/video_coding/codecs/vp9/svc_rate_allocator.h index 4592c18543..260061a9ae 100644 --- a/modules/video_coding/codecs/vp9/svc_rate_allocator.h +++ b/modules/video_coding/codecs/vp9/svc_rate_allocator.h @@ -20,6 +20,9 @@ namespace webrtc { +extern const float kSpatialLayeringRateScalingFactor; +extern const float kTemporalLayeringRateScalingFactor; + class SvcRateAllocator : public VideoBitrateAllocator { public: explicit SvcRateAllocator(const VideoCodec& codec); diff --git a/video/full_stack_tests.cc b/video/full_stack_tests.cc index 61346a9e3f..cf3ad580d6 100644 --- a/video/full_stack_tests.cc +++ b/video/full_stack_tests.cc @@ -813,6 +813,20 @@ TEST_F(FullStackTest, VP9KSVC_3SL_Low) { std::vector(), false}; RunTest(simulcast); } + +TEST_F(FullStackTest, VP9KSVC_3SL_Medium_Network_Restricted) { + VideoQualityTest::Params simulcast; + simulcast.call.send_side_bwe = true; + simulcast.video[0] = kSvcVp9Video; + simulcast.analyzer = {"vp9ksvc_3sl_medium_network_restricted", 0.0, 0.0, + kFullStackTestDurationSecs}; + simulcast.ss[0] = { + std::vector(), 0, 3, 1, InterLayerPredMode::kOnKeyPic, + std::vector(), false}; + simulcast.pipe.link_capacity_kbps = 1000; + RunTest(simulcast); +} + #endif // !defined(RTC_DISABLE_VP9) // Android bots can't handle FullHD, so disable the test. diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc index f2bb8d3d6b..c8fae7f34e 100644 --- a/video/video_send_stream_impl.cc +++ b/video/video_send_stream_impl.cc @@ -633,8 +633,15 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged( encoder_max_bitrate_bps_ = std::max(static_cast(encoder_min_bitrate_bps_), encoder_max_bitrate_bps_); - max_padding_bitrate_ = CalculateMaxPadBitrateBps( - streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate); + + const VideoCodecType codec_type = + PayloadStringToCodecType(config_->rtp.payload_name); + if (codec_type == kVideoCodecVP9) { + max_padding_bitrate_ = streams[0].target_bitrate_bps; + } else { + max_padding_bitrate_ = CalculateMaxPadBitrateBps( + streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate); + } // Clear stats for disabled layers. for (size_t i = streams.size(); i < config_->rtp.ssrcs.size(); ++i) { diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index 92062855ba..33f6df74fb 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -514,6 +514,28 @@ void VideoStreamEncoder::ReconfigureEncoder() { RTC_LOG(LS_ERROR) << "Failed to create encoder configuration."; } + // 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].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. + streams[0].target_bitrate_bps = + std::min(static_cast(streams[0].max_bitrate_bps), + codec.spatialLayers[codec.VP9()->numberOfSpatialLayers - 1] + .targetBitrate * + 1000); + } + codec.startBitrate = std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate); codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);