Detach H264 sps pps tracker from VCMPacket

Bug: webrtc:10979
Change-Id: I6ec5db570c3957dd068109accad88d2f62304163
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158523
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29639}
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index e5e80d1..dd202ce 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -80,6 +80,7 @@
   visibility = [ "*" ]
   deps = [
     "..:module_fec_api",
+    "../../api:array_view",
     "../../api:scoped_refptr",
     "../../api/video:encoded_image",
     "../../api/video:video_bitrate_allocation",
diff --git a/modules/video_coding/h264_sps_pps_tracker.cc b/modules/video_coding/h264_sps_pps_tracker.cc
index 9c0e521..26a0705 100644
--- a/modules/video_coding/h264_sps_pps_tracker.cc
+++ b/modules/video_coding/h264_sps_pps_tracker.cc
@@ -10,15 +10,15 @@
 
 #include "modules/video_coding/h264_sps_pps_tracker.h"
 
+#include <memory>
 #include <string>
 #include <utility>
 
+#include "absl/types/variant.h"
 #include "common_video/h264/h264_common.h"
 #include "common_video/h264/pps_parser.h"
 #include "common_video/h264/sps_parser.h"
 #include "modules/video_coding/codecs/h264/include/h264_globals.h"
-#include "modules/video_coding/frame_object.h"
-#include "modules/video_coding/packet_buffer.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 
@@ -44,15 +44,14 @@
     SpsInfo&& rhs) = default;
 H264SpsPpsTracker::SpsInfo::~SpsInfo() = default;
 
