Implement H.264 packetization mode 0.

This approach extends the H.264 specific information with
a packetization mode enum.

Status: Parameter is in code. No way to set it yet.

Rebase of CL  2009213002

BUG=600254

Review-Url: https://codereview.webrtc.org/2337453002
Cr-Commit-Position: refs/heads/master@{#15032}
diff --git a/webrtc/api/android/jni/androidmediaencoder_jni.cc b/webrtc/api/android/jni/androidmediaencoder_jni.cc
index 92b5aae..d575d8c 100644
--- a/webrtc/api/android/jni/androidmediaencoder_jni.cc
+++ b/webrtc/api/android/jni/androidmediaencoder_jni.cc
@@ -1113,6 +1113,9 @@
           info.codecSpecific.VP9.height[0] = height_;
           info.codecSpecific.VP9.gof.CopyGofInfoVP9(gof_);
         }
+      } else if (codecType_ == kVideoCodecH264) {
+        info.codecSpecific.H264.packetization_mode =
+            webrtc::kH264PacketizationMode1;
       }
       picture_id_ = (picture_id_ + 1) & 0x7FFF;
 
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index 24ba00a..e470b43 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -540,9 +540,18 @@
 };
 
 // H264 specific.
+enum H264PacketizationMode {
+  // Because VideoCodecH264 was initialized in multiple places using memset,
+  // we let 0 have the meaning of "not set".
+  kH264PacketizationModeNotSet = 0,
+  kH264PacketizationMode0,  // Only single NALU allowed
+  kH264PacketizationMode1   // Non-interleaved - STAP-A, FU-A is allowed
+};
+
 struct VideoCodecH264 {
   bool frameDroppingOn;
   int keyFrameInterval;
+  H264PacketizationMode packetization_mode;
   // These are NULL/0 if not externally negotiated.
   const uint8_t* spsData;
   size_t spsLen;
diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn
index 8321bcd..1279af1 100644
--- a/webrtc/modules/BUILD.gn
+++ b/webrtc/modules/BUILD.gn
@@ -542,6 +542,10 @@
           [ "video_coding/codecs/vp9/vp9_screenshare_layers_unittest.cc" ]
     }
 
