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