Home | History | Annotate | Download | only in source
      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