+    if (rtc_use_h264) {
+      sources += [ "video_coding/codecs/h264/h264_encoder_impl_unittest.cc" ]
+    }
+
     if (rtc_desktop_capture_supported || is_android) {
       deps += [ "desktop_capture" ]
       sources += [
diff --git a/webrtc/modules/include/module_common_types.h b/webrtc/modules/include/module_common_types.h
index a5ea5c8..bd70573 100644
--- a/webrtc/modules/include/module_common_types.h
+++ b/webrtc/modules/include/module_common_types.h
@@ -273,14 +273,19 @@
 const size_t kMaxNalusPerPacket = 10;
 
 struct RTPVideoHeaderH264 {
-  uint8_t nalu_type;  // The NAL unit type. If this is a header for a
-                      // fragmented packet, it's the NAL unit type of
-                      // the original data. If this is the header for an
-                      // aggregated packet, it's the NAL unit type of
-                      // the first NAL unit in the packet.
+  // The NAL unit type. If this is a header for a
+  // fragmented packet, it's the NAL unit type of
+  // the original data. If this is the header for an
+  // aggregated packet, it's the NAL unit type of
+  // the first NAL unit in the packet.
+  uint8_t nalu_type;
+  // The packetization type of this buffer - single, aggregated or fragmented.
   H264PacketizationTypes packetization_type;
   NaluInfo nalus[kMaxNalusPerPacket];
   size_t nalus_length;
+  // The packetization mode of this transport. Packetization mode
+  // determines which packetization types are allowed when packetizing.
+  H264PacketizationMode packetization_mode;
 };
 
 union RTPVideoTypeHeader {
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format.cc b/webrtc/modules/rtp_rtcp/source/rtp_format.cc
index cdb9c49..c9800f7 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_format.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_format.cc
@@ -8,6 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <utility>
+
 #include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
 
 #include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
@@ -22,7 +24,9 @@
                                      FrameType frame_type) {
   switch (type) {
     case kRtpVideoH264:
-      return new RtpPacketizerH264(frame_type, max_payload_len);
+      assert(rtp_type_header != NULL);
+      return new RtpPacketizerH264(max_payload_len,
+                                   rtp_type_header->H264.packetization_mode);
     case kRtpVideoVp8:
       assert(rtp_type_header != NULL);
       return new RtpPacketizerVp8(rtp_type_header->VP8, max_payload_len);
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
index b32e78e..395506d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc
@@ -77,9 +77,10 @@
 
 }  // namespace
 
-RtpPacketizerH264::RtpPacketizerH264(FrameType frame_type,
-                                     size_t max_payload_len)
-    : max_payload_len_(max_payload_len) {}
+RtpPacketizerH264::RtpPacketizerH264(size_t max_payload_len,
+                                     H264PacketizationMode packetization_mode)
+    : max_payload_len_(max_payload_len),
+      packetization_mode_(packetization_mode) {}
 
 RtpPacketizerH264::~RtpPacketizerH264() {
 }
@@ -162,11 +163,17 @@
 
 void RtpPacketizerH264::GeneratePackets() {
   for (size_t i = 0; i < input_fragments_.size();) {
-    if (input_fragments_[i].length > max_payload_len_) {
-      PacketizeFuA(i);
+    if (packetization_mode_ == kH264PacketizationMode0) {
+      PacketizeSingleNalu(i);
       ++i;
     } else {
-      i = PacketizeStapA(i);
+      RTC_CHECK_EQ(packetization_mode_, kH264PacketizationMode1);
+      if (input_fragments_[i].length > max_payload_len_) {
+        PacketizeFuA(i);
+        ++i;
+      } else {
+        i = PacketizeStapA(i);
+      }
     }
   }
 }
@@ -229,6 +236,16 @@
   return fragment_index;
 }
 
+void RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) {
+  // Add a single NALU to the queue, no aggregation.
+  size_t payload_size_left = max_payload_len_;
+  const Fragment* fragment = &input_fragments_[fragment_index];
+  RTC_CHECK_GE(payload_size_left, fragment->length);
+  RTC_CHECK_GT(fragment->length, 0u);
+  packets_.push(PacketUnit(*fragment, true /* first */, true /* last */,
+                           false /* aggregated */, fragment->buffer[0]));
+}
+
 bool RtpPacketizerH264::NextPacket(uint8_t* buffer,
                                    size_t* bytes_to_send,
                                    bool* last_packet) {
@@ -249,9 +266,11 @@
     input_fragments_.pop_front();
     RTC_CHECK_LE(*bytes_to_send, max_payload_len_);
   } else if (packet.aggregated) {
+    RTC_CHECK_EQ(packetization_mode_, kH264PacketizationMode1);
     NextAggregatePacket(buffer, bytes_to_send);
     RTC_CHECK_LE(*bytes_to_send, max_payload_len_);
   } else {
+    RTC_CHECK_EQ(packetization_mode_, kH264PacketizationMode1);
     NextFragmentPacket(buffer, bytes_to_send);
     RTC_CHECK_LE(*bytes_to_send, max_payload_len_);
   }
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h
index 9cf3150..527599e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h
@@ -12,6 +12,7 @@
 #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_
 
 #include <deque>
+#include <memory>
 #include <queue>
 #include <string>
 
@@ -25,7 +26,8 @@
  public:
   // Initialize with payload from encoder.
   // The payload_data must be exactly one encoded H264 frame.
-  RtpPacketizerH264(FrameType frame_type, size_t max_payload_len);
+  RtpPacketizerH264(size_t max_payload_len,
+                    H264PacketizationMode packetization_mode);
 
   virtual ~RtpPacketizerH264();
 
@@ -89,10 +91,12 @@
   void GeneratePackets();
   void PacketizeFuA(size_t fragment_index);
   size_t PacketizeStapA(size_t fragment_index);
+  void PacketizeSingleNalu(size_t fragment_index);
   void NextAggregatePacket(uint8_t* buffer, size_t* bytes_to_send);
   void NextFragmentPacket(uint8_t* buffer, size_t* bytes_to_send);
 
   const size_t max_payload_len_;
+  const H264PacketizationMode packetization_mode_;
   std::deque<Fragment> input_fragments_;
   std::queue<PacketUnit> packets_;
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
index 894415d..d70ec5f 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
@@ -43,6 +43,14 @@
 // Bit masks for FU (A and B) headers.
 enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
 
+RtpPacketizer* CreateH264Packetizer(H264PacketizationMode mode,
+                                    size_t max_payload_size) {
+  RTPVideoTypeHeader type_header;
+  type_header.H264.packetization_mode = mode;
+  return RtpPacketizer::Create(kRtpVideoH264, max_payload_size, &type_header,
+                               kEmptyFrame);
+}
+
 void VerifyFua(size_t fua_index,
                const uint8_t* expected_payload,
                int offset,
@@ -84,8 +92,8 @@
   fragmentation.VerifyAndAllocateFragmentationHeader(1);
   fragmentation.fragmentationOffset[0] = 0;
   fragmentation.fragmentationLength[0] = frame_size;
-  std::unique_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create(
-      kRtpVideoH264, max_payload_size, NULL, kEmptyFrame));
+  std::unique_ptr<RtpPacketizer> packetizer(
+      CreateH264Packetizer(kH264PacketizationMode1, max_payload_size));
   packetizer->SetPayloadData(frame.get(), frame_size, &fragmentation);
 
   std::unique_ptr<uint8_t[]> packet(new uint8_t[max_payload_size]);
@@ -152,14 +160,19 @@
 }
 }  // namespace
 
