xref: /aosp_15_r20/external/webrtc/api/video/video_bitrate_allocation.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_bitrate_allocation.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
16*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
20*d9f75844SAndroid Build Coastguard Worker 
VideoBitrateAllocation()21*d9f75844SAndroid Build Coastguard Worker VideoBitrateAllocation::VideoBitrateAllocation()
22*d9f75844SAndroid Build Coastguard Worker     : sum_(0), is_bw_limited_(false) {}
23*d9f75844SAndroid Build Coastguard Worker 
SetBitrate(size_t spatial_index,size_t temporal_index,uint32_t bitrate_bps)24*d9f75844SAndroid Build Coastguard Worker bool VideoBitrateAllocation::SetBitrate(size_t spatial_index,
25*d9f75844SAndroid Build Coastguard Worker                                         size_t temporal_index,
26*d9f75844SAndroid Build Coastguard Worker                                         uint32_t bitrate_bps) {
27*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
28*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
29*d9f75844SAndroid Build Coastguard Worker   int64_t new_bitrate_sum_bps = sum_;
30*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t>& layer_bitrate =
31*d9f75844SAndroid Build Coastguard Worker       bitrates_[spatial_index][temporal_index];
32*d9f75844SAndroid Build Coastguard Worker   if (layer_bitrate) {
33*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_LE(*layer_bitrate, sum_);
34*d9f75844SAndroid Build Coastguard Worker     new_bitrate_sum_bps -= *layer_bitrate;
35*d9f75844SAndroid Build Coastguard Worker   }
36*d9f75844SAndroid Build Coastguard Worker   new_bitrate_sum_bps += bitrate_bps;
37*d9f75844SAndroid Build Coastguard Worker   if (new_bitrate_sum_bps > kMaxBitrateBps)
38*d9f75844SAndroid Build Coastguard Worker     return false;
39*d9f75844SAndroid Build Coastguard Worker 
40*d9f75844SAndroid Build Coastguard Worker   layer_bitrate = bitrate_bps;
41*d9f75844SAndroid Build Coastguard Worker   sum_ = rtc::dchecked_cast<uint32_t>(new_bitrate_sum_bps);
42*d9f75844SAndroid Build Coastguard Worker   return true;
43*d9f75844SAndroid Build Coastguard Worker }
44*d9f75844SAndroid Build Coastguard Worker 
HasBitrate(size_t spatial_index,size_t temporal_index) const45*d9f75844SAndroid Build Coastguard Worker bool VideoBitrateAllocation::HasBitrate(size_t spatial_index,
46*d9f75844SAndroid Build Coastguard Worker                                         size_t temporal_index) const {
47*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
48*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
49*d9f75844SAndroid Build Coastguard Worker   return bitrates_[spatial_index][temporal_index].has_value();
50*d9f75844SAndroid Build Coastguard Worker }
51*d9f75844SAndroid Build Coastguard Worker 
GetBitrate(size_t spatial_index,size_t temporal_index) const52*d9f75844SAndroid Build Coastguard Worker uint32_t VideoBitrateAllocation::GetBitrate(size_t spatial_index,
53*d9f75844SAndroid Build Coastguard Worker                                             size_t temporal_index) const {
54*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
55*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
56*d9f75844SAndroid Build Coastguard Worker   return bitrates_[spatial_index][temporal_index].value_or(0);
57*d9f75844SAndroid Build Coastguard Worker }
58*d9f75844SAndroid Build Coastguard Worker 
59*d9f75844SAndroid Build Coastguard Worker // Whether the specific spatial layers has the bitrate set in any of its
60*d9f75844SAndroid Build Coastguard Worker // temporal layers.
IsSpatialLayerUsed(size_t spatial_index) const61*d9f75844SAndroid Build Coastguard Worker bool VideoBitrateAllocation::IsSpatialLayerUsed(size_t spatial_index) const {
62*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
63*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < kMaxTemporalStreams; ++i) {
64*d9f75844SAndroid Build Coastguard Worker     if (bitrates_[spatial_index][i].has_value())
65*d9f75844SAndroid Build Coastguard Worker       return true;
66*d9f75844SAndroid Build Coastguard Worker   }
67*d9f75844SAndroid Build Coastguard Worker   return false;
68*d9f75844SAndroid Build Coastguard Worker }
69*d9f75844SAndroid Build Coastguard Worker 
70*d9f75844SAndroid Build Coastguard Worker // Get the sum of all the temporal layer for a specific spatial layer.
GetSpatialLayerSum(size_t spatial_index) const71*d9f75844SAndroid Build Coastguard Worker uint32_t VideoBitrateAllocation::GetSpatialLayerSum(
72*d9f75844SAndroid Build Coastguard Worker     size_t spatial_index) const {
73*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
74*d9f75844SAndroid Build Coastguard Worker   return GetTemporalLayerSum(spatial_index, kMaxTemporalStreams - 1);
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker 
GetTemporalLayerSum(size_t spatial_index,size_t temporal_index) const77*d9f75844SAndroid Build Coastguard Worker uint32_t VideoBitrateAllocation::GetTemporalLayerSum(
78*d9f75844SAndroid Build Coastguard Worker     size_t spatial_index,
79*d9f75844SAndroid Build Coastguard Worker     size_t temporal_index) const {
80*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
81*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
82*d9f75844SAndroid Build Coastguard Worker   uint32_t sum = 0;
83*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i <= temporal_index; ++i) {
84*d9f75844SAndroid Build Coastguard Worker     sum += bitrates_[spatial_index][i].value_or(0);
85*d9f75844SAndroid Build Coastguard Worker   }
86*d9f75844SAndroid Build Coastguard Worker   return sum;
87*d9f75844SAndroid Build Coastguard Worker }
88*d9f75844SAndroid Build Coastguard Worker 
GetTemporalLayerAllocation(size_t spatial_index) const89*d9f75844SAndroid Build Coastguard Worker std::vector<uint32_t> VideoBitrateAllocation::GetTemporalLayerAllocation(
90*d9f75844SAndroid Build Coastguard Worker     size_t spatial_index) const {
91*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
92*d9f75844SAndroid Build Coastguard Worker   std::vector<uint32_t> temporal_rates;
93*d9f75844SAndroid Build Coastguard Worker 
94*d9f75844SAndroid Build Coastguard Worker   // Find the highest temporal layer with a defined bitrate in order to
95*d9f75844SAndroid Build Coastguard Worker   // determine the size of the temporal layer allocation.
96*d9f75844SAndroid Build Coastguard Worker   for (size_t i = kMaxTemporalStreams; i > 0; --i) {
97*d9f75844SAndroid Build Coastguard Worker     if (bitrates_[spatial_index][i - 1].has_value()) {
98*d9f75844SAndroid Build Coastguard Worker       temporal_rates.resize(i);
99*d9f75844SAndroid Build Coastguard Worker       break;
100*d9f75844SAndroid Build Coastguard Worker     }
101*d9f75844SAndroid Build Coastguard Worker   }
102*d9f75844SAndroid Build Coastguard Worker 
103*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < temporal_rates.size(); ++i) {
104*d9f75844SAndroid Build Coastguard Worker     temporal_rates[i] = bitrates_[spatial_index][i].value_or(0);
105*d9f75844SAndroid Build Coastguard Worker   }
106*d9f75844SAndroid Build Coastguard Worker 
107*d9f75844SAndroid Build Coastguard Worker   return temporal_rates;
108*d9f75844SAndroid Build Coastguard Worker }
109*d9f75844SAndroid Build Coastguard Worker 
110*d9f75844SAndroid Build Coastguard Worker std::vector<absl::optional<VideoBitrateAllocation>>
GetSimulcastAllocations() const111*d9f75844SAndroid Build Coastguard Worker VideoBitrateAllocation::GetSimulcastAllocations() const {
112*d9f75844SAndroid Build Coastguard Worker   std::vector<absl::optional<VideoBitrateAllocation>> bitrates;
113*d9f75844SAndroid Build Coastguard Worker   for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
114*d9f75844SAndroid Build Coastguard Worker     absl::optional<VideoBitrateAllocation> layer_bitrate;
115*d9f75844SAndroid Build Coastguard Worker     if (IsSpatialLayerUsed(si)) {
116*d9f75844SAndroid Build Coastguard Worker       layer_bitrate = VideoBitrateAllocation();
117*d9f75844SAndroid Build Coastguard Worker       for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
118*d9f75844SAndroid Build Coastguard Worker         if (HasBitrate(si, tl))
119*d9f75844SAndroid Build Coastguard Worker           layer_bitrate->SetBitrate(0, tl, GetBitrate(si, tl));
120*d9f75844SAndroid Build Coastguard Worker       }
121*d9f75844SAndroid Build Coastguard Worker     }
122*d9f75844SAndroid Build Coastguard Worker     bitrates.push_back(layer_bitrate);
123*d9f75844SAndroid Build Coastguard Worker   }
124*d9f75844SAndroid Build Coastguard Worker   return bitrates;
125*d9f75844SAndroid Build Coastguard Worker }
126*d9f75844SAndroid Build Coastguard Worker 
operator ==(const VideoBitrateAllocation & other) const127*d9f75844SAndroid Build Coastguard Worker bool VideoBitrateAllocation::operator==(
128*d9f75844SAndroid Build Coastguard Worker     const VideoBitrateAllocation& other) const {
129*d9f75844SAndroid Build Coastguard Worker   for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
130*d9f75844SAndroid Build Coastguard Worker     for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
131*d9f75844SAndroid Build Coastguard Worker       if (bitrates_[si][ti] != other.bitrates_[si][ti])
132*d9f75844SAndroid Build Coastguard Worker         return false;
133*d9f75844SAndroid Build Coastguard Worker     }
134*d9f75844SAndroid Build Coastguard Worker   }
135*d9f75844SAndroid Build Coastguard Worker   return true;
136*d9f75844SAndroid Build Coastguard Worker }
137*d9f75844SAndroid Build Coastguard Worker 
ToString() const138*d9f75844SAndroid Build Coastguard Worker std::string VideoBitrateAllocation::ToString() const {
139*d9f75844SAndroid Build Coastguard Worker   if (sum_ == 0)
140*d9f75844SAndroid Build Coastguard Worker     return "VideoBitrateAllocation [ [] ]";
141*d9f75844SAndroid Build Coastguard Worker 
142*d9f75844SAndroid Build Coastguard Worker   // Max string length in practice is 260, but let's have some overhead and
143*d9f75844SAndroid Build Coastguard Worker   // round up to nearest power of two.
144*d9f75844SAndroid Build Coastguard Worker   char string_buf[512];
145*d9f75844SAndroid Build Coastguard Worker   rtc::SimpleStringBuilder ssb(string_buf);
146*d9f75844SAndroid Build Coastguard Worker 
147*d9f75844SAndroid Build Coastguard Worker   ssb << "VideoBitrateAllocation [";
148*d9f75844SAndroid Build Coastguard Worker   uint32_t spatial_cumulator = 0;
149*d9f75844SAndroid Build Coastguard Worker   for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
150*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_LE(spatial_cumulator, sum_);
151*d9f75844SAndroid Build Coastguard Worker     if (spatial_cumulator == sum_)
152*d9f75844SAndroid Build Coastguard Worker       break;
153*d9f75844SAndroid Build Coastguard Worker 
154*d9f75844SAndroid Build Coastguard Worker     const uint32_t layer_sum = GetSpatialLayerSum(si);
155*d9f75844SAndroid Build Coastguard Worker     if (layer_sum == sum_ && si == 0) {
156*d9f75844SAndroid Build Coastguard Worker       ssb << " [";
157*d9f75844SAndroid Build Coastguard Worker     } else {
158*d9f75844SAndroid Build Coastguard Worker       if (si > 0)
159*d9f75844SAndroid Build Coastguard Worker         ssb << ",";
160*d9f75844SAndroid Build Coastguard Worker       ssb << '\n' << "  [";
161*d9f75844SAndroid Build Coastguard Worker     }
162*d9f75844SAndroid Build Coastguard Worker     spatial_cumulator += layer_sum;
163*d9f75844SAndroid Build Coastguard Worker 
164*d9f75844SAndroid Build Coastguard Worker     uint32_t temporal_cumulator = 0;
165*d9f75844SAndroid Build Coastguard Worker     for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
166*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_LE(temporal_cumulator, layer_sum);
167*d9f75844SAndroid Build Coastguard Worker       if (temporal_cumulator == layer_sum)
168*d9f75844SAndroid Build Coastguard Worker         break;
169*d9f75844SAndroid Build Coastguard Worker 
170*d9f75844SAndroid Build Coastguard Worker       if (ti > 0)
171*d9f75844SAndroid Build Coastguard Worker         ssb << ", ";
172*d9f75844SAndroid Build Coastguard Worker 
173*d9f75844SAndroid Build Coastguard Worker       uint32_t bitrate = bitrates_[si][ti].value_or(0);
174*d9f75844SAndroid Build Coastguard Worker       ssb << bitrate;
175*d9f75844SAndroid Build Coastguard Worker       temporal_cumulator += bitrate;
176*d9f75844SAndroid Build Coastguard Worker     }
177*d9f75844SAndroid Build Coastguard Worker     ssb << "]";
178*d9f75844SAndroid Build Coastguard Worker   }
179*d9f75844SAndroid Build Coastguard Worker 
180*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(spatial_cumulator, sum_);
181*d9f75844SAndroid Build Coastguard Worker   ssb << " ]";
182*d9f75844SAndroid Build Coastguard Worker   return ssb.str();
183*d9f75844SAndroid Build Coastguard Worker }
184*d9f75844SAndroid Build Coastguard Worker 
185*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
186