Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / rtp_rtcp / source / rtp_format_h264.cc
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/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"
16
17 namespace webrtc {
18 namespace {
19
20 enum Nalu {
21   kSlice = 1,
22   kIdr = 5,
23   kSei = 6,
24   kSps = 7,
25   kPps = 8,
26   kStapA = 24,
27   kFuA = 28
28 };
29
30 static const size_t kNalHeaderSize = 1;
31 static const size_t kFuAHeaderSize = 2;
32 static const size_t kLengthFieldSize = 2;
33
34 // Bit masks for FU (A and B) indicators.
35 enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F };
36
37 // Bit masks for FU (A and B) headers.
38 enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
39
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;
51
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;
56   }
57
58   switch (nal_type) {
59     case kSps:
60     case kPps:
61     case kIdr:
62       parsed_payload->frame_type = kVideoFrameKey;
63       break;
64     default:
65       parsed_payload->frame_type = kVideoFrameDelta;
66       break;
67   }
68 }
69
70 void ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
71                   const uint8_t* payload_data,
72                   size_t payload_data_length,
73                   size_t* offset) {
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;
77
78   uint8_t original_nal_header = fnri | original_nal_type;
79   if (first_fragment) {
80     *offset = kNalHeaderSize;
81     uint8_t* payload = const_cast<uint8_t*>(payload_data + *offset);
82     payload[0] = original_nal_header;
83   } else {
84     *offset = kFuAHeaderSize;
85   }
86
87   if (original_nal_type == kIdr) {
88     parsed_payload->frame_type = kVideoFrameKey;
89   } else {
90     parsed_payload->frame_type = kVideoFrameDelta;
91   }
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;
100 }
101 }  // namespace
102
103 RtpPacketizerH264::RtpPacketizerH264(FrameType frame_type,
104                                      size_t max_payload_len)
105     : payload_data_(NULL),
106       payload_size_(0),
107       max_payload_len_(max_payload_len),
108       frame_type_(frame_type) {
109 }
110
111 RtpPacketizerH264::~RtpPacketizerH264() {
112 }
113
114 void RtpPacketizerH264::SetPayloadData(
115     const uint8_t* payload_data,
116     size_t payload_size,
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);
123   GeneratePackets();
124 }
125
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);
132       ++i;
133     } else {
134       i = PacketizeStapA(i, fragment_offset, fragment_length);
135     }
136   }
137 }
138
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;
146   size_t fragments =
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,
155                          packet_length,
156                          offset - kNalHeaderSize == fragment_offset,
157                          fragment_length == packet_length,
158                          false,
159                          header));
160     offset += packet_length;
161     fragment_length -= packet_length;
162   }
163 }
164
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,
177                          fragment_length,
178                          aggregated_fragments == 0,
179                          false,
180                          true,
181                          header));
182     payload_size_left -= fragment_length;
183     payload_size_left -= fragment_headers_length;
184
185     // Next fragment.
186     ++fragment_index;
187     if (fragment_index == fragmentation_.fragmentationVectorSize)
188       break;
189     fragment_offset = fragmentation_.fragmentationOffset[fragment_index];
190     fragment_length = fragmentation_.fragmentationLength[fragment_index];
191
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;
199   }
200   packets_.back().last_fragment = true;
201   return fragment_index;
202 }
203
204 bool RtpPacketizerH264::NextPacket(uint8_t* buffer,
205                                    size_t* bytes_to_send,
206                                    bool* last_packet) {
207   *bytes_to_send = 0;
208   if (packets_.empty()) {
209     *bytes_to_send = 0;
210     *last_packet = true;
211     return false;
212   }
213
214   Packet packet = packets_.front();
215
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);
220     packets_.pop();
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_);
225   } else {
226     NextFragmentPacket(buffer, bytes_to_send);
227     assert(*bytes_to_send <= max_payload_len_);
228   }
229   *last_packet = packets_.empty();
230   return true;
231 }
232
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;
246     // Add NAL unit.
247     memcpy(&buffer[index], &payload_data_[packet.offset], packet.size);
248     index += packet.size;
249     *bytes_to_send += packet.size;
250     packets_.pop();
251     if (packet.last_fragment)
252       break;
253     packet = packets_.front();
254   }
255   assert(packet.last_fragment);
256 }
257
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;
266
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;
271   fu_header |= type;
272   buffer[0] = fu_indicator;
273   buffer[1] = fu_header;
274
275   if (packet.last_fragment) {
276     *bytes_to_send = packet.size + kFuAHeaderSize;
277     memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size);
278   } else {
279     *bytes_to_send = packet.size + kFuAHeaderSize;
280     memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size);
281   }
282   packets_.pop();
283 }
284
285 ProtectionType RtpPacketizerH264::GetProtectionType() {
286   return (frame_type_ == kVideoFrameKey) ? kProtectedPacket
287                                          : kUnprotectedPacket;
288 }
289
290 StorageType RtpPacketizerH264::GetStorageType(
291     uint32_t retransmission_settings) {
292   return kAllowRetransmission;
293 }
294
295 std::string RtpPacketizerH264::ToString() {
296   return "RtpPacketizerH264";
297 }
298
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;
304   size_t offset = 0;
305   if (nal_type == kFuA) {
306     // Fragmented NAL units (FU-A).
307     ParseFuaNalu(parsed_payload, payload_data, payload_data_length, &offset);
308   } else {
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);
312   }
313
314   parsed_payload->payload = payload_data + offset;
315   parsed_payload->payload_length = payload_data_length - offset;
316   return true;
317 }
318 }  // namespace webrtc