Bug 985254: review cleanups from H264 packetization patch r=pkerr
authorRandell Jesup <rjesup@jesup.org>
Sat, 24 May 2014 18:28:01 -0400
changeset 204067 5246ba3954b76a779c44a00695ddccc4913245fc
parent 204066 e88a722da07ec2c30240bd0f6475327686614124
child 204068 d2c1d93b369846c6e8a51d142898eaf14ec474c1
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspkerr
bugs985254
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 985254: review cleanups from H264 packetization patch r=pkerr
media/webrtc/trunk/webrtc/modules/interface/module_common_types.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
media/webrtc/trunk/webrtc/modules/video_coding/codecs/interface/video_codec_interface.h
media/webrtc/trunk/webrtc/modules/video_coding/main/source/internal_defines.h
media/webrtc/trunk/webrtc/modules/video_coding/main/source/packet.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/source/session_info.cc
--- a/media/webrtc/trunk/webrtc/modules/interface/module_common_types.h
+++ b/media/webrtc/trunk/webrtc/modules/interface/module_common_types.h
@@ -86,18 +86,18 @@ struct RTPVideoHeaderVP8
                                    // Disabled if temporalIdx == kNoTemporalIdx.
     int            keyIdx;         // 5 bits; kNoKeyIdx means not used.
     int            partitionId;    // VP8 partition ID
     bool           beginningOfPartition;  // True if this packet is the first
                                           // in a VP8 partition. Otherwise false
 };
 
 struct RTPVideoHeaderH264 {
-  unsigned char nalu_header;
-  bool          single_nalu;
+  uint8_t nalu_header;
+  bool    single_nalu;
 };
 
 union RTPVideoTypeHeader
 {
     RTPVideoHeaderVP8       VP8;
     RTPVideoHeaderH264 H264;
 };
 
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
@@ -1,10 +1,10 @@
 /*
- *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
@@ -23,57 +23,70 @@ RtpFormatH264::RtpFormatH264(const uint8
       max_payload_len_(static_cast<int>(max_payload_len)),
       fragments_(0),
       fragment_size_(0),
       next_fragment_(-1) {
   if (payload_size_ <= max_payload_len_) {
     fragments_ = 0;
   } else {
     fragment_size_ = max_payload_len_ - kH264FUAHeaderLengthInBytes;
-    fragments_ = (payload_size_ - kH264NALHeaderLengthInBytes) / fragment_size_;
-    if (fragments_ * fragment_size_ !=
-        (payload_size_ - kH264NALHeaderLengthInBytes)) {
-      ++fragments_;
-    }
+    fragments_ = ((payload_size_ - kH264NALHeaderLengthInBytes) + (fragment_size_-1)) /
+                 fragment_size_;
     next_fragment_ = 0;
   }
 }
 
 RtpFormatH264::~RtpFormatH264() {
 }
 
 int RtpFormatH264::NextPacket(uint8_t* buffer,
                               int* bytes_to_send,
                               bool* last_packet) {
   if (next_fragment_ == fragments_) {
     *bytes_to_send = 0;
     *last_packet   = true;
     return -1;
   }
 
+  // TODO(jesup) This supports Mode 1 packetization only
+
+  // For mode 0, it's all single-NAL, and maybe deal with that by simply
+  // setting a large max_payload_len when constructing this (and tell the
+  // codec to keep generated NAL sizes less than one packet).  If the codec
+  // goes over, a fragmented RTP packet would be sent (and may work or not).
+  uint8_t header = payload_data_[0];
+  uint8_t type   = header & kH264NAL_TypeMask;
   if (payload_size_ <= max_payload_len_) {
     // single NAL_UNIT
     *bytes_to_send = payload_size_;
-    *last_packet   = false;
+    // TODO(jesup) - this doesn't work correctly for Mode 0.
+    // Unfortunately, we don't have a good signal to which NAL generated by
+    // the encoder is the last NAL of the frame.  We need that to be passed
+    // through to this point, instead of trying to generate it from the packets
+    if (type == kH264NALU_SPS || type == kH264NALU_PPS ||
+        type == kH264NALU_SEI) {
+      *last_packet   = false;
+    } else {
+      *last_packet   = true;
+    }
     memcpy(buffer, payload_data_, payload_size_);
     WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
                  "RtpFormatH264(single NALU with type:%d, payload_size:%d",
-                 payload_data_[0] & 0x1F, payload_size_);
+                 type, payload_size_);
     return 0;
   } else {
-    unsigned char header = payload_data_[0];
-    unsigned char type   = header & 0x1F;
-    unsigned char fu_indicator = (header & 0xE0) | kH264FUANALUType;
-    unsigned char fu_header = 0;
+    uint8_t fu_indicator = (header & (kH264NAL_FBit | kH264NAL_NRIMask)) |
+                           kH264NALU_FUA;
+    uint8_t fu_header = 0;
     bool first_fragment = (next_fragment_ == 0);
     bool last_fragment = (next_fragment_ == (fragments_ -1));
 
     // S | E | R | 5 bit type.
-    fu_header |= (first_fragment ? 128 : 0);  // S bit
-    fu_header |= (last_fragment ? 64 :0);  // E bit
+    fu_header |= (first_fragment ? kH264FU_SBit : 0);
+    fu_header |= (last_fragment ? kH264FU_EBit :0);
     fu_header |= type;
     buffer[0] = fu_indicator;
     buffer[1] = fu_header;
 
     if (last_fragment) {
       // last fragment
       *bytes_to_send = payload_size_ -
                        kH264NALHeaderLengthInBytes -
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h
@@ -1,10 +1,10 @@
  /*
-  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
 
@@ -30,22 +30,40 @@
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
 
 // Packetizer for H264.
 class RtpFormatH264 {
  public:
   enum {
-    kH264NALHeaderLengthInBytes = 1,
-    kH264FUAHeaderLengthInBytes = 2,
-    kH264FUANALUType            = 28,
+    kH264NALU_SLICE             = 1,
+    kH264NALU_IDR               = 5,
+    kH264NALU_SEI               = 6,
     kH264NALU_SPS               = 7,
     kH264NALU_PPS               = 8,
-    kH264NALU_IDR               = 5
+    kH264NALU_STAPA             = 24,
+    kH264NALU_FUA               = 28
+  };
+
+  static const int kH264NALHeaderLengthInBytes = 1;
+  static const int kH264FUAHeaderLengthInBytes = 2;
+
+// bits for FU (A and B) indicators
+  enum H264NalDefs {
+    kH264NAL_FBit = 0x80,
+    kH264NAL_NRIMask = 0x60,
+    kH264NAL_TypeMask = 0x1F
+  };
+
+  enum H264FUDefs {
+    // bits for FU (A and B) headers
+    kH264FU_SBit = 0x80,
+    kH264FU_EBit = 0x40,
+    kH264FU_RBit = 0x20
   };
 
   // Initialize with payload from encoder.
   // The payload_data must be exactly one encoded H264 frame.
   RtpFormatH264(const uint8_t* payload_data,
                 uint32_t payload_size,
                 int max_payload_len);
 
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc
@@ -224,27 +224,28 @@ int32_t RTPReceiverVideo::ReceiveVp8Code
 }
 
 int32_t RTPReceiverVideo::ReceiveH264Codec(WebRtcRTPHeader* rtp_header,
                                           const uint8_t* payload_data,
                                           uint16_t payload_data_length) {
   // real payload
   uint8_t* payload;
   uint16_t payload_length;
-  unsigned char nal_type = payload_data[0] & 0x1F;
+  uint8_t nal_type = payload_data[0] & RtpFormatH264::kH264NAL_TypeMask;
 
   // Note: This code handles only FU-A and single NALU mode packets.
-  if (nal_type == RtpFormatH264::kH264FUANALUType) {
+  if (nal_type == RtpFormatH264::kH264NALU_FUA) {
     // Fragmentation
-    unsigned char fnri = payload_data[0] & 0xE0;
-    unsigned char original_nal_type = payload_data[1] & 0x1F;
-    bool first_fragment = (payload_data[1] & 0x80) >> 7;
-    //bool last_fragment = (payload_data[1] & 0x40) >> 6;
+    uint8_t fnri = payload_data[0] & 
+                   (RtpFormatH264::kH264NAL_FBit | RtpFormatH264::kH264NAL_NRIMask);
+    uint8_t original_nal_type = payload_data[1] & RtpFormatH264::kH264NAL_TypeMask;
+    bool first_fragment = !!(payload_data[1] & RtpFormatH264::kH264FU_SBit);
+    //bool last_fragment = !!(payload_data[1] & RtpFormatH264::kH264FU_EBit);
 
-    unsigned char original_nal_header = fnri | original_nal_type;
+    uint8_t original_nal_header = fnri | original_nal_type;
     if (first_fragment) {
       payload = const_cast<uint8_t*> (payload_data) +
           RtpFormatH264::kH264NALHeaderLengthInBytes;
       payload[0] = original_nal_header;
       payload_length = payload_data_length -
           RtpFormatH264::kH264NALHeaderLengthInBytes;
     } else {
       payload = const_cast<uint8_t*> (payload_data)  +
@@ -271,18 +272,17 @@ int32_t RTPReceiverVideo::ReceiveH264Cod
 
     rtp_header->type.Video.codec    = kRtpVideoH264;
     rtp_header->type.Video.isFirstPacket = true; // First packet
     RTPVideoHeaderH264* h264_header = &rtp_header->type.Video.codecHeader.H264;
     h264_header->nalu_header        = payload_data[0];
     h264_header->single_nalu        = true;
 
     // WebRtcRTPHeader
-    if (nal_type == RtpFormatH264::kH264NALU_SPS ||
-        nal_type == RtpFormatH264::kH264NALU_PPS) {
+    if (nal_type == RtpFormatH264::kH264NALU_IDR) {
       rtp_header->frameType = kVideoFrameKey;
       rtp_header->type.Video.isFirstPacket = false;
     } else {
       rtp_header->frameType = kVideoFrameDelta;
     }
   }
 
   if (data_callback_->OnReceivedPayloadData(payload,
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -523,21 +523,16 @@ int32_t RTPSenderVideo::SendH264(const F
     // Write RTP header.
     // Set marker bit true if this is the last packet in frame.
     _rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
                               captureTimeStamp, capture_time_ms);
     if (-1 == SendVideoPacket(dataBuffer, payloadBytesInPacket,
                               rtpHeaderLength, captureTimeStamp,
                               capture_time_ms, storage, protect)) {
     }
-
-    if (ret_val == 0) {
-      // single NAL unit
-      last = true;
-    }
   }
   return 0;
 }
 
 void RTPSenderVideo::ProcessBitrate() {
   _videoBitrate.Process();
   _fecOverheadRate.Process();
 }
--- a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/interface/video_codec_interface.h
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/interface/video_codec_interface.h
@@ -43,18 +43,19 @@ struct CodecSpecificInfoVP8
     int8_t     keyIdx;            // negative value to skip keyIdx
 };
 
 struct CodecSpecificInfoGeneric {
   uint8_t simulcast_idx;
 };
 
 struct CodecSpecificInfoH264 {
-  unsigned char nalu_header;
-  bool          single_nalu;
+  uint8_t nalu_header;
+  bool    single_nalu;
+  uint8_t simulcastIdx;
 };
 
 union CodecSpecificInfoUnion {
     CodecSpecificInfoGeneric   generic;
     CodecSpecificInfoVP8       VP8;
     CodecSpecificInfoH264      H264;
 };
 
--- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/internal_defines.h
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/internal_defines.h
@@ -35,19 +35,19 @@ inline uint32_t MaskWord64ToUWord32(int6
 // Helper macros for creating the static codec list
 #define VCM_NO_CODEC_IDX -1
 #ifdef VIDEOCODEC_VP8
   #define VCM_VP8_IDX VCM_NO_CODEC_IDX + 1
 #else
   #define VCM_VP8_IDX VCM_NO_CODEC_IDX
 #endif
 #ifdef VIDEOCODEC_I420
-  #define VCM_I420_IDX VIDEOCODEC_VP8 + 1
+  #define VCM_I420_IDX VCM_VP8_IDX + 1
 #else
-  #define VCM_I420_IDX VIDEOCODEC_VP8
+  #define VCM_I420_IDX VCM_VP8_IDX
 #endif
 #define VCM_NUM_VIDEO_CODECS_AVAILABLE VCM_I420_IDX + 1
 
 #define VCM_NO_RECEIVER_ID 0
 
 inline int32_t VCMId(const int32_t vcmId, const int32_t receiverId = 0)
 {
     return static_cast<int32_t>((vcmId << 16) + receiverId);
--- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/packet.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/packet.cc
@@ -105,17 +105,17 @@ void VCMPacket::CopyCodecSpecifics(const
           completeNALU = kNaluEnd;
       else
           completeNALU = kNaluIncomplete;
 
       codec = kVideoCodecVP8;
       break;
     }
     case kRtpVideoH264: {
-      unsigned char nal_type = videoHeader.codecHeader.H264.nalu_header & 0x1F;
+      uint8_t nal_type = videoHeader.codecHeader.H264.nalu_header & RtpFormatH264::kH264NAL_TypeMask;
       if (videoHeader.codecHeader.H264.single_nalu) {
         if (nal_type == RtpFormatH264::kH264NALU_SPS ||
             nal_type == RtpFormatH264::kH264NALU_PPS) {
           insertStartCode = true;
           isFirstPacket   = false;
           markerBit       = false;
         } else {
           isFirstPacket   = true;
--- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/session_info.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/session_info.cc
@@ -132,17 +132,17 @@ int VCMSessionInfo::InsertBuffer(uint8_t
   // Set the data pointer to pointing to the start of this packet in the
   // frame buffer.
   const uint8_t* data = packet.dataPtr;
   packet.dataPtr = frame_buffer + offset;
   packet.sizeBytes = packet_size;
 
   ShiftSubsequentPackets(packet_it, packet_size);
 
-  const unsigned char startCode[] = {0, 0, 0, 1};
+  const uint8_t startCode[] = {0, 0, 0, 1};
   if (packet.insertStartCode) {
     memcpy(const_cast<uint8_t*>(packet.dataPtr), startCode,
            kH264StartCodeLengthBytes);
   }
   memcpy(const_cast<uint8_t*>(packet.dataPtr
       + (packet.insertStartCode ? kH264StartCodeLengthBytes : 0)),
       data,
       packet.sizeBytes);
@@ -417,17 +417,17 @@ int VCMSessionInfo::InsertPacket(const V
   // Check for duplicate packets.
   if (rit != packets_.rend() &&
       (*rit).seqNum == packet.seqNum && (*rit).sizeBytes > 0)
     return -2;
 
   PacketIterator packet_list_it;
   if (packet.codec == kVideoCodecH264) {
     RTPVideoHeaderH264 h264 = packet.codecSpecificHeader.codecHeader.H264;
-    unsigned char nal_type = h264.nalu_header & 0x1F;
+    uint8_t nal_type = h264.nalu_header & RtpFormatH264::kH264NAL_TypeMask;
     bool potential_start = false;
     if (nal_type == RtpFormatH264::kH264NALU_SPS ||
         nal_type == RtpFormatH264::kH264NALU_PPS ||
         packet.codecSpecificHeader.codecHeader.H264.single_nalu) {
       potential_start = true;
     } else {
       potential_start = packet.isFirstPacket;
     }
@@ -439,18 +439,18 @@ int VCMSessionInfo::InsertPacket(const V
       }
     }
 
     // Track the marker bit, should only be set for one packet per session.
     if (packet.markerBit && last_packet_seq_num_ == -1) {
       last_packet_seq_num_ = static_cast<int>(packet.seqNum);
     } else if (last_packet_seq_num_ != -1 &&
       IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_)) {
-      LOG(LS_WARNING) << "Received packet with a sequence number which is out "
-                       " of frame boundaries";
+      //LOG(LS_WARNING) << "Received packet with a sequence number which is out "
+      //                 " of frame boundaries";
       return -3;
     }
 
     if (first_packet_seq_num_ == packet.seqNum &&
         packet.completeNALU != kNaluComplete) {
       VCMPacket& npacket = const_cast<VCMPacket&> (packet);
       npacket.isFirstPacket = true;
       npacket.completeNALU = kNaluStart;
@@ -467,32 +467,32 @@ int VCMSessionInfo::InsertPacket(const V
     // Should only be set for one packet per session.
     if (packet.isFirstPacket && first_packet_seq_num_ == -1) {
       // The first packet in a frame signals the frame type.
       frame_type_ = packet.frameType;
       // Store the sequence number for the first packet.
       first_packet_seq_num_ = static_cast<int>(packet.seqNum);
     } else if (first_packet_seq_num_ != -1 &&
       !IsNewerSequenceNumber(packet.seqNum, first_packet_seq_num_)) {
-      LOG(LS_WARNING) << "Received packet with a sequence number which is out "
-                       "of frame boundaries";
+      //LOG(LS_WARNING) << "Received packet with a sequence number which is out "
+      //                 "of frame boundaries";
       return -3;
     } else if (frame_type_ == kFrameEmpty && packet.frameType != kFrameEmpty) {
       // Update the frame type with the type of the first media packet.
       // TODO(mikhal): Can this trigger?
       frame_type_ = packet.frameType;
     }
 
     // Track the marker bit, should only be set for one packet per session.
     if (packet.markerBit && last_packet_seq_num_ == -1) {
       last_packet_seq_num_ = static_cast<int>(packet.seqNum);
     } else if (last_packet_seq_num_ != -1 &&
         IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_)) {
-      LOG(LS_WARNING) << "Received packet with a sequence number which is out "
-                       "of frame boundaries";
+      //LOG(LS_WARNING) << "Received packet with a sequence number which is out "
+      //                 "of frame boundaries";
       return -3;
     }
 
     // The insert operation invalidates the iterator |rit|.
     packet_list_it = packets_.insert(rit.base(), packet);
   }
 
   int returnLength = InsertBuffer(frame_buffer, packet_list_it);