Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/modules/video_coding/h26x_packet_buffer_gn/./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc
Warning:line 117, column 5
Value stored to 'last_continuous_unwrapped_seq_num' 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_26x_packet_buffer_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/h26x_packet_buffer_gn -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/modules/video_coding/h26x_packet_buffer_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/h26x_packet_buffer_gn -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/modules/video_coding/h26x_packet_buffer_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_26x_packet_buffer_gn0.cpp
1/*
2 * Copyright (c) 2021 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/h26x_packet_buffer.h"
12
13#include <algorithm>
14#include <cstddef>
15#include <cstdint>
16#include <cstring>
17#include <limits>
18#include <memory>
19#include <optional>
20#include <span>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include "absl/algorithm/container.h"
26#include "api/video/video_codec_type.h"
27#include "api/video/video_frame_type.h"
28#include "common_video/h264/h264_common.h"
29#include "common_video/h264/pps_parser.h"
30#include "common_video/h264/sps_parser.h"
31#include "modules/rtp_rtcp/source/rtp_video_header.h"
32#include "modules/video_coding/codecs/h264/include/h264_globals.h"
33#include "modules/video_coding/h264_sprop_parameter_sets.h"
34#include "rtc_base/checks.h"
35#include "rtc_base/copy_on_write_buffer.h"
36#include "rtc_base/logging.h"
37#include "rtc_base/numerics/sequence_number_util.h"
38#ifdef RTC_ENABLE_H265
39#include "common_video/h265/h265_common.h"
40#endif
41
42namespace webrtc {
43namespace {
44
45int64_t EuclideanMod(int64_t n, int64_t div) {
46 RTC_DCHECK_GT(div, 0)::webrtc::SafeGt((div), (0)) ? static_cast<void>(0) : ::
webrtc::webrtc_checks_impl::FatalLogCall<true>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 46, "div" " " ">" " " "0") & ::webrtc::webrtc_checks_impl
::LogStreamer<>() << (div) << (0)
;
47 return (n %= div) < 0 ? n + div : n;
48}
49
50bool IsFirstPacketOfFragment(const RTPVideoHeaderH264& h264_header) {
51 return !h264_header.nalus.empty();
52}
53
54bool BeginningOfIdr(const H26xPacketBuffer::Packet& packet) {
55 const auto& h264_header =
56 std::get<RTPVideoHeaderH264>(packet.video_header.video_type_header);
57 const bool contains_idr_nalu =
58 absl::c_any_of(h264_header.nalus, [](const auto& nalu_info) {
59 return nalu_info.type == H264::NaluType::kIdr;
60 });
61 switch (h264_header.packetization_type) {
62 case kH264StapA:
63 case kH264SingleNalu: {
64 return contains_idr_nalu;
65 }
66 case kH264FuA: {
67 return contains_idr_nalu && IsFirstPacketOfFragment(h264_header);
68 }
69 }
70}
71
72bool HasSps(const H26xPacketBuffer::Packet& packet) {
73 auto& h264_header =
74 std::get<RTPVideoHeaderH264>(packet.video_header.video_type_header);
75 return absl::c_any_of(h264_header.nalus, [](const auto& nalu_info) {
76 return nalu_info.type == H264::NaluType::kSps;
77 });
78}
79
80int64_t* GetContinuousSequence(std::span<int64_t> last_continuous,
81 int64_t unwrapped_seq_num) {
82 for (int64_t& last : last_continuous) {
83 if (unwrapped_seq_num - 1 == last) {
84 return &last;
85 }
86 }
87 return nullptr;
88}
89
90#ifdef RTC_ENABLE_H265
91bool HasVps(const H26xPacketBuffer::Packet& packet) {
92 std::vector<H265::NaluIndex> nalu_indices =
93 H265::FindNaluIndices(packet.video_payload);
94 return absl::c_any_of((nalu_indices), [&packet](
95 const H265::NaluIndex& nalu_index) {
96 return H265::ParseNaluType(
97 packet.video_payload.cdata()[nalu_index.payload_start_offset]) ==
98 H265::NaluType::kVps;
99 });
100}
101#endif
102
103} // namespace
104
105H26xPacketBuffer::H26xPacketBuffer(bool h264_idr_only_keyframes_allowed)
106 : h264_idr_only_keyframes_allowed_(h264_idr_only_keyframes_allowed) {
107 last_continuous_in_sequence_.fill(std::numeric_limits<int64_t>::min());
108}
109
110H26xPacketBuffer::InsertResult H26xPacketBuffer::InsertPadding(
111 uint16_t unwrapped_seq_num) {
112 int64_t* last_continuous_unwrapped_seq_num =
113 GetContinuousSequence(last_continuous_in_sequence_, unwrapped_seq_num);
114 if (last_continuous_unwrapped_seq_num == nullptr) {
115 last_continuous_in_sequence_[last_continuous_in_sequence_index_] =
116 unwrapped_seq_num;
117 last_continuous_unwrapped_seq_num =
Value stored to 'last_continuous_unwrapped_seq_num' is never read
118 &last_continuous_in_sequence_[last_continuous_in_sequence_index_];
119 last_continuous_in_sequence_index_ =
120 (last_continuous_in_sequence_index_ + 1) %
121 last_continuous_in_sequence_.size();
122 } else {
123 *last_continuous_unwrapped_seq_num = unwrapped_seq_num;
124 }
125 return {};
126}
127
128H26xPacketBuffer::InsertResult H26xPacketBuffer::InsertPacket(
129 std::unique_ptr<Packet> packet) {
130 RTC_DCHECK(packet->video_header.codec == kVideoCodecH264 ||(packet->video_header.codec == kVideoCodecH264 || packet->
video_header.codec == kVideoCodecH265) ? static_cast<void>
(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<false>
( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 131, "packet->video_header.codec == kVideoCodecH264 || packet->video_header.codec == kVideoCodecH265"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
131 packet->video_header.codec == kVideoCodecH265)(packet->video_header.codec == kVideoCodecH264 || packet->
video_header.codec == kVideoCodecH265) ? static_cast<void>
(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<false>
( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 131, "packet->video_header.codec == kVideoCodecH264 || packet->video_header.codec == kVideoCodecH265"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
;
132
133 InsertResult result;
134
135 int64_t unwrapped_seq_num = packet->sequence_number;
136 auto& packet_slot = GetPacket(unwrapped_seq_num);
137 if (packet_slot != nullptr &&
138 AheadOrAt(packet_slot->timestamp, packet->timestamp)) {
139 // The incoming `packet` is old or a duplicate.
140 return result;
141 } else {
142 packet_slot = std::move(packet);
143 }
144
145 return FindFrames(unwrapped_seq_num);
146}
147
148std::unique_ptr<H26xPacketBuffer::Packet>& H26xPacketBuffer::GetPacket(
149 int64_t unwrapped_seq_num) {
150 return buffer_[EuclideanMod(unwrapped_seq_num, kBufferSize)];
151}
152
153bool H26xPacketBuffer::BeginningOfStream(
154 const H26xPacketBuffer::Packet& packet) const {
155 if (packet.codec() == kVideoCodecH264) {
156 return HasSps(packet) ||
157 (h264_idr_only_keyframes_allowed_ && BeginningOfIdr(packet));
158#ifdef RTC_ENABLE_H265
159 } else if (packet.codec() == kVideoCodecH265) {
160 return HasVps(packet);
161#endif
162 }
163 RTC_DCHECK_NOTREACHED()(false) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 163, "false") & ::webrtc::webrtc_checks_impl::LogStreamer
<>()
;
164 return false;
165}
166
167H26xPacketBuffer::InsertResult H26xPacketBuffer::FindFrames(
168 int64_t unwrapped_seq_num) {
169 InsertResult result;
170
171 Packet* packet = GetPacket(unwrapped_seq_num).get();
172 RTC_CHECK(packet != nullptr)(packet != nullptr) ? static_cast<void>(0) : ::webrtc::
webrtc_checks_impl::FatalLogCall<false>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 172, "packet != nullptr") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
173
174 // Check if the packet is continuous or the beginning of a new coded video
175 // sequence.
176 int64_t* last_continuous_unwrapped_seq_num =
177 GetContinuousSequence(last_continuous_in_sequence_, unwrapped_seq_num);
178 if (last_continuous_unwrapped_seq_num == nullptr) {
179 if (!BeginningOfStream(*packet)) {
180 return result;
181 }
182
183 last_continuous_in_sequence_[last_continuous_in_sequence_index_] =
184 unwrapped_seq_num;
185 last_continuous_unwrapped_seq_num =
186 &last_continuous_in_sequence_[last_continuous_in_sequence_index_];
187 last_continuous_in_sequence_index_ =
188 (last_continuous_in_sequence_index_ + 1) %
189 last_continuous_in_sequence_.size();
190 }
191
192 for (int64_t seq_num = unwrapped_seq_num;
193 seq_num < unwrapped_seq_num + kBufferSize;) {
194 RTC_DCHECK_GE(seq_num, *last_continuous_unwrapped_seq_num)::webrtc::SafeGe((seq_num), (*last_continuous_unwrapped_seq_num
)) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<true>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 194, "seq_num" " " ">=" " " "*last_continuous_unwrapped_seq_num"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>() <<
(seq_num) << (*last_continuous_unwrapped_seq_num)
;
195
196 // Packets that were never assembled into a completed frame will stay in
197 // the 'buffer_'. Check that the `packet` sequence number match the expected
198 // unwrapped sequence number.
199 if (seq_num != packet->sequence_number) {
200 return result;
201 }
202
203 *last_continuous_unwrapped_seq_num = seq_num;
204 // Last packet of the frame, try to assemble the frame.
205 if (packet->marker_bit) {
206 uint32_t rtp_timestamp = packet->timestamp;
207
208 // Iterate backwards to find where the frame starts.
209 for (int64_t seq_num_start = seq_num;
210 seq_num_start > seq_num - kBufferSize; --seq_num_start) {
211 auto& prev_packet = GetPacket(seq_num_start - 1);
212
213 if (prev_packet == nullptr || prev_packet->timestamp != rtp_timestamp) {
214 if (MaybeAssembleFrame(seq_num_start, seq_num, result)) {
215 // Frame was assembled, continue to look for more frames.
216 break;
217 } else {
218 // Frame was not assembled, no subsequent frame will be continuous.
219 return result;
220 }
221 }
222 }
223 }
224
225 seq_num++;
226 packet = GetPacket(seq_num).get();
227 if (packet == nullptr) {
228 return result;
229 }
230 }
231
232 return result;
233}
234
235bool H26xPacketBuffer::MaybeAssembleFrame(int64_t start_seq_num_unwrapped,
236 int64_t end_sequence_number_unwrapped,
237 InsertResult& result) {
238#ifdef RTC_ENABLE_H265
239 bool has_vps = false;
240#endif
241 bool has_sps = false;
242 bool has_pps = false;
243 // Includes IDR, CRA and BLA for HEVC.
244 bool has_idr = false;
245
246 int width = -1;
247 int height = -1;
248
249 for (int64_t seq_num = start_seq_num_unwrapped;
250 seq_num <= end_sequence_number_unwrapped; ++seq_num) {
251 const auto& packet = GetPacket(seq_num);
252 if (packet->codec() == kVideoCodecH264) {
253 const auto& h264_header =
254 std::get<RTPVideoHeaderH264>(packet->video_header.video_type_header);
255 for (const auto& nalu : h264_header.nalus) {
256 has_idr |= nalu.type == H264::NaluType::kIdr;
257 has_sps |= nalu.type == H264::NaluType::kSps;
258 has_pps |= nalu.type == H264::NaluType::kPps;
259 }
260 if (has_idr) {
261 if (!h264_idr_only_keyframes_allowed_ && (!has_sps || !has_pps)) {
262 return false;
263 }
264 }
265#ifdef RTC_ENABLE_H265
266 } else if (packet->codec() == kVideoCodecH265) {
267 std::vector<H265::NaluIndex> nalu_indices =
268 H265::FindNaluIndices(packet->video_payload);
269 for (const auto& nalu_index : nalu_indices) {
270 uint8_t nalu_type = H265::ParseNaluType(
271 packet->video_payload.cdata()[nalu_index.payload_start_offset]);
272 has_idr |= (nalu_type >= H265::NaluType::kBlaWLp &&
273 nalu_type <= H265::NaluType::kRsvIrapVcl23);
274 has_vps |= nalu_type == H265::NaluType::kVps;
275 has_sps |= nalu_type == H265::NaluType::kSps;
276 has_pps |= nalu_type == H265::NaluType::kPps;
277 }
278 if (has_idr) {
279 if (!has_vps || !has_sps || !has_pps) {
280 return false;
281 }
282 }
283#endif // RTC_ENABLE_H265
284 }
285
286 width = std::max<int>(packet->video_header.width, width);
287 height = std::max<int>(packet->video_header.height, height);
288 }
289
290 for (int64_t seq_num = start_seq_num_unwrapped;
291 seq_num <= end_sequence_number_unwrapped; ++seq_num) {
292 auto& packet = GetPacket(seq_num);
293
294 packet->video_header.is_first_packet_in_frame =
295 (seq_num == start_seq_num_unwrapped);
296 packet->video_header.is_last_packet_in_frame =
297 (seq_num == end_sequence_number_unwrapped);
298
299 if (packet->video_header.is_first_packet_in_frame) {
300 if (width > 0 && height > 0) {
301 packet->video_header.width = width;
302 packet->video_header.height = height;
303 }
304
305 packet->video_header.frame_type = has_idr
306 ? VideoFrameType::kVideoFrameKey
307 : VideoFrameType::kVideoFrameDelta;
308 }
309
310 // Only applies to H.264 because start code is inserted by depacktizer for
311 // H.265 and out-of-band parameter sets is not supported by H.265.
312 if (packet->codec() == kVideoCodecH264) {
313 if (!FixH264Packet(*packet)) {
314 // The buffer is not cleared actually, but a key frame request is
315 // needed.
316 result.buffer_cleared = true;
317 return false;
318 }
319 }
320
321 result.packets.push_back(std::move(packet));
322 }
323
324 return true;
325}
326
327void H26xPacketBuffer::SetH264IdrOnlyKeyframesAllowed(bool allowed) {
328 h264_idr_only_keyframes_allowed_ = allowed;
329}
330
331void H26xPacketBuffer::SetSpropParameterSets(
332 const std::string& sprop_parameter_sets) {
333 if (!h264_idr_only_keyframes_allowed_) {
334 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 334, ::webrtc::LS_WARNING)
<< "Ignore sprop parameter sets because IDR only "
335 "keyframe is not allowed.";
336 return;
337 }
338 H264SpropParameterSets sprop_decoder;
339 if (!sprop_decoder.DecodeSprop(sprop_parameter_sets)) {
340 return;
341 }
342 InsertSpsPpsNalus(sprop_decoder.sps_nalu(), sprop_decoder.pps_nalu());
343}
344
345void H26xPacketBuffer::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
346 const std::vector<uint8_t>& pps) {
347 RTC_CHECK(h264_idr_only_keyframes_allowed_)(h264_idr_only_keyframes_allowed_) ? static_cast<void>(
0) : ::webrtc::webrtc_checks_impl::FatalLogCall<false>(
"./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 347, "h264_idr_only_keyframes_allowed_") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
348 constexpr size_t kNaluHeaderOffset = 1;
349 if (sps.size() < kNaluHeaderOffset) {
350 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 350, ::webrtc::LS_WARNING)
<< "SPS size " << sps.size() << " is smaller than "
351 << kNaluHeaderOffset;
352 return;
353 }
354 if ((sps[0] & 0x1f) != H264::NaluType::kSps) {
355 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 355, ::webrtc::LS_WARNING)
<< "SPS Nalu header missing";
356 return;
357 }
358 if (pps.size() < kNaluHeaderOffset) {
359 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 359, ::webrtc::LS_WARNING)
<< "PPS size " << pps.size() << " is smaller than "
360 << kNaluHeaderOffset;
361 return;
362 }
363 if ((pps[0] & 0x1f) != H264::NaluType::kPps) {
364 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 364, ::webrtc::LS_WARNING)
<< "SPS Nalu header missing";
365 return;
366 }
367 std::optional<SpsParser::SpsState> parsed_sps = SpsParser::ParseSps(
368 std::span<const uint8_t>(sps).subspan(kNaluHeaderOffset));
369 std::optional<PpsParser::PpsState> parsed_pps = PpsParser::ParsePps(
370 std::span<const uint8_t>(pps).subspan(kNaluHeaderOffset));
371
372 if (!parsed_sps) {
373 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 373, ::webrtc::LS_WARNING)
<< "Failed to parse SPS.";
374 }
375
376 if (!parsed_pps) {
377 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 377, ::webrtc::LS_WARNING)
<< "Failed to parse PPS.";
378 }
379
380 if (!parsed_pps || !parsed_sps) {
381 return;
382 }
383
384 if (parsed_sps->id > H264::kMaxSpsId || parsed_pps->id > H264::kMaxPpsId ||
385 parsed_pps->sps_id > H264::kMaxSpsId) {
386 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 386, ::webrtc::LS_WARNING)
<< "Parsed SPS/PPS ID out of bounds.";
387 return;
388 }
389
390 SpsInfo sps_info;
391 sps_info.size = sps.size();
392 sps_info.width = parsed_sps->width;
393 sps_info.height = parsed_sps->height;
394 uint8_t* sps_data = new uint8_t[sps_info.size];
395 memcpy(sps_data, sps.data(), sps_info.size);
396 sps_info.payload.reset(sps_data);
397 sps_data_[parsed_sps->id] = std::move(sps_info);
398
399 PpsInfo pps_info;
400 pps_info.size = pps.size();
401 pps_info.sps_id = parsed_pps->sps_id;
402 uint8_t* pps_data = new uint8_t[pps_info.size];
403 memcpy(pps_data, pps.data(), pps_info.size);
404 pps_info.payload.reset(pps_data);
405 pps_data_[parsed_pps->id] = std::move(pps_info);
406
407 RTC_LOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 407, ::webrtc::LS_INFO)
<< "Inserted SPS id " << parsed_sps->id << " and PPS id "
408 << parsed_pps->id << " (referencing SPS "
409 << parsed_pps->sps_id << ")";
410}
411
412// TODO(bugs.webrtc.org/13157): Update the H264 depacketizer so we don't have to
413// fiddle with the payload at this point.
414bool H26xPacketBuffer::FixH264Packet(Packet& packet) {
415 constexpr uint8_t kStartCode[] = {0, 0, 0, 1};
416
417 RTPVideoHeader& video_header = packet.video_header;
418 RTPVideoHeaderH264& h264_header =
419 std::get<RTPVideoHeaderH264>(video_header.video_type_header);
420
421 CopyOnWriteBuffer result;
422
423 if (h264_idr_only_keyframes_allowed_) {
424 // Check if sps and pps insertion is needed.
425 bool prepend_sps_pps = false;
426 auto sps = sps_data_.end();
427 auto pps = pps_data_.end();
428
429 for (const NaluInfo& nalu : h264_header.nalus) {
430 switch (nalu.type) {
431 case H264::NaluType::kSps: {
432 if (nalu.sps_id < 0 || nalu.sps_id > H264::kMaxSpsId) {
433 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 433, ::webrtc::LS_WARNING)
<< "SPS id out of bounds: " << nalu.sps_id;
434 return false;
435 }
436 SpsInfo& sps_info = sps_data_[nalu.sps_id];
437 sps_info.width = video_header.width;
438 sps_info.height = video_header.height;
439 break;
440 }
441 case H264::NaluType::kPps: {
442 if (nalu.pps_id < 0 || nalu.pps_id > H264::kMaxPpsId ||
443 nalu.sps_id < 0 || nalu.sps_id > H264::kMaxSpsId) {
444 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 444, ::webrtc::LS_WARNING)
445 << "PPS or SPS id out of bounds: pps_id=" << nalu.pps_id
446 << " sps_id=" << nalu.sps_id;
447 return false;
448 }
449 pps_data_[nalu.pps_id].sps_id = nalu.sps_id;
450 break;
451 }
452 case H264::NaluType::kIdr: {
453 // If this is the first packet of an IDR, make sure we have the
454 // required SPS/PPS and also calculate how much extra space we need
455 // in the buffer to prepend the SPS/PPS to the bitstream with start
456 // codes.
457 if (video_header.is_first_packet_in_frame) {
458 if (nalu.pps_id == -1) {
459 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 459, ::webrtc::LS_WARNING)
<< "No PPS id in IDR nalu.";
460 return false;
461 }
462
463 pps = pps_data_.find(nalu.pps_id);
464 if (pps == pps_data_.end()) {
465 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 465, ::webrtc::LS_WARNING)
466 << "No PPS with id << " << nalu.pps_id << " received";
467 return false;
468 }
469
470 sps = sps_data_.find(pps->second.sps_id);
471 if (sps == sps_data_.end()) {
472 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 472, ::webrtc::LS_WARNING)
473 << "No SPS with id << " << pps->second.sps_id << " received";
474 return false;
475 }
476
477 // Since the first packet of every keyframe should have its width
478 // and height set we set it here in the case of it being supplied
479 // out of band.
480 video_header.width = sps->second.width;
481 video_header.height = sps->second.height;
482
483 // If the SPS/PPS was supplied out of band then we will have saved
484 // the actual bitstream in `data`.
485 if (sps->second.payload && pps->second.payload) {
486 RTC_DCHECK_GT(sps->second.size, 0)::webrtc::SafeGt((sps->second.size), (0)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 486, "sps->second.size" " " ">" " " "0") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (sps->
second.size) << (0)
;
487 RTC_DCHECK_GT(pps->second.size, 0)::webrtc::SafeGt((pps->second.size), (0)) ? static_cast<
void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<true
>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 487, "pps->second.size" " " ">" " " "0") & ::webrtc
::webrtc_checks_impl::LogStreamer<>() << (pps->
second.size) << (0)
;
488 prepend_sps_pps = true;
489 }
490 }
491 break;
492 }
493 default:
494 break;
495 }
496 }
497
498 RTC_CHECK(!prepend_sps_pps ||(!prepend_sps_pps || (sps != sps_data_.end() && pps !=
pps_data_.end())) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 499, "!prepend_sps_pps || (sps != sps_data_.end() && pps != pps_data_.end())"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
499 (sps != sps_data_.end() && pps != pps_data_.end()))(!prepend_sps_pps || (sps != sps_data_.end() && pps !=
pps_data_.end())) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 499, "!prepend_sps_pps || (sps != sps_data_.end() && pps != pps_data_.end())"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
;
500
501 // Insert SPS and PPS if they are missing.
502 if (prepend_sps_pps) {
503 // Insert SPS.
504 result.AppendData(kStartCode);
505 result.AppendData(sps->second.payload.get(), sps->second.size);
506
507 // Insert PPS.
508 result.AppendData(kStartCode);
509 result.AppendData(pps->second.payload.get(), pps->second.size);
510
511 // Update codec header to reflect the newly added SPS and PPS.
512 h264_header.nalus.push_back(
513 {.type = H264::NaluType::kSps, .sps_id = sps->first, .pps_id = -1});
514 h264_header.nalus.push_back({.type = H264::NaluType::kPps,
515 .sps_id = sps->first,
516 .pps_id = pps->first});
517 }
518 }
519
520 // Insert start code.
521 switch (h264_header.packetization_type) {
522 case kH264StapA: {
523 const uint8_t* payload_end =
524 packet.video_payload.data() + packet.video_payload.size();
525 const uint8_t* nalu_ptr = packet.video_payload.data() + 1;
526 while (nalu_ptr < payload_end - 1) {
527 // The first two bytes describe the length of the segment, where a
528 // segment is the nalu type plus nalu payload.
529 uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
530 nalu_ptr += 2;
531
532 if (nalu_ptr + segment_length <= payload_end) {
533 result.AppendData(kStartCode);
534 result.AppendData(nalu_ptr, segment_length);
535 }
536 nalu_ptr += segment_length;
537 }
538 packet.video_payload = result;
539 return true;
540 }
541
542 case kH264FuA: {
543 if (IsFirstPacketOfFragment(h264_header)) {
544 result.AppendData(kStartCode);
545 }
546 result.AppendData(packet.video_payload);
547 packet.video_payload = result;
548 return true;
549 }
550
551 case kH264SingleNalu: {
552 result.AppendData(kStartCode);
553 result.AppendData(packet.video_payload);
554 packet.video_payload = result;
555 return true;
556 }
557 }
558
559 RTC_DCHECK_NOTREACHED()(false) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../../third_party/libwebrtc/modules/video_coding/h26x_packet_buffer.cc"
, 559, "false") & ::webrtc::webrtc_checks_impl::LogStreamer
<>()
;
560 return false;
561}
562
563} // namespace webrtc