From 32b917ac41abf196cc7a2a14303484cfd5746eed Mon Sep 17 00:00:00 2001 From: Danil Chapovalov Date: Fri, 10 Sep 2021 12:30:09 +0200 Subject: [PATCH] With Svc controller do not produce frame that will be dropped anyway This cover scenario where target bitrate is changed in a middle of of group of frame after spatial upswitch. This change should avoid wasting encoder resources to produce those frames, reduce number of errors "Encoder produced a frame for layer that wasn't requested" Bug: webrtc:11999 Change-Id: I06045259b1cee2c21bfdabbafff3892b57c82a84 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/230543 Commit-Queue: Danil Chapovalov Reviewed-by: Philip Eliasson Cr-Commit-Position: refs/heads/main@{#34969} --- .../codecs/vp9/libvpx_vp9_encoder.cc | 59 +++++++++++++++++-- .../codecs/vp9/libvpx_vp9_encoder.h | 6 ++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc index f920a64ead..a95519dfa4 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc @@ -399,22 +399,72 @@ bool LibvpxVp9Encoder::SetSvcRates( } if (svc_controller_) { - VideoBitrateAllocation allocation; for (int sid = 0; sid < num_spatial_layers_; ++sid) { for (int tid = 0; tid < num_temporal_layers_; ++tid) { - allocation.SetBitrate( + current_bitrate_allocation_.SetBitrate( sid, tid, config_->layer_target_bitrate[sid * num_temporal_layers_ + tid] * 1000); } } - svc_controller_->OnRatesUpdated(allocation); + svc_controller_->OnRatesUpdated(current_bitrate_allocation_); + } else { + current_bitrate_allocation_ = bitrate_allocation; } - current_bitrate_allocation_ = bitrate_allocation; config_changed_ = true; return true; } +void LibvpxVp9Encoder::DisableSpatialLayer(int sid) { + RTC_DCHECK_LT(sid, num_spatial_layers_); + if (config_->ss_target_bitrate[sid] == 0) { + return; + } + config_->ss_target_bitrate[sid] = 0; + for (int tid = 0; tid < num_temporal_layers_; ++tid) { + config_->layer_target_bitrate[sid * num_temporal_layers_ + tid] = 0; + } + config_changed_ = true; +} + +void LibvpxVp9Encoder::EnableSpatialLayer(int sid) { + RTC_DCHECK_LT(sid, num_spatial_layers_); + if (config_->ss_target_bitrate[sid] > 0) { + return; + } + for (int tid = 0; tid < num_temporal_layers_; ++tid) { + config_->layer_target_bitrate[sid * num_temporal_layers_ + tid] = + current_bitrate_allocation_.GetBitrate(sid, tid) / 1000; + } + config_->ss_target_bitrate[sid] = + current_bitrate_allocation_.GetSpatialLayerSum(sid) / 1000; + RTC_DCHECK_GT(config_->ss_target_bitrate[sid], 0); + config_changed_ = true; +} + +void LibvpxVp9Encoder::SetActiveSpatialLayers() { + // Svc controller may decide to skip a frame at certain spatial layer even + // when bitrate for it is non-zero, however libvpx uses configured bitrate as + // a signal which layers should be produced. + RTC_DCHECK(svc_controller_); + RTC_DCHECK(!layer_frames_.empty()); + RTC_DCHECK(absl::c_is_sorted( + layer_frames_, [](const ScalableVideoController::LayerFrameConfig& lhs, + const ScalableVideoController::LayerFrameConfig& rhs) { + return lhs.SpatialId() < rhs.SpatialId(); + })); + + auto frame_it = layer_frames_.begin(); + for (int sid = 0; sid < num_spatial_layers_; ++sid) { + if (frame_it != layer_frames_.end() && frame_it->SpatialId() == sid) { + EnableSpatialLayer(sid); + ++frame_it; + } else { + DisableSpatialLayer(sid); + } + } +} + void LibvpxVp9Encoder::SetRates(const RateControlParameters& parameters) { if (!inited_) { RTC_LOG(LS_WARNING) << "SetRates() calll while uninitialzied."; @@ -978,6 +1028,7 @@ int LibvpxVp9Encoder::Encode(const VideoFrame& input_image, layer_id.temporal_layer_id_per_spatial[layer.SpatialId()] = layer.TemporalId(); } + SetActiveSpatialLayers(); } if (is_svc_ && performance_flags_.use_per_layer_speed) { diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h index c2790f06ad..fc4018954f 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h @@ -82,6 +82,12 @@ class LibvpxVp9Encoder : public VP9Encoder { bool ExplicitlyConfiguredSpatialLayers() const; bool SetSvcRates(const VideoBitrateAllocation& bitrate_allocation); + // Configures which spatial layers libvpx should encode according to + // configuration provided by svc_controller_. + void EnableSpatialLayer(int sid); + void DisableSpatialLayer(int sid); + void SetActiveSpatialLayers(); + void GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt); // Callback function for outputting packets per spatial layer.