Chromium Code Reviews| Index: webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc |
| diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc |
| index 4c8f7954f4ccb97358b176233044e1955c18937e..ee9af9a52019e881b4f4a239b33670b7b49bdf23 100644 |
| --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc |
| +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc |
| @@ -30,10 +30,6 @@ namespace { |
| // Length of VP9 payload descriptors' fixed part. |
| const size_t kFixedPayloadDescriptorBytes = 1; |
| -// Packet fragmentation mode. If true, packets are split into (almost) equal |
| -// sizes. Otherwise, as many bytes as possible are fit into one packet. |
| -const bool kBalancedMode = true; |
| - |
| const uint32_t kReservedBitValue0 = 0; |
| uint8_t TemporalIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) { |
| @@ -462,29 +458,16 @@ bool ParseSsData(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) { |
| } |
| return true; |
| } |
| - |
| -// Gets the size of next payload chunk to send. Returns 0 on error. |
| -size_t CalcNextSize(size_t max_length, size_t rem_bytes) { |
| - if (max_length == 0 || rem_bytes == 0) { |
| - return 0; |
| - } |
| - if (kBalancedMode) { |
| - size_t num_frags = std::ceil(static_cast<double>(rem_bytes) / max_length); |
| - return static_cast<size_t>( |
| - static_cast<double>(rem_bytes) / num_frags + 0.5); |
| - } |
| - return max_length >= rem_bytes ? rem_bytes : max_length; |
| -} |
| } // namespace |
| - |
| RtpPacketizerVp9::RtpPacketizerVp9(const RTPVideoHeaderVP9& hdr, |
| - size_t max_payload_length) |
| + size_t max_payload_length, |
| + size_t last_packet_reduction_len) |
| : hdr_(hdr), |
| max_payload_length_(max_payload_length), |
| payload_(nullptr), |
| - payload_size_(0) { |
| -} |
| + payload_size_(0), |
| + last_packet_reduction_len_(last_packet_reduction_len) {} |
| RtpPacketizerVp9::~RtpPacketizerVp9() { |
| } |
| @@ -511,54 +494,102 @@ std::string RtpPacketizerVp9::ToString() { |
| return "RtpPacketizerVp9"; |
| } |
| -void RtpPacketizerVp9::SetPayloadData( |
| +size_t RtpPacketizerVp9::SetPayloadData( |
| const uint8_t* payload, |
| size_t payload_size, |
| const RTPFragmentationHeader* fragmentation) { |
| payload_ = payload; |
| payload_size_ = payload_size; |
| GeneratePackets(); |
| + return packets_.size(); |
| } |
| +// Splits payload in minimal number of roughly equal in size packets. |
| void RtpPacketizerVp9::GeneratePackets() { |
| if (max_payload_length_ < PayloadDescriptorLength(hdr_) + 1) { |
| - LOG(LS_ERROR) << "Payload header and one payload byte won't fit."; |
| + LOG(LS_ERROR) << "Payload header and one payload byte won't fit in the " |
| + "first packet."; |
| + return; |
| + } |
| + if (max_payload_length_ < PayloadDescriptorLengthMinusSsData(hdr_) + 1 + |
| + last_packet_reduction_len_) { |
| + LOG(LS_ERROR) << "Payload header and one payload byte won't fit in the last" |
| + " packet."; |
| return; |
| } |
| + if (payload_size_ == 1 && |
| + max_payload_length_ < |
| + PayloadDescriptorLength(hdr_) + 1 + last_packet_reduction_len_) { |
| + LOG(LS_ERROR) << "Can't fit header and payload into single packet, but " |
| + "payload size is one: no way to generate packets with " |
| + "nonzero payload."; |
| + return; |
| + } |
| + |
| + // Instead of making last packet smaller, we pretend that we must write |
| + // additional data into it. We account for this virtual payload while |
| + // calculating packets number and sizes. We also pretend that all packets |
| + // headers are the same length and extra SS header data in the fits packet |
| + // is also treated as a payload here. |
| + |
| + // Payload, virtual payload and SS hdr data in the first packet together. |
| + size_t total_bytes = |
| + SsDataLength(hdr_) + payload_size_ + last_packet_reduction_len_; |
| + // Now all packets will have the same lenght of vp9 headers. |
| + size_t capacity = |
|
danilchap
2017/05/17 10:31:19
may be per_packet_capacity
ilnik
2017/05/17 12:30:55
Done.
|
| + max_payload_length_ - PayloadDescriptorLengthMinusSsData(hdr_); |
| + // Integer divisions rounding up. |
| + size_t num_packets = (total_bytes + capacity - 1) / capacity; |
| + size_t per_packet_data = (total_bytes + num_packets - 1) / num_packets; |
|
danilchap
2017/05/17 10:31:19
per_packet_bytes
ilnik
2017/05/17 12:30:55
Done.
|
| + // Several last packets are 1 byte smaller than the rest. |
| + // i.e. if 14 bytes were splitted between 4 packets, it would be 4+4+3+3. |
| + size_t smaller_packets = num_packets - total_bytes % num_packets; |
|
danilchap
2017/05/17 10:31:19
may be num_smaller_packets
ilnik
2017/05/17 12:30:55
Done.
|
| + // If all packets are the same size, we assume 0 packets are smaller. |
| + if (smaller_packets == num_packets) |
| + smaller_packets = 0; |
| size_t bytes_processed = 0; |
| + size_t packets_left = num_packets; |
|
danilchap
2017/05/17 10:31:19
num_packets_left
ilnik
2017/05/17 12:30:55
Done.
|
| while (bytes_processed < payload_size_) { |
| + if (packets_left == smaller_packets) |
| + per_packet_data--; |
| + size_t packet_bytes = per_packet_data; |
| + // First packet also has SS hdr data. |
| + if (bytes_processed == 0) |
| + packet_bytes -= SsDataLength(hdr_); |
| + // Must write at least one byte of the real payload to the packet. |
| + if (packet_bytes < 1) |
| + packet_bytes = 1; |
| size_t rem_bytes = payload_size_ - bytes_processed; |
| - size_t rem_payload_len = max_payload_length_ - |
| - (bytes_processed ? PayloadDescriptorLengthMinusSsData(hdr_) |
| - : PayloadDescriptorLength(hdr_)); |
| - |
| - size_t packet_bytes = CalcNextSize(rem_payload_len, rem_bytes); |
| - if (packet_bytes == 0) { |
| - LOG(LS_ERROR) << "Failed to generate VP9 packets."; |
| - while (!packets_.empty()) |
| - packets_.pop(); |
| - return; |
| + if (packet_bytes >= rem_bytes) { |
| + // All remaining payload fits into this packet. |
| + packet_bytes = rem_bytes; |
| + // If this is the pre-last packet, leave at least 1 byte of payload for |
| + // the last packet. |
| + if (packets_left == 2) |
| + packet_bytes--; |
| } |
| QueuePacket(bytes_processed, packet_bytes, bytes_processed == 0, |
| rem_bytes == packet_bytes, &packets_); |
| + packets_left--; |
| bytes_processed += packet_bytes; |
| + // Last packet should be smaller |
| + RTC_DCHECK(packets_left > 0 || |
| + capacity >= packet_bytes + last_packet_reduction_len_); |
| } |
| assert(bytes_processed == payload_size_); |
| } |
| -bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet, bool* last_packet) { |
| +bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet) { |
| RTC_DCHECK(packet); |
| - RTC_DCHECK(last_packet); |
| if (packets_.empty()) { |
| return false; |
| } |
| PacketInfo packet_info = packets_.front(); |
| packets_.pop(); |
| - if (!WriteHeaderAndPayload(packet_info, packet)) { |
| + if (!WriteHeaderAndPayload(packet_info, packet, packets_.empty())) { |
| return false; |
| } |
| - *last_packet = packets_.empty(); |
| packet->SetMarker(packets_.empty() && |
| (hdr_.spatial_idx == kNoSpatialIdx || |
| hdr_.spatial_idx == hdr_.num_spatial_layers - 1)); |
| @@ -602,8 +633,11 @@ bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet, bool* last_packet) { |
| // +-+-+-+-+-+-+-+-+ |
| bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info, |
| - RtpPacketToSend* packet) const { |
| - uint8_t* buffer = packet->AllocatePayload(max_payload_length_); |
| + RtpPacketToSend* packet, |
| + bool last) const { |
| + uint8_t* buffer = packet->AllocatePayload( |
| + last ? max_payload_length_ - last_packet_reduction_len_ |
| + : max_payload_length_); |
| RTC_DCHECK(buffer); |
| size_t header_length; |
| if (!WriteHeader(packet_info, buffer, &header_length)) |