-TEST(RtpPacketizerH264Test, TestSingleNalu) {
+// Tests that should work with both packetization mode 0 and
+// packetization mode 1.
+class RtpPacketizerH264ModeTest
+    : public ::testing::TestWithParam<H264PacketizationMode> {};
+
+TEST_P(RtpPacketizerH264ModeTest, TestSingleNalu) {
   const uint8_t frame[2] = {0x05, 0xFF};  // F=0, NRI=0, Type=5.
   RTPFragmentationHeader fragmentation;
   fragmentation.VerifyAndAllocateFragmentationHeader(1);
   fragmentation.fragmentationOffset[0] = 0;
   fragmentation.fragmentationLength[0] = sizeof(frame);
   std::unique_ptr<RtpPacketizer> packetizer(
-      RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
+      CreateH264Packetizer(GetParam(), kMaxPayloadSize));
   packetizer->SetPayloadData(frame, sizeof(frame), &fragmentation);
   uint8_t packet[kMaxPayloadSize] = {0};
   size_t length = 0;
@@ -167,12 +180,12 @@
   ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
   EXPECT_EQ(2u, length);
   EXPECT_TRUE(last);
-  VerifySingleNaluPayload(
-      fragmentation, 0, frame, sizeof(frame), packet, length);
+  VerifySingleNaluPayload(fragmentation, 0, frame, sizeof(frame), packet,
+                          length);
   EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
 }
 
-TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) {
+TEST_P(RtpPacketizerH264ModeTest, TestSingleNaluTwoPackets) {
   const size_t kFrameSize = kMaxPayloadSize + 100;
   uint8_t frame[kFrameSize] = {0};
   for (size_t i = 0; i < kFrameSize; ++i)
@@ -188,7 +201,7 @@
   frame[fragmentation.fragmentationOffset[1]] = 0x01;
 
   std::unique_ptr<RtpPacketizer> packetizer(
-      RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
+      CreateH264Packetizer(GetParam(), kMaxPayloadSize));
   packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
 
   uint8_t packet[kMaxPayloadSize] = {0};
@@ -206,6 +219,11 @@
   EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
 }
 
+INSTANTIATE_TEST_CASE_P(PacketMode,
+                        RtpPacketizerH264ModeTest,
+                        ::testing::Values(kH264PacketizationMode0,
+                                          kH264PacketizationMode1));
+
 TEST(RtpPacketizerH264Test, TestStapA) {
   const size_t kFrameSize =
       kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize;
@@ -225,7 +243,7 @@
   fragmentation.fragmentationLength[2] =
       kNalHeaderSize + kFrameSize - kPayloadOffset;
   std::unique_ptr<RtpPacketizer> packetizer(
-      RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
+      CreateH264Packetizer(kH264PacketizationMode1, kMaxPayloadSize));
   packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
 
   uint8_t packet[kMaxPayloadSize] = {0};
@@ -242,6 +260,39 @@
   EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
 }
 
+TEST(RtpPacketizerH264Test, TestMode0HasNoStapA) {
+  // This is the same setup as for the TestStapA test.
+  const size_t kFrameSize =
+      kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize;
+  uint8_t frame[kFrameSize] = {0x07, 0xFF,  // F=0, NRI=0, Type=7 (SPS).
+                               0x08, 0xFF,  // F=0, NRI=0, Type=8 (PPS).
+                               0x05};       // F=0, NRI=0, Type=5 (IDR).
+  const size_t kPayloadOffset = 5;
+  for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i)
+    frame[i + kPayloadOffset] = i;
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(3);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = 2;
+  fragmentation.fragmentationOffset[1] = 2;
+  fragmentation.fragmentationLength[1] = 2;
+  fragmentation.fragmentationOffset[2] = 4;
+  fragmentation.fragmentationLength[2] =
+      kNalHeaderSize + kFrameSize - kPayloadOffset;
+  std::unique_ptr<RtpPacketizer> packetizer(
+      CreateH264Packetizer(kH264PacketizationMode0, kMaxPayloadSize));
+  packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
+
+  uint8_t packet[kMaxPayloadSize] = {0};
+  size_t length = 0;
+  bool last = false;
+  // The three fragments should be returned as three packets.
+  ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
+  ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
+  ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
+  EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
+}
+
 TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) {
   const size_t kFrameSize = kMaxPayloadSize - 1;
   uint8_t frame[kFrameSize] = {0x07, 0xFF,  // F=0, NRI=0, Type=7.
@@ -260,7 +311,7 @@
   fragmentation.fragmentationLength[2] =
       kNalHeaderSize + kFrameSize - kPayloadOffset;
   std::unique_ptr<RtpPacketizer> packetizer(
-      RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
+      CreateH264Packetizer(kH264PacketizationMode1, kMaxPayloadSize));
   packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
 
   uint8_t packet[kMaxPayloadSize] = {0};
@@ -308,7 +359,7 @@
     }
   }
   std::unique_ptr<RtpPacketizer> packetizer(
-      RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
+      CreateH264Packetizer(kH264PacketizationMode1, kMaxPayloadSize));
   packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
 
   // First expecting two FU-A packets.
