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

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

Issue 2871173008: Fix packetization logic to leave space for extensions in the last packet (Closed)
Patch Set: Implemented 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) 2014 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2014 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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 72
73 offsets->push_back(offset + kStapAHeaderSize); 73 offsets->push_back(offset + kStapAHeaderSize);
74 offset += kLengthFieldSize + nalu_size; 74 offset += kLengthFieldSize + nalu_size;
75 } 75 }
76 return true; 76 return true;
77 } 77 }
78 78
79 } // namespace 79 } // namespace
80 80
81 RtpPacketizerH264::RtpPacketizerH264(size_t max_payload_len, 81 RtpPacketizerH264::RtpPacketizerH264(size_t max_payload_len,
82 size_t last_packet_reduction_len,
82 H264PacketizationMode packetization_mode) 83 H264PacketizationMode packetization_mode)
83 : max_payload_len_(max_payload_len), 84 : max_payload_len_(max_payload_len),
85 last_packet_reduction_len_(last_packet_reduction_len),
86 total_packets_(0),
84 packetization_mode_(packetization_mode) { 87 packetization_mode_(packetization_mode) {
85 // Guard against uninitialized memory in packetization_mode. 88 // Guard against uninitialized memory in packetization_mode.
86 RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved || 89 RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved ||
87 packetization_mode == H264PacketizationMode::SingleNalUnit); 90 packetization_mode == H264PacketizationMode::SingleNalUnit);
sprang_webrtc 2017/05/17 13:10:07 quite an edge case, but maybe assert that max_payl
ilnik 2017/05/17 15:06:33 Sure. However, in that case the old implementation
88 } 91 }
89 92
90 RtpPacketizerH264::~RtpPacketizerH264() { 93 RtpPacketizerH264::~RtpPacketizerH264() {
91 } 94 }
92 95
93 RtpPacketizerH264::Fragment::Fragment(const uint8_t* buffer, size_t length) 96 RtpPacketizerH264::Fragment::Fragment(const uint8_t* buffer, size_t length)
94 : buffer(buffer), length(length) {} 97 : buffer(buffer), length(length) {}
95 RtpPacketizerH264::Fragment::Fragment(const Fragment& fragment) 98 RtpPacketizerH264::Fragment::Fragment(const Fragment& fragment)
96 : buffer(fragment.buffer), length(fragment.length) {} 99 : buffer(fragment.buffer), length(fragment.length) {}
97 100
98 void RtpPacketizerH264::SetPayloadData( 101 size_t RtpPacketizerH264::SetPayloadData(
99 const uint8_t* payload_data, 102 const uint8_t* payload_data,
100 size_t payload_size, 103 size_t payload_size,
101 const RTPFragmentationHeader* fragmentation) { 104 const RTPFragmentationHeader* fragmentation) {
102 RTC_DCHECK(packets_.empty()); 105 RTC_DCHECK(packets_.empty());
103 RTC_DCHECK(input_fragments_.empty()); 106 RTC_DCHECK(input_fragments_.empty());
104 RTC_DCHECK(fragmentation); 107 RTC_DCHECK(fragmentation);
105 for (int i = 0; i < fragmentation->fragmentationVectorSize; ++i) { 108 for (int i = 0; i < fragmentation->fragmentationVectorSize; ++i) {
106 const uint8_t* buffer = 109 const uint8_t* buffer =
107 &payload_data[fragmentation->fragmentationOffset[i]]; 110 &payload_data[fragmentation->fragmentationOffset[i]];
108 size_t length = fragmentation->fragmentationLength[i]; 111 size_t length = fragmentation->fragmentationLength[i];
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 SpsValidEvent::kSentSpsParseFailure, 160 SpsValidEvent::kSentSpsParseFailure,
158 SpsValidEvent::kSpsRewrittenMax); 161 SpsValidEvent::kSpsRewrittenMax);
159 break; 162 break;
160 } 163 }
161 } 164 }
162 165
163 if (!updated_sps) 166 if (!updated_sps)
164 input_fragments_.push_back(Fragment(buffer, length)); 167 input_fragments_.push_back(Fragment(buffer, length));
165 } 168 }
166 GeneratePackets(); 169 GeneratePackets();
170 return total_packets_;
167 } 171 }
168 172
169 void RtpPacketizerH264::GeneratePackets() { 173 void RtpPacketizerH264::GeneratePackets() {
170 for (size_t i = 0; i < input_fragments_.size();) { 174 for (size_t i = 0; i < input_fragments_.size();) {
171 switch (packetization_mode_) { 175 switch (packetization_mode_) {
172 case H264PacketizationMode::SingleNalUnit: 176 case H264PacketizationMode::SingleNalUnit:
173 PacketizeSingleNalu(i); 177 PacketizeSingleNalu(i);
174 ++i; 178 ++i;
175 break; 179 break;
176 case H264PacketizationMode::NonInterleaved: 180 case H264PacketizationMode::NonInterleaved:
177 if (input_fragments_[i].length > max_payload_len_) { 181 if (input_fragments_[i].length > max_payload_len_ ||
182 (i + 1 == input_fragments_.size() &&
183 (input_fragments_[i].length + last_packet_reduction_len_ >
184 max_payload_len_))) {
sprang_webrtc 2017/05/17 13:10:07 nit: Maybe you can clarify this a bit by having a
ilnik 2017/05/17 15:06:33 Done.
178 PacketizeFuA(i); 185 PacketizeFuA(i);
179 ++i; 186 ++i;
180 } else { 187 } else {
181 i = PacketizeStapA(i); 188 i = PacketizeStapA(i);
182 } 189 }
183 break; 190 break;
184 } 191 }
185 } 192 }
186 } 193 }
187 194
188 void RtpPacketizerH264::PacketizeFuA(size_t fragment_index) { 195 void RtpPacketizerH264::PacketizeFuA(size_t fragment_index) {
189 // Fragment payload into packets (FU-A). 196 // Fragment payload into packets (FU-A).
190 // Strip out the original header and leave room for the FU-A header. 197 // Strip out the original header and leave room for the FU-A header.
191 const Fragment& fragment = input_fragments_[fragment_index]; 198 const Fragment& fragment = input_fragments_[fragment_index];
192 199 bool is_last_fragment = fragment_index + 1 == input_fragments_.size();
193 size_t fragment_length = fragment.length - kNalHeaderSize; 200 size_t payload_left = fragment.length - kNalHeaderSize;
194 size_t offset = kNalHeaderSize; 201 size_t offset = kNalHeaderSize;
195 size_t bytes_available = max_payload_len_ - kFuAHeaderSize; 202 size_t bytes_available = max_payload_len_ - kFuAHeaderSize;
196 const size_t num_fragments =
197 (fragment_length + (bytes_available - 1)) / bytes_available;
198 203
199 const size_t avg_size = (fragment_length + num_fragments - 1) / num_fragments; 204 // Instead of making the last packet smaller we pretend that all packets are
200 while (fragment_length > 0) { 205 // of the same size but we write additional virtual payload to the last
201 size_t packet_length = avg_size; 206 // packet.
202 if (fragment_length < avg_size) 207 size_t extra_len = is_last_fragment ? last_packet_reduction_len_ : 0;
203 packet_length = fragment_length; 208
209 // Integer divisions with rounding up. Minimal number of packets to fit all
210 // payload and virtual payload.
211 size_t num_packets =
212 (payload_left + extra_len + (bytes_available - 1)) / bytes_available;
213 // Bytes per packet.
214 size_t payload_per_packet =
215 (payload_left + extra_len + num_packets - 1) / num_packets;
sprang_webrtc 2017/05/17 13:10:07 nit: maybe (num_packets - 1) for consistency with
ilnik 2017/05/17 15:06:33 Done.
216 // We make several first packets to be 1 bytes larger than the rest.
217 // i.e 14 bytes splitted in 4 packets would be 4+4+3+3.
218 size_t num_smaller_packets =
219 num_packets - (payload_left + extra_len) % num_packets;
sprang_webrtc 2017/05/17 13:10:06 If you use num_larger_packets instead you can get
ilnik 2017/05/17 15:06:33 Done.
220 // If all the packets are of equal size, we assume they all are 1 byte larger.
221 if (num_smaller_packets == num_packets)
222 num_smaller_packets = 0;
223 while (payload_left > 0) {
224 // Reduce payload per packet at the right time.
225 if (num_packets == num_smaller_packets)
226 payload_per_packet--;
227 size_t packet_length = payload_per_packet;
228 if (payload_left <= packet_length) { // Last portion of the payload
229 packet_length = payload_left;
230 // One additional packet may be used for extensions in the last packet.
231 // Together with last payload packet there may be at most 2 of them.
232 RTC_DCHECK_LE(num_packets, 2);
233 if (num_packets == 2) {
234 // Whole payload fits in the first num_packets-1 packets but extra
235 // packet is used for virtual payload. Leave at least one byte of data
236 // for the last packet.
237 packet_length = packet_length - 1;
238 }
239 }
240 RTC_CHECK_GT(packet_length, 0);
204 packets_.push(PacketUnit(Fragment(fragment.buffer + offset, packet_length), 241 packets_.push(PacketUnit(Fragment(fragment.buffer + offset, packet_length),
205 offset - kNalHeaderSize == 0, 242 offset - kNalHeaderSize == 0,
206 fragment_length == packet_length, false, 243 payload_left == packet_length, false,
207 fragment.buffer[0])); 244 fragment.buffer[0]));
208 offset += packet_length; 245 offset += packet_length;
209 fragment_length -= packet_length; 246 payload_left -= packet_length;
247 total_packets_++;
sprang_webrtc 2017/05/17 13:10:07 nit: just do total_packet_ += num_packets before t
ilnik 2017/05/17 15:06:33 Done.
248 num_packets--;
sprang_webrtc 2017/05/17 13:10:07 nit: prefer pre-increments (here and otherwise)
ilnik 2017/05/17 15:06:33 Done.
210 } 249 }
211 RTC_CHECK_EQ(0, fragment_length); 250 RTC_CHECK_EQ(0, payload_left);
212 } 251 }
213 252
214 size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) { 253 size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) {
215 // Aggregate fragments into one packet (STAP-A). 254 // Aggregate fragments into one packet (STAP-A).
216 size_t payload_size_left = max_payload_len_; 255 size_t payload_size_left = max_payload_len_;
217 int aggregated_fragments = 0; 256 int aggregated_fragments = 0;
218 size_t fragment_headers_length = 0; 257 size_t fragment_headers_length = 0;
219 const Fragment* fragment = &input_fragments_[fragment_index]; 258 const Fragment* fragment = &input_fragments_[fragment_index];
220 RTC_CHECK_GE(payload_size_left, fragment->length); 259 RTC_CHECK_GE(payload_size_left, fragment->length);
221 while (payload_size_left >= fragment->length + fragment_headers_length) { 260 total_packets_++;
261 while (payload_size_left >= fragment->length + fragment_headers_length &&
262 (fragment_index + 1 < input_fragments_.size() ||
263 payload_size_left >= fragment->length + fragment_headers_length +
264 last_packet_reduction_len_)) {
222 RTC_CHECK_GT(fragment->length, 0); 265 RTC_CHECK_GT(fragment->length, 0);
223 packets_.push(PacketUnit(*fragment, aggregated_fragments == 0, false, true, 266 packets_.push(PacketUnit(*fragment, aggregated_fragments == 0, false, true,
224 fragment->buffer[0])); 267 fragment->buffer[0]));
225 payload_size_left -= fragment->length; 268 payload_size_left -= fragment->length;
226 payload_size_left -= fragment_headers_length; 269 payload_size_left -= fragment_headers_length;
227 270
228 // Next fragment.
229 ++fragment_index;
230 if (fragment_index == input_fragments_.size())
231 break;
232 fragment = &input_fragments_[fragment_index];
233
234 fragment_headers_length = kLengthFieldSize; 271 fragment_headers_length = kLengthFieldSize;
235 // If we are going to try to aggregate more fragments into this packet 272 // If we are going to try to aggregate more fragments into this packet
236 // we need to add the STAP-A NALU header and a length field for the first 273 // we need to add the STAP-A NALU header and a length field for the first
237 // NALU of this packet. 274 // NALU of this packet.
238 if (aggregated_fragments == 0) 275 if (aggregated_fragments == 0)
239 fragment_headers_length += kNalHeaderSize + kLengthFieldSize; 276 fragment_headers_length += kNalHeaderSize + kLengthFieldSize;
240 ++aggregated_fragments; 277 ++aggregated_fragments;
278
279 // Next fragment.
280 ++fragment_index;
281 if (fragment_index == input_fragments_.size())
282 break;
283 fragment = &input_fragments_[fragment_index];
241 } 284 }
285 RTC_CHECK_GT(aggregated_fragments, 0);
242 packets_.back().last_fragment = true; 286 packets_.back().last_fragment = true;
243 return fragment_index; 287 return fragment_index;
244 } 288 }
245 289
246 void RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) { 290 void RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) {
247 // Add a single NALU to the queue, no aggregation. 291 // Add a single NALU to the queue, no aggregation.
248 size_t payload_size_left = max_payload_len_; 292 size_t payload_size_left = max_payload_len_;
293 if (fragment_index + 1 == input_fragments_.size())
294 payload_size_left -= last_packet_reduction_len_;
249 const Fragment* fragment = &input_fragments_[fragment_index]; 295 const Fragment* fragment = &input_fragments_[fragment_index];
250 RTC_CHECK_GE(payload_size_left, fragment->length) 296 RTC_CHECK_GE(payload_size_left, fragment->length)
251 << "Payload size left " << payload_size_left << ", fragment length " 297 << "Payload size left " << payload_size_left << ", fragment length "
252 << fragment->length << ", packetization mode " << packetization_mode_; 298 << fragment->length << ", packetization mode " << packetization_mode_;
253 RTC_CHECK_GT(fragment->length, 0u); 299 RTC_CHECK_GT(fragment->length, 0u);
254 packets_.push(PacketUnit(*fragment, true /* first */, true /* last */, 300 packets_.push(PacketUnit(*fragment, true /* first */, true /* last */,
255 false /* aggregated */, fragment->buffer[0])); 301 false /* aggregated */, fragment->buffer[0]));
302 total_packets_++;
256 } 303 }
257 304
258 bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet, 305 bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet) {
259 bool* last_packet) {
260 RTC_DCHECK(rtp_packet); 306 RTC_DCHECK(rtp_packet);
261 RTC_DCHECK(last_packet);
262 if (packets_.empty()) { 307 if (packets_.empty()) {
263 *last_packet = true;
264 return false; 308 return false;
265 } 309 }
266 310
267 PacketUnit packet = packets_.front(); 311 PacketUnit packet = packets_.front();
268 if (packet.first_fragment && packet.last_fragment) { 312 if (packet.first_fragment && packet.last_fragment) {
269 // Single NAL unit packet. 313 // Single NAL unit packet.
270 size_t bytes_to_send = packet.source_fragment.length; 314 size_t bytes_to_send = packet.source_fragment.length;
271 uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send); 315 uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send);
272 memcpy(buffer, packet.source_fragment.buffer, bytes_to_send); 316 memcpy(buffer, packet.source_fragment.buffer, bytes_to_send);
273 packets_.pop(); 317 packets_.pop();
274 input_fragments_.pop_front(); 318 input_fragments_.pop_front();
275 } else if (packet.aggregated) { 319 } else if (packet.aggregated) {
276 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); 320 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_);
277 NextAggregatePacket(rtp_packet); 321 NextAggregatePacket(rtp_packet, total_packets_ == 1);
278 } else { 322 } else {
279 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); 323 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_);
280 NextFragmentPacket(rtp_packet); 324 NextFragmentPacket(rtp_packet);
281 } 325 }
282 RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_); 326 RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_);
283 *last_packet = packets_.empty(); 327 if (packets_.empty()) {
284 rtp_packet->SetMarker(*last_packet); 328 RTC_DCHECK_LE(rtp_packet->payload_size(),
329 max_payload_len_ - last_packet_reduction_len_);
330 }
331 rtp_packet->SetMarker(packets_.empty());
332 total_packets_--;
285 return true; 333 return true;
286 } 334 }
287 335
288 void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet) { 336 void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet,
289 uint8_t* buffer = rtp_packet->AllocatePayload(max_payload_len_); 337 bool last) {
338 uint8_t* buffer = rtp_packet->AllocatePayload(
339 last ? max_payload_len_ - last_packet_reduction_len_ : max_payload_len_);
290 RTC_DCHECK(buffer); 340 RTC_DCHECK(buffer);
291 PacketUnit* packet = &packets_.front(); 341 PacketUnit* packet = &packets_.front();
292 RTC_CHECK(packet->first_fragment); 342 RTC_CHECK(packet->first_fragment);
293 // STAP-A NALU header. 343 // STAP-A NALU header.
294 buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA; 344 buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA;
295 size_t index = kNalHeaderSize; 345 size_t index = kNalHeaderSize;
296 bool is_last_fragment = packet->last_fragment; 346 bool is_last_fragment = packet->last_fragment;
297 while (packet->aggregated) { 347 while (packet->aggregated) {
298 const Fragment& fragment = packet->source_fragment; 348 const Fragment& fragment = packet->source_fragment;
299 // Add NAL unit length field. 349 // Add NAL unit length field.
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 h264->packetization_type = kH264FuA; 669 h264->packetization_type = kH264FuA;
620 h264->nalu_type = original_nal_type; 670 h264->nalu_type = original_nal_type;
621 if (first_fragment) { 671 if (first_fragment) {
622 h264->nalus[h264->nalus_length] = nalu; 672 h264->nalus[h264->nalus_length] = nalu;
623 h264->nalus_length = 1; 673 h264->nalus_length = 1;
624 } 674 }
625 return true; 675 return true;
626 } 676 }
627 677
628 } // namespace webrtc 678 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698