Line data Source code
1 : /*
2 : * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "webrtc/common_video/include/bitrate_adjuster.h"
12 :
13 : #include <algorithm>
14 : #include <cmath>
15 :
16 : #include "webrtc/base/checks.h"
17 : #include "webrtc/base/logging.h"
18 : #include "webrtc/system_wrappers/include/clock.h"
19 :
20 : namespace webrtc {
21 :
22 : // Update bitrate at most once every second.
23 : const uint32_t BitrateAdjuster::kBitrateUpdateIntervalMs = 1000;
24 :
25 : // Update bitrate at most once every 30 frames.
26 : const uint32_t BitrateAdjuster::kBitrateUpdateFrameInterval = 30;
27 :
28 : // 10 percent of original.
29 : const float BitrateAdjuster::kBitrateTolerancePct = .1f;
30 :
31 : const float BitrateAdjuster::kBytesPerMsToBitsPerSecond = 8 * 1000;
32 :
33 0 : BitrateAdjuster::BitrateAdjuster(Clock* clock,
34 : float min_adjusted_bitrate_pct,
35 0 : float max_adjusted_bitrate_pct)
36 : : clock_(clock),
37 : min_adjusted_bitrate_pct_(min_adjusted_bitrate_pct),
38 : max_adjusted_bitrate_pct_(max_adjusted_bitrate_pct),
39 : bitrate_tracker_(1.5 * kBitrateUpdateIntervalMs,
40 0 : kBytesPerMsToBitsPerSecond) {
41 0 : Reset();
42 0 : }
43 :
44 0 : void BitrateAdjuster::SetTargetBitrateBps(uint32_t bitrate_bps) {
45 0 : rtc::CritScope cs(&crit_);
46 : // If the change in target bitrate is large, update the adjusted bitrate
47 : // immediately since it's likely we have gained or lost a sizeable amount of
48 : // bandwidth and we'll want to respond quickly.
49 : // If the change in target bitrate fits within the existing tolerance of
50 : // encoder output, wait for the next adjustment time to preserve
51 : // existing penalties and not forcibly reset the adjusted bitrate to target.
52 : // However, if we received many small deltas within an update time
53 : // window and one of them exceeds the tolerance when compared to the last
54 : // target we updated against, treat it as a large change in target bitrate.
55 0 : if (!IsWithinTolerance(bitrate_bps, target_bitrate_bps_) ||
56 0 : !IsWithinTolerance(bitrate_bps, last_adjusted_target_bitrate_bps_)) {
57 0 : adjusted_bitrate_bps_ = bitrate_bps;
58 0 : last_adjusted_target_bitrate_bps_ = bitrate_bps;
59 : }
60 0 : target_bitrate_bps_ = bitrate_bps;
61 0 : }
62 :
63 0 : uint32_t BitrateAdjuster::GetTargetBitrateBps() const {
64 0 : rtc::CritScope cs(&crit_);
65 0 : return target_bitrate_bps_;
66 : }
67 :
68 0 : uint32_t BitrateAdjuster::GetAdjustedBitrateBps() const {
69 0 : rtc::CritScope cs(&crit_);
70 0 : return adjusted_bitrate_bps_;
71 : }
72 :
73 0 : rtc::Optional<uint32_t> BitrateAdjuster::GetEstimatedBitrateBps() {
74 0 : rtc::CritScope cs(&crit_);
75 0 : return bitrate_tracker_.Rate(clock_->TimeInMilliseconds());
76 : }
77 :
78 0 : void BitrateAdjuster::Update(size_t frame_size) {
79 0 : rtc::CritScope cs(&crit_);
80 0 : uint32_t current_time_ms = clock_->TimeInMilliseconds();
81 0 : bitrate_tracker_.Update(frame_size, current_time_ms);
82 0 : UpdateBitrate(current_time_ms);
83 0 : }
84 :
85 0 : bool BitrateAdjuster::IsWithinTolerance(uint32_t bitrate_bps,
86 : uint32_t target_bitrate_bps) {
87 0 : if (target_bitrate_bps == 0) {
88 0 : return false;
89 : }
90 0 : float delta = std::abs(static_cast<float>(bitrate_bps) -
91 0 : static_cast<float>(target_bitrate_bps));
92 0 : float delta_pct = delta / target_bitrate_bps;
93 0 : return delta_pct < kBitrateTolerancePct;
94 : }
95 :
96 0 : uint32_t BitrateAdjuster::GetMinAdjustedBitrateBps() const {
97 0 : return min_adjusted_bitrate_pct_ * target_bitrate_bps_;
98 : }
99 :
100 0 : uint32_t BitrateAdjuster::GetMaxAdjustedBitrateBps() const {
101 0 : return max_adjusted_bitrate_pct_ * target_bitrate_bps_;
102 : }
103 :
104 : // Only safe to call this after Update calls have stopped
105 0 : void BitrateAdjuster::Reset() {
106 0 : rtc::CritScope cs(&crit_);
107 0 : target_bitrate_bps_ = 0;
108 0 : adjusted_bitrate_bps_ = 0;
109 0 : last_adjusted_target_bitrate_bps_ = 0;
110 0 : last_bitrate_update_time_ms_ = 0;
111 0 : frames_since_last_update_ = 0;
112 0 : bitrate_tracker_.Reset();
113 0 : }
114 :
115 0 : void BitrateAdjuster::UpdateBitrate(uint32_t current_time_ms) {
116 : uint32_t time_since_last_update_ms =
117 0 : current_time_ms - last_bitrate_update_time_ms_;
118 : // Don't attempt to update bitrate unless enough time and frames have passed.
119 0 : ++frames_since_last_update_;
120 0 : if (time_since_last_update_ms < kBitrateUpdateIntervalMs ||
121 0 : frames_since_last_update_ < kBitrateUpdateFrameInterval) {
122 0 : return;
123 : }
124 0 : float target_bitrate_bps = target_bitrate_bps_;
125 : float estimated_bitrate_bps =
126 0 : bitrate_tracker_.Rate(current_time_ms).value_or(target_bitrate_bps);
127 0 : float error = target_bitrate_bps - estimated_bitrate_bps;
128 :
129 : // Adjust if we've overshot by any amount or if we've undershot too much.
130 0 : if (estimated_bitrate_bps > target_bitrate_bps ||
131 0 : error > kBitrateTolerancePct * target_bitrate_bps) {
132 : // Adjust the bitrate by a fraction of the error.
133 0 : float adjustment = .5 * error;
134 0 : float adjusted_bitrate_bps = target_bitrate_bps + adjustment;
135 :
136 : // Clamp the adjustment.
137 0 : float min_bitrate_bps = GetMinAdjustedBitrateBps();
138 0 : float max_bitrate_bps = GetMaxAdjustedBitrateBps();
139 0 : adjusted_bitrate_bps = std::max(adjusted_bitrate_bps, min_bitrate_bps);
140 0 : adjusted_bitrate_bps = std::min(adjusted_bitrate_bps, max_bitrate_bps);
141 :
142 : // Set the adjustment if it's not already set.
143 0 : float last_adjusted_bitrate_bps = adjusted_bitrate_bps_;
144 0 : if (adjusted_bitrate_bps != last_adjusted_bitrate_bps) {
145 0 : LOG(LS_VERBOSE) << "Adjusting encoder bitrate:"
146 0 : << "\n target_bitrate:"
147 0 : << static_cast<uint32_t>(target_bitrate_bps)
148 0 : << "\n estimated_bitrate:"
149 0 : << static_cast<uint32_t>(estimated_bitrate_bps)
150 0 : << "\n last_adjusted_bitrate:"
151 0 : << static_cast<uint32_t>(last_adjusted_bitrate_bps)
152 0 : << "\n adjusted_bitrate:"
153 0 : << static_cast<uint32_t>(adjusted_bitrate_bps);
154 0 : adjusted_bitrate_bps_ = adjusted_bitrate_bps;
155 : }
156 : }
157 0 : last_bitrate_update_time_ms_ = current_time_ms;
158 0 : frames_since_last_update_ = 0;
159 0 : last_adjusted_target_bitrate_bps_ = target_bitrate_bps_;
160 : }
161 :
162 : } // namespace webrtc
|