-H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
-    VCMPacket* packet) {
-  RTC_DCHECK(packet->codec() == kVideoCodecH264);
+H264SpsPpsTracker::FixedBitstream H264SpsPpsTracker::CopyAndFixBitstream(
+    rtc::ArrayView<const uint8_t> bitstream,
+    RTPVideoHeader* video_header) {
+  RTC_DCHECK(video_header);
+  RTC_DCHECK(video_header->codec == kVideoCodecH264);
 
-  const uint8_t* data = packet->dataPtr;
-  const size_t data_size = packet->sizeBytes;
-  const RTPVideoHeader& video_header = packet->video_header;
   auto& h264_header =
-      absl::get<RTPVideoHeaderH264>(packet->video_header.video_type_header);
+      absl::get<RTPVideoHeaderH264>(video_header->video_type_header);
 
   bool append_sps_pps = false;
   auto sps = sps_data_.end();
@@ -62,8 +61,9 @@
     const NaluInfo& nalu = h264_header.nalus[i];
     switch (nalu.type) {
       case H264::NaluType::kSps: {
-        sps_data_[nalu.sps_id].width = packet->width();
-        sps_data_[nalu.sps_id].height = packet->height();
+        SpsInfo& sps_info = sps_data_[nalu.sps_id];
+        sps_info.width = video_header->width;
+        sps_info.height = video_header->height;
         break;
       }
       case H264::NaluType::kPps: {
@@ -74,31 +74,31 @@
         // If this is the first packet of an IDR, make sure we have the required
         // SPS/PPS and also calculate how much extra space we need in the buffer
         // to prepend the SPS/PPS to the bitstream with start codes.
-        if (video_header.is_first_packet_in_frame) {
+        if (video_header->is_first_packet_in_frame) {
           if (nalu.pps_id == -1) {
             RTC_LOG(LS_WARNING) << "No PPS id in IDR nalu.";
-            return kRequestKeyframe;
+            return {kRequestKeyframe};
           }
 
           pps = pps_data_.find(nalu.pps_id);
           if (pps == pps_data_.end()) {
             RTC_LOG(LS_WARNING)
                 << "No PPS with id << " << nalu.pps_id << " received";
-            return kRequestKeyframe;
+            return {kRequestKeyframe};
           }
 
           sps = sps_data_.find(pps->second.sps_id);
           if (sps == sps_data_.end()) {
             RTC_LOG(LS_WARNING)
                 << "No SPS with id << " << pps->second.sps_id << " received";
-            return kRequestKeyframe;
+            return {kRequestKeyframe};
           }
 
           // Since the first packet of every keyframe should have its width and
           // height set we set it here in the case of it being supplied out of
           // band.
-          packet->video_header.width = sps->second.width;
-          packet->video_header.height = sps->second.height;
+          video_header->width = sps->second.width;
+          video_header->height = sps->second.height;
 
           // If the SPS/PPS was supplied out of band then we will have saved
           // the actual bitstream in |data|.
@@ -127,9 +127,9 @@
   }
 
   if (h264_header.packetization_type == kH264StapA) {
-    const uint8_t* nalu_ptr = data + 1;
-    while (nalu_ptr < data + data_size) {
-      RTC_DCHECK(video_header.is_first_packet_in_frame);
+    const uint8_t* nalu_ptr = bitstream.data() + 1;
+    while (nalu_ptr < bitstream.data() + bitstream.size()) {
+      RTC_DCHECK(video_header->is_first_packet_in_frame);
       required_size += sizeof(start_code_h264);
 
       // The first two bytes describe the length of a segment.
@@ -143,12 +143,14 @@
     if (h264_header.nalus_length > 0) {
       required_size += sizeof(start_code_h264);
     }
-    required_size += data_size;
+    required_size += bitstream.size();
   }
 
   // Then we copy to the new buffer.
-  uint8_t* buffer = new uint8_t[required_size];
-  uint8_t* insert_at = buffer;
+  H264SpsPpsTracker::FixedBitstream fixed;
+  fixed.data = std::make_unique<uint8_t[]>(required_size);
+  fixed.size = required_size;
+  uint8_t* insert_at = fixed.data.get();
 
   if (append_sps_pps) {
     // Insert SPS.
@@ -183,8 +185,8 @@
 
   // Copy the rest of the bitstream and insert start codes.
   if (h264_header.packetization_type == kH264StapA) {
-    const uint8_t* nalu_ptr = data + 1;
-    while (nalu_ptr < data + data_size) {
+    const uint8_t* nalu_ptr = bitstream.data() + 1;
+    while (nalu_ptr < bitstream.data() + bitstream.size()) {
       memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
       insert_at += sizeof(start_code_h264);
 
@@ -192,10 +194,9 @@
       uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
       nalu_ptr += 2;
 
-      size_t copy_end = nalu_ptr - data + segment_length;
-      if (copy_end > data_size) {
-        delete[] buffer;
-        return kDrop;
+      size_t copy_end = nalu_ptr - bitstream.data() + segment_length;
+      if (copy_end > bitstream.size()) {
+        return {kDrop};
       }
 
       memcpy(insert_at, nalu_ptr, segment_length);
@@ -207,12 +208,11 @@
       memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
       insert_at += sizeof(start_code_h264);
     }
-    memcpy(insert_at, data, data_size);
+    memcpy(insert_at, bitstream.data(), bitstream.size());
   }
 
-  packet->dataPtr = buffer;
-  packet->sizeBytes = required_size;
-  return kInsert;
+  fixed.action = kInsert;
+  return fixed;
 }
 
 void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
diff --git a/modules/video_coding/h264_sps_pps_tracker.h b/modules/video_coding/h264_sps_pps_tracker.h
index 88fc8ca..0d1815b 100644
--- a/modules/video_coding/h264_sps_pps_tracker.h
+++ b/modules/video_coding/h264_sps_pps_tracker.h
@@ -11,25 +11,33 @@
 #ifndef MODULES_VIDEO_CODING_H264_SPS_PPS_TRACKER_H_
 #define MODULES_VIDEO_CODING_H264_SPS_PPS_TRACKER_H_
 
+#include <cstddef>
 #include <cstdint>
 #include <map>
 #include <memory>
 #include <vector>
 
+#include "api/array_view.h"
+#include "modules/rtp_rtcp/source/rtp_video_header.h"
+
 namespace webrtc {
-
-class VCMPacket;
-
 namespace video_coding {
 
 class H264SpsPpsTracker {
  public:
   enum PacketAction { kInsert, kDrop, kRequestKeyframe };
+  struct FixedBitstream {
+    PacketAction action;
+    std::unique_ptr<uint8_t[]> data;
+    size_t size;
+  };
 
   H264SpsPpsTracker();
   ~H264SpsPpsTracker();
 
-  PacketAction CopyAndFixBitstream(VCMPacket* packet);
+  // Returns fixed bitstream and modifies |video_header|.
+  FixedBitstream CopyAndFixBitstream(rtc::ArrayView<const uint8_t> bitstream,
+                                     RTPVideoHeader* video_header);
 
   void InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
                          const std::vector<uint8_t>& pps);
diff --git a/modules/video_coding/h264_sps_pps_tracker_unittest.cc b/modules/video_coding/h264_sps_pps_tracker_unittest.cc
index 7857aa7..00a95ec 100644
--- a/modules/video_coding/h264_sps_pps_tracker_unittest.cc
+++ b/modules/video_coding/h264_sps_pps_tracker_unittest.cc
@@ -19,14 +19,22 @@
 #include "modules/rtp_rtcp/source/rtp_video_header.h"
 #include "modules/video_coding/codecs/h264/include/h264_globals.h"
 #include "modules/video_coding/packet.h"
+#include "test/gmock.h"
 #include "test/gtest.h"
 
 namespace webrtc {
 namespace video_coding {
-
 namespace {
+
+using ::testing::ElementsAreArray;
+
 const uint8_t start_code[] = {0, 0, 0, 1};
 
+rtc::ArrayView<const uint8_t> Bitstream(
+    const H264SpsPpsTracker::FixedBitstream& fixed) {
+  return rtc::MakeArrayView(fixed.data.get(), fixed.size);
+}
+
 void ExpectSpsPpsIdr(const RTPVideoHeaderH264& codec_header,
                      uint8_t sps_id,
                      uint8_t pps_id) {
@@ -51,19 +59,18 @@
   EXPECT_TRUE(contains_idr);
 }
 
-class H264VcmPacket : public VCMPacket {
+class H264VideoHeader : public RTPVideoHeader {
  public:
-  H264VcmPacket() {
-    video_header.codec = kVideoCodecH264;
-    video_header.is_first_packet_in_frame = false;
-    auto& type_header =
-        video_header.video_type_header.emplace<RTPVideoHeaderH264>();
-    type_header.nalus_length = 0;
-    type_header.packetization_type = kH264SingleNalu;
+  H264VideoHeader() {
+    codec = kVideoCodecH264;
+    is_first_packet_in_frame = false;
+    auto& h264_header = video_type_header.emplace<RTPVideoHeaderH264>();
+    h264_header.nalus_length = 0;
+    h264_header.packetization_type = kH264SingleNalu;
   }
 
   RTPVideoHeaderH264& h264() {
-    return absl::get<RTPVideoHeaderH264>(video_header.video_type_header);
+    return absl::get<RTPVideoHeaderH264>(video_type_header);
   }
 };
 
@@ -71,7 +78,7 @@
 
 class TestH264SpsPpsTracker : public ::testing::Test {
  public:
-  void AddSps(H264VcmPacket* packet,
+  void AddSps(H264VideoHeader* header,
               uint8_t sps_id,
               std::vector<uint8_t>* data) {
     NaluInfo info;
@@ -81,10 +88,10 @@
     data->push_back(H264::NaluType::kSps);
     data->push_back(sps_id);  // The sps data, just a single byte.
 
-    packet->h264().nalus[packet->h264().nalus_length++] = info;
+    header->h264().nalus[header->h264().nalus_length++] = info;
   }
 
-  void AddPps(H264VcmPacket* packet,
+  void AddPps(H264VideoHeader* header,
               uint8_t sps_id,
               uint8_t pps_id,
               std::vector<uint8_t>* data) {
@@ -95,16 +102,16 @@
     data->push_back(H264::NaluType::kPps);
     data->push_back(pps_id);  // The pps data, just a single byte.
 
-    packet->h264().nalus[packet->h264().nalus_length++] = info;
+    header->h264().nalus[header->h264().nalus_length++] = info;
   }
 
-  void AddIdr(H264VcmPacket* packet, int pps_id) {
+  void AddIdr(H264VideoHeader* header, int pps_id) {
     NaluInfo info;
     info.type = H264::NaluType::kIdr;
     info.sps_id = -1;
     info.pps_id = pps_id;
 
-    packet->h264().nalus[packet->h264().nalus_length++] = info;
+    header->h264().nalus[header->h264().nalus_length++] = info;
   }
 
  protected:
@@ -113,165 +120,149 @@
 
 TEST_F(TestH264SpsPpsTracker, NoNalus) {
   uint8_t data[] = {1, 2, 3};
-  H264VcmPacket packet;
-  packet.h264().packetization_type = kH264FuA;
-  packet.dataPtr = data;
-  packet.sizeBytes = sizeof(data);
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264FuA;
 
-  EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
-  EXPECT_EQ(memcmp(packet.dataPtr, data, sizeof(data)), 0);
-  delete[] packet.dataPtr;
+  H264SpsPpsTracker::FixedBitstream fixed =
+      tracker_.CopyAndFixBitstream(data, &header);
+
+  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
+  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(data));
 }
 
 TEST_F(TestH264SpsPpsTracker, FuAFirstPacket) {
   uint8_t data[] = {1, 2, 3};
-  H264VcmPacket packet;
-  packet.h264().packetization_type = kH264FuA;
-  packet.h264().nalus_length = 1;
-  packet.video_header.is_first_packet_in_frame = true;
-  packet.dataPtr = data;
-  packet.sizeBytes = sizeof(data);
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264FuA;
+  header.h264().nalus_length = 1;
+  header.is_first_packet_in_frame = true;
 
-  EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
+  H264SpsPpsTracker::FixedBitstream fixed =
+      tracker_.CopyAndFixBitstream(data, &header);
+
+  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
   std::vector<uint8_t> expected;
   expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
   expected.insert(expected.end(), {1, 2, 3});
-  EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0);
-  delete[] packet.dataPtr;
+  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
 }
 
 TEST_F(TestH264SpsPpsTracker, StapAIncorrectSegmentLength) {
   uint8_t data[] = {0, 0, 2, 0};
-  H264VcmPacket packet;
-  packet.h264().packetization_type = kH264StapA;
-  packet.video_header.is_first_packet_in_frame = true;
-  packet.dataPtr = data;
-  packet.sizeBytes = sizeof(data);
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264StapA;
+  header.is_first_packet_in_frame = true;
 
-  EXPECT_EQ(H264SpsPpsTracker::kDrop, tracker_.CopyAndFixBitstream(&packet));
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
+            H264SpsPpsTracker::kDrop);
 }
 
 TEST_F(TestH264SpsPpsTracker, SingleNaluInsertStartCode) {
   uint8_t data[] = {1, 2, 3};
-  H264VcmPacket packet;
-  packet.h264().nalus_length = 1;
-  packet.dataPtr = data;
-  packet.sizeBytes = sizeof(data);
+  H264VideoHeader header;
+  header.h264().nalus_length = 1;
 
-  EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
+  H264SpsPpsTracker::FixedBitstream fixed =
+      tracker_.CopyAndFixBitstream(data, &header);
+
+  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
   std::vector<uint8_t> expected;
   expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
   expected.insert(expected.end(), {1, 2, 3});
-  EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0);
-  delete[] packet.dataPtr;
+  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
 }
 
 TEST_F(TestH264SpsPpsTracker, NoStartCodeInsertedForSubsequentFuAPacket) {
   std::vector<uint8_t> data = {1, 2, 3};
-  H264VcmPacket packet;
-  packet.h264().packetization_type = kH264FuA;
-
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264FuA;
   // Since no NALU begin in this packet the nalus_length is zero.
-  packet.h264().nalus_length = 0;
+  header.h264().nalus_length = 0;
 
-  packet.dataPtr = data.data();
-  packet.sizeBytes = data.size();
+  H264SpsPpsTracker::FixedBitstream fixed =
+      tracker_.CopyAndFixBitstream(data, &header);
 
-  EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
-  EXPECT_EQ(memcmp(packet.dataPtr, data.data(), data.size()), 0);
-  delete[] packet.dataPtr;
+  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
+  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(data));
 }
 
 TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsPpsInserted) {
   std::vector<uint8_t> data = {1, 2, 3};
-  H264VcmPacket packet;
-  packet.video_header.is_first_packet_in_frame = true;
+  H264VideoHeader header;
+  header.is_first_packet_in_frame = true;
+  AddIdr(&header, 0);
 
-  AddIdr(&packet, 0);
-  packet.dataPtr = data.data();
-  packet.sizeBytes = data.size();
-
-  EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
-            tracker_.CopyAndFixBitstream(&packet));
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
+            H264SpsPpsTracker::kRequestKeyframe);
 }
 
 TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoPpsInserted) {
   std::vector<uint8_t> data = {1, 2, 3};
-  H264VcmPacket packet;
-  packet.video_header.is_first_packet_in_frame = true;
+  H264VideoHeader header;
+  header.is_first_packet_in_frame = true;
+  AddSps(&header, 0, &data);
+  AddIdr(&header, 0);
 
-  AddSps(&packet, 0, &data);
-  AddIdr(&packet, 0);
-  packet.dataPtr = data.data();
-  packet.sizeBytes = data.size();
-
-  EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
-            tracker_.CopyAndFixBitstream(&packet));
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
+            H264SpsPpsTracker::kRequestKeyframe);
 }
 
 TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsInserted) {
   std::vector<uint8_t> data = {1, 2, 3};
-  H264VcmPacket packet;
-  packet.video_header.is_first_packet_in_frame = true;
+  H264VideoHeader header;
+  header.is_first_packet_in_frame = true;
+  AddPps(&header, 0, 0, &data);
+  AddIdr(&header, 0);
 
-  AddPps(&packet, 0, 0, &data);
-  AddIdr(&packet, 0);
-  packet.dataPtr = data.data();
-  packet.sizeBytes = data.size();
-
-  EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
-            tracker_.CopyAndFixBitstream(&packet));
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
+            H264SpsPpsTracker::kRequestKeyframe);
 }
 
 TEST_F(TestH264SpsPpsTracker, SpsPpsPacketThenIdrFirstPacket) {
   std::vector<uint8_t> data;
-  H264VcmPacket sps_pps_packet;
-
+  H264VideoHeader sps_pps_header;
   // Insert SPS/PPS
-  AddSps(&sps_pps_packet, 0, &data);
-  AddPps(&sps_pps_packet, 0, 1, &data);
-  sps_pps_packet.dataPtr = data.data();
-  sps_pps_packet.sizeBytes = data.size();
-  EXPECT_EQ(H264SpsPpsTracker::kInsert,
-            tracker_.CopyAndFixBitstream(&sps_pps_packet));
-  delete[] sps_pps_packet.dataPtr;
-  data.clear();
+  AddSps(&sps_pps_header, 0, &data);
+  AddPps(&sps_pps_header, 0, 1, &data);
+
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &sps_pps_header).action,
+            H264SpsPpsTracker::kInsert);
 
   // Insert first packet of the IDR
-  H264VcmPacket idr_packet;
-  idr_packet.video_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_packet, 1);
-  data.insert(data.end(), {1, 2, 3});
-  idr_packet.dataPtr = data.data();
-  idr_packet.sizeBytes = data.size();
-  EXPECT_EQ(H264SpsPpsTracker::kInsert,
-            tracker_.CopyAndFixBitstream(&idr_packet));
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 1);
+  data = {1, 2, 3};
+
+  H264SpsPpsTracker::FixedBitstream fixed =
+      tracker_.CopyAndFixBitstream(data, &idr_header);
+  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
 
   std::vector<uint8_t> expected;
   expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
   expected.insert(expected.end(), {1, 2, 3});
-  EXPECT_EQ(memcmp(idr_packet.dataPtr, expected.data(), expected.size()), 0);
-  delete[] idr_packet.dataPtr;
+  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
 }
 
 TEST_F(TestH264SpsPpsTracker, SpsPpsIdrInStapA) {
   std::vector<uint8_t> data;
-  H264VcmPacket packet;
-  packet.h264().packetization_type = kH264StapA;
-  packet.video_header.is_first_packet_in_frame = true;  // Always true for StapA
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264StapA;
+  header.is_first_packet_in_frame = true;  // Always true for StapA
 
   data.insert(data.end(), {0});     // First byte is ignored
   data.insert(data.end(), {0, 2});  // Length of segment
-  AddSps(&packet, 13, &data);
+  AddSps(&header, 13, &data);
   data.insert(data.end(), {0, 2});  // Length of segment
-  AddPps(&packet, 13, 27, &data);
+  AddPps(&header, 13, 27, &data);
   data.insert(data.end(), {0, 5});  // Length of segment
-  AddIdr(&packet, 27);
+  AddIdr(&header, 27);
   data.insert(data.end(), {1, 2, 3, 2, 1});
 
-  packet.dataPtr = data.data();
-  packet.sizeBytes = data.size();
-  EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
+  H264SpsPpsTracker::FixedBitstream fixed =
+      tracker_.CopyAndFixBitstream(data, &header);
+
+  EXPECT_THAT(fixed.action, H264SpsPpsTracker::kInsert);
 
   std::vector<uint8_t> expected;
   expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
@@ -280,9 +271,7 @@
   expected.insert(expected.end(), {H264::NaluType::kPps, 27});
   expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
   expected.insert(expected.end(), {1, 2, 3, 2, 1});
-
-  EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0);
-  delete[] packet.dataPtr;
+  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
 }
 
 TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) {
@@ -297,25 +286,18 @@
   tracker_.InsertSpsPpsNalus(sps, pps);
 
   // Insert first packet of the IDR.
-  H264VcmPacket idr_packet;
-  idr_packet.video_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_packet, 0);
-  idr_packet.dataPtr = kData;
-  idr_packet.sizeBytes = sizeof(kData);
-  EXPECT_EQ(1u, idr_packet.h264().nalus_length);
-  EXPECT_EQ(H264SpsPpsTracker::kInsert,
-            tracker_.CopyAndFixBitstream(&idr_packet));
-  EXPECT_EQ(3u, idr_packet.h264().nalus_length);
-  EXPECT_EQ(320, idr_packet.width());
-  EXPECT_EQ(240, idr_packet.height());
-  ExpectSpsPpsIdr(idr_packet.h264(), 0, 0);
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 0);
+  EXPECT_EQ(idr_header.h264().nalus_length, 1u);
 
