Index: webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc |
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc |
index 2d847c17a608ba5f64dae5f938b3ca4b7689693f..b5e8d518114a699098fa05f4f7d118013fcb0578 100644 |
--- a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc |
+++ b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc |
@@ -20,12 +20,14 @@ namespace webrtc { |
static const size_t kGenericHeaderLength = 1; |
RtpPacketizerGeneric::RtpPacketizerGeneric(FrameType frame_type, |
- size_t max_payload_len) |
+ size_t max_payload_len, |
+ size_t last_packet_extension_len) |
: payload_data_(NULL), |
payload_size_(0), |
max_payload_len_(max_payload_len - kGenericHeaderLength), |
- frame_type_(frame_type) { |
-} |
+ last_packet_extension_len_(last_packet_extension_len), |
+ frame_type_(frame_type), |
+ num_packets_(0) {} |
RtpPacketizerGeneric::~RtpPacketizerGeneric() { |
} |
@@ -37,42 +39,59 @@ void RtpPacketizerGeneric::SetPayloadData( |
payload_data_ = payload_data; |
payload_size_ = payload_size; |
+ size_t total_data = payload_size_ + last_packet_extension_len_; |
+ |
// Fragment packets more evenly by splitting the payload up evenly. |
- size_t num_packets = |
- (payload_size_ + max_payload_len_ - 1) / max_payload_len_; |
- payload_length_ = (payload_size_ + num_packets - 1) / num_packets; |
- assert(payload_length_ <= max_payload_len_); |
+ num_packets_ = (total_data + max_payload_len_ - 1) / max_payload_len_; |
+ payload_per_packet_ = (total_data + num_packets_ - 1) / num_packets_; |
+ smaller_packets_ = num_packets_ - total_data % num_packets_; |
+ if (smaller_packets_ == num_packets_) |
+ smaller_packets_ = 0; |
+ assert(payload_per_packet_ <= max_payload_len_); |
generic_header_ = RtpFormatVideoGeneric::kFirstPacketBit; |
+ if (frame_type_ == kVideoFrameKey) { |
+ generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit; |
+ } |
} |
-bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet, |
- bool* last_packet) { |
+size_t RtpPacketizerGeneric::TotalPackets() { |
+ return num_packets_; |
+} |
+ |
+bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet) { |
RTC_DCHECK(packet); |
- RTC_DCHECK(last_packet); |
- if (payload_size_ < payload_length_) { |
- payload_length_ = payload_size_; |
+ // last smaller_packets_ packets are 1 byte smaller than previous packets. |
+ if (num_packets_ == smaller_packets_) |
+ payload_per_packet_--; |
+ // whole payload fit into this packet |
+ size_t current_payload = payload_per_packet_; |
+ if (payload_size_ <= current_payload) { |
+ current_payload = payload_size_; |
+ // But this is the pre-last packet. Leave at least 1 payload byte for the |
+ // last packet. Should happen only if extensions take at least half of |
+ // available capacity. |
+ if (num_packets_ == 2) { |
+ RTC_DCHECK(last_packet_extension_len_ >= max_payload_len_ / 2); |
+ current_payload -= 1; |
+ } |
} |
- |
- payload_size_ -= payload_length_; |
- RTC_DCHECK_LE(payload_length_, max_payload_len_); |
+ RTC_DCHECK_LE(current_payload, max_payload_len_); |
uint8_t* out_ptr = |
- packet->AllocatePayload(kGenericHeaderLength + payload_length_); |
+ packet->AllocatePayload(kGenericHeaderLength + current_payload); |
// Put generic header in packet |
- if (frame_type_ == kVideoFrameKey) { |
- generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit; |
- } |
out_ptr[0] = generic_header_; |
// Remove first-packet bit, following packets are intermediate |
generic_header_ &= ~RtpFormatVideoGeneric::kFirstPacketBit; |
// Put payload in packet |
- memcpy(out_ptr + kGenericHeaderLength, payload_data_, payload_length_); |
- payload_data_ += payload_length_; |
+ memcpy(out_ptr + kGenericHeaderLength, payload_data_, current_payload); |
+ payload_data_ += current_payload; |
+ payload_size_ -= current_payload; |
+ num_packets_--; |
- *last_packet = payload_size_ <= 0; |
- packet->SetMarker(*last_packet); |
+ packet->SetMarker(payload_size_ == 0); |
return true; |
} |