Bug 1036049 - Support H.264 STAP-A depacketization in webrtc. r=ehugg, a=2.0+
authorRandell Jesup <rjesup@jesup.org>
Fri, 11 Jul 2014 01:48:14 -0400
changeset 208970 d4d12cf51c497bf5db595f4967d93044bc068cb6
parent 208969 83c99da37fe31c49fcdca44b46392ea43eaf6782
child 208971 e79e3269116d7147737d3e2d03e8bb5c261fb9fe
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehugg, 2
bugs1036049
milestone32.0a2
Bug 1036049 - Support H.264 STAP-A depacketization in webrtc. r=ehugg, a=2.0+
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];