-  if (idr_packet.dataPtr != kData) {
-    // In case CopyAndFixBitStream() prepends SPS/PPS nalus to the packet, it
-    // uses new uint8_t[] to allocate memory. Caller of CopyAndFixBitStream()
-    // needs to take care of freeing the memory.
-    delete[] idr_packet.dataPtr;
-  }
+  H264SpsPpsTracker::FixedBitstream fixed =
+      tracker_.CopyAndFixBitstream(kData, &idr_header);
+
+  EXPECT_EQ(idr_header.h264().nalus_length, 3u);
+  EXPECT_EQ(idr_header.width, 320u);
+  EXPECT_EQ(idr_header.height, 240u);
+  ExpectSpsPpsIdr(idr_header.h264(), 0, 0);
 }
 
 TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandWrongNaluHeader) {
@@ -330,13 +312,12 @@
   tracker_.InsertSpsPpsNalus(sps, pps);
 
   // Insert first packet of the IDR.
-  H264VcmPacket idr_packet;
-  idr_packet.video_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_packet, 0);
-  idr_packet.dataPtr = kData;
-  idr_packet.sizeBytes = sizeof(kData);
-  EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
-            tracker_.CopyAndFixBitstream(&idr_packet));
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 0);
+
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(kData, &idr_header).action,
+            H264SpsPpsTracker::kRequestKeyframe);
 }
 
 TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandIncompleteNalu) {
@@ -349,13 +330,12 @@
   tracker_.InsertSpsPpsNalus(sps, pps);
 
   // Insert first packet of the IDR.
-  H264VcmPacket idr_packet;
-  idr_packet.video_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_packet, 0);
-  idr_packet.dataPtr = kData;
-  idr_packet.sizeBytes = sizeof(kData);
-  EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
-            tracker_.CopyAndFixBitstream(&idr_packet));
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 0);
+
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(kData, &idr_header).action,
+            H264SpsPpsTracker::kRequestKeyframe);
 }
 
 TEST_F(TestH264SpsPpsTracker, SaveRestoreWidthHeight) {
@@ -363,29 +343,25 @@
 
   // Insert an SPS/PPS packet with width/height and make sure
   // that information is set on the first IDR packet.
-  H264VcmPacket sps_pps_packet;
-  AddSps(&sps_pps_packet, 0, &data);
-  AddPps(&sps_pps_packet, 0, 1, &data);
-  sps_pps_packet.dataPtr = data.data();
-  sps_pps_packet.sizeBytes = data.size();
-  sps_pps_packet.video_header.width = 320;
-  sps_pps_packet.video_header.height = 240;
-  EXPECT_EQ(H264SpsPpsTracker::kInsert,
-            tracker_.CopyAndFixBitstream(&sps_pps_packet));
-  delete[] sps_pps_packet.dataPtr;
+  H264VideoHeader sps_pps_header;
+  AddSps(&sps_pps_header, 0, &data);
+  AddPps(&sps_pps_header, 0, 1, &data);
+  sps_pps_header.width = 320;
+  sps_pps_header.height = 240;
 
-  H264VcmPacket idr_packet;
-  idr_packet.video_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_packet, 1);
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &sps_pps_header).action,
+            H264SpsPpsTracker::kInsert);
+
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 1);
   data.insert(data.end(), {1, 2, 3});
