OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |