Bug 1036049: Support H.264 STAP-A depacketization in webrtc r=ehugg
authorRandell Jesup <rjesup@jesup.org>
Fri, 11 Jul 2014 01:48:14 -0400
changeset 193455 2bdf8a5472ce8815c4bf8450803c4c67043a6d13
parent 193454 e08b171b9a02ddafd725b2b772d5a3209fea6637
child 193456 91d7659bb35145e10ff737753688e0972c1a79b5
push id46107
push userrjesup@wgate.com
push dateFri, 11 Jul 2014 05:50:31 +0000
treeherdermozilla-inbound@2bdf8a5472ce [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehugg
bugs1036049
milestone33.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 1036049: Support H.264 STAP-A depacketization in webrtc r=ehugg
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc
--- 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
@@ -5,16 +5,23 @@
  *  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.
  */
 
 #include <string.h>  // memcpy
 
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+#ifdef WEBRTC_LINUX
+#include <netinet/in.h>
+#endif
+
 #include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
 #include "webrtc/system_wrappers/interface/trace.h"
 
 namespace webrtc {
 
 RtpFormatH264::RtpFormatH264(const uint8_t* payload_data,
                              uint32_t payload_size,
                              int max_payload_len)
@@ -50,16 +57,39 @@ int RtpFormatH264::NextPacket(uint8_t* b
 
   // 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_) {
+//#define TEST_STAP_A
+#ifdef TEST_STAP_A
+    static uint8_t sps_buffer[256];
+    static uint32_t sps_size;
+    if (type == kH264NALU_SPS) {
+
+      sps_buffer[0] = kH264NALU_STAPA;
+      *(reinterpret_cast<uint16_t*>(&sps_buffer[1])) = htons(payload_size_); // include NAL byte
+      memcpy(&sps_buffer[1 + sizeof(uint16_t)], payload_data_, payload_size_);
+      sps_size = 1 + sizeof(uint16_t) + payload_size_;
+      *bytes_to_send = 0;
+      return -1;
+    } else if (type == kH264NALU_PPS && sps_size != 0) {
+      // Send a STAP-A of SPS/PPS
+      *(reinterpret_cast<uint16_t*>(&sps_buffer[sps_size])) = htons(payload_size_);
+      memcpy(&sps_buffer[sps_size + sizeof(uint16_t)], payload_data_, payload_size_);
+      memcpy(buffer, sps_buffer, sps_size + 2 + payload_size_);
+      *bytes_to_send = sps_size + 2 + payload_size_;
+      sps_size = 0;
+      *last_packet   = false;
+      return 0;
+    }
+#endif
     // single NAL_UNIT
     *bytes_to_send = payload_size_;
     // 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) {
--- 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
@@ -8,16 +8,23 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
 
 #include <assert.h>
 #include <string.h>
 
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+#ifdef WEBRTC_LINUX
+#include <netinet/in.h>
+#endif
+
 #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/trace.h"
 #include "webrtc/system_wrappers/interface/trace_event.h"
 
@@ -260,17 +267,65 @@ int32_t RTPReceiverVideo::ReceiveH264Cod
     } else {
       rtp_header->frameType = kVideoFrameDelta;
     }
     rtp_header->type.Video.codec    = kRtpVideoH264;
     rtp_header->type.Video.isFirstPacket = first_fragment;
     RTPVideoHeaderH264* h264_header = &rtp_header->type.Video.codecHeader.H264;
     h264_header->nalu_header        = original_nal_header;
     h264_header->single_nalu        = false;
+
+  } else if (nal_type == RtpFormatH264::kH264NALU_STAPA) {
+
+    payload = const_cast<uint8_t*> (payload_data) +
+              RtpFormatH264::kH264NALHeaderLengthInBytes;
+    size_t size = payload_data_length -
+                  RtpFormatH264::kH264NALHeaderLengthInBytes;
+    uint32_t timestamp = rtp_header->header.timestamp;
+    rtp_header->type.Video.codec    = kRtpVideoH264;
+    rtp_header->type.Video.isFirstPacket = true;
+    RTPVideoHeaderH264* h264_header = &rtp_header->type.Video.codecHeader.H264;
+    h264_header->single_nalu        = true;
+
+    while (size > 0) {
+      payload_length = ntohs(*(reinterpret_cast<uint16_t*>(payload)));
+      // payload_length includes the NAL type byte
+      payload += sizeof(uint16_t); // points to NAL byte and then N bytes of NAL data
+      h264_header->nalu_header        = payload[0];
+      switch (*payload & RtpFormatH264::kH264NAL_TypeMask) {
+        case RtpFormatH264::kH264NALU_SPS:
+          // TODO(jesup): Evil hack.  see below
+          rtp_header->header.timestamp = timestamp - 20;
+          rtp_header->frameType = kVideoFrameKey;
+          break;
+        case RtpFormatH264::kH264NALU_PPS:
+          // TODO(jesup): Evil hack.  see below
+          rtp_header->header.timestamp = timestamp - 10;
+          rtp_header->frameType = kVideoFrameKey;
+          break;
+        case RtpFormatH264::kH264NALU_IDR:
+          rtp_header->frameType = kVideoFrameKey;
+          break;
+        default:
+          rtp_header->frameType = kVideoFrameDelta;
+          break;
+      }
+      if (data_callback_->OnReceivedPayloadData(payload,
+                                                payload_length,
+                                                rtp_header) != 0) {
+        return -1;
+      }
+      payload += payload_length;
+      assert(size >= sizeof(uint16_t) + payload_length);
+      size -= sizeof(uint16_t) + payload_length;
+    }
+    return 0;
+
   } else {
+
     // single NALU
     payload = const_cast<uint8_t*> (payload_data);
     payload_length = payload_data_length;
 
     rtp_header->type.Video.codec    = kRtpVideoH264;
     rtp_header->type.Video.isFirstPacket = true;
     RTPVideoHeaderH264* h264_header = &rtp_header->type.Video.codecHeader.H264;
     h264_header->nalu_header        = payload_data[0];