-  idr_packet.dataPtr = data.data();
-  idr_packet.sizeBytes = data.size();
-  EXPECT_EQ(H264SpsPpsTracker::kInsert,
-            tracker_.CopyAndFixBitstream(&idr_packet));
 
-  EXPECT_EQ(320, idr_packet.width());
-  EXPECT_EQ(240, idr_packet.height());
-  delete[] idr_packet.dataPtr;
+  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &idr_header).action,
+            H264SpsPpsTracker::kInsert);
+
+  EXPECT_EQ(idr_header.width, 320);
+  EXPECT_EQ(idr_header.height, 240);
 }
 
 }  // namespace video_coding
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index 18a7c57..65047ad 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -443,7 +443,10 @@
       InsertSpsPpsIntoTracker(packet.payloadType);
     }
 
-    switch (tracker_.CopyAndFixBitstream(&packet)) {
+    video_coding::H264SpsPpsTracker::FixedBitstream fixed =
+        tracker_.CopyAndFixBitstream(codec_payload, &packet.video_header);
+
+    switch (fixed.action) {
       case video_coding::H264SpsPpsTracker::kRequestKeyframe:
         rtcp_feedback_buffer_.RequestKeyFrame();
         rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
@@ -451,6 +454,8 @@
       case video_coding::H264SpsPpsTracker::kDrop:
         return;
       case video_coding::H264SpsPpsTracker::kInsert:
+        packet.dataPtr = fixed.data.release();
+        packet.sizeBytes = fixed.size;
         break;
     }