@@ -381,6 +432,28 @@
                               sizeof(kExpectedPayloadSizes) / sizeof(size_t)));
 }
 
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+TEST(RtpPacketizerH264DeathTest, SendOverlongDataInPacketizationMode0) {
+  const size_t kFrameSize = kMaxPayloadSize + 100;
+  uint8_t frame[kFrameSize] = {0};
+  for (size_t i = 0; i < kFrameSize; ++i)
+    frame[i] = i;
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(1);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = kFrameSize;
+  // Set NAL headers.
+  frame[fragmentation.fragmentationOffset[0]] = 0x01;
+
+  std::unique_ptr<RtpPacketizer> packetizer(
+      CreateH264Packetizer(kH264PacketizationMode0, kMaxPayloadSize));
+  EXPECT_DEATH(packetizer->SetPayloadData(frame, kFrameSize, &fragmentation),
+               "payload_size");
+}
+
+#endif  // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
 namespace {
 const uint8_t kStartSequence[] = {0x00, 0x00, 0x00, 0x01};
 const uint8_t kOriginalSps[] = {kSps, 0x00, 0x00, 0x03, 0x03,
@@ -421,9 +494,8 @@
   const size_t kHeaderOverhead = kFuAHeaderSize + 1;
 
   // Set size to fragment SPS into two FU-A packets.
-  packetizer_.reset(RtpPacketizer::Create(
-      kRtpVideoH264, sizeof(kOriginalSps) - 2 + kHeaderOverhead, nullptr,
-      kEmptyFrame));
+  packetizer_.reset(CreateH264Packetizer(
+      kH264PacketizationMode1, sizeof(kOriginalSps) - 2 + kHeaderOverhead));
 
   packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(),
                               &fragmentation_header_);
@@ -459,9 +531,8 @@
                                     sizeof(kIdrTwo) + (kLengthFieldLength * 3);
 
   // Set size to include SPS and the rest of the packets in a Stap-A package.
-  packetizer_.reset(RtpPacketizer::Create(kRtpVideoH264,
-                                          kExpectedTotalSize + kHeaderOverhead,
-                                          nullptr, kEmptyFrame));
+  packetizer_.reset(CreateH264Packetizer(kH264PacketizationMode1,
+                                         kExpectedTotalSize + kHeaderOverhead));
 
   packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(),
                               &fragmentation_header_);
diff --git a/webrtc/modules/video_coding/codec_database.cc b/webrtc/modules/video_coding/codec_database.cc
index 9d8c8f3..5adc899 100644
--- a/webrtc/modules/video_coding/codec_database.cc
+++ b/webrtc/modules/video_coding/codec_database.cc
@@ -64,6 +64,7 @@
 
   h264_settings.frameDroppingOn = true;
   h264_settings.keyFrameInterval = 3000;
+  h264_settings.packetization_mode = kH264PacketizationMode1;
   h264_settings.spsData = nullptr;
   h264_settings.spsLen = 0;
   h264_settings.ppsData = nullptr;
diff --git a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc
index 5c0aa1b..4223efb 100644
--- a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc
+++ b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc
@@ -152,6 +152,15 @@
 
 H264EncoderImpl::H264EncoderImpl()
     : openh264_encoder_(nullptr),
+      width_(0),
+      height_(0),
+      max_frame_rate_(0.0f),
+      target_bps_(0),
+      max_bps_(0),
+      mode_(kRealtimeVideo),
+      frame_dropping_on_(false),
+      key_frame_interval_(0),
+      max_payload_size_(0),
       number_of_cores_(0),
       encoded_image_callback_(nullptr),
       has_reported_init_(false),
@@ -163,7 +172,7 @@
 
 int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
                                     int32_t number_of_cores,
-                                    size_t /*max_payload_size*/) {
+                                    size_t max_payload_size) {
   ReportInit();
   if (!codec_settings ||
       codec_settings->codecType != kVideoCodecH264) {
@@ -210,6 +219,7 @@
   mode_ = codec_settings->mode;
   frame_dropping_on_ = codec_settings->H264().frameDroppingOn;
   key_frame_interval_ = codec_settings->H264().keyFrameInterval;
+  max_payload_size_ = max_payload_size;
 
   // Codec_settings uses kbits/second; encoder uses bits/second.
   max_bps_ = codec_settings->maxBitrate * 1000;
@@ -217,8 +227,12 @@
     target_bps_ = codec_settings->startBitrate * 1000;
   else
     target_bps_ = codec_settings->targetBitrate * 1000;
+  RTC_DCHECK(codec_settings->H264().packetization_mode !=
+             kH264PacketizationModeNotSet);
+  packetization_mode_ = codec_settings->H264().packetization_mode;
 
   SEncParamExt encoder_params = CreateEncoderParams();
+
   // Initialize.
   if (openh264_encoder_->InitializeExt(&encoder_params) != 0) {
     LOG(LS_ERROR) << "Failed to initialize OpenH264 encoder";
@@ -377,6 +391,7 @@
     // Deliver encoded image.
     CodecSpecificInfo codec_specific;
     codec_specific.codecType = kVideoCodecH264;
+    codec_specific.codecSpecific.H264.packetization_mode = packetization_mode_;
     encoded_image_callback_->OnEncodedImage(encoded_image_, &codec_specific,
                                             &frag_header);
 
@@ -445,19 +460,50 @@
       encoder_params.iTargetBitrate;
   encoder_params.sSpatialLayers[0].iMaxSpatialBitrate =
       encoder_params.iMaxBitrate;
+  LOG(INFO) << "OpenH264 version is " << OPENH264_MAJOR << "."
+            << OPENH264_MINOR;
+  switch (packetization_mode_) {
+    case kH264PacketizationMode0:
 #if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
-  // Slice num according to number of threads.
-  encoder_params.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_AUTO_SLICE;
+      // Limit the size of packets produced.
+      encoder_params.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_DYN_SLICE;
+      // The slice size is max payload size - room for a NAL header.
+      // The constant 50 is NAL_HEADER_ADD_0X30BYTES in openh264 source,
+      // but is not exported.
+      encoder_params.sSpatialLayers[0]
+          .sSliceCfg.sSliceArgument.uiSliceSizeConstraint =
+          static_cast<unsigned int>(max_payload_size_ - 50);
+      encoder_params.uiMaxNalSize =
+          static_cast<unsigned int>(max_payload_size_);
 #else
-  // When uiSliceMode = SM_FIXEDSLCNUM_SLICE, uiSliceNum = 0 means auto design
-  // it with cpu core number.
-  // TODO(sprang): Set to 0 when we understand why the rate controller borks
-  //               when uiSliceNum > 1.
-  encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = 1;
-  encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceMode =
-      SM_FIXEDSLCNUM_SLICE;
+      // When uiSliceMode = SM_FIXEDSLCNUM_SLICE, uiSliceNum = 0 means auto
+      // design
+      // it with cpu core number.
+      encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = 1;
+      encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceMode =
+          SM_SIZELIMITED_SLICE;
+      encoder_params.sSpatialLayers[0]
+          .sSliceArgument.uiSliceSizeConstraint =
+          static_cast<unsigned int>(max_payload_size_);
 #endif
-
+      break;
+    case kH264PacketizationMode1:
+#if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
+      // Slice num according to number of threads.
+      encoder_params.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_AUTO_SLICE;
+#else
+      // When uiSliceMode = SM_FIXEDSLCNUM_SLICE, uiSliceNum = 0 means auto
+      // design it with cpu core number.
+      // TODO(sprang): Set to 0 when we understand why the rate controller borks
+      //               when uiSliceNum > 1.
+      encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = 1;
+      encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceMode =
+          SM_FIXEDSLCNUM_SLICE;
+#endif
+      break;
+    default:
+      RTC_NOTREACHED() << "Illegal packetization mode specified";
+  }
   return encoder_params;
 }
 
diff --git a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h
index 1e461b9..a88377b 100644
--- a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h
+++ b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h
@@ -39,7 +39,7 @@
   // - height
   int32_t InitEncode(const VideoCodec* codec_settings,
                      int32_t number_of_cores,
-                     size_t /*max_payload_size*/) override;
+                     size_t max_payload_size) override;
   int32_t Release() override;
 
   int32_t RegisterEncodeCompleteCallback(
@@ -80,7 +80,9 @@
   // H.264 specifc parameters
   bool frame_dropping_on_;
   int key_frame_interval_;
+  H264PacketizationMode packetization_mode_;
 
+  size_t max_payload_size_;
   int32_t number_of_cores_;
 
   EncodedImage encoded_image_;
diff --git a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc
new file mode 100644
index 0000000..73a7f3e
--- /dev/null
+++ b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2015 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.
+ *
+ */
+
+#include "webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h"
+
+#include "webrtc/test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+const int kMaxPayloadSize = 1024;
+
+void SetDefaultSettings(VideoCodec* codec_settings) {
+  codec_settings->codecType = kVideoCodecH264;
+  codec_settings->maxFramerate = 60;
+  codec_settings->width = 640;
+  codec_settings->height = 480;
+  codec_settings->H264()->packetization_mode = kH264PacketizationMode1;
+  // If frame dropping is false, we get a warning that bitrate can't
+  // be controlled for RC_QUALITY_MODE; RC_BITRATE_MODE and RC_TIMESTAMP_MODE
+  codec_settings->H264()->frameDroppingOn = true;
+  codec_settings->targetBitrate = 2000;
+  codec_settings->maxBitrate = 4000;
+}
+
+TEST(H264EncoderImplTest, CanInitializeWithDefaultParameters) {
+  H264EncoderImpl encoder;
+  VideoCodec codec_settings;
+  SetDefaultSettings(&codec_settings);
+  EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+            encoder.InitEncode(&codec_settings, 1, kMaxPayloadSize));
+}
+
+TEST(H264EncoderImplTest, CanInitializeWithPacketizationMode0) {
+  H264EncoderImpl encoder;
+  VideoCodec codec_settings;
+  SetDefaultSettings(&codec_settings);
+  codec_settings.H264()->packetization_mode = kH264PacketizationMode0;
+  EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+            encoder.InitEncode(&codec_settings, 1, kMaxPayloadSize));
+}
+
+}  // anonymous namespace
+
+}  // namespace webrtc
diff --git a/webrtc/modules/video_coding/include/video_codec_interface.h b/webrtc/modules/video_coding/include/video_codec_interface.h
index f0a11e7..5dcfaff 100644
--- a/webrtc/modules/video_coding/include/video_codec_interface.h
+++ b/webrtc/modules/video_coding/include/video_codec_interface.h
@@ -77,7 +77,9 @@
   uint8_t simulcast_idx;
 };
 
-struct CodecSpecificInfoH264 {};
+struct CodecSpecificInfoH264 {
+  H264PacketizationMode packetization_mode;
+};
 
 union CodecSpecificInfoUnion {
   CodecSpecificInfoGeneric generic;
diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc
index f518ce3..f9c3b53 100644
--- a/webrtc/test/fake_encoder.cc
+++ b/webrtc/test/fake_encoder.cc
@@ -200,6 +200,7 @@
   CodecSpecificInfo specifics;
   memset(&specifics, 0, sizeof(specifics));
   specifics.codecType = kVideoCodecH264;
+  specifics.codecSpecific.H264.packetization_mode = kH264PacketizationMode1;
   return callback_->OnEncodedImage(encoded_image, &specifics, &fragmentation);
 }
 
diff --git a/webrtc/video/BUILD.gn b/webrtc/video/BUILD.gn
index e97de6f..ba5ba6b 100644
--- a/webrtc/video/BUILD.gn
+++ b/webrtc/video/BUILD.gn
@@ -143,6 +143,7 @@
   # TODO(pbos): Rename test suite.
   rtc_source_set("video_tests") {
     testonly = true
+    defines = []
     sources = [
       "call_stats_unittest.cc",
       "encoder_rtcp_feedback_unittest.cc",
@@ -170,5 +171,8 @@
       # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
       suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
     }
+    if (rtc_use_h264) {
+      defines += [ "WEBRTC_USE_H264" ]
+    }
   }
 }
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 492f55d..a936624 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -130,6 +130,15 @@
       Transport* transport);
 };
 
+void SetPacketizationMode(H264PacketizationMode mode, VideoEncoder* encoder) {
+  VideoCodec codec_settings;
+  codec_settings.codecType = kVideoCodecH264;
+  codec_settings.H264()->packetization_mode = mode;
+  // TODO(hta): Determine appropriate value for max packet size.
+  static const int kMaxPacketSize = 1024;
+  encoder->InitEncode(&codec_settings, 0, kMaxPacketSize);
+}
+
 TEST_F(EndToEndTest, ReceiverCanBeStartedTwice) {
   CreateCalls(Call::Config(&event_log_), Call::Config(&event_log_));
 
@@ -375,7 +384,7 @@
 }
 #endif  // !defined(RTC_DISABLE_VP9)
 
