blob: e189db1c1997515c0dd76103574459a17566c11e [file] [log] [blame]
Erik Språng566124a2018-04-23 12:32:22 +02001/*
2 * Copyright (c) 2018 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 "api/video/video_bitrate_allocation.h"
12
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <cstdint>
14
Erik Språng566124a2018-04-23 12:32:22 +020015#include "rtc_base/checks.h"
16#include "rtc_base/numerics/safe_conversions.h"
17#include "rtc_base/strings/string_builder.h"
Erik Språng566124a2018-04-23 12:32:22 +020018
19namespace webrtc {
20
Ilya Nikolaevskiy5963c7c2019-10-09 18:06:58 +020021VideoBitrateAllocation::VideoBitrateAllocation()
22 : sum_(0), is_bw_limited_(false) {}
Erik Språng566124a2018-04-23 12:32:22 +020023
24bool VideoBitrateAllocation::SetBitrate(size_t spatial_index,
25 size_t temporal_index,
26 uint32_t bitrate_bps) {
27 RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
28 RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
29 int64_t new_bitrate_sum_bps = sum_;
Danil Chapovalov0bc58cf2018-06-21 13:32:56 +020030 absl::optional<uint32_t>& layer_bitrate =
Erik Språng566124a2018-04-23 12:32:22 +020031 bitrates_[spatial_index][temporal_index];
32 if (layer_bitrate) {
33 RTC_DCHECK_LE(*layer_bitrate, sum_);
34 new_bitrate_sum_bps -= *layer_bitrate;
35 }
36 new_bitrate_sum_bps += bitrate_bps;
37 if (new_bitrate_sum_bps > kMaxBitrateBps)
38 return false;
39
40 layer_bitrate = bitrate_bps;
41 sum_ = rtc::dchecked_cast<uint32_t>(new_bitrate_sum_bps);
42 return true;
43}
44
45bool VideoBitrateAllocation::HasBitrate(size_t spatial_index,
46 size_t temporal_index) const {
47 RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
48 RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
49 return bitrates_[spatial_index][temporal_index].has_value();
50}
51
52uint32_t VideoBitrateAllocation::GetBitrate(size_t spatial_index,
53 size_t temporal_index) const {
54 RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
55 RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
56 return bitrates_[spatial_index][temporal_index].value_or(0);
57}
58
59// Whether the specific spatial layers has the bitrate set in any of its
60// temporal layers.
61bool VideoBitrateAllocation::IsSpatialLayerUsed(size_t spatial_index) const {
62 RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
63 for (size_t i = 0; i < kMaxTemporalStreams; ++i) {
64 if (bitrates_[spatial_index][i].has_value())
65 return true;
66 }
67 return false;
68}
69
70// Get the sum of all the temporal layer for a specific spatial layer.
71uint32_t VideoBitrateAllocation::GetSpatialLayerSum(
72 size_t spatial_index) const {
73 RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
74 return GetTemporalLayerSum(spatial_index, kMaxTemporalStreams - 1);
75}
76
77uint32_t VideoBitrateAllocation::GetTemporalLayerSum(
78 size_t spatial_index,
79 size_t temporal_index) const {
80 RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
81 RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
82 uint32_t sum = 0;
83 for (size_t i = 0; i <= temporal_index; ++i) {
84 sum += bitrates_[spatial_index][i].value_or(0);
85 }
86 return sum;
87}
88
89std::vector<uint32_t> VideoBitrateAllocation::GetTemporalLayerAllocation(
90 size_t spatial_index) const {
91 RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
92 std::vector<uint32_t> temporal_rates;
93
94 // Find the highest temporal layer with a defined bitrate in order to
95 // determine the size of the temporal layer allocation.
96 for (size_t i = kMaxTemporalStreams; i > 0; --i) {
97 if (bitrates_[spatial_index][i - 1].has_value()) {
98 temporal_rates.resize(i);
99 break;
100 }
101 }
102
103 for (size_t i = 0; i < temporal_rates.size(); ++i) {
104 temporal_rates[i] = bitrates_[spatial_index][i].value_or(0);
105 }
106
107 return temporal_rates;
108}
109
Stefan Holmerf7044682018-07-17 10:16:41 +0200110std::vector<absl::optional<VideoBitrateAllocation>>
111VideoBitrateAllocation::GetSimulcastAllocations() const {
112 std::vector<absl::optional<VideoBitrateAllocation>> bitrates;
113 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
114 absl::optional<VideoBitrateAllocation> layer_bitrate;
115 if (IsSpatialLayerUsed(si)) {
116 layer_bitrate = VideoBitrateAllocation();
117 for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
118 if (HasBitrate(si, tl))
119 layer_bitrate->SetBitrate(0, tl, GetBitrate(si, tl));
120 }
121 }
122 bitrates.push_back(layer_bitrate);
123 }
124 return bitrates;
125}
126
Erik Språng566124a2018-04-23 12:32:22 +0200127bool VideoBitrateAllocation::operator==(
128 const VideoBitrateAllocation& other) const {
129 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
130 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
131 if (bitrates_[si][ti] != other.bitrates_[si][ti])
132 return false;
133 }
134 }
135 return true;
136}
137
138std::string VideoBitrateAllocation::ToString() const {
139 if (sum_ == 0)
140 return "VideoBitrateAllocation [ [] ]";
141
142 // Max string length in practice is 260, but let's have some overhead and
143 // round up to nearest power of two.
144 char string_buf[512];
145 rtc::SimpleStringBuilder ssb(string_buf);
146
147 ssb << "VideoBitrateAllocation [";
148 uint32_t spatial_cumulator = 0;
149 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
150 RTC_DCHECK_LE(spatial_cumulator, sum_);
151 if (spatial_cumulator == sum_)
152 break;
153
154 const uint32_t layer_sum = GetSpatialLayerSum(si);
Ilya Nikolaevskiy002b6f42019-09-30 10:32:13 +0200155 if (layer_sum == sum_ && si == 0) {
Erik Språng566124a2018-04-23 12:32:22 +0200156 ssb << " [";
157 } else {
158 if (si > 0)
159 ssb << ",";
160 ssb << '\n' << " [";
161 }
162 spatial_cumulator += layer_sum;
163
164 uint32_t temporal_cumulator = 0;
165 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
166 RTC_DCHECK_LE(temporal_cumulator, layer_sum);
167 if (temporal_cumulator == layer_sum)
168 break;
169
170 if (ti > 0)
171 ssb << ", ";
172
173 uint32_t bitrate = bitrates_[si][ti].value_or(0);
174 ssb << bitrate;
175 temporal_cumulator += bitrate;
176 }
177 ssb << "]";
178 }
179
180 RTC_DCHECK_EQ(spatial_cumulator, sum_);
181 ssb << " ]";
182 return ssb.str();
183}
184
185} // namespace webrtc