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