Ignore fragmentation header when packetizing H264

instead reparse nalu boundaries from the bitstream.

H264 is the last use of the RTPFragmentationHeader and this would allow
to avoid passing and precalculating this legacy structure.

Bug: webrtc:6471
Change-Id: Ia6e8bf0836fd5c022423d836894cde81f136d1f1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/178911
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31746}
diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc
index 28f63f1..f6f4a48 100644
--- a/modules/rtp_rtcp/source/rtp_format.cc
+++ b/modules/rtp_rtcp/source/rtp_format.cc
@@ -31,7 +31,7 @@
     PayloadSizeLimits limits,
     // Codec-specific details.
     const RTPVideoHeader& rtp_video_header,
-    const RTPFragmentationHeader* fragmentation) {
+    const RTPFragmentationHeader* /*fragmentation*/) {
   if (!type) {
     // Use raw packetizer.
     return std::make_unique<RtpPacketizerGeneric>(payload, limits);
@@ -39,11 +39,10 @@
 
   switch (*type) {
     case kVideoCodecH264: {
-      RTC_CHECK(fragmentation);
       const auto& h264 =
           absl::get<RTPVideoHeaderH264>(rtp_video_header.video_type_header);
-      return std::make_unique<RtpPacketizerH264>(
-          payload, limits, h264.packetization_mode, *fragmentation);
+      return std::make_unique<RtpPacketizerH264>(payload, limits,
+                                                 h264.packetization_mode);
     }
     case kVideoCodecVP8: {
       const auto& vp8 =
diff --git a/modules/rtp_rtcp/source/rtp_format_h264.cc b/modules/rtp_rtcp/source/rtp_format_h264.cc
index 6f19e38..6c3966c 100644
--- a/modules/rtp_rtcp/source/rtp_format_h264.cc
+++ b/modules/rtp_rtcp/source/rtp_format_h264.cc
@@ -25,7 +25,6 @@
 #include "common_video/h264/pps_parser.h"
 #include "common_video/h264/sps_parser.h"
 #include "common_video/h264/sps_vui_rewriter.h"
-#include "modules/include/module_common_types.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "rtc_base/checks.h"
@@ -46,19 +45,18 @@
 
 }  // namespace
 
-RtpPacketizerH264::RtpPacketizerH264(
-    rtc::ArrayView<const uint8_t> payload,
-    PayloadSizeLimits limits,
-    H264PacketizationMode packetization_mode,
-    const RTPFragmentationHeader& fragmentation)
+RtpPacketizerH264::RtpPacketizerH264(rtc::ArrayView<const uint8_t> payload,
+                                     PayloadSizeLimits limits,
+                                     H264PacketizationMode packetization_mode)
     : limits_(limits), num_packets_left_(0) {
   // Guard against uninitialized memory in packetization_mode.
   RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved ||
             packetization_mode == H264PacketizationMode::SingleNalUnit);
 
-  for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i) {
+  for (const auto& nalu :
+       H264::FindNaluIndices(payload.data(), payload.size())) {
     input_fragments_.push_back(
-        payload.subview(fragmentation.Offset(i), fragmentation.Length(i)));
+        payload.subview(nalu.payload_start_offset, nalu.payload_size));
   }
 
   if (!GeneratePackets(packetization_mode)) {
diff --git a/modules/rtp_rtcp/source/rtp_format_h264.h b/modules/rtp_rtcp/source/rtp_format_h264.h
index 4661dc2..7c10dd5 100644
--- a/modules/rtp_rtcp/source/rtp_format_h264.h
+++ b/modules/rtp_rtcp/source/rtp_format_h264.h
@@ -19,7 +19,6 @@
 #include <queue>
 
 #include "api/array_view.h"
-#include "modules/include/module_common_types.h"
 #include "modules/rtp_rtcp/source/rtp_format.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "modules/video_coding/codecs/h264/include/h264_globals.h"
@@ -34,8 +33,7 @@
   // The payload_data must be exactly one encoded H264 frame.
   RtpPacketizerH264(rtc::ArrayView<const uint8_t> payload,
                     PayloadSizeLimits limits,
-                    H264PacketizationMode packetization_mode,
-                    const RTPFragmentationHeader& fragmentation);
+                    H264PacketizationMode packetization_mode);
 
   ~RtpPacketizerH264() override;
 
diff --git a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
index bf9771a..9f660b7 100644
--- a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
@@ -13,9 +13,9 @@
 #include <memory>
 #include <vector>
 
+#include "absl/algorithm/container.h"
 #include "api/array_view.h"
 #include "common_video/h264/h264_common.h"
-#include "modules/include/module_common_types.h"
 #include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
@@ -56,45 +56,61 @@
 // Bit masks for FU (A and B) headers.
 enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
 
-RTPFragmentationHeader CreateFragmentation(rtc::ArrayView<const size_t> sizes) {
-  RTPFragmentationHeader fragmentation;
-  fragmentation.VerifyAndAllocateFragmentationHeader(sizes.size());
-  size_t offset = 0;
-  for (size_t i = 0; i < sizes.size(); ++i) {
-    fragmentation.fragmentationOffset[i] = offset;
-    fragmentation.fragmentationLength[i] = sizes[i];
-    offset += sizes[i];
-  }
-  return fragmentation;
-}
-
-// Create fragmentation with single fragment of same size as |frame|
-RTPFragmentationHeader NoFragmentation(rtc::ArrayView<const uint8_t> frame) {
-  size_t frame_size[] = {frame.size()};
-  return CreateFragmentation(frame_size);
-}
-
-// Create frame of given size.
-rtc::Buffer CreateFrame(size_t frame_size) {
-  rtc::Buffer frame(frame_size);
+// Creates Buffer that looks like nal unit of given size.
+rtc::Buffer GenerateNalUnit(size_t size) {
+  RTC_CHECK_GT(size, 0);
+  rtc::Buffer buffer(size);
   // Set some valid header.
-  frame[0] = 0x01;
-  // Generate payload to detect when shifted payload was put into a packet.
-  for (size_t i = 1; i < frame_size; ++i)
-    frame[i] = static_cast<uint8_t>(i);
+  buffer[0] = kSlice;
+  for (size_t i = 1; i < size; ++i) {
+    buffer[i] = static_cast<uint8_t>(i);
+  }
+  // Last byte shouldn't be 0, or it may be counted as part of next 4-byte start
+  // sequence.
+  buffer[size - 1] |= 0x10;
+  return buffer;
+}
+
+// Create frame consisting of nalus of given size.
+rtc::Buffer CreateFrame(std::initializer_list<size_t> nalu_sizes) {
+  static constexpr int kStartCodeSize = 3;
+  rtc::Buffer frame(absl::c_accumulate(nalu_sizes, 0) +
+                    kStartCodeSize * nalu_sizes.size());
+  size_t offset = 0;
+  for (size_t nalu_size : nalu_sizes) {
+    EXPECT_GE(nalu_size, 1u);
+    // Insert nalu start code
+    frame[offset] = 0;
+    frame[offset + 1] = 0;
+    frame[offset + 2] = 1;
+    // Set some valid header.
+    frame[offset + 3] = 1;
+    // Fill payload avoiding accidental start codes
+    if (nalu_size > 1) {
+      memset(frame.data() + offset + 4, 0x3f, nalu_size - 1);
+    }
+    offset += (kStartCodeSize + nalu_size);
+  }
   return frame;
 }
 
-// Create frame with size deduced from fragmentation.
-rtc::Buffer CreateFrame(const RTPFragmentationHeader& fragmentation) {
-  size_t last_frame_index = fragmentation.fragmentationVectorSize - 1;
-  size_t frame_size = fragmentation.fragmentationOffset[last_frame_index] +
-                      fragmentation.fragmentationLength[last_frame_index];
-  rtc::Buffer frame = CreateFrame(frame_size);
-  // Set some headers.
-  // Tests can expect those are valid but shouln't rely on actual values.
-  for (size_t i = 0; i <= last_frame_index; ++i) {
-    frame[fragmentation.fragmentationOffset[i]] = i + 1;
+// Create frame consisting of given nalus.
+rtc::Buffer CreateFrame(rtc::ArrayView<const rtc::Buffer> nalus) {
+  static constexpr int kStartCodeSize = 3;
+  int frame_size = 0;
+  for (const rtc::Buffer& nalu : nalus) {
+    frame_size += (kStartCodeSize + nalu.size());
+  }
+  rtc::Buffer frame(frame_size);
+  size_t offset = 0;
+  for (const rtc::Buffer& nalu : nalus) {
+    // Insert nalu start code
+    frame[offset] = 0;
+    frame[offset + 1] = 0;
+    frame[offset + 2] = 1;
+    // Copy the nalu unit.
+    memcpy(frame.data() + offset + 3, nalu.data(), nalu.size());
+    offset += (kStartCodeSize + nalu.size());
   }
   return frame;
 }
@@ -117,31 +133,28 @@
     : public ::testing::TestWithParam<H264PacketizationMode> {};
 
 TEST_P(RtpPacketizerH264ModeTest, SingleNalu) {
-  const uint8_t frame[2] = {kIdr, 0xFF};
+  const uint8_t frame[] = {0, 0, 1, kIdr, 0xFF};
 
-  RtpPacketizerH264 packetizer(frame, kNoLimits, GetParam(),
-                               NoFragmentation(frame));
+  RtpPacketizerH264 packetizer(frame, kNoLimits, GetParam());
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(1));
-  EXPECT_THAT(packets[0].payload(), ElementsAreArray(frame));
+  EXPECT_THAT(packets[0].payload(), ElementsAre(kIdr, 0xFF));
 }
 
 TEST_P(RtpPacketizerH264ModeTest, SingleNaluTwoPackets) {
   RtpPacketizer::PayloadSizeLimits limits;
   limits.max_payload_len = kMaxPayloadSize;
-  const size_t fragment_sizes[] = {kMaxPayloadSize, 100};
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragment_sizes);
-  rtc::Buffer frame = CreateFrame(fragmentation);
+  rtc::Buffer nalus[] = {GenerateNalUnit(kMaxPayloadSize),
+                         GenerateNalUnit(100)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits, GetParam());
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(2));
-  EXPECT_THAT(packets[0].payload(),
-              ElementsAreArray(frame.data(), kMaxPayloadSize));
-  EXPECT_THAT(packets[1].payload(),
-              ElementsAreArray(frame.data() + kMaxPayloadSize, 100));
+  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
+  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
 }
 
 TEST_P(RtpPacketizerH264ModeTest,
@@ -149,21 +162,18 @@
   RtpPacketizer::PayloadSizeLimits limits;
   limits.max_payload_len = 200;
   limits.first_packet_reduction_len = 5;
-  const size_t fragments[] = {195, 200, 200};
+  rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/195),
+                         GenerateNalUnit(/*size=*/200),
+                         GenerateNalUnit(/*size=*/200)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
-
-  RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits, GetParam());
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(3));
-  const uint8_t* next_fragment = frame.data();
-  EXPECT_THAT(packets[0].payload(), ElementsAreArray(next_fragment, 195));
-  next_fragment += 195;
-  EXPECT_THAT(packets[1].payload(), ElementsAreArray(next_fragment, 200));
-  next_fragment += 200;
-  EXPECT_THAT(packets[2].payload(), ElementsAreArray(next_fragment, 200));
+  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
+  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
+  EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2]));
 }
 
 TEST_P(RtpPacketizerH264ModeTest,
@@ -171,21 +181,18 @@
   RtpPacketizer::PayloadSizeLimits limits;
   limits.max_payload_len = 200;
   limits.last_packet_reduction_len = 5;
-  const size_t fragments[] = {200, 200, 195};
+  rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/200),
+                         GenerateNalUnit(/*size=*/200),
+                         GenerateNalUnit(/*size=*/195)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
-
-  RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits, GetParam());
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(3));
-  const uint8_t* next_fragment = frame.data();
-  EXPECT_THAT(packets[0].payload(), ElementsAreArray(next_fragment, 200));
-  next_fragment += 200;
-  EXPECT_THAT(packets[1].payload(), ElementsAreArray(next_fragment, 200));
-  next_fragment += 200;
-  EXPECT_THAT(packets[2].payload(), ElementsAreArray(next_fragment, 195));
+  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
+  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
+  EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2]));
 }
 
 TEST_P(RtpPacketizerH264ModeTest,
@@ -194,10 +201,9 @@
   limits.max_payload_len = 200;
   limits.first_packet_reduction_len = 20;
   limits.last_packet_reduction_len = 30;
-  rtc::Buffer frame = CreateFrame(150);
+  rtc::Buffer frame = CreateFrame({150});
 
-  RtpPacketizerH264 packetizer(frame, limits, GetParam(),
-                               NoFragmentation(frame));
+  RtpPacketizerH264 packetizer(frame, limits, GetParam());
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   EXPECT_THAT(packets, SizeIs(1));
@@ -211,19 +217,19 @@
 
 // Aggregation tests.
 TEST(RtpPacketizerH264Test, StapA) {
-  size_t fragments[] = {2, 2, 0x123};
+  rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2),
+                         GenerateNalUnit(/*size=*/2),
+                         GenerateNalUnit(/*size=*/0x123)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
-
-  RtpPacketizerH264 packetizer(
-      frame, kNoLimits, H264PacketizationMode::NonInterleaved, fragmentation);
+  RtpPacketizerH264 packetizer(frame, kNoLimits,
+                               H264PacketizationMode::NonInterleaved);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(1));
   auto payload = packets[0].payload();
   EXPECT_EQ(payload.size(),
-            kNalHeaderSize + 3 * kLengthFieldLength + frame.size());
+            kNalHeaderSize + 3 * kLengthFieldLength + 2 + 2 + 0x123);
 
   EXPECT_EQ(payload[0], kStapA);
   payload = payload.subview(kNalHeaderSize);
@@ -231,29 +237,26 @@
   EXPECT_THAT(payload.subview(0, kLengthFieldLength),
               ElementsAre(0, 2));  // Size.
   EXPECT_THAT(payload.subview(kLengthFieldLength, 2),
-              ElementsAreArray(frame.data(), 2));
+              ElementsAreArray(nalus[0]));
   payload = payload.subview(kLengthFieldLength + 2);
   // 2nd fragment.
   EXPECT_THAT(payload.subview(0, kLengthFieldLength),
               ElementsAre(0, 2));  // Size.
   EXPECT_THAT(payload.subview(kLengthFieldLength, 2),
-              ElementsAreArray(frame.data() + 2, 2));
+              ElementsAreArray(nalus[1]));
   payload = payload.subview(kLengthFieldLength + 2);
   // 3rd fragment.
   EXPECT_THAT(payload.subview(0, kLengthFieldLength),
               ElementsAre(0x1, 0x23));  // Size.
-  EXPECT_THAT(payload.subview(kLengthFieldLength),
-              ElementsAreArray(frame.data() + 4, 0x123));
+  EXPECT_THAT(payload.subview(kLengthFieldLength), ElementsAreArray(nalus[2]));
 }
 
 TEST(RtpPacketizerH264Test, SingleNalUnitModeHasNoStapA) {
   // This is the same setup as for the StapA test.
-  size_t fragments[] = {2, 2, 0x123};
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
+  rtc::Buffer frame = CreateFrame({2, 2, 0x123});
 
-  RtpPacketizerH264 packetizer(
-      frame, kNoLimits, H264PacketizationMode::SingleNalUnit, fragmentation);
+  RtpPacketizerH264 packetizer(frame, kNoLimits,
+                               H264PacketizationMode::SingleNalUnit);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   // The three fragments should be returned as three packets.
@@ -269,23 +272,23 @@
   limits.first_packet_reduction_len = 100;
   const size_t kFirstFragmentSize =
       limits.max_payload_len - limits.first_packet_reduction_len;
-  size_t fragments[] = {kFirstFragmentSize, 2, 2};
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
+  rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/kFirstFragmentSize),
+                         GenerateNalUnit(/*size=*/2),
+                         GenerateNalUnit(/*size=*/2)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RtpPacketizerH264 packetizer(
-      frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits,
+                               H264PacketizationMode::NonInterleaved);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(2));
   // Expect 1st packet is single nalu.
-  EXPECT_THAT(packets[0].payload(),
-              ElementsAreArray(frame.data(), kFirstFragmentSize));
+  EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
   // Expect 2nd packet is aggregate of last two fragments.
-  const uint8_t* tail = frame.data() + kFirstFragmentSize;
-  EXPECT_THAT(packets[1].payload(), ElementsAre(kStapA,                  //
-                                                0, 2, tail[0], tail[1],  //
-                                                0, 2, tail[2], tail[3]));
+  EXPECT_THAT(packets[1].payload(),
+              ElementsAre(kStapA,                          //
+                          0, 2, nalus[1][0], nalus[1][1],  //
+                          0, 2, nalus[2][0], nalus[2][1]));
 }
 
 TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) {
@@ -294,22 +297,23 @@
   limits.last_packet_reduction_len = 100;
   const size_t kLastFragmentSize =
       limits.max_payload_len - limits.last_packet_reduction_len;
-  size_t fragments[] = {2, 2, kLastFragmentSize};
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
+  rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2),
+                         GenerateNalUnit(/*size=*/2),
+                         GenerateNalUnit(/*size=*/kLastFragmentSize)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RtpPacketizerH264 packetizer(
-      frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits,
+                               H264PacketizationMode::NonInterleaved);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(2));
   // Expect 1st packet is aggregate of 1st two fragments.
-  EXPECT_THAT(packets[0].payload(), ElementsAre(kStapA,                    //
-                                                0, 2, frame[0], frame[1],  //
-                                                0, 2, frame[2], frame[3]));
+  EXPECT_THAT(packets[0].payload(),
+              ElementsAre(kStapA,                          //
+                          0, 2, nalus[0][0], nalus[0][1],  //
+                          0, 2, nalus[1][0], nalus[1][1]));
   // Expect 2nd packet is single nalu.
-  EXPECT_THAT(packets[1].payload(),
-              ElementsAreArray(frame.data() + 4, kLastFragmentSize));
+  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2]));
 }
 
 TEST(RtpPacketizerH264Test, TooSmallForStapAHeaders) {
@@ -317,22 +321,23 @@
   limits.max_payload_len = 1000;
   const size_t kLastFragmentSize =
       limits.max_payload_len - 3 * kLengthFieldLength - 4;
-  size_t fragments[] = {2, 2, kLastFragmentSize};
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
+  rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2),
+                         GenerateNalUnit(/*size=*/2),
+                         GenerateNalUnit(/*size=*/kLastFragmentSize)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RtpPacketizerH264 packetizer(
-      frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits,
+                               H264PacketizationMode::NonInterleaved);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(2));
   // Expect 1st packet is aggregate of 1st two fragments.
-  EXPECT_THAT(packets[0].payload(), ElementsAre(kStapA,                    //
-                                                0, 2, frame[0], frame[1],  //
-                                                0, 2, frame[2], frame[3]));
+  EXPECT_THAT(packets[0].payload(),
+              ElementsAre(kStapA,                          //
+                          0, 2, nalus[0][0], nalus[0][1],  //
+                          0, 2, nalus[1][0], nalus[1][1]));
   // Expect 2nd packet is single nalu.
-  EXPECT_THAT(packets[1].payload(),
-              ElementsAreArray(frame.data() + 4, kLastFragmentSize));
+  EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2]));
 }
 
 // Fragmentation + aggregation.
@@ -342,28 +347,29 @@
   const size_t kFuaPayloadSize = 70;
   const size_t kFuaNaluSize = kNalHeaderSize + 2 * kFuaPayloadSize;
   const size_t kStapANaluSize = 20;
-  size_t fragments[] = {kFuaNaluSize, kStapANaluSize, kStapANaluSize};
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
+  rtc::Buffer nalus[] = {GenerateNalUnit(kFuaNaluSize),
+                         GenerateNalUnit(kStapANaluSize),
+                         GenerateNalUnit(kStapANaluSize)};
+  rtc::Buffer frame = CreateFrame(nalus);
 
-  RtpPacketizerH264 packetizer(
-      frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits,
+                               H264PacketizationMode::NonInterleaved);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   ASSERT_THAT(packets, SizeIs(3));
-  const uint8_t* next_fragment = frame.data() + kNalHeaderSize;
   // First expect two FU-A packets.
   EXPECT_THAT(packets[0].payload().subview(0, kFuAHeaderSize),
-              ElementsAre(kFuA, FuDefs::kSBit | frame[0]));
-  EXPECT_THAT(packets[0].payload().subview(kFuAHeaderSize),
-              ElementsAreArray(next_fragment, kFuaPayloadSize));
-  next_fragment += kFuaPayloadSize;
+              ElementsAre(kFuA, FuDefs::kSBit | nalus[0][0]));
+  EXPECT_THAT(
+      packets[0].payload().subview(kFuAHeaderSize),
+      ElementsAreArray(nalus[0].data() + kNalHeaderSize, kFuaPayloadSize));
 
   EXPECT_THAT(packets[1].payload().subview(0, kFuAHeaderSize),
-              ElementsAre(kFuA, FuDefs::kEBit | frame[0]));
-  EXPECT_THAT(packets[1].payload().subview(kFuAHeaderSize),
-              ElementsAreArray(next_fragment, kFuaPayloadSize));
-  next_fragment += kFuaPayloadSize;
+              ElementsAre(kFuA, FuDefs::kEBit | nalus[0][0]));
+  EXPECT_THAT(
+      packets[1].payload().subview(kFuAHeaderSize),
+      ElementsAreArray(nalus[0].data() + kNalHeaderSize + kFuaPayloadSize,
+                       kFuaPayloadSize));
 
   // Then expect one STAP-A packet with two nal units.
   EXPECT_THAT(packets[2].payload()[0], kStapA);
