OLD | NEW |
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 Loading... |
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_extensions_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_extensions_len_(last_packet_extensions_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); |
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) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 } | 170 } |
168 | 171 |
169 void RtpPacketizerH264::GeneratePackets() { | 172 void RtpPacketizerH264::GeneratePackets() { |
170 for (size_t i = 0; i < input_fragments_.size();) { | 173 for (size_t i = 0; i < input_fragments_.size();) { |
171 switch (packetization_mode_) { | 174 switch (packetization_mode_) { |
172 case H264PacketizationMode::SingleNalUnit: | 175 case H264PacketizationMode::SingleNalUnit: |
173 PacketizeSingleNalu(i); | 176 PacketizeSingleNalu(i); |
174 ++i; | 177 ++i; |
175 break; | 178 break; |
176 case H264PacketizationMode::NonInterleaved: | 179 case H264PacketizationMode::NonInterleaved: |
177 if (input_fragments_[i].length > max_payload_len_) { | 180 if (input_fragments_[i].length > max_payload_len_ || |
| 181 (i + 1 == input_fragments_.size() && |
| 182 (input_fragments_[i].length + last_packet_extensions_len_ > |
| 183 max_payload_len_))) { |
178 PacketizeFuA(i); | 184 PacketizeFuA(i); |
179 ++i; | 185 ++i; |
180 } else { | 186 } else { |
181 i = PacketizeStapA(i); | 187 i = PacketizeStapA(i); |
182 } | 188 } |
183 break; | 189 break; |
184 } | 190 } |
185 } | 191 } |
186 } | 192 } |
187 | 193 |
188 void RtpPacketizerH264::PacketizeFuA(size_t fragment_index) { | 194 void RtpPacketizerH264::PacketizeFuA(size_t fragment_index) { |
189 // Fragment payload into packets (FU-A). | 195 // Fragment payload into packets (FU-A). |
190 // Strip out the original header and leave room for the FU-A header. | 196 // Strip out the original header and leave room for the FU-A header. |
191 const Fragment& fragment = input_fragments_[fragment_index]; | 197 const Fragment& fragment = input_fragments_[fragment_index]; |
192 | 198 bool is_last_fragment = fragment_index + 1 == input_fragments_.size(); |
193 size_t fragment_length = fragment.length - kNalHeaderSize; | 199 size_t fragment_length = fragment.length - kNalHeaderSize; |
194 size_t offset = kNalHeaderSize; | 200 size_t offset = kNalHeaderSize; |
195 size_t bytes_available = max_payload_len_ - kFuAHeaderSize; | 201 size_t bytes_available = max_payload_len_ - kFuAHeaderSize; |
196 const size_t num_fragments = | 202 size_t extra_len = is_last_fragment ? last_packet_extensions_len_ : 0; |
197 (fragment_length + (bytes_available - 1)) / bytes_available; | |
198 | 203 |
199 const size_t avg_size = (fragment_length + num_fragments - 1) / num_fragments; | 204 size_t num_packets = |
| 205 (fragment_length + extra_len + (bytes_available - 1)) / bytes_available; |
| 206 |
| 207 const size_t avg_size = |
| 208 (fragment_length + extra_len + num_packets - 1) / num_packets; |
| 209 |
200 while (fragment_length > 0) { | 210 while (fragment_length > 0) { |
201 size_t packet_length = avg_size; | 211 size_t packet_length = avg_size; |
202 if (fragment_length < avg_size) | 212 if (fragment_length <= packet_length) { // Last portion of the payload |
203 packet_length = fragment_length; | 213 packet_length = fragment_length; |
| 214 // One additional packet may be used for extensions in the last packet. |
| 215 // Together with last payload packet there may be at most 2 of them. |
| 216 RTC_CHECK_LE(num_packets, 2); |
| 217 // Whole payload fits in the first num_packets-1 packets but extra packet |
| 218 // is used for extensions. |
| 219 if (num_packets == 2) { |
| 220 // Leave at least one byte of data for the last packet. |
| 221 packet_length = packet_length - 1; |
| 222 } |
| 223 } |
| 224 RTC_CHECK_GT(packet_length, 0); |
204 packets_.push(PacketUnit(Fragment(fragment.buffer + offset, packet_length), | 225 packets_.push(PacketUnit(Fragment(fragment.buffer + offset, packet_length), |
205 offset - kNalHeaderSize == 0, | 226 offset - kNalHeaderSize == 0, |
206 fragment_length == packet_length, false, | 227 fragment_length == packet_length, false, |
207 fragment.buffer[0])); | 228 fragment.buffer[0])); |
208 offset += packet_length; | 229 offset += packet_length; |
209 fragment_length -= packet_length; | 230 fragment_length -= packet_length; |
| 231 total_packets_++; |
| 232 num_packets--; |
210 } | 233 } |
211 RTC_CHECK_EQ(0, fragment_length); | 234 RTC_CHECK_EQ(0, fragment_length); |
212 } | 235 } |
213 | 236 |
214 size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) { | 237 size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) { |
215 // Aggregate fragments into one packet (STAP-A). | 238 // Aggregate fragments into one packet (STAP-A). |
216 size_t payload_size_left = max_payload_len_; | 239 size_t payload_size_left = max_payload_len_; |
217 int aggregated_fragments = 0; | 240 int aggregated_fragments = 0; |
218 size_t fragment_headers_length = 0; | 241 size_t fragment_headers_length = 0; |
219 const Fragment* fragment = &input_fragments_[fragment_index]; | 242 const Fragment* fragment = &input_fragments_[fragment_index]; |
220 RTC_CHECK_GE(payload_size_left, fragment->length); | 243 RTC_CHECK_GE(payload_size_left, fragment->length); |
221 while (payload_size_left >= fragment->length + fragment_headers_length) { | 244 total_packets_++; |
| 245 while (payload_size_left >= fragment->length + fragment_headers_length && |
| 246 (fragment_index + 1 < input_fragments_.size() || |
| 247 payload_size_left >= fragment->length + fragment_headers_length + |
| 248 last_packet_extensions_len_)) { |
222 RTC_CHECK_GT(fragment->length, 0); | 249 RTC_CHECK_GT(fragment->length, 0); |
223 packets_.push(PacketUnit(*fragment, aggregated_fragments == 0, false, true, | 250 packets_.push(PacketUnit(*fragment, aggregated_fragments == 0, false, true, |
224 fragment->buffer[0])); | 251 fragment->buffer[0])); |
225 payload_size_left -= fragment->length; | 252 payload_size_left -= fragment->length; |
226 payload_size_left -= fragment_headers_length; | 253 payload_size_left -= fragment_headers_length; |
227 | 254 |
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; | 255 fragment_headers_length = kLengthFieldSize; |
235 // If we are going to try to aggregate more fragments into this packet | 256 // 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 | 257 // we need to add the STAP-A NALU header and a length field for the first |
237 // NALU of this packet. | 258 // NALU of this packet. |
238 if (aggregated_fragments == 0) | 259 if (aggregated_fragments == 0) |
239 fragment_headers_length += kNalHeaderSize + kLengthFieldSize; | 260 fragment_headers_length += kNalHeaderSize + kLengthFieldSize; |
240 ++aggregated_fragments; | 261 ++aggregated_fragments; |
| 262 |
| 263 // Next fragment. |
| 264 ++fragment_index; |
| 265 if (fragment_index == input_fragments_.size()) |
| 266 break; |
| 267 fragment = &input_fragments_[fragment_index]; |
241 } | 268 } |
| 269 RTC_CHECK_GT(aggregated_fragments, 0); |
242 packets_.back().last_fragment = true; | 270 packets_.back().last_fragment = true; |
243 return fragment_index; | 271 return fragment_index; |
244 } | 272 } |
245 | 273 |
246 void RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) { | 274 void RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) { |
247 // Add a single NALU to the queue, no aggregation. | 275 // Add a single NALU to the queue, no aggregation. |
248 size_t payload_size_left = max_payload_len_; | 276 size_t payload_size_left = max_payload_len_; |
| 277 if (fragment_index + 1 == input_fragments_.size()) |
| 278 payload_size_left -= last_packet_extensions_len_; |
249 const Fragment* fragment = &input_fragments_[fragment_index]; | 279 const Fragment* fragment = &input_fragments_[fragment_index]; |
250 RTC_CHECK_GE(payload_size_left, fragment->length) | 280 RTC_CHECK_GE(payload_size_left, fragment->length) |
251 << "Payload size left " << payload_size_left << ", fragment length " | 281 << "Payload size left " << payload_size_left << ", fragment length " |
252 << fragment->length << ", packetization mode " << packetization_mode_; | 282 << fragment->length << ", packetization mode " << packetization_mode_; |
253 RTC_CHECK_GT(fragment->length, 0u); | 283 RTC_CHECK_GT(fragment->length, 0u); |
254 packets_.push(PacketUnit(*fragment, true /* first */, true /* last */, | 284 packets_.push(PacketUnit(*fragment, true /* first */, true /* last */, |
255 false /* aggregated */, fragment->buffer[0])); | 285 false /* aggregated */, fragment->buffer[0])); |
| 286 total_packets_++; |
256 } | 287 } |
257 | 288 |
258 bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet, | 289 bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet) { |
259 bool* last_packet) { | |
260 RTC_DCHECK(rtp_packet); | 290 RTC_DCHECK(rtp_packet); |
261 RTC_DCHECK(last_packet); | |
262 if (packets_.empty()) { | 291 if (packets_.empty()) { |
263 *last_packet = true; | |
264 return false; | 292 return false; |
265 } | 293 } |
266 | 294 |
267 PacketUnit packet = packets_.front(); | 295 PacketUnit packet = packets_.front(); |
268 if (packet.first_fragment && packet.last_fragment) { | 296 if (packet.first_fragment && packet.last_fragment) { |
269 // Single NAL unit packet. | 297 // Single NAL unit packet. |
270 size_t bytes_to_send = packet.source_fragment.length; | 298 size_t bytes_to_send = packet.source_fragment.length; |
271 uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send); | 299 uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send); |
272 memcpy(buffer, packet.source_fragment.buffer, bytes_to_send); | 300 memcpy(buffer, packet.source_fragment.buffer, bytes_to_send); |
273 packets_.pop(); | 301 packets_.pop(); |
274 input_fragments_.pop_front(); | 302 input_fragments_.pop_front(); |
275 } else if (packet.aggregated) { | 303 } else if (packet.aggregated) { |
276 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); | 304 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); |
277 NextAggregatePacket(rtp_packet); | 305 NextAggregatePacket(rtp_packet, total_packets_ == 1); |
278 } else { | 306 } else { |
279 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); | 307 RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); |
280 NextFragmentPacket(rtp_packet); | 308 NextFragmentPacket(rtp_packet); |
281 } | 309 } |
282 RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_); | 310 RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_); |
283 *last_packet = packets_.empty(); | 311 if (packets_.empty()) { |
284 rtp_packet->SetMarker(*last_packet); | 312 RTC_DCHECK_LE(rtp_packet->payload_size(), |
| 313 max_payload_len_ - last_packet_extensions_len_); |
| 314 } |
| 315 rtp_packet->SetMarker(packets_.empty()); |
| 316 total_packets_--; |
285 return true; | 317 return true; |
286 } | 318 } |
287 | 319 |
288 void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet) { | 320 size_t RtpPacketizerH264::TotalPackets() { |
289 uint8_t* buffer = rtp_packet->AllocatePayload(max_payload_len_); | 321 return total_packets_; |
| 322 } |
| 323 |
| 324 void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet, |
| 325 bool last) { |
| 326 uint8_t* buffer = rtp_packet->AllocatePayload( |
| 327 last ? max_payload_len_ - last_packet_extensions_len_ : max_payload_len_); |
290 RTC_DCHECK(buffer); | 328 RTC_DCHECK(buffer); |
291 PacketUnit* packet = &packets_.front(); | 329 PacketUnit* packet = &packets_.front(); |
292 RTC_CHECK(packet->first_fragment); | 330 RTC_CHECK(packet->first_fragment); |
293 // STAP-A NALU header. | 331 // STAP-A NALU header. |
294 buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA; | 332 buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA; |
295 size_t index = kNalHeaderSize; | 333 size_t index = kNalHeaderSize; |
296 bool is_last_fragment = packet->last_fragment; | 334 bool is_last_fragment = packet->last_fragment; |
297 while (packet->aggregated) { | 335 while (packet->aggregated) { |
298 const Fragment& fragment = packet->source_fragment; | 336 const Fragment& fragment = packet->source_fragment; |
299 // Add NAL unit length field. | 337 // Add NAL unit length field. |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 h264->packetization_type = kH264FuA; | 657 h264->packetization_type = kH264FuA; |
620 h264->nalu_type = original_nal_type; | 658 h264->nalu_type = original_nal_type; |
621 if (first_fragment) { | 659 if (first_fragment) { |
622 h264->nalus[h264->nalus_length] = nalu; | 660 h264->nalus[h264->nalus_length] = nalu; |
623 h264->nalus_length = 1; | 661 h264->nalus_length = 1; |
624 } | 662 } |
625 return true; | 663 return true; |
626 } | 664 } |
627 | 665 |
628 } // namespace webrtc | 666 } // namespace webrtc |
OLD | NEW |