-#if defined(WEBRTC_END_TO_END_H264_TESTS)
+#if defined(WEBRTC_USE_H264)
 
 TEST_F(EndToEndTest, SendsAndReceivesH264) {
   CodecObserver test(500, kVideoRotation_0, "H264",
@@ -391,7 +400,25 @@
   RunBaseTest(&test);
 }
 
-#endif  // defined(WEBRTC_END_TO_END_H264_TESTS)
+TEST_F(EndToEndTest, SendsAndReceivesH264PacketizationMode0) {
+  VideoEncoder* encoder = VideoEncoder::Create(VideoEncoder::kH264);
+  SetPacketizationMode(kH264PacketizationMode0, encoder);
+  // The CodecObserver takes ownership of the encoder.
+  CodecObserver test(500, kVideoRotation_0, "H264", encoder,
+                     H264Decoder::Create());
+  RunBaseTest(&test);
+}
+
+TEST_F(EndToEndTest, SendsAndReceivesH264PacketizationMode1) {
+  VideoEncoder* encoder = VideoEncoder::Create(VideoEncoder::kH264);
+  SetPacketizationMode(kH264PacketizationMode1, encoder);
+  // The CodecObserver takes ownership of the encoder.
+  CodecObserver test(500, kVideoRotation_0, "H264", encoder,
+                     H264Decoder::Create());
+  RunBaseTest(&test);
+}
+
+#endif  // defined(WEBRTC_USE_H264)
 
 TEST_F(EndToEndTest, ReceiverUsesLocalSsrc) {
   class SyncRtcpObserver : public test::EndToEndTest {
diff --git a/webrtc/video/payload_router.cc b/webrtc/video/payload_router.cc
index 2cc3e88..4410ad0 100644
--- a/webrtc/video/payload_router.cc
+++ b/webrtc/video/payload_router.cc
@@ -75,6 +75,8 @@
     }
     case kVideoCodecH264:
       rtp->codec = kRtpVideoH264;
+      rtp->codecHeader.H264.packetization_mode =
+          info->codecSpecific.H264.packetization_mode;
       return;
     case kVideoCodecGeneric:
       rtp->codec = kRtpVideoGeneric;
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
index 2b5c6e6..a601a10 100644
--- a/webrtc/video/video_send_stream_tests.cc
+++ b/webrtc/video/video_send_stream_tests.cc
@@ -1970,6 +1970,7 @@
         num_initializations_(0),
         stream_(nullptr) {
     memset(&encoder_settings_, 0, sizeof(encoder_settings_));
+    InitCodecSpecifics();
   }
 
  private:
@@ -1993,6 +1994,8 @@
     }
   };
 
+  void InitCodecSpecifics();
+
   void ModifyVideoConfigs(
       VideoSendStream::Config* send_config,
       std::vector<VideoReceiveStream::Config>* receive_configs,
@@ -2057,11 +2060,20 @@
   VideoEncoderConfig encoder_config_;
 };
 
+template <typename T>
+void VideoCodecConfigObserver<T>::InitCodecSpecifics() {}
+
+template <>
+void VideoCodecConfigObserver<VideoCodecH264>::InitCodecSpecifics() {
+  encoder_settings_.packetization_mode = kH264PacketizationMode1;
+}
 template <>
 void VideoCodecConfigObserver<VideoCodecH264>::VerifyCodecSpecifics(
     const VideoCodec& config) const {
   EXPECT_EQ(
       0, memcmp(&config.H264(), &encoder_settings_, sizeof(encoder_settings_)));
+  // Check that packetization mode has propagated.
+  EXPECT_EQ(kH264PacketizationMode1, config.H264().packetization_mode);
 }
 
 template <>