| 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 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | |
| 42 | namespace webrtc { |
| 43 | namespace { |
| 44 | |
| 45 | int64_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 | |
| 50 | bool IsFirstPacketOfFragment(const RTPVideoHeaderH264& h264_header) { |
| 51 | return !h264_header.nalus.empty(); |
| 52 | } |
| 53 | |
| 54 | bool 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 | |
| 72 | bool 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 | |
| 80 | int64_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 |
| 91 | bool 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 | |
| 105 | H26xPacketBuffer::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 | |
| 110 | H26xPacketBuffer::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 | |
| 128 | H26xPacketBuffer::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 | |
| 148 | std::unique_ptr<H26xPacketBuffer::Packet>& H26xPacketBuffer::GetPacket( |
| 149 | int64_t unwrapped_seq_num) { |
| 150 | return buffer_[EuclideanMod(unwrapped_seq_num, kBufferSize)]; |
| 151 | } |
| 152 | |
| 153 | bool 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 | |
| 167 | H26xPacketBuffer::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 | |
| 235 | bool 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 | |
| 327 | void H26xPacketBuffer::SetH264IdrOnlyKeyframesAllowed(bool allowed) { |
| 328 | h264_idr_only_keyframes_allowed_ = allowed; |
| 329 | } |
| 330 | |
| 331 | void 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 | |
| 345 | void 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. |
| 414 | bool 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 |