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