@@ -371,13 +377,11 @@
   EXPECT_THAT(payload.subview(0, kLengthFieldLength),
               ElementsAre(0, kStapANaluSize));
   EXPECT_THAT(payload.subview(kLengthFieldLength, kStapANaluSize),
-              ElementsAreArray(next_fragment, kStapANaluSize));
+              ElementsAreArray(nalus[1]));
   payload = payload.subview(kLengthFieldLength + kStapANaluSize);
-  next_fragment += kStapANaluSize;
   EXPECT_THAT(payload.subview(0, kLengthFieldLength),
               ElementsAre(0, kStapANaluSize));
-  EXPECT_THAT(payload.subview(kLengthFieldLength),
-              ElementsAreArray(next_fragment, kStapANaluSize));
+  EXPECT_THAT(payload.subview(kLengthFieldLength), ElementsAreArray(nalus[2]));
 }
 
 TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) {
@@ -387,12 +391,10 @@
   limits.last_packet_reduction_len = 20;
   limits.single_packet_reduction_len = 20;
   // Actual sizes, which triggered this bug.
-  size_t fragments[] = {20, 8, 18, 1161};
-  RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
-  rtc::Buffer frame = CreateFrame(fragmentation);
+  rtc::Buffer frame = CreateFrame({20, 8, 18, 1161});
 
-  RtpPacketizerH264 packetizer(
-      frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits,
+                               H264PacketizationMode::NonInterleaved);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   // Last packet has to be of correct size.
@@ -406,11 +408,11 @@
 // Returns sizes of the payloads excluding fua headers.
 std::vector<int> TestFua(size_t frame_payload_size,
                          const RtpPacketizer::PayloadSizeLimits& limits) {
-  rtc::Buffer frame = CreateFrame(kNalHeaderSize + frame_payload_size);
+  rtc::Buffer nalu[] = {GenerateNalUnit(kNalHeaderSize + frame_payload_size)};
+  rtc::Buffer frame = CreateFrame(nalu);
 
   RtpPacketizerH264 packetizer(frame, limits,
-                               H264PacketizationMode::NonInterleaved,
-                               NoFragmentation(frame));
+                               H264PacketizationMode::NonInterleaved);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   EXPECT_GE(packets.size(), 2u);  // Single packet indicates it is not FuA.
@@ -429,7 +431,7 @@
   // Clear S and E bits before testing all are duplicating same original header.
   fua_header.front() &= ~FuDefs::kSBit;
   fua_header.back() &= ~FuDefs::kEBit;
-  EXPECT_THAT(fua_header, Each(Eq((kFuA << 8) | frame[0])));
+  EXPECT_THAT(fua_header, Each(Eq((kFuA << 8) | nalu[0][0])));
 
   return payload_sizes;
 }
@@ -488,11 +490,10 @@
 
 TEST(RtpPacketizerH264Test, RejectsOverlongDataInPacketizationMode0) {
   RtpPacketizer::PayloadSizeLimits limits;
-  rtc::Buffer frame = CreateFrame(kMaxPayloadSize + 1);
-  RTPFragmentationHeader fragmentation = NoFragmentation(frame);
+  rtc::Buffer frame = CreateFrame({kMaxPayloadSize + 1});
 
-  RtpPacketizerH264 packetizer(
-      frame, limits, H264PacketizationMode::SingleNalUnit, fragmentation);
+  RtpPacketizerH264 packetizer(frame, limits,
+                               H264PacketizationMode::SingleNalUnit);
   std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
 
   EXPECT_THAT(packets, IsEmpty());
diff --git a/test/fake_encoder.cc b/test/fake_encoder.cc
index 84a4afd..219dafc 100644
--- a/test/fake_encoder.cc
+++ b/test/fake_encoder.cc
@@ -290,6 +290,7 @@
 std::unique_ptr<RTPFragmentationHeader> FakeH264Encoder::EncodeHook(
     EncodedImage* encoded_image,
     CodecSpecificInfo* codec_specific) {
+  static constexpr std::array<uint8_t, 3> kStartCode = {0, 0, 1};
   const size_t kSpsSize = 8;
   const size_t kPpsSize = 11;
   const int kIdrFrequency = 10;
@@ -299,46 +300,46 @@
     current_idr_counter = idr_counter_;
     ++idr_counter_;
   }
+  for (size_t i = 0; i < encoded_image->size(); ++i) {
+    encoded_image->data()[i] = static_cast<uint8_t>(i);
+  }
+
   auto fragmentation = std::make_unique<RTPFragmentationHeader>();
 
   if (current_idr_counter % kIdrFrequency == 0 &&
-      encoded_image->size() > kSpsSize + kPpsSize + 1) {
+      encoded_image->size() > kSpsSize + kPpsSize + 1 + 3 * kStartCode.size()) {
     const size_t kNumSlices = 3;
     fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices);
-    fragmentation->fragmentationOffset[0] = 0;
+    fragmentation->fragmentationOffset[0] = kStartCode.size();
     fragmentation->fragmentationLength[0] = kSpsSize;
-    fragmentation->fragmentationOffset[1] = kSpsSize;
+    fragmentation->fragmentationOffset[1] = 2 * kStartCode.size() + kSpsSize;
     fragmentation->fragmentationLength[1] = kPpsSize;
-    fragmentation->fragmentationOffset[2] = kSpsSize + kPpsSize;
+    fragmentation->fragmentationOffset[2] =
+        3 * kStartCode.size() + kSpsSize + kPpsSize;
     fragmentation->fragmentationLength[2] =
-        encoded_image->size() - (kSpsSize + kPpsSize);
+        encoded_image->size() - (3 * kStartCode.size() + kSpsSize + kPpsSize);
     const size_t kSpsNalHeader = 0x67;
     const size_t kPpsNalHeader = 0x68;
     const size_t kIdrNalHeader = 0x65;
-    encoded_image->data()[fragmentation->fragmentationOffset[0]] =
-        kSpsNalHeader;
-    encoded_image->data()[fragmentation->fragmentationOffset[1]] =
-        kPpsNalHeader;
-    encoded_image->data()[fragmentation->fragmentationOffset[2]] =
-        kIdrNalHeader;
+    memcpy(encoded_image->data(), kStartCode.data(), kStartCode.size());
+    encoded_image->data()[fragmentation->Offset(0)] = kSpsNalHeader;
+    memcpy(encoded_image->data() + fragmentation->Offset(1) - kStartCode.size(),
+           kStartCode.data(), kStartCode.size());
+    encoded_image->data()[fragmentation->Offset(1)] = kPpsNalHeader;
+    memcpy(encoded_image->data() + fragmentation->Offset(2) - kStartCode.size(),
+           kStartCode.data(), kStartCode.size());
+    encoded_image->data()[fragmentation->Offset(2)] = kIdrNalHeader;
   } else {
     const size_t kNumSlices = 1;
     fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices);
-    fragmentation->fragmentationOffset[0] = 0;
-    fragmentation->fragmentationLength[0] = encoded_image->size();
+    fragmentation->fragmentationOffset[0] = kStartCode.size();
+    fragmentation->fragmentationLength[0] =
+        encoded_image->size() - kStartCode.size();
+    memcpy(encoded_image->data(), kStartCode.data(), kStartCode.size());
     const size_t kNalHeader = 0x41;
     encoded_image->data()[fragmentation->fragmentationOffset[0]] = kNalHeader;
   }
-  uint8_t value = 0;
-  int fragment_counter = 0;
-  for (size_t i = 0; i < encoded_image->size(); ++i) {
-    if (fragment_counter == fragmentation->fragmentationVectorSize ||
-        i != fragmentation->fragmentationOffset[fragment_counter]) {
-      encoded_image->data()[i] = value++;
-    } else {
-      ++fragment_counter;
-    }
-  }
+
   codec_specific->codecType = kVideoCodecH264;
   codec_specific->codecSpecific.H264.packetization_mode =
       H264PacketizationMode::NonInterleaved;