• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3  *
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
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <string.h>
12 
13 #include "webrtc/base/logging.h"
14 #include "webrtc/modules/include/module_common_types.h"
15 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
16 #include "webrtc/modules/rtp_rtcp/source/h264_sps_parser.h"
17 #include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
18 
19 namespace webrtc {
20 namespace {
21 
22 enum Nalu {
23   kSlice = 1,
24   kIdr = 5,
25   kSei = 6,
26   kSps = 7,
27   kPps = 8,
28   kStapA = 24,
29   kFuA = 28
30 };
31 
32 static const size_t kNalHeaderSize = 1;
33 static const size_t kFuAHeaderSize = 2;
34 static const size_t kLengthFieldSize = 2;
35 static const size_t kStapAHeaderSize = kNalHeaderSize + kLengthFieldSize;
36 
37 // Bit masks for FU (A and B) indicators.
38 enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F };
39 
40 // Bit masks for FU (A and B) headers.
41 enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
42 
43 // TODO(pbos): Avoid parsing this here as well as inside the jitter buffer.
VerifyStapANaluLengths(const uint8_t * nalu_ptr,size_t length_remaining)44 bool VerifyStapANaluLengths(const uint8_t* nalu_ptr, size_t length_remaining) {
45   while (length_remaining > 0) {
46     // Buffer doesn't contain room for additional nalu length.
47     if (length_remaining < sizeof(uint16_t))
48       return false;
49     uint16_t nalu_size = nalu_ptr[0] << 8 | nalu_ptr[1];
50     nalu_ptr += sizeof(uint16_t);
51     length_remaining -= sizeof(uint16_t);
52     if (nalu_size > length_remaining)
53       return false;
54     nalu_ptr += nalu_size;
55     length_remaining -= nalu_size;
56   }
57   return true;
58 }
59 
ParseSingleNalu(RtpDepacketizer::ParsedPayload * parsed_payload,const uint8_t * payload_data,size_t payload_data_length)60 bool ParseSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
61                      const uint8_t* payload_data,
62                      size_t payload_data_length) {
63   parsed_payload->type.Video.width = 0;
64   parsed_payload->type.Video.height = 0;
65   parsed_payload->type.Video.codec = kRtpVideoH264;
66   parsed_payload->type.Video.isFirstPacket = true;
67   RTPVideoHeaderH264* h264_header =
68       &parsed_payload->type.Video.codecHeader.H264;
69 
70   const uint8_t* nalu_start = payload_data + kNalHeaderSize;
71   size_t nalu_length = payload_data_length - kNalHeaderSize;
72   uint8_t nal_type = payload_data[0] & kTypeMask;
73   if (nal_type == kStapA) {
74     // Skip the StapA header (StapA nal type + length).
75     if (payload_data_length <= kStapAHeaderSize) {
76       LOG(LS_ERROR) << "StapA header truncated.";
77       return false;
78     }
79     if (!VerifyStapANaluLengths(nalu_start, nalu_length)) {
80       LOG(LS_ERROR) << "StapA packet with incorrect NALU packet lengths.";
81       return false;
82     }
83 
84     nal_type = payload_data[kStapAHeaderSize] & kTypeMask;
85     nalu_start += kStapAHeaderSize;
86     nalu_length -= kStapAHeaderSize;
87     h264_header->packetization_type = kH264StapA;
88   } else {
89     h264_header->packetization_type = kH264SingleNalu;
90   }
91   h264_header->nalu_type = nal_type;
92 
93   // We can read resolution out of sps packets.
94   if (nal_type == kSps) {
95     H264SpsParser parser(nalu_start, nalu_length);
96     if (parser.Parse()) {
97       parsed_payload->type.Video.width = parser.width();
98       parsed_payload->type.Video.height = parser.height();
99     }
100   }
101   switch (nal_type) {
102     case kSps:
103     case kPps:
104     case kIdr:
105       parsed_payload->frame_type = kVideoFrameKey;
106       break;
107     default:
108       parsed_payload->frame_type = kVideoFrameDelta;
109       break;
110   }
111   return true;
112 }
113 
ParseFuaNalu(RtpDepacketizer::ParsedPayload * parsed_payload,const uint8_t * payload_data,size_t payload_data_length,size_t * offset)114 bool ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
115                   const uint8_t* payload_data,
116                   size_t payload_data_length,
117                   size_t* offset) {
118   if (payload_data_length < kFuAHeaderSize) {
119     LOG(LS_ERROR) << "FU-A NAL units truncated.";
120     return false;
121   }
122   uint8_t fnri = payload_data[0] & (kFBit | kNriMask);
123   uint8_t original_nal_type = payload_data[1] & kTypeMask;
124   bool first_fragment = (payload_data[1] & kSBit) > 0;
125 
126   uint8_t original_nal_header = fnri | original_nal_type;
127   if (first_fragment) {
128     *offset = kNalHeaderSize;
129     uint8_t* payload = const_cast<uint8_t*>(payload_data + *offset);
130     payload[0] = original_nal_header;
131   } else {
132     *offset = kFuAHeaderSize;
133   }
134 
135   if (original_nal_type == kIdr) {
136     parsed_payload->frame_type = kVideoFrameKey;
137   } else {
138     parsed_payload->frame_type = kVideoFrameDelta;
139   }
140   parsed_payload->type.Video.width = 0;
141   parsed_payload->type.Video.height = 0;
142   parsed_payload->type.Video.codec = kRtpVideoH264;
143   parsed_payload->type.Video.isFirstPacket = first_fragment;
144   RTPVideoHeaderH264* h264_header =
145       &parsed_payload->type.Video.codecHeader.H264;
146   h264_header->packetization_type = kH264FuA;
147   h264_header->nalu_type = original_nal_type;
148   return true;
149 }
150 }  // namespace
151 
RtpPacketizerH264(FrameType frame_type,size_t max_payload_len)152 RtpPacketizerH264::RtpPacketizerH264(FrameType frame_type,
153                                      size_t max_payload_len)
154     : payload_data_(NULL),
155       payload_size_(0),
156       max_payload_len_(max_payload_len) {
157 }
158 
~RtpPacketizerH264()159 RtpPacketizerH264::~RtpPacketizerH264() {
160 }
161 
SetPayloadData(const uint8_t * payload_data,size_t payload_size,const RTPFragmentationHeader * fragmentation)162 void RtpPacketizerH264::SetPayloadData(
163     const uint8_t* payload_data,
164     size_t payload_size,
165     const RTPFragmentationHeader* fragmentation) {
166   assert(packets_.empty());
167   assert(fragmentation);
168   payload_data_ = payload_data;
169   payload_size_ = payload_size;
170   fragmentation_.CopyFrom(*fragmentation);
171   GeneratePackets();
172 }
173 
GeneratePackets()174 void RtpPacketizerH264::GeneratePackets() {
175   for (size_t i = 0; i < fragmentation_.fragmentationVectorSize;) {
176     size_t fragment_offset = fragmentation_.fragmentationOffset[i];
177     size_t fragment_length = fragmentation_.fragmentationLength[i];
178     if (fragment_length > max_payload_len_) {
179       PacketizeFuA(fragment_offset, fragment_length);
180       ++i;
181     } else {
182       i = PacketizeStapA(i, fragment_offset, fragment_length);
183     }
184   }
185 }
186 
PacketizeFuA(size_t fragment_offset,size_t fragment_length)187 void RtpPacketizerH264::PacketizeFuA(size_t fragment_offset,
188                                      size_t fragment_length) {
189   // Fragment payload into packets (FU-A).
190   // Strip out the original header and leave room for the FU-A header.
191   fragment_length -= kNalHeaderSize;
192   size_t offset = fragment_offset + kNalHeaderSize;
193   size_t bytes_available = max_payload_len_ - kFuAHeaderSize;
194   size_t fragments =
195       (fragment_length + (bytes_available - 1)) / bytes_available;
196   size_t avg_size = (fragment_length + fragments - 1) / fragments;
197   while (fragment_length > 0) {
198     size_t packet_length = avg_size;
199     if (fragment_length < avg_size)
200       packet_length = fragment_length;
201     uint8_t header = payload_data_[fragment_offset];
202     packets_.push(Packet(offset,
203                          packet_length,
204                          offset - kNalHeaderSize == fragment_offset,
205                          fragment_length == packet_length,
206                          false,
207                          header));
208     offset += packet_length;
209     fragment_length -= packet_length;
210   }
211 }
212 
PacketizeStapA(size_t fragment_index,size_t fragment_offset,size_t fragment_length)213 int RtpPacketizerH264::PacketizeStapA(size_t fragment_index,
214                                       size_t fragment_offset,
215                                       size_t fragment_length) {
216   // Aggregate fragments into one packet (STAP-A).
217   size_t payload_size_left = max_payload_len_;
218   int aggregated_fragments = 0;
219   size_t fragment_headers_length = 0;
220   assert(payload_size_left >= fragment_length);
221   while (payload_size_left >= fragment_length + fragment_headers_length) {
222     assert(fragment_length > 0);
223     uint8_t header = payload_data_[fragment_offset];
224     packets_.push(Packet(fragment_offset,
225                          fragment_length,
226                          aggregated_fragments == 0,
227                          false,
228                          true,
229                          header));
230     payload_size_left -= fragment_length;
231     payload_size_left -= fragment_headers_length;
232 
233     // Next fragment.
234     ++fragment_index;
235     if (fragment_index == fragmentation_.fragmentationVectorSize)
236       break;
237     fragment_offset = fragmentation_.fragmentationOffset[fragment_index];
238     fragment_length = fragmentation_.fragmentationLength[fragment_index];
239 
240     fragment_headers_length = kLengthFieldSize;
241     // If we are going to try to aggregate more fragments into this packet
242     // we need to add the STAP-A NALU header and a length field for the first
243     // NALU of this packet.
244     if (aggregated_fragments == 0)
245       fragment_headers_length += kNalHeaderSize + kLengthFieldSize;
246     ++aggregated_fragments;
247   }
248   packets_.back().last_fragment = true;
249   return fragment_index;
250 }
251 
NextPacket(uint8_t * buffer,size_t * bytes_to_send,bool * last_packet)252 bool RtpPacketizerH264::NextPacket(uint8_t* buffer,
253                                    size_t* bytes_to_send,
254                                    bool* last_packet) {
255   *bytes_to_send = 0;
256   if (packets_.empty()) {
257     *bytes_to_send = 0;
258     *last_packet = true;
259     return false;
260   }
261 
262   Packet packet = packets_.front();
263 
264   if (packet.first_fragment && packet.last_fragment) {
265     // Single NAL unit packet.
266     *bytes_to_send = packet.size;
267     memcpy(buffer, &payload_data_[packet.offset], packet.size);
268     packets_.pop();
269     assert(*bytes_to_send <= max_payload_len_);
270   } else if (packet.aggregated) {
271     NextAggregatePacket(buffer, bytes_to_send);
272     assert(*bytes_to_send <= max_payload_len_);
273   } else {
274     NextFragmentPacket(buffer, bytes_to_send);
275     assert(*bytes_to_send <= max_payload_len_);
276   }
277   *last_packet = packets_.empty();
278   return true;
279 }
280 
NextAggregatePacket(uint8_t * buffer,size_t * bytes_to_send)281 void RtpPacketizerH264::NextAggregatePacket(uint8_t* buffer,
282                                             size_t* bytes_to_send) {
283   Packet packet = packets_.front();
284   assert(packet.first_fragment);
285   // STAP-A NALU header.
286   buffer[0] = (packet.header & (kFBit | kNriMask)) | kStapA;
287   int index = kNalHeaderSize;
288   *bytes_to_send += kNalHeaderSize;
289   while (packet.aggregated) {
290     // Add NAL unit length field.
291     ByteWriter<uint16_t>::WriteBigEndian(&buffer[index], packet.size);
292     index += kLengthFieldSize;
293     *bytes_to_send += kLengthFieldSize;
294     // Add NAL unit.
295     memcpy(&buffer[index], &payload_data_[packet.offset], packet.size);
296     index += packet.size;
297     *bytes_to_send += packet.size;
298     packets_.pop();
299     if (packet.last_fragment)
300       break;
301     packet = packets_.front();
302   }
303   assert(packet.last_fragment);
304 }
305 
NextFragmentPacket(uint8_t * buffer,size_t * bytes_to_send)306 void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer,
307                                            size_t* bytes_to_send) {
308   Packet packet = packets_.front();
309   // NAL unit fragmented over multiple packets (FU-A).
310   // We do not send original NALU header, so it will be replaced by the
311   // FU indicator header of the first packet.
312   uint8_t fu_indicator = (packet.header & (kFBit | kNriMask)) | kFuA;
313   uint8_t fu_header = 0;
314 
315   // S | E | R | 5 bit type.
316   fu_header |= (packet.first_fragment ? kSBit : 0);
317   fu_header |= (packet.last_fragment ? kEBit : 0);
318   uint8_t type = packet.header & kTypeMask;
319   fu_header |= type;
320   buffer[0] = fu_indicator;
321   buffer[1] = fu_header;
322 
323   if (packet.last_fragment) {
324     *bytes_to_send = packet.size + kFuAHeaderSize;
325     memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size);
326   } else {
327     *bytes_to_send = packet.size + kFuAHeaderSize;
328     memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size);
329   }
330   packets_.pop();
331 }
332 
GetProtectionType()333 ProtectionType RtpPacketizerH264::GetProtectionType() {
334   return kProtectedPacket;
335 }
336 
GetStorageType(uint32_t retransmission_settings)337 StorageType RtpPacketizerH264::GetStorageType(
338     uint32_t retransmission_settings) {
339   return kAllowRetransmission;
340 }
341 
ToString()342 std::string RtpPacketizerH264::ToString() {
343   return "RtpPacketizerH264";
344 }
345 
Parse(ParsedPayload * parsed_payload,const uint8_t * payload_data,size_t payload_data_length)346 bool RtpDepacketizerH264::Parse(ParsedPayload* parsed_payload,
347                                 const uint8_t* payload_data,
348                                 size_t payload_data_length) {
349   assert(parsed_payload != NULL);
350   if (payload_data_length == 0) {
351     LOG(LS_ERROR) << "Empty payload.";
352     return false;
353   }
354 
355   uint8_t nal_type = payload_data[0] & kTypeMask;
356   size_t offset = 0;
357   if (nal_type == kFuA) {
358     // Fragmented NAL units (FU-A).
359     if (!ParseFuaNalu(
360             parsed_payload, payload_data, payload_data_length, &offset)) {
361       return false;
362     }
363   } else {
364     // We handle STAP-A and single NALU's the same way here. The jitter buffer
365     // will depacketize the STAP-A into NAL units later.
366     if (!ParseSingleNalu(parsed_payload, payload_data, payload_data_length))
367       return false;
368   }
369 
370   parsed_payload->payload = payload_data + offset;
371   parsed_payload->payload_length = payload_data_length - offset;
372   return true;
373 }
374 }  // namespace webrtc
375