session_info.cc (18374B)
1 /* 2 * Copyright (c) 2012 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/deprecated/session_info.h" 12 13 #include <cstdint> 14 #include <cstring> 15 #include <iterator> 16 #include <variant> 17 #include <vector> 18 19 #include "absl/algorithm/container.h" 20 #include "api/video/video_codec_type.h" 21 #include "api/video/video_frame_type.h" 22 #include "modules/include/module_common_types_public.h" 23 #include "modules/video_coding/codecs/h264/include/h264_globals.h" 24 #include "modules/video_coding/codecs/interface/common_constants.h" 25 #include "modules/video_coding/codecs/vp8/include/vp8_globals.h" 26 #include "modules/video_coding/codecs/vp9/include/vp9_globals.h" 27 #include "modules/video_coding/deprecated/jitter_buffer_common.h" 28 #include "modules/video_coding/deprecated/packet.h" 29 #include "rtc_base/checks.h" 30 #include "rtc_base/logging.h" 31 32 namespace webrtc { 33 34 namespace { 35 36 uint16_t BufferToUWord16(const uint8_t* dataBuffer) { 37 return (dataBuffer[0] << 8) | dataBuffer[1]; 38 } 39 40 } // namespace 41 42 VCMSessionInfo::VCMSessionInfo() 43 : complete_(false), 44 frame_type_(VideoFrameType::kVideoFrameDelta), 45 packets_(), 46 empty_seq_num_low_(-1), 47 empty_seq_num_high_(-1), 48 first_packet_seq_num_(-1), 49 last_packet_seq_num_(-1) {} 50 51 VCMSessionInfo::~VCMSessionInfo() {} 52 53 void VCMSessionInfo::UpdateDataPointers(const uint8_t* old_base_ptr, 54 const uint8_t* new_base_ptr) { 55 for (PacketIterator it = packets_.begin(); it != packets_.end(); ++it) 56 if ((*it).dataPtr != nullptr) { 57 RTC_DCHECK(old_base_ptr != nullptr && new_base_ptr != nullptr); 58 (*it).dataPtr = new_base_ptr + ((*it).dataPtr - old_base_ptr); 59 } 60 } 61 62 int VCMSessionInfo::LowSequenceNumber() const { 63 if (packets_.empty()) 64 return empty_seq_num_low_; 65 return packets_.front().seqNum; 66 } 67 68 int VCMSessionInfo::HighSequenceNumber() const { 69 if (packets_.empty()) 70 return empty_seq_num_high_; 71 if (empty_seq_num_high_ == -1) 72 return packets_.back().seqNum; 73 return LatestSequenceNumber(packets_.back().seqNum, empty_seq_num_high_); 74 } 75 76 int VCMSessionInfo::PictureId() const { 77 if (packets_.empty()) 78 return kNoPictureId; 79 if (packets_.front().video_header.codec == kVideoCodecVP8) { 80 return std::get<RTPVideoHeaderVP8>( 81 packets_.front().video_header.video_type_header) 82 .pictureId; 83 } else if (packets_.front().video_header.codec == kVideoCodecVP9) { 84 return std::get<RTPVideoHeaderVP9>( 85 packets_.front().video_header.video_type_header) 86 .picture_id; 87 } else { 88 return kNoPictureId; 89 } 90 } 91 92 int VCMSessionInfo::TemporalId() const { 93 if (packets_.empty()) 94 return kNoTemporalIdx; 95 if (packets_.front().video_header.codec == kVideoCodecVP8) { 96 return std::get<RTPVideoHeaderVP8>( 97 packets_.front().video_header.video_type_header) 98 .temporalIdx; 99 } else if (packets_.front().video_header.codec == kVideoCodecVP9) { 100 return std::get<RTPVideoHeaderVP9>( 101 packets_.front().video_header.video_type_header) 102 .temporal_idx; 103 } else { 104 return kNoTemporalIdx; 105 } 106 } 107 108 bool VCMSessionInfo::LayerSync() const { 109 if (packets_.empty()) 110 return false; 111 if (packets_.front().video_header.codec == kVideoCodecVP8) { 112 return std::get<RTPVideoHeaderVP8>( 113 packets_.front().video_header.video_type_header) 114 .layerSync; 115 } else if (packets_.front().video_header.codec == kVideoCodecVP9) { 116 return std::get<RTPVideoHeaderVP9>( 117 packets_.front().video_header.video_type_header) 118 .temporal_up_switch; 119 } else { 120 return false; 121 } 122 } 123 124 int VCMSessionInfo::Tl0PicId() const { 125 if (packets_.empty()) 126 return kNoTl0PicIdx; 127 if (packets_.front().video_header.codec == kVideoCodecVP8) { 128 return std::get<RTPVideoHeaderVP8>( 129 packets_.front().video_header.video_type_header) 130 .tl0PicIdx; 131 } else if (packets_.front().video_header.codec == kVideoCodecVP9) { 132 return std::get<RTPVideoHeaderVP9>( 133 packets_.front().video_header.video_type_header) 134 .tl0_pic_idx; 135 } else { 136 return kNoTl0PicIdx; 137 } 138 } 139 140 std::vector<NaluInfo> VCMSessionInfo::GetNaluInfos() const { 141 if (packets_.empty() || 142 packets_.front().video_header.codec != kVideoCodecH264) 143 return std::vector<NaluInfo>(); 144 std::vector<NaluInfo> nalu_infos; 145 for (const VCMPacket& packet : packets_) { 146 const auto& h264 = 147 std::get<RTPVideoHeaderH264>(packet.video_header.video_type_header); 148 absl::c_copy(h264.nalus, std::back_inserter(nalu_infos)); 149 } 150 return nalu_infos; 151 } 152 153 void VCMSessionInfo::SetGofInfo(const GofInfoVP9& gof_info, size_t idx) { 154 if (packets_.empty()) 155 return; 156 157 auto* vp9_header = std::get_if<RTPVideoHeaderVP9>( 158 &packets_.front().video_header.video_type_header); 159 if (!vp9_header || vp9_header->flexible_mode) 160 return; 161 162 vp9_header->temporal_idx = gof_info.temporal_idx[idx]; 163 vp9_header->temporal_up_switch = gof_info.temporal_up_switch[idx]; 164 vp9_header->num_ref_pics = gof_info.num_ref_pics[idx]; 165 for (uint8_t i = 0; i < gof_info.num_ref_pics[idx]; ++i) { 166 vp9_header->pid_diff[i] = gof_info.pid_diff[idx][i]; 167 } 168 } 169 170 void VCMSessionInfo::Reset() { 171 complete_ = false; 172 frame_type_ = VideoFrameType::kVideoFrameDelta; 173 packets_.clear(); 174 empty_seq_num_low_ = -1; 175 empty_seq_num_high_ = -1; 176 first_packet_seq_num_ = -1; 177 last_packet_seq_num_ = -1; 178 } 179 180 size_t VCMSessionInfo::SessionLength() const { 181 size_t length = 0; 182 for (PacketIteratorConst it = packets_.begin(); it != packets_.end(); ++it) 183 length += (*it).sizeBytes; 184 return length; 185 } 186 187 int VCMSessionInfo::NumPackets() const { 188 return packets_.size(); 189 } 190 191 size_t VCMSessionInfo::InsertBuffer(uint8_t* frame_buffer, 192 PacketIterator packet_it) { 193 VCMPacket& packet = *packet_it; 194 PacketIterator it; 195 196 // Calculate the offset into the frame buffer for this packet. 197 size_t offset = 0; 198 for (it = packets_.begin(); it != packet_it; ++it) 199 offset += (*it).sizeBytes; 200 201 // Set the data pointer to pointing to the start of this packet in the 202 // frame buffer. 203 const uint8_t* packet_buffer = packet.dataPtr; 204 packet.dataPtr = frame_buffer + offset; 205 206 // We handle H.264 STAP-A packets in a special way as we need to remove the 207 // two length bytes between each NAL unit, and potentially add start codes. 208 // TODO(pbos): Remove H264 parsing from this step and use a fragmentation 209 // header supplied by the H264 depacketizer. 210 const size_t kH264NALHeaderLengthInBytes = 1; 211 const size_t kLengthFieldLength = 2; 212 const auto* h264 = 213 std::get_if<RTPVideoHeaderH264>(&packet.video_header.video_type_header); 214 if (h264 && h264->packetization_type == kH264StapA) { 215 size_t required_length = 0; 216 const uint8_t* nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; 217 while (nalu_ptr < packet_buffer + packet.sizeBytes) { 218 size_t length = BufferToUWord16(nalu_ptr); 219 required_length += 220 length + (packet.insertStartCode ? kH264StartCodeLengthBytes : 0); 221 nalu_ptr += kLengthFieldLength + length; 222 } 223 ShiftSubsequentPackets(packet_it, required_length); 224 nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; 225 uint8_t* frame_buffer_ptr = frame_buffer + offset; 226 while (nalu_ptr < packet_buffer + packet.sizeBytes) { 227 size_t length = BufferToUWord16(nalu_ptr); 228 nalu_ptr += kLengthFieldLength; 229 frame_buffer_ptr += Insert(nalu_ptr, length, packet.insertStartCode, 230 const_cast<uint8_t*>(frame_buffer_ptr)); 231 nalu_ptr += length; 232 } 233 packet.sizeBytes = required_length; 234 return packet.sizeBytes; 235 } 236 ShiftSubsequentPackets( 237 packet_it, packet.sizeBytes + 238 (packet.insertStartCode ? kH264StartCodeLengthBytes : 0)); 239 240 packet.sizeBytes = 241 Insert(packet_buffer, packet.sizeBytes, packet.insertStartCode, 242 const_cast<uint8_t*>(packet.dataPtr)); 243 return packet.sizeBytes; 244 } 245 246 size_t VCMSessionInfo::Insert(const uint8_t* buffer, 247 size_t length, 248 bool insert_start_code, 249 uint8_t* frame_buffer) { 250 if (!buffer || !frame_buffer) { 251 return 0; 252 } 253 if (insert_start_code) { 254 const unsigned char startCode[] = {0, 0, 0, 1}; 255 memcpy(frame_buffer, startCode, kH264StartCodeLengthBytes); 256 } 257 memcpy(frame_buffer + (insert_start_code ? kH264StartCodeLengthBytes : 0), 258 buffer, length); 259 length += (insert_start_code ? kH264StartCodeLengthBytes : 0); 260 261 return length; 262 } 263 264 void VCMSessionInfo::ShiftSubsequentPackets(PacketIterator it, 265 int steps_to_shift) { 266 ++it; 267 if (it == packets_.end()) 268 return; 269 uint8_t* first_packet_ptr = const_cast<uint8_t*>((*it).dataPtr); 270 int shift_length = 0; 271 // Calculate the total move length and move the data pointers in advance. 272 for (; it != packets_.end(); ++it) { 273 shift_length += (*it).sizeBytes; 274 if ((*it).dataPtr != nullptr) 275 (*it).dataPtr += steps_to_shift; 276 } 277 memmove(first_packet_ptr + steps_to_shift, first_packet_ptr, shift_length); 278 } 279 280 void VCMSessionInfo::UpdateCompleteSession() { 281 if (HaveFirstPacket() && HaveLastPacket()) { 282 // Do we have all the packets in this session? 283 bool complete_session = true; 284 PacketIterator it = packets_.begin(); 285 PacketIterator prev_it = it; 286 ++it; 287 for (; it != packets_.end(); ++it) { 288 if (!InSequence(it, prev_it)) { 289 complete_session = false; 290 break; 291 } 292 prev_it = it; 293 } 294 complete_ = complete_session; 295 } 296 } 297 298 bool VCMSessionInfo::complete() const { 299 return complete_; 300 } 301 302 // Find the end of the NAL unit which the packet pointed to by `packet_it` 303 // belongs to. Returns an iterator to the last packet of the frame if the end 304 // of the NAL unit wasn't found. 305 VCMSessionInfo::PacketIterator VCMSessionInfo::FindNaluEnd( 306 PacketIterator packet_it) const { 307 if ((*packet_it).completeNALU == kNaluEnd || 308 (*packet_it).completeNALU == kNaluComplete) { 309 return packet_it; 310 } 311 // Find the end of the NAL unit. 312 for (; packet_it != packets_.end(); ++packet_it) { 313 if (((*packet_it).completeNALU == kNaluComplete && 314 (*packet_it).sizeBytes > 0) || 315 // Found next NALU. 316 (*packet_it).completeNALU == kNaluStart) 317 return --packet_it; 318 if ((*packet_it).completeNALU == kNaluEnd) 319 return packet_it; 320 } 321 // The end wasn't found. 322 return --packet_it; 323 } 324 325 size_t VCMSessionInfo::DeletePacketData(PacketIterator start, 326 PacketIterator end) { 327 size_t bytes_to_delete = 0; // The number of bytes to delete. 328 PacketIterator packet_after_end = end; 329 ++packet_after_end; 330 331 // Get the number of bytes to delete. 332 // Clear the size of these packets. 333 for (PacketIterator it = start; it != packet_after_end; ++it) { 334 bytes_to_delete += (*it).sizeBytes; 335 (*it).sizeBytes = 0; 336 (*it).dataPtr = nullptr; 337 } 338 if (bytes_to_delete > 0) 339 ShiftSubsequentPackets(end, -static_cast<int>(bytes_to_delete)); 340 return bytes_to_delete; 341 } 342 343 VCMSessionInfo::PacketIterator VCMSessionInfo::FindNextPartitionBeginning( 344 PacketIterator it) const { 345 while (it != packets_.end()) { 346 if (std::get<RTPVideoHeaderVP8>((*it).video_header.video_type_header) 347 .beginningOfPartition) { 348 return it; 349 } 350 ++it; 351 } 352 return it; 353 } 354 355 VCMSessionInfo::PacketIterator VCMSessionInfo::FindPartitionEnd( 356 PacketIterator it) const { 357 RTC_DCHECK_EQ((*it).codec(), kVideoCodecVP8); 358 PacketIterator prev_it = it; 359 const int partition_id = 360 std::get<RTPVideoHeaderVP8>((*it).video_header.video_type_header) 361 .partitionId; 362 while (it != packets_.end()) { 363 bool beginning = 364 std::get<RTPVideoHeaderVP8>((*it).video_header.video_type_header) 365 .beginningOfPartition; 366 int current_partition_id = 367 std::get<RTPVideoHeaderVP8>((*it).video_header.video_type_header) 368 .partitionId; 369 bool packet_loss_found = (!beginning && !InSequence(it, prev_it)); 370 if (packet_loss_found || 371 (beginning && current_partition_id != partition_id)) { 372 // Missing packet, the previous packet was the last in sequence. 373 return prev_it; 374 } 375 prev_it = it; 376 ++it; 377 } 378 return prev_it; 379 } 380 381 bool VCMSessionInfo::InSequence(const PacketIterator& packet_it, 382 const PacketIterator& prev_packet_it) { 383 // If the two iterators are pointing to the same packet they are considered 384 // to be in sequence. 385 return (packet_it == prev_packet_it || 386 (static_cast<uint16_t>((*prev_packet_it).seqNum + 1) == 387 (*packet_it).seqNum)); 388 } 389 390 size_t VCMSessionInfo::MakeDecodable() { 391 size_t return_length = 0; 392 if (packets_.empty()) { 393 return 0; 394 } 395 PacketIterator it = packets_.begin(); 396 // Make sure we remove the first NAL unit if it's not decodable. 397 if ((*it).completeNALU == kNaluIncomplete || (*it).completeNALU == kNaluEnd) { 398 PacketIterator nalu_end = FindNaluEnd(it); 399 return_length += DeletePacketData(it, nalu_end); 400 it = nalu_end; 401 } 402 PacketIterator prev_it = it; 403 // Take care of the rest of the NAL units. 404 for (; it != packets_.end(); ++it) { 405 bool start_of_nalu = ((*it).completeNALU == kNaluStart || 406 (*it).completeNALU == kNaluComplete); 407 if (!start_of_nalu && !InSequence(it, prev_it)) { 408 // Found a sequence number gap due to packet loss. 409 PacketIterator nalu_end = FindNaluEnd(it); 410 return_length += DeletePacketData(it, nalu_end); 411 it = nalu_end; 412 } 413 prev_it = it; 414 } 415 return return_length; 416 } 417 418 bool VCMSessionInfo::HaveFirstPacket() const { 419 return !packets_.empty() && (first_packet_seq_num_ != -1); 420 } 421 422 bool VCMSessionInfo::HaveLastPacket() const { 423 return !packets_.empty() && (last_packet_seq_num_ != -1); 424 } 425 426 int VCMSessionInfo::InsertPacket(const VCMPacket& packet, 427 uint8_t* frame_buffer, 428 const FrameData& /* frame_data */) { 429 if (packet.video_header.frame_type == VideoFrameType::kEmptyFrame) { 430 // Update sequence number of an empty packet. 431 // Only media packets are inserted into the packet list. 432 InformOfEmptyPacket(packet.seqNum); 433 return 0; 434 } 435 436 if (packets_.size() == kMaxPacketsInSession) { 437 RTC_LOG(LS_ERROR) << "Max number of packets per frame has been reached."; 438 return -1; 439 } 440 441 // Find the position of this packet in the packet list in sequence number 442 // order and insert it. Loop over the list in reverse order. 443 ReversePacketIterator rit = packets_.rbegin(); 444 for (; rit != packets_.rend(); ++rit) 445 if (LatestSequenceNumber(packet.seqNum, (*rit).seqNum) == packet.seqNum) 446 break; 447 448 // Check for duplicate packets. 449 if (rit != packets_.rend() && (*rit).seqNum == packet.seqNum && 450 (*rit).sizeBytes > 0) 451 return -2; 452 453 if (packet.codec() == kVideoCodecH264) { 454 frame_type_ = packet.video_header.frame_type; 455 if (packet.is_first_packet_in_frame() && 456 (first_packet_seq_num_ == -1 || 457 IsNewerSequenceNumber(first_packet_seq_num_, packet.seqNum))) { 458 first_packet_seq_num_ = packet.seqNum; 459 } 460 if (packet.markerBit && 461 (last_packet_seq_num_ == -1 || 462 IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_))) { 463 last_packet_seq_num_ = packet.seqNum; 464 } 465 } else { 466 // Only insert media packets between first and last packets (when 467 // available). 468 // Placing check here, as to properly account for duplicate packets. 469 // Check if this is first packet (only valid for some codecs) 470 // Should only be set for one packet per session. 471 if (packet.is_first_packet_in_frame() && first_packet_seq_num_ == -1) { 472 // The first packet in a frame signals the frame type. 473 frame_type_ = packet.video_header.frame_type; 474 // Store the sequence number for the first packet. 475 first_packet_seq_num_ = static_cast<int>(packet.seqNum); 476 } else if (first_packet_seq_num_ != -1 && 477 IsNewerSequenceNumber(first_packet_seq_num_, packet.seqNum)) { 478 RTC_LOG(LS_WARNING) 479 << "Received packet with a sequence number which is out " 480 "of frame boundaries"; 481 return -3; 482 } else if (frame_type_ == VideoFrameType::kEmptyFrame && 483 packet.video_header.frame_type != VideoFrameType::kEmptyFrame) { 484 // Update the frame type with the type of the first media packet. 485 // TODO(mikhal): Can this trigger? 486 frame_type_ = packet.video_header.frame_type; 487 } 488 489 // Track the marker bit, should only be set for one packet per session. 490 if (packet.markerBit && last_packet_seq_num_ == -1) { 491 last_packet_seq_num_ = static_cast<int>(packet.seqNum); 492 } else if (last_packet_seq_num_ != -1 && 493 IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_)) { 494 RTC_LOG(LS_WARNING) 495 << "Received packet with a sequence number which is out " 496 "of frame boundaries"; 497 return -3; 498 } 499 } 500 501 // The insert operation invalidates the iterator `rit`. 502 PacketIterator packet_list_it = packets_.insert(rit.base(), packet); 503 504 size_t returnLength = InsertBuffer(frame_buffer, packet_list_it); 505 UpdateCompleteSession(); 506 507 return static_cast<int>(returnLength); 508 } 509 510 void VCMSessionInfo::InformOfEmptyPacket(uint16_t seq_num) { 511 // Empty packets may be FEC or filler packets. They are sequential and 512 // follow the data packets, therefore, we should only keep track of the high 513 // and low sequence numbers and may assume that the packets in between are 514 // empty packets belonging to the same frame (timestamp). 515 if (empty_seq_num_high_ == -1) 516 empty_seq_num_high_ = seq_num; 517 else 518 empty_seq_num_high_ = LatestSequenceNumber(seq_num, empty_seq_num_high_); 519 if (empty_seq_num_low_ == -1 || 520 IsNewerSequenceNumber(empty_seq_num_low_, seq_num)) 521 empty_seq_num_low_ = seq_num; 522 } 523 524 } // namespace webrtc