| /* |
| * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "modules/video_coding/utility/bandwidth_quality_scaler.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "api/video/video_adaptation_reason.h" |
| #include "api/video_codecs/video_encoder.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/logging.h" |
| #include "rtc_base/numerics/exp_filter.h" |
| #include "rtc_base/time_utils.h" |
| #include "rtc_base/weak_ptr.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| |
| constexpr int kDefaultMaxWindowSizeMs = 5000; |
| constexpr float kHigherMaxBitrateTolerationFactor = 0.95; |
| constexpr float kLowerMinBitrateTolerationFactor = 0.8; |
| } // namespace |
| |
| BandwidthQualityScaler::BandwidthQualityScaler( |
| BandwidthQualityScalerUsageHandlerInterface* handler) |
| : handler_(handler), |
| encoded_bitrate_(kDefaultMaxWindowSizeMs, RateStatistics::kBpsScale), |
| weak_ptr_factory_(this) { |
| RTC_DCHECK_RUN_ON(&task_checker_); |
| RTC_DCHECK(handler_ != nullptr); |
| |
| StartCheckForBitrate(); |
| } |
| |
| BandwidthQualityScaler::~BandwidthQualityScaler() { |
| RTC_DCHECK_RUN_ON(&task_checker_); |
| } |
| |
| void BandwidthQualityScaler::StartCheckForBitrate() { |
| RTC_DCHECK_RUN_ON(&task_checker_); |
| TaskQueueBase::Current()->PostDelayedTask( |
| [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(), this] { |
| if (!this_weak_ptr) { |
| // The caller BandwidthQualityScaler has been deleted. |
| return; |
| } |
| RTC_DCHECK_RUN_ON(&task_checker_); |
| switch (CheckBitrate()) { |
| case BandwidthQualityScaler::CheckBitrateResult::kHighBitRate: { |
| handler_->OnReportUsageBandwidthHigh(); |
| last_frame_size_pixels_.reset(); |
| break; |
| } |
| case BandwidthQualityScaler::CheckBitrateResult::kLowBitRate: { |
| handler_->OnReportUsageBandwidthLow(); |
| last_frame_size_pixels_.reset(); |
| break; |
| } |
| case BandwidthQualityScaler::CheckBitrateResult::kNormalBitrate: { |
| break; |
| } |
| case BandwidthQualityScaler::CheckBitrateResult:: |
| kInsufficientSamples: { |
| break; |
| } |
| } |
| StartCheckForBitrate(); |
| }, |
| kBitrateStateUpdateInterval); |
| } |
| |
| void BandwidthQualityScaler::ReportEncodeInfo(int frame_size_bytes, |
| int64_t time_sent_in_ms, |
| uint32_t encoded_width, |
| uint32_t encoded_height) { |
| RTC_DCHECK_RUN_ON(&task_checker_); |
| last_time_sent_in_ms_ = time_sent_in_ms; |
| last_frame_size_pixels_ = encoded_width * encoded_height; |
| encoded_bitrate_.Update(frame_size_bytes, time_sent_in_ms); |
| } |
| |
| void BandwidthQualityScaler::SetResolutionBitrateLimits( |
| const std::vector<VideoEncoder::ResolutionBitrateLimits>& |
| resolution_bitrate_limits) { |
| if (resolution_bitrate_limits.empty()) { |
| resolution_bitrate_limits_ = EncoderInfoSettings:: |
| GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted(); |
| } else { |
| resolution_bitrate_limits_ = resolution_bitrate_limits; |
| } |
| } |
| |
| BandwidthQualityScaler::CheckBitrateResult |
| BandwidthQualityScaler::CheckBitrate() { |
| RTC_DCHECK_RUN_ON(&task_checker_); |
| if (!last_frame_size_pixels_.has_value() || |
| !last_time_sent_in_ms_.has_value()) { |
| return BandwidthQualityScaler::CheckBitrateResult::kInsufficientSamples; |
| } |
| |
| std::optional<int64_t> current_bitrate_bps = |
| encoded_bitrate_.Rate(last_time_sent_in_ms_.value()); |
| if (!current_bitrate_bps.has_value()) { |
| // We can't get a valid bitrate due to not enough data points. |
| return BandwidthQualityScaler::CheckBitrateResult::kInsufficientSamples; |
| } |
| std::optional<VideoEncoder::ResolutionBitrateLimits> suitable_bitrate_limit = |
| EncoderInfoSettings:: |
| GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted( |
| last_frame_size_pixels_, resolution_bitrate_limits_); |
| |
| if (!suitable_bitrate_limit.has_value()) { |
| return BandwidthQualityScaler::CheckBitrateResult::kInsufficientSamples; |
| } |
| |
| // Multiply by toleration factor to solve the frequent adaptation due to |
| // critical value. |
| if (current_bitrate_bps > suitable_bitrate_limit->max_bitrate_bps * |
| kHigherMaxBitrateTolerationFactor) { |
| return BandwidthQualityScaler::CheckBitrateResult::kLowBitRate; |
| } else if (current_bitrate_bps < |
| suitable_bitrate_limit->min_start_bitrate_bps * |
| kLowerMinBitrateTolerationFactor) { |
| return BandwidthQualityScaler::CheckBitrateResult::kHighBitRate; |
| } |
| return BandwidthQualityScaler::CheckBitrateResult::kNormalBitrate; |
| } |
| |
| BandwidthQualityScalerUsageHandlerInterface:: |
| ~BandwidthQualityScalerUsageHandlerInterface() {} |
| } // namespace webrtc |