1 /* 2 * Copyright (c) 2011 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 "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" 12 13 #include <assert.h> // assert 14 #include <string.h> // memcpy 15 16 #include <vector> 17 18 #include "webrtc/base/logging.h" 19 #include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h" 20 21 namespace webrtc { 22 namespace { 23 int ParseVP8PictureID(RTPVideoHeaderVP8* vp8, 24 const uint8_t** data, 25 size_t* data_length, 26 size_t* parsed_bytes) { 27 assert(vp8 != NULL); 28 if (*data_length == 0) 29 return -1; 30 31 vp8->pictureId = (**data & 0x7F); 32 if (**data & 0x80) { 33 (*data)++; 34 (*parsed_bytes)++; 35 if (--(*data_length) == 0) 36 return -1; 37 // PictureId is 15 bits 38 vp8->pictureId = (vp8->pictureId << 8) + **data; 39 } 40 (*data)++; 41 (*parsed_bytes)++; 42 (*data_length)--; 43 return 0; 44 } 45 46 int ParseVP8Tl0PicIdx(RTPVideoHeaderVP8* vp8, 47 const uint8_t** data, 48 size_t* data_length, 49 size_t* parsed_bytes) { 50 assert(vp8 != NULL); 51 if (*data_length == 0) 52 return -1; 53 54 vp8->tl0PicIdx = **data; 55 (*data)++; 56 (*parsed_bytes)++; 57 (*data_length)--; 58 return 0; 59 } 60 61 int ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8* vp8, 62 const uint8_t** data, 63 size_t* data_length, 64 size_t* parsed_bytes, 65 bool has_tid, 66 bool has_key_idx) { 67 assert(vp8 != NULL); 68 if (*data_length == 0) 69 return -1; 70 71 if (has_tid) { 72 vp8->temporalIdx = ((**data >> 6) & 0x03); 73 vp8->layerSync = (**data & 0x20) ? true : false; // Y bit 74 } 75 if (has_key_idx) { 76 vp8->keyIdx = (**data & 0x1F); 77 } 78 (*data)++; 79 (*parsed_bytes)++; 80 (*data_length)--; 81 return 0; 82 } 83 84 int ParseVP8Extension(RTPVideoHeaderVP8* vp8, 85 const uint8_t* data, 86 size_t data_length) { 87 assert(vp8 != NULL); 88 assert(data_length > 0); 89 size_t parsed_bytes = 0; 90 // Optional X field is present. 91 bool has_picture_id = (*data & 0x80) ? true : false; // I bit 92 bool has_tl0_pic_idx = (*data & 0x40) ? true : false; // L bit 93 bool has_tid = (*data & 0x20) ? true : false; // T bit 94 bool has_key_idx = (*data & 0x10) ? true : false; // K bit 95 96 // Advance data and decrease remaining payload size. 97 data++; 98 parsed_bytes++; 99 data_length--; 100 101 if (has_picture_id) { 102 if (ParseVP8PictureID(vp8, &data, &data_length, &parsed_bytes) != 0) { 103 return -1; 104 } 105 } 106 107 if (has_tl0_pic_idx) { 108 if (ParseVP8Tl0PicIdx(vp8, &data, &data_length, &parsed_bytes) != 0) { 109 return -1; 110 } 111 } 112 113 if (has_tid || has_key_idx) { 114 if (ParseVP8TIDAndKeyIdx( 115 vp8, &data, &data_length, &parsed_bytes, has_tid, has_key_idx) != 116 0) { 117 return -1; 118 } 119 } 120 return static_cast<int>(parsed_bytes); 121 } 122 123 int ParseVP8FrameSize(RtpDepacketizer::ParsedPayload* parsed_payload, 124 const uint8_t* data, 125 size_t data_length) { 126 assert(parsed_payload != NULL); 127 if (parsed_payload->frame_type != kVideoFrameKey) { 128 // Included in payload header for I-frames. 129 return 0; 130 } 131 if (data_length < 10) { 132 // For an I-frame we should always have the uncompressed VP8 header 133 // in the beginning of the partition. 134 return -1; 135 } 136 parsed_payload->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF; 137 parsed_payload->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF; 138 return 0; 139 } 140 } // namespace 141 142 // Define how the VP8PacketizerModes are implemented. 143 // Modes are: kStrict, kAggregate, kEqualSize. 144 const RtpPacketizerVp8::AggregationMode RtpPacketizerVp8::aggr_modes_ 145 [kNumModes] = {kAggrNone, kAggrPartitions, kAggrFragments}; 146 const bool RtpPacketizerVp8::balance_modes_[kNumModes] = {true, true, true}; 147 const bool RtpPacketizerVp8::separate_first_modes_[kNumModes] = {true, false, 148 false}; 149 150 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, 151 size_t max_payload_len, 152 VP8PacketizerMode mode) 153 : payload_data_(NULL), 154 payload_size_(0), 155 vp8_fixed_payload_descriptor_bytes_(1), 156 aggr_mode_(aggr_modes_[mode]), 157 balance_(balance_modes_[mode]), 158 separate_first_(separate_first_modes_[mode]), 159 hdr_info_(hdr_info), 160 num_partitions_(0), 161 max_payload_len_(max_payload_len), 162 packets_calculated_(false) { 163 } 164 165 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, 166 size_t max_payload_len) 167 : payload_data_(NULL), 168 payload_size_(0), 169 part_info_(), 170 vp8_fixed_payload_descriptor_bytes_(1), 171 aggr_mode_(aggr_modes_[kEqualSize]), 172 balance_(balance_modes_[kEqualSize]), 173 separate_first_(separate_first_modes_[kEqualSize]), 174 hdr_info_(hdr_info), 175 num_partitions_(0), 176 max_payload_len_(max_payload_len), 177 packets_calculated_(false) { 178 } 179 180 RtpPacketizerVp8::~RtpPacketizerVp8() { 181 } 182 183 void RtpPacketizerVp8::SetPayloadData( 184 const uint8_t* payload_data, 185 size_t payload_size, 186 const RTPFragmentationHeader* fragmentation) { 187 payload_data_ = payload_data; 188 payload_size_ = payload_size; 189 if (fragmentation) { 190 part_info_.CopyFrom(*fragmentation); 191 num_partitions_ = fragmentation->fragmentationVectorSize; 192 } else { 193 part_info_.VerifyAndAllocateFragmentationHeader(1); 194 part_info_.fragmentationLength[0] = payload_size; 195 part_info_.fragmentationOffset[0] = 0; 196 num_partitions_ = part_info_.fragmentationVectorSize; 197 } 198 } 199 200 bool RtpPacketizerVp8::NextPacket(uint8_t* buffer, 201 size_t* bytes_to_send, 202 bool* last_packet) { 203 if (!packets_calculated_) { 204 int ret = 0; 205 if (aggr_mode_ == kAggrPartitions && balance_) { 206 ret = GeneratePacketsBalancedAggregates(); 207 } else { 208 ret = GeneratePackets(); 209 } 210 if (ret < 0) { 211 return false; 212 } 213 } 214 if (packets_.empty()) { 215 return false; 216 } 217 InfoStruct packet_info = packets_.front(); 218 packets_.pop(); 219 220 int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_); 221 if (bytes < 0) { 222 return false; 223 } 224 *bytes_to_send = static_cast<size_t>(bytes); 225 226 *last_packet = packets_.empty(); 227 return true; 228 } 229 230 ProtectionType RtpPacketizerVp8::GetProtectionType() { 231 bool protect = 232 hdr_info_.temporalIdx == 0 || hdr_info_.temporalIdx == kNoTemporalIdx; 233 return protect ? kProtectedPacket : kUnprotectedPacket; 234 } 235 236 StorageType RtpPacketizerVp8::GetStorageType(uint32_t retransmission_settings) { 237 if (hdr_info_.temporalIdx == 0 && 238 !(retransmission_settings & kRetransmitBaseLayer)) { 239 return kDontRetransmit; 240 } 241 if (hdr_info_.temporalIdx != kNoTemporalIdx && 242 hdr_info_.temporalIdx > 0 && 243 !(retransmission_settings & kRetransmitHigherLayers)) { 244 return kDontRetransmit; 245 } 246 return kAllowRetransmission; 247 } 248 249 std::string RtpPacketizerVp8::ToString() { 250 return "RtpPacketizerVp8"; 251 } 252 253 size_t RtpPacketizerVp8::CalcNextSize(size_t max_payload_len, 254 size_t remaining_bytes, 255 bool split_payload) const { 256 if (max_payload_len == 0 || remaining_bytes == 0) { 257 return 0; 258 } 259 if (!split_payload) { 260 return max_payload_len >= remaining_bytes ? remaining_bytes : 0; 261 } 262 263 if (balance_) { 264 // Balance payload sizes to produce (almost) equal size 265 // fragments. 266 // Number of fragments for remaining_bytes: 267 size_t num_frags = remaining_bytes / max_payload_len + 1; 268 // Number of bytes in this fragment: 269 return static_cast<size_t>( 270 static_cast<double>(remaining_bytes) / num_frags + 0.5); 271 } else { 272 return max_payload_len >= remaining_bytes ? remaining_bytes 273 : max_payload_len; 274 } 275 } 276 277 int RtpPacketizerVp8::GeneratePackets() { 278 if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ + 279 PayloadDescriptorExtraLength() + 1) { 280 // The provided payload length is not long enough for the payload 281 // descriptor and one payload byte. Return an error. 282 return -1; 283 } 284 size_t total_bytes_processed = 0; 285 bool start_on_new_fragment = true; 286 bool beginning = true; 287 size_t part_ix = 0; 288 while (total_bytes_processed < payload_size_) { 289 size_t packet_bytes = 0; // How much data to send in this packet. 290 bool split_payload = true; // Splitting of partitions is initially allowed. 291 size_t remaining_in_partition = part_info_.fragmentationOffset[part_ix] - 292 total_bytes_processed + 293 part_info_.fragmentationLength[part_ix]; 294 size_t rem_payload_len = 295 max_payload_len_ - 296 (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength()); 297 size_t first_partition_in_packet = part_ix; 298 299 while (size_t next_size = CalcNextSize( 300 rem_payload_len, remaining_in_partition, split_payload)) { 301 packet_bytes += next_size; 302 rem_payload_len -= next_size; 303 remaining_in_partition -= next_size; 304 305 if (remaining_in_partition == 0 && !(beginning && separate_first_)) { 306 // Advance to next partition? 307 // Check that there are more partitions; verify that we are either 308 // allowed to aggregate fragments, or that we are allowed to 309 // aggregate intact partitions and that we started this packet 310 // with an intact partition (indicated by first_fragment_ == true). 311 if (part_ix + 1 < num_partitions_ && 312 ((aggr_mode_ == kAggrFragments) || 313 (aggr_mode_ == kAggrPartitions && start_on_new_fragment))) { 314 assert(part_ix < num_partitions_); 315 remaining_in_partition = part_info_.fragmentationLength[++part_ix]; 316 // Disallow splitting unless kAggrFragments. In kAggrPartitions, 317 // we can only aggregate intact partitions. 318 split_payload = (aggr_mode_ == kAggrFragments); 319 } 320 } else if (balance_ && remaining_in_partition > 0) { 321 break; 322 } 323 } 324 if (remaining_in_partition == 0) { 325 ++part_ix; // Advance to next partition. 326 } 327 assert(packet_bytes > 0); 328 329 QueuePacket(total_bytes_processed, 330 packet_bytes, 331 first_partition_in_packet, 332 start_on_new_fragment); 333 total_bytes_processed += packet_bytes; 334 start_on_new_fragment = (remaining_in_partition == 0); 335 beginning = false; // Next packet cannot be first packet in frame. 336 } 337 packets_calculated_ = true; 338 assert(total_bytes_processed == payload_size_); 339 return 0; 340 } 341 342 int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() { 343 if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ + 344 PayloadDescriptorExtraLength() + 1) { 345 // The provided payload length is not long enough for the payload 346 // descriptor and one payload byte. Return an error. 347 return -1; 348 } 349 std::vector<int> partition_decision; 350 const size_t overhead = 351 vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength(); 352 const size_t max_payload_len = max_payload_len_ - overhead; 353 int min_size, max_size; 354 AggregateSmallPartitions(&partition_decision, &min_size, &max_size); 355 356 size_t total_bytes_processed = 0; 357 size_t part_ix = 0; 358 while (part_ix < num_partitions_) { 359 if (partition_decision[part_ix] == -1) { 360 // Split large partitions. 361 size_t remaining_partition = part_info_.fragmentationLength[part_ix]; 362 size_t num_fragments = Vp8PartitionAggregator::CalcNumberOfFragments( 363 remaining_partition, max_payload_len, overhead, min_size, max_size); 364 const size_t packet_bytes = 365 (remaining_partition + num_fragments - 1) / num_fragments; 366 for (size_t n = 0; n < num_fragments; ++n) { 367 const size_t this_packet_bytes = packet_bytes < remaining_partition 368 ? packet_bytes 369 : remaining_partition; 370 QueuePacket( 371 total_bytes_processed, this_packet_bytes, part_ix, (n == 0)); 372 remaining_partition -= this_packet_bytes; 373 total_bytes_processed += this_packet_bytes; 374 if (static_cast<int>(this_packet_bytes) < min_size) { 375 min_size = this_packet_bytes; 376 } 377 if (static_cast<int>(this_packet_bytes) > max_size) { 378 max_size = this_packet_bytes; 379 } 380 } 381 assert(remaining_partition == 0); 382 ++part_ix; 383 } else { 384 size_t this_packet_bytes = 0; 385 const size_t first_partition_in_packet = part_ix; 386 const int aggregation_index = partition_decision[part_ix]; 387 while (part_ix < partition_decision.size() && 388 partition_decision[part_ix] == aggregation_index) { 389 // Collect all partitions that were aggregated into the same packet. 390 this_packet_bytes += part_info_.fragmentationLength[part_ix]; 391 ++part_ix; 392 } 393 QueuePacket(total_bytes_processed, 394 this_packet_bytes, 395 first_partition_in_packet, 396 true); 397 total_bytes_processed += this_packet_bytes; 398 } 399 } 400 packets_calculated_ = true; 401 return 0; 402 } 403 404 void RtpPacketizerVp8::AggregateSmallPartitions(std::vector<int>* partition_vec, 405 int* min_size, 406 int* max_size) { 407 assert(min_size && max_size); 408 *min_size = -1; 409 *max_size = -1; 410 assert(partition_vec); 411 partition_vec->assign(num_partitions_, -1); 412 const size_t overhead = 413 vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength(); 414 const size_t max_payload_len = max_payload_len_ - overhead; 415 size_t first_in_set = 0; 416 size_t last_in_set = 0; 417 int num_aggregate_packets = 0; 418 // Find sets of partitions smaller than max_payload_len_. 419 while (first_in_set < num_partitions_) { 420 if (part_info_.fragmentationLength[first_in_set] < max_payload_len) { 421 // Found start of a set. 422 last_in_set = first_in_set; 423 while (last_in_set + 1 < num_partitions_ && 424 part_info_.fragmentationLength[last_in_set + 1] < 425 max_payload_len) { 426 ++last_in_set; 427 } 428 // Found end of a set. Run optimized aggregator. It is ok if start == end. 429 Vp8PartitionAggregator aggregator(part_info_, first_in_set, last_in_set); 430 if (*min_size >= 0 && *max_size >= 0) { 431 aggregator.SetPriorMinMax(*min_size, *max_size); 432 } 433 Vp8PartitionAggregator::ConfigVec optimal_config = 434 aggregator.FindOptimalConfiguration(max_payload_len, overhead); 435 aggregator.CalcMinMax(optimal_config, min_size, max_size); 436 for (size_t i = first_in_set, j = 0; i <= last_in_set; ++i, ++j) { 437 // Transfer configuration for this set of partitions to the joint 438 // partition vector representing all partitions in the frame. 439 (*partition_vec)[i] = num_aggregate_packets + optimal_config[j]; 440 } 441 num_aggregate_packets += optimal_config.back() + 1; 442 first_in_set = last_in_set; 443 } 444 ++first_in_set; 445 } 446 } 447 448 void RtpPacketizerVp8::QueuePacket(size_t start_pos, 449 size_t packet_size, 450 size_t first_partition_in_packet, 451 bool start_on_new_fragment) { 452 // Write info to packet info struct and store in packet info queue. 453 InfoStruct packet_info; 454 packet_info.payload_start_pos = start_pos; 455 packet_info.size = packet_size; 456 packet_info.first_partition_ix = first_partition_in_packet; 457 packet_info.first_fragment = start_on_new_fragment; 458 packets_.push(packet_info); 459 } 460 461 int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info, 462 uint8_t* buffer, 463 size_t buffer_length) const { 464 // Write the VP8 payload descriptor. 465 // 0 466 // 0 1 2 3 4 5 6 7 8 467 // +-+-+-+-+-+-+-+-+-+ 468 // |X| |N|S| PART_ID | 469 // +-+-+-+-+-+-+-+-+-+ 470 // X: |I|L|T|K| | (mandatory if any of the below are used) 471 // +-+-+-+-+-+-+-+-+-+ 472 // I: |PictureID (8/16b)| (optional) 473 // +-+-+-+-+-+-+-+-+-+ 474 // L: | TL0PIC_IDX | (optional) 475 // +-+-+-+-+-+-+-+-+-+ 476 // T/K: |TID:Y| KEYIDX | (optional) 477 // +-+-+-+-+-+-+-+-+-+ 478 479 assert(packet_info.size > 0); 480 buffer[0] = 0; 481 if (XFieldPresent()) 482 buffer[0] |= kXBit; 483 if (hdr_info_.nonReference) 484 buffer[0] |= kNBit; 485 if (packet_info.first_fragment) 486 buffer[0] |= kSBit; 487 buffer[0] |= (packet_info.first_partition_ix & kPartIdField); 488 489 const int extension_length = WriteExtensionFields(buffer, buffer_length); 490 if (extension_length < 0) 491 return -1; 492 493 memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length], 494 &payload_data_[packet_info.payload_start_pos], 495 packet_info.size); 496 497 // Return total length of written data. 498 return packet_info.size + vp8_fixed_payload_descriptor_bytes_ + 499 extension_length; 500 } 501 502 int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer, 503 size_t buffer_length) const { 504 size_t extension_length = 0; 505 if (XFieldPresent()) { 506 uint8_t* x_field = buffer + vp8_fixed_payload_descriptor_bytes_; 507 *x_field = 0; 508 extension_length = 1; // One octet for the X field. 509 if (PictureIdPresent()) { 510 if (WritePictureIDFields( 511 x_field, buffer, buffer_length, &extension_length) < 0) { 512 return -1; 513 } 514 } 515 if (TL0PicIdxFieldPresent()) { 516 if (WriteTl0PicIdxFields( 517 x_field, buffer, buffer_length, &extension_length) < 0) { 518 return -1; 519 } 520 } 521 if (TIDFieldPresent() || KeyIdxFieldPresent()) { 522 if (WriteTIDAndKeyIdxFields( 523 x_field, buffer, buffer_length, &extension_length) < 0) { 524 return -1; 525 } 526 } 527 assert(extension_length == PayloadDescriptorExtraLength()); 528 } 529 return static_cast<int>(extension_length); 530 } 531 532 int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field, 533 uint8_t* buffer, 534 size_t buffer_length, 535 size_t* extension_length) const { 536 *x_field |= kIBit; 537 assert(buffer_length >= 538 vp8_fixed_payload_descriptor_bytes_ + *extension_length); 539 const int pic_id_length = WritePictureID( 540 buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length, 541 buffer_length - vp8_fixed_payload_descriptor_bytes_ - *extension_length); 542 if (pic_id_length < 0) 543 return -1; 544 *extension_length += pic_id_length; 545 return 0; 546 } 547 548 int RtpPacketizerVp8::WritePictureID(uint8_t* buffer, 549 size_t buffer_length) const { 550 const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId); 551 size_t picture_id_len = PictureIdLength(); 552 if (picture_id_len > buffer_length) 553 return -1; 554 if (picture_id_len == 2) { 555 buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F); 556 buffer[1] = pic_id & 0xFF; 557 } else if (picture_id_len == 1) { 558 buffer[0] = pic_id & 0x7F; 559 } 560 return static_cast<int>(picture_id_len); 561 } 562 563 int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field, 564 uint8_t* buffer, 565 size_t buffer_length, 566 size_t* extension_length) const { 567 if (buffer_length < 568 vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) { 569 return -1; 570 } 571 *x_field |= kLBit; 572 buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] = 573 hdr_info_.tl0PicIdx; 574 ++*extension_length; 575 return 0; 576 } 577 578 int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field, 579 uint8_t* buffer, 580 size_t buffer_length, 581 size_t* extension_length) const { 582 if (buffer_length < 583 vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) { 584 return -1; 585 } 586 uint8_t* data_field = 587 &buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length]; 588 *data_field = 0; 589 if (TIDFieldPresent()) { 590 *x_field |= kTBit; 591 assert(hdr_info_.temporalIdx <= 3); 592 *data_field |= hdr_info_.temporalIdx << 6; 593 *data_field |= hdr_info_.layerSync ? kYBit : 0; 594 } 595 if (KeyIdxFieldPresent()) { 596 *x_field |= kKBit; 597 *data_field |= (hdr_info_.keyIdx & kKeyIdxField); 598 } 599 ++*extension_length; 600 return 0; 601 } 602 603 size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const { 604 size_t length_bytes = PictureIdLength(); 605 if (TL0PicIdxFieldPresent()) 606 ++length_bytes; 607 if (TIDFieldPresent() || KeyIdxFieldPresent()) 608 ++length_bytes; 609 if (length_bytes > 0) 610 ++length_bytes; // Include the extension field. 611 return length_bytes; 612 } 613 614 size_t RtpPacketizerVp8::PictureIdLength() const { 615 if (hdr_info_.pictureId == kNoPictureId) { 616 return 0; 617 } 618 if (hdr_info_.pictureId <= 0x7F) { 619 return 1; 620 } 621 return 2; 622 } 623 624 bool RtpPacketizerVp8::XFieldPresent() const { 625 return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() || 626 KeyIdxFieldPresent()); 627 } 628 629 bool RtpPacketizerVp8::TIDFieldPresent() const { 630 assert((hdr_info_.layerSync == false) || 631 (hdr_info_.temporalIdx != kNoTemporalIdx)); 632 return (hdr_info_.temporalIdx != kNoTemporalIdx); 633 } 634 635 bool RtpPacketizerVp8::KeyIdxFieldPresent() const { 636 return (hdr_info_.keyIdx != kNoKeyIdx); 637 } 638 639 bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const { 640 return (hdr_info_.tl0PicIdx != kNoTl0PicIdx); 641 } 642 643 // 644 // VP8 format: 645 // 646 // Payload descriptor 647 // 0 1 2 3 4 5 6 7 648 // +-+-+-+-+-+-+-+-+ 649 // |X|R|N|S|PartID | (REQUIRED) 650 // +-+-+-+-+-+-+-+-+ 651 // X: |I|L|T|K| RSV | (OPTIONAL) 652 // +-+-+-+-+-+-+-+-+ 653 // I: | PictureID | (OPTIONAL) 654 // +-+-+-+-+-+-+-+-+ 655 // L: | TL0PICIDX | (OPTIONAL) 656 // +-+-+-+-+-+-+-+-+ 657 // T/K: |TID:Y| KEYIDX | (OPTIONAL) 658 // +-+-+-+-+-+-+-+-+ 659 // 660 // Payload header (considered part of the actual payload, sent to decoder) 661 // 0 1 2 3 4 5 6 7 662 // +-+-+-+-+-+-+-+-+ 663 // |Size0|H| VER |P| 664 // +-+-+-+-+-+-+-+-+ 665 // | ... | 666 // + + 667 bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload, 668 const uint8_t* payload_data, 669 size_t payload_data_length) { 670 assert(parsed_payload != NULL); 671 if (payload_data_length == 0) { 672 LOG(LS_ERROR) << "Empty payload."; 673 return false; 674 } 675 676 // Parse mandatory first byte of payload descriptor. 677 bool extension = (*payload_data & 0x80) ? true : false; // X bit 678 bool beginning_of_partition = (*payload_data & 0x10) ? true : false; // S bit 679 int partition_id = (*payload_data & 0x0F); // PartID field 680 681 parsed_payload->type.Video.width = 0; 682 parsed_payload->type.Video.height = 0; 683 parsed_payload->type.Video.isFirstPacket = 684 beginning_of_partition && (partition_id == 0); 685 parsed_payload->type.Video.simulcastIdx = 0; 686 parsed_payload->type.Video.codec = kRtpVideoVp8; 687 parsed_payload->type.Video.codecHeader.VP8.nonReference = 688 (*payload_data & 0x20) ? true : false; // N bit 689 parsed_payload->type.Video.codecHeader.VP8.partitionId = partition_id; 690 parsed_payload->type.Video.codecHeader.VP8.beginningOfPartition = 691 beginning_of_partition; 692 parsed_payload->type.Video.codecHeader.VP8.pictureId = kNoPictureId; 693 parsed_payload->type.Video.codecHeader.VP8.tl0PicIdx = kNoTl0PicIdx; 694 parsed_payload->type.Video.codecHeader.VP8.temporalIdx = kNoTemporalIdx; 695 parsed_payload->type.Video.codecHeader.VP8.layerSync = false; 696 parsed_payload->type.Video.codecHeader.VP8.keyIdx = kNoKeyIdx; 697 698 if (partition_id > 8) { 699 // Weak check for corrupt payload_data: PartID MUST NOT be larger than 8. 700 return false; 701 } 702 703 // Advance payload_data and decrease remaining payload size. 704 payload_data++; 705 if (payload_data_length <= 1) { 706 LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!"; 707 return false; 708 } 709 payload_data_length--; 710 711 if (extension) { 712 const int parsed_bytes = 713 ParseVP8Extension(&parsed_payload->type.Video.codecHeader.VP8, 714 payload_data, 715 payload_data_length); 716 if (parsed_bytes < 0) 717 return false; 718 payload_data += parsed_bytes; 719 payload_data_length -= parsed_bytes; 720 if (payload_data_length == 0) { 721 LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!"; 722 return false; 723 } 724 } 725 726 // Read P bit from payload header (only at beginning of first partition). 727 if (beginning_of_partition && partition_id == 0) { 728 parsed_payload->frame_type = 729 (*payload_data & 0x01) ? kVideoFrameDelta : kVideoFrameKey; 730 } else { 731 parsed_payload->frame_type = kVideoFrameDelta; 732 } 733 734 if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) != 735 0) { 736 return false; 737 } 738 739 parsed_payload->payload = payload_data; 740 parsed_payload->payload_length = payload_data_length; 741 return true; 742 } 743 } // namespace webrtc 744