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