2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
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.
13 #include "webrtc/modules/interface/module_common_types.h"
14 #include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
15 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
30 static const size_t kNalHeaderSize = 1;
31 static const size_t kFuAHeaderSize = 2;
32 static const size_t kLengthFieldSize = 2;
34 // Bit masks for FU (A and B) indicators.
35 enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F };
37 // Bit masks for FU (A and B) headers.
38 enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
40 void ParseSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
41 const uint8_t* payload_data,
42 size_t payload_data_length) {
43 parsed_payload->type.Video.width = 0;
44 parsed_payload->type.Video.height = 0;
45 parsed_payload->type.Video.codec = kRtpVideoH264;
46 parsed_payload->type.Video.isFirstPacket = true;
47 RTPVideoHeaderH264* h264_header =
48 &parsed_payload->type.Video.codecHeader.H264;
49 h264_header->single_nalu = true;
50 h264_header->stap_a = false;
52 uint8_t nal_type = payload_data[0] & kTypeMask;
53 if (nal_type == kStapA) {
54 nal_type = payload_data[3] & kTypeMask;
55 h264_header->stap_a = true;
62 parsed_payload->frame_type = kVideoFrameKey;
65 parsed_payload->frame_type = kVideoFrameDelta;
70 void ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
71 const uint8_t* payload_data,
72 size_t payload_data_length,
74 uint8_t fnri = payload_data[0] & (kFBit | kNriMask);
75 uint8_t original_nal_type = payload_data[1] & kTypeMask;
76 bool first_fragment = (payload_data[1] & kSBit) > 0;
78 uint8_t original_nal_header = fnri | original_nal_type;
80 *offset = kNalHeaderSize;
81 uint8_t* payload = const_cast<uint8_t*>(payload_data + *offset);
82 payload[0] = original_nal_header;
84 *offset = kFuAHeaderSize;
87 if (original_nal_type == kIdr) {
88 parsed_payload->frame_type = kVideoFrameKey;
90 parsed_payload->frame_type = kVideoFrameDelta;
92 parsed_payload->type.Video.width = 0;
93 parsed_payload->type.Video.height = 0;
94 parsed_payload->type.Video.codec = kRtpVideoH264;
95 parsed_payload->type.Video.isFirstPacket = first_fragment;
96 RTPVideoHeaderH264* h264_header =
97 &parsed_payload->type.Video.codecHeader.H264;
98 h264_header->single_nalu = false;
99 h264_header->stap_a = false;
103 RtpPacketizerH264::RtpPacketizerH264(FrameType frame_type,
104 size_t max_payload_len)
105 : payload_data_(NULL),
107 max_payload_len_(max_payload_len),
108 frame_type_(frame_type) {
111 RtpPacketizerH264::~RtpPacketizerH264() {
114 void RtpPacketizerH264::SetPayloadData(
115 const uint8_t* payload_data,
117 const RTPFragmentationHeader* fragmentation) {
118 assert(packets_.empty());
119 assert(fragmentation);
120 payload_data_ = payload_data;
121 payload_size_ = payload_size;
122 fragmentation_.CopyFrom(*fragmentation);
126 void RtpPacketizerH264::GeneratePackets() {
127 for (size_t i = 0; i < fragmentation_.fragmentationVectorSize;) {
128 size_t fragment_offset = fragmentation_.fragmentationOffset[i];
129 size_t fragment_length = fragmentation_.fragmentationLength[i];
130 if (fragment_length > max_payload_len_) {
131 PacketizeFuA(fragment_offset, fragment_length);
134 i = PacketizeStapA(i, fragment_offset, fragment_length);
139 void RtpPacketizerH264::PacketizeFuA(size_t fragment_offset,
140 size_t fragment_length) {
141 // Fragment payload into packets (FU-A).
142 // Strip out the original header and leave room for the FU-A header.
143 fragment_length -= kNalHeaderSize;
144 size_t offset = fragment_offset + kNalHeaderSize;
145 size_t bytes_available = max_payload_len_ - kFuAHeaderSize;
147 (fragment_length + (bytes_available - 1)) / bytes_available;
148 size_t avg_size = (fragment_length + fragments - 1) / fragments;
149 while (fragment_length > 0) {
150 size_t packet_length = avg_size;
151 if (fragment_length < avg_size)
152 packet_length = fragment_length;
153 uint8_t header = payload_data_[fragment_offset];
154 packets_.push(Packet(offset,
156 offset - kNalHeaderSize == fragment_offset,
157 fragment_length == packet_length,
160 offset += packet_length;
161 fragment_length -= packet_length;
165 int RtpPacketizerH264::PacketizeStapA(size_t fragment_index,
166 size_t fragment_offset,
167 size_t fragment_length) {
168 // Aggregate fragments into one packet (STAP-A).
169 size_t payload_size_left = max_payload_len_;
170 int aggregated_fragments = 0;
171 size_t fragment_headers_length = 0;
172 assert(payload_size_left >= fragment_length);
173 while (payload_size_left >= fragment_length + fragment_headers_length) {
174 assert(fragment_length > 0);
175 uint8_t header = payload_data_[fragment_offset];
176 packets_.push(Packet(fragment_offset,
178 aggregated_fragments == 0,
182 payload_size_left -= fragment_length;
183 payload_size_left -= fragment_headers_length;
187 if (fragment_index == fragmentation_.fragmentationVectorSize)
189 fragment_offset = fragmentation_.fragmentationOffset[fragment_index];
190 fragment_length = fragmentation_.fragmentationLength[fragment_index];
192 fragment_headers_length = kLengthFieldSize;
193 // If we are going to try to aggregate more fragments into this packet
194 // we need to add the STAP-A NALU header and a length field for the first
195 // NALU of this packet.
196 if (aggregated_fragments == 0)
197 fragment_headers_length += kNalHeaderSize + kLengthFieldSize;
198 ++aggregated_fragments;
200 packets_.back().last_fragment = true;
201 return fragment_index;
204 bool RtpPacketizerH264::NextPacket(uint8_t* buffer,
205 size_t* bytes_to_send,
208 if (packets_.empty()) {
214 Packet packet = packets_.front();
216 if (packet.first_fragment && packet.last_fragment) {
217 // Single NAL unit packet.
218 *bytes_to_send = packet.size;
219 memcpy(buffer, &payload_data_[packet.offset], packet.size);
221 assert(*bytes_to_send <= max_payload_len_);
222 } else if (packet.aggregated) {
223 NextAggregatePacket(buffer, bytes_to_send);
224 assert(*bytes_to_send <= max_payload_len_);
226 NextFragmentPacket(buffer, bytes_to_send);
227 assert(*bytes_to_send <= max_payload_len_);
229 *last_packet = packets_.empty();
233 void RtpPacketizerH264::NextAggregatePacket(uint8_t* buffer,
234 size_t* bytes_to_send) {
235 Packet packet = packets_.front();
236 assert(packet.first_fragment);
237 // STAP-A NALU header.
238 buffer[0] = (packet.header & (kFBit | kNriMask)) | kStapA;
239 int index = kNalHeaderSize;
240 *bytes_to_send += kNalHeaderSize;
241 while (packet.aggregated) {
242 // Add NAL unit length field.
243 RtpUtility::AssignUWord16ToBuffer(&buffer[index], packet.size);
244 index += kLengthFieldSize;
245 *bytes_to_send += kLengthFieldSize;
247 memcpy(&buffer[index], &payload_data_[packet.offset], packet.size);
248 index += packet.size;
249 *bytes_to_send += packet.size;
251 if (packet.last_fragment)
253 packet = packets_.front();
255 assert(packet.last_fragment);
258 void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer,
259 size_t* bytes_to_send) {
260 Packet packet = packets_.front();
261 // NAL unit fragmented over multiple packets (FU-A).
262 // We do not send original NALU header, so it will be replaced by the
263 // FU indicator header of the first packet.
264 uint8_t fu_indicator = (packet.header & (kFBit | kNriMask)) | kFuA;
265 uint8_t fu_header = 0;
267 // S | E | R | 5 bit type.
268 fu_header |= (packet.first_fragment ? kSBit : 0);
269 fu_header |= (packet.last_fragment ? kEBit : 0);
270 uint8_t type = packet.header & kTypeMask;
272 buffer[0] = fu_indicator;
273 buffer[1] = fu_header;
275 if (packet.last_fragment) {
276 *bytes_to_send = packet.size + kFuAHeaderSize;
277 memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size);
279 *bytes_to_send = packet.size + kFuAHeaderSize;
280 memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size);
285 ProtectionType RtpPacketizerH264::GetProtectionType() {
286 return (frame_type_ == kVideoFrameKey) ? kProtectedPacket
287 : kUnprotectedPacket;
290 StorageType RtpPacketizerH264::GetStorageType(
291 uint32_t retransmission_settings) {
292 return kAllowRetransmission;
295 std::string RtpPacketizerH264::ToString() {
296 return "RtpPacketizerH264";
299 bool RtpDepacketizerH264::Parse(ParsedPayload* parsed_payload,
300 const uint8_t* payload_data,
301 size_t payload_data_length) {
302 assert(parsed_payload != NULL);
303 uint8_t nal_type = payload_data[0] & kTypeMask;
305 if (nal_type == kFuA) {
306 // Fragmented NAL units (FU-A).
307 ParseFuaNalu(parsed_payload, payload_data, payload_data_length, &offset);
309 // We handle STAP-A and single NALU's the same way here. The jitter buffer
310 // will depacketize the STAP-A into NAL units later.
311 ParseSingleNalu(parsed_payload, payload_data, payload_data_length);
314 parsed_payload->payload = payload_data + offset;
315 parsed_payload->payload_length = payload_data_length - offset;
318 } // namespace webrtc