Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator_gn/./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc
Warning:line 326, column 5
Value stored to 'num_spatial_layers' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_vc_rate_allocator_gn0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator_gn -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator_gn -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D ABSL_ALLOCATOR_NOTHROW=1 -D PROTOBUF_ENABLE_DEBUG_LOGGING_MAY_LEAK_PII=0 -D RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY -D RTC_ENABLE_VP9 -D WEBRTC_DEPRECATE_PLAN_B -D WEBRTC_ENABLE_PROTOBUF=0 -D WEBRTC_ENCODER_PSNR_STATS -D WEBRTC_LIBRARY_IMPL -D WEBRTC_MOZILLA_BUILD -D WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0 -D WEBRTC_STRICT_FIELD_TRIALS=0 -D DYNAMIC_ANNOTATIONS_ENABLED=1 -D USE_AURA=1 -D USE_GLIB=1 -D USE_OZONE=1 -D USE_UDEV -D WEBRTC_LINUX -D WEBRTC_POSIX -D _FILE_OFFSET_BITS=64 -D _LARGEFILE64_SOURCE -D _LARGEFILE_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D WEBRTC_ENABLE_AVX2 -D _DEBUG -D _GNU_SOURCE -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator_gn -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator_gn -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/libwebrtc_overrides -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/gen -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/third_party/libwebrtc -I /root/firefox-clang/tools/profiler/public -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_vc_rate_allocator_gn0.cpp
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 "modules/video_coding/svc/svc_rate_allocator.h"
12
13#include <algorithm>
14#include <cmath>
15#include <cstddef>
16#include <numeric>
17#include <optional>
18#include <span>
19#include <vector>
20
21#include "absl/container/inlined_vector.h"
22#include "api/field_trials_view.h"
23#include "api/units/data_rate.h"
24#include "api/video/video_bitrate_allocation.h"
25#include "api/video/video_bitrate_allocator.h"
26#include "api/video/video_codec_constants.h"
27#include "api/video/video_codec_type.h"
28#include "api/video_codecs/scalability_mode.h"
29#include "api/video_codecs/video_codec.h"
30#include "modules/video_coding/svc/create_scalability_structure.h"
31#include "modules/video_coding/svc/scalable_video_controller.h"
32#include "rtc_base/checks.h"
33
34namespace webrtc {
35namespace {
36
37constexpr float kSpatialLayeringRateScalingFactor = 0.55f;
38constexpr float kTemporalLayeringRateScalingFactor = 0.55f;
39
40struct ActiveSpatialLayers {
41 size_t first = 0;
42 size_t num = 0;
43};
44
45ActiveSpatialLayers GetActiveSpatialLayers(const VideoCodec& codec,
46 size_t num_spatial_layers) {
47 ActiveSpatialLayers active;
48 for (active.first = 0; active.first < num_spatial_layers; ++active.first) {
49 if (codec.spatialLayers[active.first].active) {
50 break;
51 }
52 }
53
54 size_t last_active_layer = active.first;
55 for (; last_active_layer < num_spatial_layers; ++last_active_layer) {
56 if (!codec.spatialLayers[last_active_layer].active) {
57 break;
58 }
59 }
60 active.num = last_active_layer - active.first;
61
62 return active;
63}
64
65std::vector<DataRate> AdjustAndVerify(
66 const VideoCodec& codec,
67 size_t first_active_layer,
68 const std::vector<DataRate>& spatial_layer_rates) {
69 std::vector<DataRate> adjusted_spatial_layer_rates;
70 // Keep track of rate that couldn't be applied to the previous layer due to
71 // max bitrate constraint, try to pass it forward to the next one.
72 DataRate excess_rate = DataRate::Zero();
73 for (size_t sl_idx = 0; sl_idx < spatial_layer_rates.size(); ++sl_idx) {
74 DataRate min_rate = DataRate::KilobitsPerSec(
75 codec.spatialLayers[first_active_layer + sl_idx].minBitrate);
76 DataRate max_rate = DataRate::KilobitsPerSec(
77 codec.spatialLayers[first_active_layer + sl_idx].maxBitrate);
78
79 DataRate layer_rate = spatial_layer_rates[sl_idx] + excess_rate;
80 if (layer_rate < min_rate) {
81 // Not enough rate to reach min bitrate for desired number of layers,
82 // abort allocation.
83 if (spatial_layer_rates.size() == 1) {
84 return spatial_layer_rates;
85 }
86 return adjusted_spatial_layer_rates;
87 }
88
89 if (layer_rate <= max_rate) {
90 excess_rate = DataRate::Zero();
91 adjusted_spatial_layer_rates.push_back(layer_rate);
92 } else {
93 excess_rate = layer_rate - max_rate;
94 adjusted_spatial_layer_rates.push_back(max_rate);
95 }
96 }
97
98 return adjusted_spatial_layer_rates;
99}
100
101std::vector<DataRate> SplitBitrate(size_t num_layers,
102 DataRate total_bitrate,
103 float rate_scaling_factor) {
104 std::vector<DataRate> bitrates;
105
106 double denominator = 0.0;
107 for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
108 denominator += std::pow(rate_scaling_factor, layer_idx);
109 }
110
111 double numerator = std::pow(rate_scaling_factor, num_layers - 1);
112 for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
113 bitrates.push_back(numerator * total_bitrate / denominator);
114 numerator /= rate_scaling_factor;
115 }
116
117 const DataRate sum =
118 std::accumulate(bitrates.begin(), bitrates.end(), DataRate::Zero());
119
120 // Keep the sum of split bitrates equal to the total bitrate by adding or
121 // subtracting bits, which were lost due to rounding, to the latest layer.
122 if (total_bitrate > sum) {
123 bitrates.back() += total_bitrate - sum;
124 } else if (total_bitrate < sum) {
125 bitrates.back() -= sum - total_bitrate;
126 }
127
128 return bitrates;
129}
130
131VideoBitrateAllocation DistributeAllocationToTemporalLayers(
132 std::span<const DataRate> spatial_layer_bitrates,
133 size_t first_active_layer,
134 size_t num_temporal_layers) {
135 // Distribute rate across temporal layers. Allocate more bits to lower
136 // layers since they are used for prediction of higher layers and their
137 // references are far apart.
138 VideoBitrateAllocation bitrate_allocation;
139 for (size_t sl_idx = 0; sl_idx < spatial_layer_bitrates.size(); ++sl_idx) {
140 std::vector<DataRate> temporal_layer_bitrates =
141 SplitBitrate(num_temporal_layers, spatial_layer_bitrates[sl_idx],
142 kTemporalLayeringRateScalingFactor);
143
144 if (num_temporal_layers == 1) {
145 bitrate_allocation.SetBitrate(sl_idx + first_active_layer, 0,
146 temporal_layer_bitrates[0].bps());
147 } else if (num_temporal_layers == 2) {
148 bitrate_allocation.SetBitrate(sl_idx + first_active_layer, 0,
149 temporal_layer_bitrates[1].bps());
150 bitrate_allocation.SetBitrate(sl_idx + first_active_layer, 1,
151 temporal_layer_bitrates[0].bps());
152 } else {
153 RTC_CHECK_EQ(num_temporal_layers, 3)::webrtc::SafeEq((num_temporal_layers), (3)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 153, "num_temporal_layers" " " "==" " " "3") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (num_temporal_layers
) << (3)
;
154 // In case of three temporal layers the high layer has two frames and the
155 // middle layer has one frame within GOP (in between two consecutive low
156 // layer frames). Thus high layer requires more bits (comparing pure
157 // bitrate of layer, excluding bitrate of base layers) to keep quality on
158 // par with lower layers.
159 bitrate_allocation.SetBitrate(sl_idx + first_active_layer, 0,
160 temporal_layer_bitrates[2].bps());
161 bitrate_allocation.SetBitrate(sl_idx + first_active_layer, 1,
162 temporal_layer_bitrates[0].bps());
163 bitrate_allocation.SetBitrate(sl_idx + first_active_layer, 2,
164 temporal_layer_bitrates[1].bps());
165 }
166 }
167
168 return bitrate_allocation;
169}
170
171// Returns the minimum bitrate needed for `num_active_layers` spatial layers to
172// become active using the configuration specified by `codec`.
173DataRate FindLayerTogglingThreshold(const VideoCodec& codec,
174 size_t first_active_layer,
175 size_t num_active_layers) {
176 if (num_active_layers == 1) {
177 return DataRate::KilobitsPerSec(codec.spatialLayers[0].minBitrate);
178 }
179
180 if (codec.mode == VideoCodecMode::kRealtimeVideo) {
181 DataRate lower_bound = DataRate::Zero();
182 DataRate upper_bound = DataRate::Zero();
183 if (num_active_layers > 1) {
184 for (size_t i = 0; i < num_active_layers - 1; ++i) {
185 lower_bound += DataRate::KilobitsPerSec(
186 codec.spatialLayers[first_active_layer + i].minBitrate);
187 upper_bound += DataRate::KilobitsPerSec(
188 codec.spatialLayers[first_active_layer + i].maxBitrate);
189 }
190 }
191 upper_bound += DataRate::KilobitsPerSec(
192 codec.spatialLayers[first_active_layer + num_active_layers - 1]
193 .minBitrate);
194
195 // Do a binary search until upper and lower bound is the highest bitrate for
196 // `num_active_layers` - 1 layers and lowest bitrate for `num_active_layers`
197 // layers respectively.
198 while (upper_bound - lower_bound > DataRate::BitsPerSec(1)) {
199 DataRate try_rate = (lower_bound + upper_bound) / 2;
200 if (AdjustAndVerify(codec, first_active_layer,
201 SplitBitrate(num_active_layers, try_rate,
202 kSpatialLayeringRateScalingFactor))
203 .size() == num_active_layers) {
204 upper_bound = try_rate;
205 } else {
206 lower_bound = try_rate;
207 }
208 }
209 return upper_bound;
210 } else {
211 DataRate toggling_rate = DataRate::Zero();
212 for (size_t i = 0; i < num_active_layers - 1; ++i) {
213 toggling_rate += DataRate::KilobitsPerSec(
214 codec.spatialLayers[first_active_layer + i].targetBitrate);
215 }
216 toggling_rate += DataRate::KilobitsPerSec(
217 codec.spatialLayers[first_active_layer + num_active_layers - 1]
218 .minBitrate);
219 return toggling_rate;
220 }
221}
222
223} // namespace
224
225SvcRateAllocator::NumLayers SvcRateAllocator::GetNumLayers(
226 const VideoCodec& codec) {
227 NumLayers layers;
228 if (std::optional<ScalabilityMode> scalability_mode =
229 codec.GetScalabilityMode();
230 scalability_mode.has_value()) {
231 if (auto structure = CreateScalabilityStructure(*scalability_mode)) {
232 ScalableVideoController::StreamLayersConfig config =
233 structure->StreamConfig();
234 layers.spatial = config.num_spatial_layers;
235 layers.temporal = config.num_temporal_layers;
236 return layers;
237 }
238 }
239 if (codec.codecType == kVideoCodecVP9) {
240 layers.spatial = codec.VP9().numberOfSpatialLayers;
241 layers.temporal = codec.VP9().numberOfTemporalLayers;
242 return layers;
243 }
244 layers.spatial = 1;
245 layers.temporal = 1;
246 return layers;
247}
248
249SvcRateAllocator::SvcRateAllocator(const VideoCodec& codec,
250 const FieldTrialsView& field_trials)
251 : codec_(codec),
252 num_layers_(GetNumLayers(codec)),
253 cumulative_layer_start_bitrates_(GetLayerStartBitrates(codec)),
254 last_active_layer_count_(0) {
255 RTC_DCHECK_GT(num_layers_.spatial, 0)::webrtc::SafeGt((num_layers_.spatial), (0)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 255, "num_layers_.spatial" " " ">" " " "0") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (num_layers_
.spatial) << (0)
;
256 RTC_DCHECK_LE(num_layers_.spatial, kMaxSpatialLayers)::webrtc::SafeLe((num_layers_.spatial), (kMaxSpatialLayers)) ?
static_cast<void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall
<true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 256, "num_layers_.spatial" " " "<=" " " "kMaxSpatialLayers"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>() <<
(num_layers_.spatial) << (kMaxSpatialLayers)
;
257 RTC_DCHECK_GT(num_layers_.temporal, 0)::webrtc::SafeGt((num_layers_.temporal), (0)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 257, "num_layers_.temporal" " " ">" " " "0") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (num_layers_
.temporal) << (0)
;
258 RTC_DCHECK_LE(num_layers_.temporal, 3)::webrtc::SafeLe((num_layers_.temporal), (3)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 258, "num_layers_.temporal" " " "<=" " " "3") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (num_layers_
.temporal) << (3)
;
259 for (size_t layer_idx = 0; layer_idx < num_layers_.spatial; ++layer_idx) {
260 // Verify min <= target <= max.
261 if (codec.spatialLayers[layer_idx].active) {
262 RTC_DCHECK_GT(codec.spatialLayers[layer_idx].maxBitrate, 0)::webrtc::SafeGt((codec.spatialLayers[layer_idx].maxBitrate),
(0)) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 262, "codec.spatialLayers[layer_idx].maxBitrate" " " ">"
" " "0") & ::webrtc::webrtc_checks_impl::LogStreamer<
>() << (codec.spatialLayers[layer_idx].maxBitrate) <<
(0)
;
263 RTC_DCHECK_GE(codec.spatialLayers[layer_idx].maxBitrate,::webrtc::SafeGe((codec.spatialLayers[layer_idx].maxBitrate),
(codec.spatialLayers[layer_idx].minBitrate)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 264, "codec.spatialLayers[layer_idx].maxBitrate" " " ">="
" " "codec.spatialLayers[layer_idx].minBitrate") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (codec.spatialLayers
[layer_idx].maxBitrate) << (codec.spatialLayers[layer_idx
].minBitrate)
264 codec.spatialLayers[layer_idx].minBitrate)::webrtc::SafeGe((codec.spatialLayers[layer_idx].maxBitrate),
(codec.spatialLayers[layer_idx].minBitrate)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 264, "codec.spatialLayers[layer_idx].maxBitrate" " " ">="
" " "codec.spatialLayers[layer_idx].minBitrate") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (codec.spatialLayers
[layer_idx].maxBitrate) << (codec.spatialLayers[layer_idx
].minBitrate)
;
265 RTC_DCHECK_GE(codec.spatialLayers[layer_idx].targetBitrate,::webrtc::SafeGe((codec.spatialLayers[layer_idx].targetBitrate
), (codec.spatialLayers[layer_idx].minBitrate)) ? static_cast
<void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<
true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 266, "codec.spatialLayers[layer_idx].targetBitrate" " " ">="
" " "codec.spatialLayers[layer_idx].minBitrate") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (codec.spatialLayers
[layer_idx].targetBitrate) << (codec.spatialLayers[layer_idx
].minBitrate)
266 codec.spatialLayers[layer_idx].minBitrate)::webrtc::SafeGe((codec.spatialLayers[layer_idx].targetBitrate
), (codec.spatialLayers[layer_idx].minBitrate)) ? static_cast
<void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<
true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 266, "codec.spatialLayers[layer_idx].targetBitrate" " " ">="
" " "codec.spatialLayers[layer_idx].minBitrate") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (codec.spatialLayers
[layer_idx].targetBitrate) << (codec.spatialLayers[layer_idx
].minBitrate)
;
267 RTC_DCHECK_GE(codec.spatialLayers[layer_idx].maxBitrate,::webrtc::SafeGe((codec.spatialLayers[layer_idx].maxBitrate),
(codec.spatialLayers[layer_idx].targetBitrate)) ? static_cast
<void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<
true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 268, "codec.spatialLayers[layer_idx].maxBitrate" " " ">="
" " "codec.spatialLayers[layer_idx].targetBitrate") & ::
webrtc::webrtc_checks_impl::LogStreamer<>() << (codec
.spatialLayers[layer_idx].maxBitrate) << (codec.spatialLayers
[layer_idx].targetBitrate)
268 codec.spatialLayers[layer_idx].targetBitrate)::webrtc::SafeGe((codec.spatialLayers[layer_idx].maxBitrate),
(codec.spatialLayers[layer_idx].targetBitrate)) ? static_cast
<void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<
true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 268, "codec.spatialLayers[layer_idx].maxBitrate" " " ">="
" " "codec.spatialLayers[layer_idx].targetBitrate") & ::
webrtc::webrtc_checks_impl::LogStreamer<>() << (codec
.spatialLayers[layer_idx].maxBitrate) << (codec.spatialLayers
[layer_idx].targetBitrate)
;
269 }
270 }
271}
272
273VideoBitrateAllocation SvcRateAllocator::Allocate(
274 VideoBitrateAllocationParameters parameters) {
275 DataRate total_bitrate = parameters.total_bitrate;
276 if (codec_.maxBitrate != 0) {
277 total_bitrate =
278 std::min(total_bitrate, DataRate::KilobitsPerSec(codec_.maxBitrate));
279 }
280
281 if (codec_.spatialLayers[0].targetBitrate == 0) {
282 // Delegate rate distribution to encoder wrapper if bitrate thresholds
283 // are not set.
284 VideoBitrateAllocation bitrate_allocation;
285 bitrate_allocation.SetBitrate(0, 0, total_bitrate.bps());
286 return bitrate_allocation;
287 }
288
289 const ActiveSpatialLayers active_layers =
290 GetActiveSpatialLayers(codec_, num_layers_.spatial);
291 size_t num_spatial_layers = active_layers.num;
292
293 if (num_spatial_layers == 0) {
294 return VideoBitrateAllocation(); // All layers are deactivated.
295 }
296
297 // Figure out how many spatial layers should be active.
298 num_spatial_layers = FindNumEnabledLayers(total_bitrate);
299 last_active_layer_count_ = num_spatial_layers;
300
301 std::vector<DataRate> spatial_layer_bitrates;
302 if (codec_.mode == VideoCodecMode::kRealtimeVideo) {
303 spatial_layer_bitrates = DistributeAllocationToSpatialLayersNormalVideo(
304 total_bitrate, active_layers.first, num_spatial_layers);
305 } else {
306 spatial_layer_bitrates = DistributeAllocationToSpatialLayersScreenSharing(
307 total_bitrate, active_layers.first, num_spatial_layers);
308 }
309
310 VideoBitrateAllocation allocation = DistributeAllocationToTemporalLayers(
311 spatial_layer_bitrates, active_layers.first, num_layers_.temporal);
312
313 allocation.set_bw_limited(num_spatial_layers < active_layers.num);
314 return allocation;
315}
316
317std::vector<DataRate>
318SvcRateAllocator::DistributeAllocationToSpatialLayersNormalVideo(
319 DataRate total_bitrate,
320 size_t first_active_layer,
321 size_t num_spatial_layers) const {
322 std::vector<DataRate> spatial_layer_rates;
323 if (num_spatial_layers == 0) {
324 // Not enough rate for even the base layer. Force allocation at the total
325 // bitrate anyway.
326 num_spatial_layers = 1;
Value stored to 'num_spatial_layers' is never read
327 spatial_layer_rates.push_back(total_bitrate);
328 return spatial_layer_rates;
329 }
330
331 spatial_layer_rates =
332 AdjustAndVerify(codec_, first_active_layer,
333 SplitBitrate(num_spatial_layers, total_bitrate,
334 kSpatialLayeringRateScalingFactor));
335 RTC_DCHECK_EQ(spatial_layer_rates.size(), num_spatial_layers)::webrtc::SafeEq((spatial_layer_rates.size()), (num_spatial_layers
)) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 335, "spatial_layer_rates.size()" " " "==" " " "num_spatial_layers"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>() <<
(spatial_layer_rates.size()) << (num_spatial_layers)
;
336 return spatial_layer_rates;
337}
338
339// Bit-rate is allocated in such a way, that the highest enabled layer will have
340// between min and max bitrate, and all others will have exactly target
341// bit-rate allocated.
342std::vector<DataRate>
343SvcRateAllocator::DistributeAllocationToSpatialLayersScreenSharing(
344 DataRate total_bitrate,
345 size_t first_active_layer,
346 size_t num_spatial_layers) const {
347 std::vector<DataRate> spatial_layer_rates;
348 if (num_spatial_layers == 0 ||
349 total_bitrate <
350 DataRate::KilobitsPerSec(
351 codec_.spatialLayers[first_active_layer].minBitrate)) {
352 // Always enable at least one layer.
353 spatial_layer_rates.push_back(total_bitrate);
354 return spatial_layer_rates;
355 }
356
357 DataRate allocated_rate = DataRate::Zero();
358 DataRate top_layer_rate = DataRate::Zero();
359 size_t sl_idx;
360 for (sl_idx = first_active_layer;
361 sl_idx < first_active_layer + num_spatial_layers; ++sl_idx) {
362 const DataRate min_rate =
363 DataRate::KilobitsPerSec(codec_.spatialLayers[sl_idx].minBitrate);
364 const DataRate target_rate =
365 DataRate::KilobitsPerSec(codec_.spatialLayers[sl_idx].targetBitrate);
366
367 if (allocated_rate + min_rate > total_bitrate) {
368 // Use stable rate to determine if layer should be enabled.
369 break;
370 }
371
372 top_layer_rate = std::min(target_rate, total_bitrate - allocated_rate);
373 spatial_layer_rates.push_back(top_layer_rate);
374 allocated_rate += top_layer_rate;
375 }
376
377 if (sl_idx > 0 && total_bitrate - allocated_rate > DataRate::Zero()) {
378 // Add leftover to the last allocated layer.
379 top_layer_rate = std::min(
380 top_layer_rate + (total_bitrate - allocated_rate),
381 DataRate::KilobitsPerSec(codec_.spatialLayers[sl_idx - 1].maxBitrate));
382 spatial_layer_rates.back() = top_layer_rate;
383 }
384
385 return spatial_layer_rates;
386}
387
388size_t SvcRateAllocator::FindNumEnabledLayers(DataRate target_rate) const {
389 if (cumulative_layer_start_bitrates_.empty()) {
390 return 0;
391 }
392
393 size_t num_enabled_layers = 0;
394 for (DataRate start_rate : cumulative_layer_start_bitrates_) {
395 // First layer is always enabled.
396 if (num_enabled_layers == 0 || start_rate <= target_rate) {
397 ++num_enabled_layers;
398 } else {
399 break;
400 }
401 }
402
403 return num_enabled_layers;
404}
405
406DataRate SvcRateAllocator::GetMaxBitrate(const VideoCodec& codec) {
407 const NumLayers num_layers = GetNumLayers(codec);
408 const ActiveSpatialLayers active_layers =
409 GetActiveSpatialLayers(codec, num_layers.spatial);
410
411 DataRate max_bitrate = DataRate::Zero();
412 for (size_t sl_idx = 0; sl_idx < active_layers.num; ++sl_idx) {
413 max_bitrate += DataRate::KilobitsPerSec(
414 codec.spatialLayers[active_layers.first + sl_idx].maxBitrate);
415 }
416
417 if (codec.maxBitrate != 0) {
418 max_bitrate =
419 std::min(max_bitrate, DataRate::KilobitsPerSec(codec.maxBitrate));
420 }
421
422 return max_bitrate;
423}
424
425DataRate SvcRateAllocator::GetPaddingBitrate(const VideoCodec& codec) {
426 auto start_bitrate = GetLayerStartBitrates(codec);
427 if (start_bitrate.empty()) {
428 return DataRate::Zero(); // All layers are deactivated.
429 }
430
431 return start_bitrate.back();
432}
433
434absl::InlinedVector<DataRate, kMaxSpatialLayers>
435SvcRateAllocator::GetLayerStartBitrates(const VideoCodec& codec) {
436 absl::InlinedVector<DataRate, kMaxSpatialLayers> start_bitrates;
437 const NumLayers num_layers = GetNumLayers(codec);
438 const ActiveSpatialLayers active_layers =
439 GetActiveSpatialLayers(codec, num_layers.spatial);
440 DataRate last_rate = DataRate::Zero();
441 for (size_t i = 1; i <= active_layers.num; ++i) {
442 DataRate layer_toggling_rate =
443 FindLayerTogglingThreshold(codec, active_layers.first, i);
444 start_bitrates.push_back(layer_toggling_rate);
445 RTC_DCHECK_LE(last_rate, layer_toggling_rate)::webrtc::SafeLe((last_rate), (layer_toggling_rate)) ? static_cast
<void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<
true>( "./../../../../../../../third_party/libwebrtc/modules/video_coding/svc/svc_rate_allocator.cc"
, 445, "last_rate" " " "<=" " " "layer_toggling_rate") &
::webrtc::webrtc_checks_impl::LogStreamer<>() <<
(last_rate) << (layer_toggling_rate)
;
446 last_rate = layer_toggling_rate;
447 }
448 return start_bitrates;
449}
450
451} // namespace webrtc