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(WebRtcRTPHeader* rtp_header, 41 const uint8_t* payload_data, 42 size_t payload_data_length) { 43 rtp_header->type.Video.codec = kRtpVideoH264; 44 rtp_header->type.Video.isFirstPacket = true; 45 RTPVideoHeaderH264* h264_header = &rtp_header->type.Video.codecHeader.H264; 46 h264_header->single_nalu = true; 47 h264_header->stap_a = false; 48 49 uint8_t nal_type = payload_data[0] & kTypeMask; 50 if (nal_type == kStapA) { 51 nal_type = payload_data[3] & kTypeMask; 52 h264_header->stap_a = true; 53 } 54 55 switch (nal_type) { 56 case kSps: 57 case kPps: 58 case kIdr: 59 rtp_header->frameType = kVideoFrameKey; 60 break; 61 default: 62 rtp_header->frameType = kVideoFrameDelta; 63 break; 64 } 65 } 66 67 void ParseFuaNalu(WebRtcRTPHeader* rtp_header, 68 const uint8_t* payload_data, 69 size_t payload_data_length, 70 size_t* offset) { 71 uint8_t fnri = payload_data[0] & (kFBit | kNriMask); 72 uint8_t original_nal_type = payload_data[1] & kTypeMask; 73 bool first_fragment = (payload_data[1] & kSBit) > 0; 74 75 uint8_t original_nal_header = fnri | original_nal_type; 76 if (first_fragment) { 77 *offset = kNalHeaderSize; 78 uint8_t* payload = const_cast<uint8_t*>(payload_data + *offset); 79 payload[0] = original_nal_header; 80 } else { 81 *offset = kFuAHeaderSize; 82 } 83 84 if (original_nal_type == kIdr) { 85 rtp_header->frameType = kVideoFrameKey; 86 } else { 87 rtp_header->frameType = kVideoFrameDelta; 88 } 89 rtp_header->type.Video.codec = kRtpVideoH264; 90 rtp_header->type.Video.isFirstPacket = first_fragment; 91 RTPVideoHeaderH264* h264_header = &rtp_header->type.Video.codecHeader.H264; 92 h264_header->single_nalu = false; 93 h264_header->stap_a = false; 94 } 95 } // namespace 96 97 RtpPacketizerH264::RtpPacketizerH264(FrameType frame_type, 98 size_t max_payload_len) 99 : payload_data_(NULL), 100 payload_size_(0), 101 max_payload_len_(max_payload_len), 102 frame_type_(frame_type) { 103 } 104 105 RtpPacketizerH264::~RtpPacketizerH264() { 106 } 107 108 void RtpPacketizerH264::SetPayloadData( 109 const uint8_t* payload_data, 110 size_t payload_size, 111 const RTPFragmentationHeader* fragmentation) { 112 assert(packets_.empty()); 113 assert(fragmentation); 114 payload_data_ = payload_data; 115 payload_size_ = payload_size; 116 fragmentation_.CopyFrom(*fragmentation); 117 GeneratePackets(); 118 } 119 120 void RtpPacketizerH264::GeneratePackets() { 121 for (size_t i = 0; i < fragmentation_.fragmentationVectorSize;) { 122 size_t fragment_offset = fragmentation_.fragmentationOffset[i]; 123 size_t fragment_length = fragmentation_.fragmentationLength[i]; 124 if (fragment_length > max_payload_len_) { 125 PacketizeFuA(fragment_offset, fragment_length); 126 ++i; 127 } else { 128 i = PacketizeStapA(i, fragment_offset, fragment_length); 129 } 130 } 131 } 132 133 void RtpPacketizerH264::PacketizeFuA(size_t fragment_offset, 134 size_t fragment_length) { 135 // Fragment payload into packets (FU-A). 136 // Strip out the original header and leave room for the FU-A header. 137 fragment_length -= kNalHeaderSize; 138 size_t offset = fragment_offset + kNalHeaderSize; 139 size_t bytes_available = max_payload_len_ - kFuAHeaderSize; 140 size_t fragments = 141 (fragment_length + (bytes_available - 1)) / bytes_available; 142 size_t avg_size = (fragment_length + fragments - 1) / fragments; 143 while (fragment_length > 0) { 144 size_t packet_length = avg_size; 145 if (fragment_length < avg_size) 146 packet_length = fragment_length; 147 uint8_t header = payload_data_[fragment_offset]; 148 packets_.push(Packet(offset, 149 packet_length, 150 offset - kNalHeaderSize == fragment_offset, 151 fragment_length == packet_length, 152 false, 153 header)); 154 offset += packet_length; 155 fragment_length -= packet_length; 156 } 157 } 158 159 int RtpPacketizerH264::PacketizeStapA(size_t fragment_index, 160 size_t fragment_offset, 161 size_t fragment_length) { 162 // Aggregate fragments into one packet (STAP-A). 163 size_t payload_size_left = max_payload_len_; 164 int aggregated_fragments = 0; 165 size_t fragment_headers_length = 0; 166 assert(payload_size_left >= fragment_length); 167 while (payload_size_left >= fragment_length + fragment_headers_length) { 168 assert(fragment_length > 0); 169 uint8_t header = payload_data_[fragment_offset]; 170 packets_.push(Packet(fragment_offset, 171 fragment_length, 172 aggregated_fragments == 0, 173 false, 174 true, 175 header)); 176 payload_size_left -= fragment_length; 177 payload_size_left -= fragment_headers_length; 178 179 // Next fragment. 180 ++fragment_index; 181 if (fragment_index == fragmentation_.fragmentationVectorSize) 182 break; 183 fragment_offset = fragmentation_.fragmentationOffset[fragment_index]; 184 fragment_length = fragmentation_.fragmentationLength[fragment_index]; 185 186 fragment_headers_length = kLengthFieldSize; 187 // If we are going to try to aggregate more fragments into this packet 188 // we need to add the STAP-A NALU header and a length field for the first 189 // NALU of this packet. 190 if (aggregated_fragments == 0) 191 fragment_headers_length += kNalHeaderSize + kLengthFieldSize; 192 ++aggregated_fragments; 193 } 194 packets_.back().last_fragment = true; 195 return fragment_index; 196 } 197 198 bool RtpPacketizerH264::NextPacket(uint8_t* buffer, 199 size_t* bytes_to_send, 200 bool* last_packet) { 201 *bytes_to_send = 0; 202 if (packets_.empty()) { 203 *bytes_to_send = 0; 204 *last_packet = true; 205 return false; 206 } 207 208 Packet packet = packets_.front(); 209 210 if (packet.first_fragment && packet.last_fragment) { 211 // Single NAL unit packet. 212 *bytes_to_send = packet.size; 213 memcpy(buffer, &payload_data_[packet.offset], packet.size); 214 packets_.pop(); 215 assert(*bytes_to_send <= max_payload_len_); 216 } else if (packet.aggregated) { 217 NextAggregatePacket(buffer, bytes_to_send); 218 assert(*bytes_to_send <= max_payload_len_); 219 } else { 220 NextFragmentPacket(buffer, bytes_to_send); 221 assert(*bytes_to_send <= max_payload_len_); 222 } 223 *last_packet = packets_.empty(); 224 return true; 225 } 226 227 void RtpPacketizerH264::NextAggregatePacket(uint8_t* buffer, 228 size_t* bytes_to_send) { 229 Packet packet = packets_.front(); 230 assert(packet.first_fragment); 231 // STAP-A NALU header. 232 buffer[0] = (packet.header & (kFBit | kNriMask)) | kStapA; 233 int index = kNalHeaderSize; 234 *bytes_to_send += kNalHeaderSize; 235 while (packet.aggregated) { 236 // Add NAL unit length field. 237 RtpUtility::AssignUWord16ToBuffer(&buffer[index], packet.size); 238 index += kLengthFieldSize; 239 *bytes_to_send += kLengthFieldSize; 240 // Add NAL unit. 241 memcpy(&buffer[index], &payload_data_[packet.offset], packet.size); 242 index += packet.size; 243 *bytes_to_send += packet.size; 244 packets_.pop(); 245 if (packet.last_fragment) 246 break; 247 packet = packets_.front(); 248 } 249 assert(packet.last_fragment); 250 } 251 252 void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer, 253 size_t* bytes_to_send) { 254 Packet packet = packets_.front(); 255 // NAL unit fragmented over multiple packets (FU-A). 256 // We do not send original NALU header, so it will be replaced by the 257 // FU indicator header of the first packet. 258 uint8_t fu_indicator = (packet.header & (kFBit | kNriMask)) | kFuA; 259 uint8_t fu_header = 0; 260 261 // S | E | R | 5 bit type. 262 fu_header |= (packet.first_fragment ? kSBit : 0); 263 fu_header |= (packet.last_fragment ? kEBit : 0); 264 uint8_t type = packet.header & kTypeMask; 265 fu_header |= type; 266 buffer[0] = fu_indicator; 267 buffer[1] = fu_header; 268 269 if (packet.last_fragment) { 270 *bytes_to_send = packet.size + kFuAHeaderSize; 271 memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size); 272 } else { 273 *bytes_to_send = packet.size + kFuAHeaderSize; 274 memcpy(buffer + kFuAHeaderSize, &payload_data_[packet.offset], packet.size); 275 } 276 packets_.pop(); 277 } 278 279 ProtectionType RtpPacketizerH264::GetProtectionType() { 280 return (frame_type_ == kVideoFrameKey) ? kProtectedPacket 281 : kUnprotectedPacket; 282 } 283 284 StorageType RtpPacketizerH264::GetStorageType( 285 uint32_t retransmission_settings) { 286 return kAllowRetransmission; 287 } 288 289 std::string RtpPacketizerH264::ToString() { 290 return "RtpPacketizerH264"; 291 } 292 293 RtpDepacketizerH264::RtpDepacketizerH264(RtpData* const callback) 294 : callback_(callback) { 295 } 296 297 bool RtpDepacketizerH264::Parse(WebRtcRTPHeader* rtp_header, 298 const uint8_t* payload_data, 299 size_t payload_data_length) { 300 uint8_t nal_type = payload_data[0] & kTypeMask; 301 size_t offset = 0; 302 if (nal_type == kFuA) { 303 // Fragmented NAL units (FU-A). 304 ParseFuaNalu(rtp_header, payload_data, payload_data_length, &offset); 305 } else { 306 // We handle STAP-A and single NALU's the same way here. The jitter buffer 307 // will depacketize the STAP-A into NAL units later. 308 ParseSingleNalu(rtp_header, payload_data, payload_data_length); 309 } 310 if (callback_->OnReceivedPayloadData(payload_data + offset, 311 payload_data_length - offset, 312 rtp_header) != 0) { 313 return false; 314 } 315 return true; 316 } 317 318 } // namespace webrtc 319