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