Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc

Issue 2871173008: Fix packetization logic to leave space for extensions in the last packet (Closed)
Patch Set: Impelemented Danilchap@ comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 12 matching lines...) Expand all
23 #define RETURN_FALSE_ON_ERROR(x) \ 23 #define RETURN_FALSE_ON_ERROR(x) \
24 if (!(x)) { \ 24 if (!(x)) { \
25 return false; \ 25 return false; \
26 } 26 }
27 27
28 namespace webrtc { 28 namespace webrtc {
29 namespace { 29 namespace {
30 // Length of VP9 payload descriptors' fixed part. 30 // Length of VP9 payload descriptors' fixed part.
31 const size_t kFixedPayloadDescriptorBytes = 1; 31 const size_t kFixedPayloadDescriptorBytes = 1;
32 32
33 // Packet fragmentation mode. If true, packets are split into (almost) equal
34 // sizes. Otherwise, as many bytes as possible are fit into one packet.
35 const bool kBalancedMode = true;
36
37 const uint32_t kReservedBitValue0 = 0; 33 const uint32_t kReservedBitValue0 = 0;
38 34
39 uint8_t TemporalIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) { 35 uint8_t TemporalIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) {
40 return (hdr.temporal_idx == kNoTemporalIdx) ? def : hdr.temporal_idx; 36 return (hdr.temporal_idx == kNoTemporalIdx) ? def : hdr.temporal_idx;
41 } 37 }
42 38
43 uint8_t SpatialIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) { 39 uint8_t SpatialIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) {
44 return (hdr.spatial_idx == kNoSpatialIdx) ? def : hdr.spatial_idx; 40 return (hdr.spatial_idx == kNoSpatialIdx) ? def : hdr.spatial_idx;
45 } 41 }
46 42
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 vp9->gof.num_ref_pics[i] = r; 451 vp9->gof.num_ref_pics[i] = r;
456 452
457 for (uint8_t p = 0; p < vp9->gof.num_ref_pics[i]; ++p) { 453 for (uint8_t p = 0; p < vp9->gof.num_ref_pics[i]; ++p) {
458 uint8_t p_diff; 454 uint8_t p_diff;
459 RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&p_diff)); 455 RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&p_diff));
460 vp9->gof.pid_diff[i][p] = p_diff; 456 vp9->gof.pid_diff[i][p] = p_diff;
461 } 457 }
462 } 458 }
463 return true; 459 return true;
464 } 460 }
465
466 // Gets the size of next payload chunk to send. Returns 0 on error.
467 size_t CalcNextSize(size_t max_length, size_t rem_bytes) {
468 if (max_length == 0 || rem_bytes == 0) {
469 return 0;
470 }
471 if (kBalancedMode) {
472 size_t num_frags = std::ceil(static_cast<double>(rem_bytes) / max_length);
473 return static_cast<size_t>(
474 static_cast<double>(rem_bytes) / num_frags + 0.5);
475 }
476 return max_length >= rem_bytes ? rem_bytes : max_length;
477 }
478 } // namespace 461 } // namespace
479 462
480
481 RtpPacketizerVp9::RtpPacketizerVp9(const RTPVideoHeaderVP9& hdr, 463 RtpPacketizerVp9::RtpPacketizerVp9(const RTPVideoHeaderVP9& hdr,
482 size_t max_payload_length) 464 size_t max_payload_length,
465 size_t last_packet_reduction_len)
483 : hdr_(hdr), 466 : hdr_(hdr),
484 max_payload_length_(max_payload_length), 467 max_payload_length_(max_payload_length),
485 payload_(nullptr), 468 payload_(nullptr),
486 payload_size_(0) { 469 payload_size_(0),
487 } 470 last_packet_reduction_len_(last_packet_reduction_len) {}
488 471
489 RtpPacketizerVp9::~RtpPacketizerVp9() { 472 RtpPacketizerVp9::~RtpPacketizerVp9() {
490 } 473 }
491 474
492 ProtectionType RtpPacketizerVp9::GetProtectionType() { 475 ProtectionType RtpPacketizerVp9::GetProtectionType() {
493 bool protect = 476 bool protect =
494 hdr_.temporal_idx == 0 || hdr_.temporal_idx == kNoTemporalIdx; 477 hdr_.temporal_idx == 0 || hdr_.temporal_idx == kNoTemporalIdx;
495 return protect ? kProtectedPacket : kUnprotectedPacket; 478 return protect ? kProtectedPacket : kUnprotectedPacket;
496 } 479 }
497 480
498 StorageType RtpPacketizerVp9::GetStorageType(uint32_t retransmission_settings) { 481 StorageType RtpPacketizerVp9::GetStorageType(uint32_t retransmission_settings) {
499 StorageType storage = kAllowRetransmission; 482 StorageType storage = kAllowRetransmission;
500 if (hdr_.temporal_idx == 0 && 483 if (hdr_.temporal_idx == 0 &&
501 !(retransmission_settings & kRetransmitBaseLayer)) { 484 !(retransmission_settings & kRetransmitBaseLayer)) {
502 storage = kDontRetransmit; 485 storage = kDontRetransmit;
503 } else if (hdr_.temporal_idx != kNoTemporalIdx && hdr_.temporal_idx > 0 && 486 } else if (hdr_.temporal_idx != kNoTemporalIdx && hdr_.temporal_idx > 0 &&
504 !(retransmission_settings & kRetransmitHigherLayers)) { 487 !(retransmission_settings & kRetransmitHigherLayers)) {
505 storage = kDontRetransmit; 488 storage = kDontRetransmit;
506 } 489 }
507 return storage; 490 return storage;
508 } 491 }
509 492
510 std::string RtpPacketizerVp9::ToString() { 493 std::string RtpPacketizerVp9::ToString() {
511 return "RtpPacketizerVp9"; 494 return "RtpPacketizerVp9";
512 } 495 }
513 496
514 void RtpPacketizerVp9::SetPayloadData( 497 size_t RtpPacketizerVp9::SetPayloadData(
515 const uint8_t* payload, 498 const uint8_t* payload,
516 size_t payload_size, 499 size_t payload_size,
517 const RTPFragmentationHeader* fragmentation) { 500 const RTPFragmentationHeader* fragmentation) {
518 payload_ = payload; 501 payload_ = payload;
519 payload_size_ = payload_size; 502 payload_size_ = payload_size;
520 GeneratePackets(); 503 GeneratePackets();
504 return packets_.size();
521 } 505 }
522 506
507 // Splits payload in minimal number of roughly equal in size packets.
523 void RtpPacketizerVp9::GeneratePackets() { 508 void RtpPacketizerVp9::GeneratePackets() {
524 if (max_payload_length_ < PayloadDescriptorLength(hdr_) + 1) { 509 if (max_payload_length_ < PayloadDescriptorLength(hdr_) + 1) {
525 LOG(LS_ERROR) << "Payload header and one payload byte won't fit."; 510 LOG(LS_ERROR) << "Payload header and one payload byte won't fit in packet.";
danilchap 2017/05/16 10:25:11 may be 'in the first packet' (since only 1st packe
ilnik 2017/05/16 12:24:08 Done.
526 return; 511 return;
527 } 512 }
513 if (max_payload_length_ < PayloadDescriptorLengthMinusSsData(hdr_) + 1 +
514 last_packet_reduction_len_) {
515 LOG(LS_ERROR) << "Payload header and one payload byte won't fit in the last"
516 " packet.";
517 return;
518 }
519
520 // Instead of making last packet smaller, we pretend that we must write
danilchap 2017/05/16 10:25:11 may be also mention 1st packet that has extra SS h
ilnik 2017/05/16 12:24:08 Done.
521 // additional data into it. We account for this virtual payload while
danilchap 2017/05/16 10:25:11 single space between 'this' and 'virtual'
ilnik 2017/05/16 12:24:08 Done.
522 // calculating packets number and sizes.
523
524 // Payload, virtual payload and SS hdr data in the first packet together.
525 size_t total_bytes =
526 payload_size_ + last_packet_reduction_len_ + SsDataLength(hdr_);
danilchap 2017/05/16 10:25:11 nit: may be reorder terms in the order closer to h
ilnik 2017/05/16 12:24:08 Done.
527 // Now all packets will have the same lenght of vp9 headers.
528 size_t capacity =
529 max_payload_length_ - PayloadDescriptorLengthMinusSsData(hdr_);
530 // Integer divisions rounding up.
531 size_t num_packets = (total_bytes + capacity - 1) / capacity;
532 size_t per_packet_data = (total_bytes + num_packets - 1) / num_packets;
533 // Several last packets are 1 byte smaller than the rest.
534 // i.e. if 14 bytes were splitted between 4 packets, it would be 4+4+3+3.
535 size_t smaller_packets = num_packets - total_bytes % num_packets;
536 // If all packets are the same size, we assume 0 packets are smaller.
537 if (smaller_packets == num_packets)
538 smaller_packets = 0;
528 size_t bytes_processed = 0; 539 size_t bytes_processed = 0;
540 size_t packets_left = num_packets;
529 while (bytes_processed < payload_size_) { 541 while (bytes_processed < payload_size_) {
542 if (packets_left == smaller_packets)
543 per_packet_data--;
544 size_t packet_bytes = per_packet_data;
545 // First packet also has SS hdr data.
546 if (bytes_processed == 0)
547 packet_bytes -= SsDataLength(hdr_);
danilchap 2017/05/16 10:25:11 can packet_bytes become negative?
ilnik 2017/05/16 12:24:08 Actually, in some extreme cases, it can. The fix f
danilchap 2017/05/17 10:31:19 Can you also add a test for this scenario. (btw, p
ilnik 2017/05/17 12:30:55 Yep, my mistake about unsignedness. Thanks for cat
530 size_t rem_bytes = payload_size_ - bytes_processed; 548 size_t rem_bytes = payload_size_ - bytes_processed;
531 size_t rem_payload_len = max_payload_length_ - 549 if (packet_bytes >= rem_bytes) {
532 (bytes_processed ? PayloadDescriptorLengthMinusSsData(hdr_) 550 // All remaining payload fits into this packet.
533 : PayloadDescriptorLength(hdr_)); 551 packet_bytes = rem_bytes;
534 552 // If this is the pre-last packet, leave at least 1 byte of payload for
535 size_t packet_bytes = CalcNextSize(rem_payload_len, rem_bytes); 553 // the last packet.
536 if (packet_bytes == 0) { 554 if (packets_left == 2)
537 LOG(LS_ERROR) << "Failed to generate VP9 packets."; 555 packet_bytes--;
danilchap 2017/05/16 10:25:11 can packet_bytes be zero before decrement?
ilnik 2017/05/16 12:24:08 Now it can't due to the fix above. There's still
538 while (!packets_.empty())
539 packets_.pop();
540 return;
541 } 556 }
542 QueuePacket(bytes_processed, packet_bytes, bytes_processed == 0, 557 QueuePacket(bytes_processed, packet_bytes, bytes_processed == 0,
543 rem_bytes == packet_bytes, &packets_); 558 rem_bytes == packet_bytes, &packets_);
559 packets_left--;
544 bytes_processed += packet_bytes; 560 bytes_processed += packet_bytes;
561 // Last packet should be smaller
562 RTC_DCHECK(packets_left > 0 ||
563 capacity >= packet_bytes + last_packet_reduction_len_);
545 } 564 }
546 assert(bytes_processed == payload_size_); 565 assert(bytes_processed == payload_size_);
547 } 566 }
548 567
549 bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet, bool* last_packet) { 568 bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet) {
550 RTC_DCHECK(packet); 569 RTC_DCHECK(packet);
551 RTC_DCHECK(last_packet);
552 if (packets_.empty()) { 570 if (packets_.empty()) {
553 return false; 571 return false;
554 } 572 }
555 PacketInfo packet_info = packets_.front(); 573 PacketInfo packet_info = packets_.front();
556 packets_.pop(); 574 packets_.pop();
557 575
558 if (!WriteHeaderAndPayload(packet_info, packet)) { 576 if (!WriteHeaderAndPayload(packet_info, packet, packets_.empty())) {
559 return false; 577 return false;
560 } 578 }
561 *last_packet = packets_.empty();
562 packet->SetMarker(packets_.empty() && 579 packet->SetMarker(packets_.empty() &&
563 (hdr_.spatial_idx == kNoSpatialIdx || 580 (hdr_.spatial_idx == kNoSpatialIdx ||
564 hdr_.spatial_idx == hdr_.num_spatial_layers - 1)); 581 hdr_.spatial_idx == hdr_.num_spatial_layers - 1));
565 return true; 582 return true;
566 } 583 }
567 584
568 // VP9 format: 585 // VP9 format:
569 // 586 //
570 // Payload descriptor for F = 1 (flexible mode) 587 // Payload descriptor for F = 1 (flexible mode)
571 // 0 1 2 3 4 5 6 7 588 // 0 1 2 3 4 5 6 7
(...skipping 23 matching lines...) Expand all
595 // +-+-+-+-+-+-+-+-+ 612 // +-+-+-+-+-+-+-+-+
596 // L: | T |U| S |D| (CONDITIONALLY RECOMMENDED) 613 // L: | T |U| S |D| (CONDITIONALLY RECOMMENDED)
597 // +-+-+-+-+-+-+-+-+ 614 // +-+-+-+-+-+-+-+-+
598 // | TL0PICIDX | (CONDITIONALLY REQUIRED) 615 // | TL0PICIDX | (CONDITIONALLY REQUIRED)
599 // +-+-+-+-+-+-+-+-+ 616 // +-+-+-+-+-+-+-+-+
600 // V: | SS | 617 // V: | SS |
601 // | .. | 618 // | .. |
602 // +-+-+-+-+-+-+-+-+ 619 // +-+-+-+-+-+-+-+-+
603 620
604 bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info, 621 bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info,
605 RtpPacketToSend* packet) const { 622 RtpPacketToSend* packet,
606 uint8_t* buffer = packet->AllocatePayload(max_payload_length_); 623 bool last) const {
624 uint8_t* buffer = packet->AllocatePayload(
625 last ? max_payload_length_ - last_packet_reduction_len_
626 : max_payload_length_);
607 RTC_DCHECK(buffer); 627 RTC_DCHECK(buffer);
608 size_t header_length; 628 size_t header_length;
609 if (!WriteHeader(packet_info, buffer, &header_length)) 629 if (!WriteHeader(packet_info, buffer, &header_length))
610 return false; 630 return false;
611 631
612 // Copy payload data. 632 // Copy payload data.
613 memcpy(&buffer[header_length], 633 memcpy(&buffer[header_length],
614 &payload_[packet_info.payload_start_pos], packet_info.size); 634 &payload_[packet_info.payload_start_pos], packet_info.size);
615 635
616 packet->SetPayloadSize(header_length + packet_info.size); 636 packet->SetPayloadSize(header_length + packet_info.size);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 if (parsed_payload->payload_length == 0) { 757 if (parsed_payload->payload_length == 0) {
738 LOG(LS_ERROR) << "Failed parsing VP9 payload data."; 758 LOG(LS_ERROR) << "Failed parsing VP9 payload data.";
739 return false; 759 return false;
740 } 760 }
741 parsed_payload->payload = 761 parsed_payload->payload =
742 payload + payload_length - parsed_payload->payload_length; 762 payload + payload_length - parsed_payload->payload_length;
743 763
744 return true; 764 return true;
745 } 765 }
746 } // namespace webrtc 766 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698