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