From 3a656d14dcf6573120739497262b5b4ea10b8f4e Mon Sep 17 00:00:00 2001 From: Ilya Nikolaevskiy Date: Thu, 14 Feb 2019 14:44:22 +0100 Subject: [PATCH] Tune bitrates and minQP thresholds for high-fps screenshare. Raise MinQP to allow easier steady-state convergence. Update SVC rate allocator to not waste bandwidth if there's not enough for the highest layer. Bug: webrtc:10257 Change-Id: Iba937bf3c224ffed256308bdb6434be8b5223f84 Reviewed-on: https://webrtc-review.googlesource.com/c/122843 Reviewed-by: Sergey Silkin Commit-Queue: Ilya Nikolaevskiy Cr-Commit-Position: refs/heads/master@{#26710} --- media/engine/webrtc_video_engine.cc | 19 ++++++++---- .../codecs/vp8/libvpx_vp8_encoder.cc | 5 ++-- modules/video_coding/codecs/vp9/svc_config.cc | 11 +++++-- .../codecs/vp9/svc_rate_allocator.cc | 30 +++++++++++++++---- .../codecs/vp9/svc_rate_allocator_unittest.cc | 4 +-- modules/video_coding/codecs/vp9/vp9_impl.cc | 5 ++-- 6 files changed, 53 insertions(+), 21 deletions(-) diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index e0018726f1..09d37b3f2c 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -227,16 +227,22 @@ bool IsCodecBlacklistedForSimulcast(const std::string& codec_name) { // 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) { +static int GetMaxDefaultVideoBitrateKbps(int width, + int height, + bool is_screenshare) { + int max_bitrate; if (width * height <= 320 * 240) { - return 600; + max_bitrate = 600; } else if (width * height <= 640 * 480) { - return 1700; + max_bitrate = 1700; } else if (width * height <= 960 * 540) { - return 2000; + max_bitrate = 2000; } else { - return 2500; + max_bitrate = 2500; } + if (is_screenshare) + max_bitrate = std::max(max_bitrate, 1200); + return max_bitrate; } bool GetVp9LayersFromFieldTrialGroup(size_t* num_spatial_layers, @@ -2783,7 +2789,8 @@ std::vector EncoderStreamFactory::CreateEncoderStreams( int max_bitrate_bps = (encoder_config.max_bitrate_bps > 0) ? encoder_config.max_bitrate_bps - : GetMaxDefaultVideoBitrateKbps(width, height) * 1000; + : GetMaxDefaultVideoBitrateKbps(width, height, is_screenshare_) * + 1000; int min_bitrate_bps = GetMinVideoBitrateBps(); if (encoder_config.simulcast_layers[0].min_bitrate_bps > 0) { diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc index 7a233258df..ea1b994ce5 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc @@ -409,7 +409,8 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst, configurations_[0].g_pass = VPX_RC_ONE_PASS; // Handle resizing outside of libvpx. configurations_[0].rc_resize_allowed = 0; - configurations_[0].rc_min_quantizer = 2; + configurations_[0].rc_min_quantizer = + codec_.mode == VideoCodecMode::kScreensharing ? 12 : 2; if (inst->qpMax >= configurations_[0].rc_min_quantizer) { qp_max_ = inst->qpMax; } @@ -645,7 +646,7 @@ int LibvpxVp8Encoder::InitAndSetControlSettings() { // Allow more screen content to be detected as static. libvpx_->codec_control( &(encoders_[i]), VP8E_SET_STATIC_THRESHOLD, - codec_.mode == VideoCodecMode::kScreensharing ? 300u : 1u); + codec_.mode == VideoCodecMode::kScreensharing ? 100u : 1u); libvpx_->codec_control(&(encoders_[i]), VP8E_SET_CPUUSED, cpu_speed_[i]); libvpx_->codec_control( &(encoders_[i]), VP8E_SET_TOKEN_PARTITIONS, diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc index 1754195d5c..138822ab92 100644 --- a/modules/video_coding/codecs/vp9/svc_config.cc +++ b/modules/video_coding/codecs/vp9/svc_config.cc @@ -24,7 +24,10 @@ const size_t kMinVp9SvcBitrateKbps = 30; const size_t kMaxNumLayersForScreenSharing = 3; const float kMaxScreenSharingLayerFramerateFps[] = {5.0, 5.0, 30.0}; -const size_t kMaxScreenSharingLayerBitrateKbps[] = {200, 500, 1250}; +const size_t kMinScreenSharingLayerBitrateKbps[] = {30, 150, 500}; +const size_t kTargetScreenSharingLayerBitrateKbps[] = {150, 350, 1000}; +const size_t kMaxScreenSharingLayerBitrateKbps[] = {200, 500, 1000}; + } // namespace std::vector ConfigureSvcScreenSharing(size_t input_width, @@ -42,10 +45,12 @@ std::vector ConfigureSvcScreenSharing(size_t input_width, spatial_layer.maxFramerate = std::min(kMaxScreenSharingLayerFramerateFps[sl_idx], max_framerate_fps); spatial_layer.numberOfTemporalLayers = 1; - spatial_layer.minBitrate = static_cast(kMinVp9SvcBitrateKbps); + spatial_layer.minBitrate = + static_cast(kMinScreenSharingLayerBitrateKbps[sl_idx]); spatial_layer.maxBitrate = static_cast(kMaxScreenSharingLayerBitrateKbps[sl_idx]); - spatial_layer.targetBitrate = spatial_layer.maxBitrate; + spatial_layer.targetBitrate = + static_cast(kTargetScreenSharingLayerBitrateKbps[sl_idx]); spatial_layer.active = true; spatial_layers.push_back(spatial_layer); } diff --git a/modules/video_coding/codecs/vp9/svc_rate_allocator.cc b/modules/video_coding/codecs/vp9/svc_rate_allocator.cc index f6ddb1e8e1..daa59b1101 100644 --- a/modules/video_coding/codecs/vp9/svc_rate_allocator.cc +++ b/modules/video_coding/codecs/vp9/svc_rate_allocator.cc @@ -184,20 +184,27 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo( return bitrate_allocation; } +// Bit-rate is allocated in such a way, that the highest enabled layer will have +// between min and max bitrate, and all others will have exactly target +// bit-rate allocated. VideoBitrateAllocation SvcRateAllocator::GetAllocationScreenSharing( uint32_t total_bitrate_bps, size_t num_spatial_layers) const { + if (num_spatial_layers == 0 || + total_bitrate_bps < codec_.spatialLayers[0].minBitrate * 1000) { + return VideoBitrateAllocation(); + } VideoBitrateAllocation bitrate_allocation; - // Add next layer after bitrate of previous layer has reached its maximum. size_t left_bitrate_bps = total_bitrate_bps; - for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) { + size_t sl_idx; + for (sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) { const size_t min_bitrate_bps = codec_.spatialLayers[sl_idx].minBitrate * 1000; - const size_t max_bitrate_bps = - codec_.spatialLayers[sl_idx].maxBitrate * 1000; + const size_t target_bitrate_bps = + codec_.spatialLayers[sl_idx].targetBitrate * 1000; - const size_t bitrate_bps = std::min(left_bitrate_bps, max_bitrate_bps); + const size_t bitrate_bps = std::min(left_bitrate_bps, target_bitrate_bps); if (bitrate_bps >= min_bitrate_bps) { bitrate_allocation.SetBitrate(sl_idx, 0, bitrate_bps); } else { @@ -207,6 +214,17 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationScreenSharing( left_bitrate_bps -= bitrate_bps; } + if (left_bitrate_bps > 0 && sl_idx > 0) { + // Add leftover to the last allocated layer. + const size_t max_bitrate_bps = + codec_.spatialLayers[sl_idx - 1].maxBitrate * 1000; + + const size_t bitrate_bps = std::min( + bitrate_allocation.GetBitrate(sl_idx - 1, 0) + left_bitrate_bps, + max_bitrate_bps); + bitrate_allocation.SetBitrate(sl_idx - 1, 0, bitrate_bps); + } + return bitrate_allocation; } @@ -245,7 +263,7 @@ uint32_t SvcRateAllocator::GetPaddingBitrateBps(const VideoCodec& codec) { 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[sl_idx].targetBitrate; } min_bitrate_kbps += codec.spatialLayers[num_spatial_layers - 1].minBitrate; 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 e1e1df7aeb..f1c6bdd7d9 100644 --- a/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc +++ b/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc @@ -159,8 +159,8 @@ TEST(SvcRateAllocatorTest, MinBitrateToGetQualityLayer) { EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0UL); allocation = allocator.GetAllocation( - (layers[0].maxBitrate + layers[1].minBitrate) * 1000, 30); - EXPECT_EQ(allocation.GetSpatialLayerSum(0) / 1000, layers[0].maxBitrate); + (layers[0].targetBitrate + layers[1].minBitrate) * 1000, 30); + EXPECT_EQ(allocation.GetSpatialLayerSum(0) / 1000, layers[0].targetBitrate); EXPECT_EQ(allocation.GetSpatialLayerSum(1) / 1000, layers[1].minBitrate); } diff --git a/modules/video_coding/codecs/vp9/vp9_impl.cc b/modules/video_coding/codecs/vp9/vp9_impl.cc index 5feca0b0a9..ac9f8f9868 100644 --- a/modules/video_coding/codecs/vp9/vp9_impl.cc +++ b/modules/video_coding/codecs/vp9/vp9_impl.cc @@ -48,7 +48,7 @@ uint8_t kUpdBufIdx[4] = {0, 0, 1, 0}; int kMaxNumTiles4kVideo = 8; // Maximum allowed PID difference for variable frame-rate mode. -const int kMaxAllowedPidDIff = 8; +const int kMaxAllowedPidDIff = 30; // Only positive speeds, range for real-time coding currently is: 5 - 8. // Lower means slower/better quality, higher means fastest/lower quality. @@ -441,7 +441,8 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst, config_->rc_dropframe_thresh = inst->VP9().frameDroppingOn ? 30 : 0; config_->rc_end_usage = VPX_CBR; config_->g_pass = VPX_RC_ONE_PASS; - config_->rc_min_quantizer = 2; + config_->rc_min_quantizer = + codec_.mode == VideoCodecMode::kScreensharing ? 8 : 2; config_->rc_max_quantizer = 52; config_->rc_undershoot_pct = 50; config_->rc_overshoot_pct = 50;