in RtpPacketizerVp8 factor out payload splitter function

so that it can be shared between different packetizers
and thus easier to extend

Bug: webrtc:9680
Change-Id: Ie5e904ad27afb8dd2ed35ef9e009f7f408017b2f
Reviewed-on: https://webrtc-review.googlesource.com/97661
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24555}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index 49ccafe..4f36a2e 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -225,6 +225,7 @@
     "../../system_wrappers:metrics_api",
     "../audio_coding:audio_format_conversion",
     "../remote_bitrate_estimator",
+    "//third_party/abseil-cpp/absl/container:inlined_vector",
     "//third_party/abseil-cpp/absl/memory",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
@@ -393,6 +394,7 @@
       "source/rtcp_transceiver_unittest.cc",
       "source/rtp_fec_unittest.cc",
       "source/rtp_format_h264_unittest.cc",
+      "source/rtp_format_unittest.cc",
       "source/rtp_format_video_generic_unittest.cc",
       "source/rtp_format_vp8_test_helper.cc",
       "source/rtp_format_vp8_test_helper.h",
diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc
index 72beb17..bddec73 100644
--- a/modules/rtp_rtcp/source/rtp_format.cc
+++ b/modules/rtp_rtcp/source/rtp_format.cc
@@ -17,6 +17,7 @@
 #include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
 #include "modules/rtp_rtcp/source/rtp_format_vp8.h"
 #include "modules/rtp_rtcp/source/rtp_format_vp9.h"
+#include "rtc_base/checks.h"
 
 namespace webrtc {
 
@@ -61,6 +62,47 @@
   }
 }
 
+std::vector<size_t> RtpPacketizer::SplitAboutEqually(
+    size_t payload_len,
+    const PayloadSizeLimits& limits) {
+  RTC_CHECK_GT(limits.max_payload_len, limits.last_packet_reduction_len);
+
+  // Last packet can be smaller. Pretend that it's the same size, but we must
+  // write more payload to it.
+  size_t total_bytes = payload_len + limits.last_packet_reduction_len;
+  // Integer divisions with rounding up.
+  size_t num_packets_left =
+      (total_bytes + limits.max_payload_len - 1) / limits.max_payload_len;
+  size_t bytes_per_packet = total_bytes / num_packets_left;
+  size_t num_larger_packets = total_bytes % num_packets_left;
+  size_t remaining_data = payload_len;
+
+  std::vector<size_t> result;
+  result.reserve(num_packets_left);
+  while (remaining_data > 0) {
+    // Last num_larger_packets are 1 byte wider than the rest. Increase
+    // per-packet payload size when needed.
+    if (num_packets_left == num_larger_packets)
+      ++bytes_per_packet;
+    size_t current_packet_bytes = bytes_per_packet;
+    if (current_packet_bytes > remaining_data) {
+      current_packet_bytes = remaining_data;
+    }
+    // This is not the last packet in the whole payload, but there's no data
+    // left for the last packet. Leave at least one byte for the last packet.
+    if (num_packets_left == 2 && current_packet_bytes == remaining_data) {
+      --current_packet_bytes;
+    }
+
+    result.push_back(current_packet_bytes);
+
+    remaining_data -= current_packet_bytes;
+    --num_packets_left;
+  }
+
+  return result;
+}
+
 RtpDepacketizer* RtpDepacketizer::Create(VideoCodecType type) {
   switch (type) {
     case kVideoCodecH264:
diff --git a/modules/rtp_rtcp/source/rtp_format.h b/modules/rtp_rtcp/source/rtp_format.h
index 007ddbc..f945d24 100644
--- a/modules/rtp_rtcp/source/rtp_format.h
+++ b/modules/rtp_rtcp/source/rtp_format.h
@@ -13,6 +13,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "api/array_view.h"
 #include "common_types.h"  // NOLINT(build/include)
@@ -47,6 +48,10 @@
   // Write payload and set marker bit of the |packet|.
   // Returns true on success, false otherwise.
   virtual bool NextPacket(RtpPacketToSend* packet) = 0;
+
+  // Split payload_len into sum of integers with respect to |limits|.
+  static std::vector<size_t> SplitAboutEqually(size_t payload_len,
+                                               const PayloadSizeLimits& limits);
 };
 
 // TODO(sprang): Update the depacketizer to return a std::unqie_ptr with a copy
diff --git a/modules/rtp_rtcp/source/rtp_format_unittest.cc b/modules/rtp_rtcp/source/rtp_format_unittest.cc
new file mode 100644
index 0000000..6b83432
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_unittest.cc
@@ -0,0 +1,168 @@
+/*
+ *  Copyright (c) 2018 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 "modules/rtp_rtcp/source/rtp_format.h"
+
+#include <memory>
+#include <numeric>
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Le;
+using ::testing::Each;
+using ::testing::IsEmpty;
+using ::testing::Not;
+using ::testing::SizeIs;
+
+// Calculate difference between largest and smallest packets respecting sizes
+// adjustement provided by limits,
+// i.e. last packet expected to be smaller than 'average' by reduction_len.
+int EffectivePacketsSizeDifference(
+    std::vector<size_t> sizes,
+    const RtpPacketizer::PayloadSizeLimits& limits) {
+  // Account for larger last packet header.
+  sizes.back() += limits.last_packet_reduction_len;
+
+  auto minmax = std::minmax_element(sizes.begin(), sizes.end());
+  // MAX-MIN
+  return *minmax.second - *minmax.first;
+}
+
+size_t Sum(const std::vector<size_t>& sizes) {
+  return std::accumulate(sizes.begin(), sizes.end(), 0);
+}
+
+TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualSumToPayloadLen) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 5;
+  limits.last_packet_reduction_len = 2;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(13, limits);
+
+  EXPECT_THAT(Sum(payload_sizes), 13);
+}
+
+TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualRespectsMaxPayloadSize) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 5;
+  limits.last_packet_reduction_len = 2;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(13, limits);
+
+  EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len)));
+}
+
+TEST(RtpPacketizerSplitAboutEqually,
+     AllPacketsAreEqualRespectsLastPacketReductionLength) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 5;
+  limits.last_packet_reduction_len = 2;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(13, limits);
+
+  ASSERT_THAT(payload_sizes, Not(IsEmpty()));
+  EXPECT_LE(payload_sizes.back() + limits.last_packet_reduction_len,
+            limits.max_payload_len);
+}
+
+TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualInSize) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 5;
+  limits.last_packet_reduction_len = 2;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(13, limits);
+
+  EXPECT_EQ(EffectivePacketsSizeDifference(payload_sizes, limits), 0);
+}
+
+TEST(RtpPacketizerSplitAboutEqually,
+     AllPacketsAreEqualGeneratesMinimumNumberOfPackets) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 5;
+  limits.last_packet_reduction_len = 2;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(13, limits);
+  // Computed by hand. 3 packets would have exactly capacity 3*5-2=13
+  // (max length - for each packet minus last packet reduction).
+  EXPECT_THAT(payload_sizes, SizeIs(3));
+}
+
+TEST(RtpPacketizerSplitAboutEqually, SomePacketsAreSmallerSumToPayloadLen) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 7;
+  limits.last_packet_reduction_len = 5;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(28, limits);
+
+  EXPECT_THAT(Sum(payload_sizes), 28);
+}
+
+TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmallerRespectsMaxPayloadSize) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 7;
+  limits.last_packet_reduction_len = 5;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(28, limits);
+
+  EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len)));
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     SomePacketsAreSmallerRespectsLastPacketReductionLength) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 7;
+  limits.last_packet_reduction_len = 5;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(28, limits);
+
+  EXPECT_LE(payload_sizes.back(),
+            limits.max_payload_len - limits.last_packet_reduction_len);
+}
+
+TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmallerPacketsAlmostEqualInSize) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 7;
+  limits.last_packet_reduction_len = 5;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(28, limits);
+
+  EXPECT_LE(EffectivePacketsSizeDifference(payload_sizes, limits), 1);
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     SomePacketsAreSmallerGeneratesMinimumNumberOfPackets) {
+  RtpPacketizer::PayloadSizeLimits limits;
+  limits.max_payload_len = 7;
+  limits.last_packet_reduction_len = 5;
+
+  std::vector<size_t> payload_sizes =
+      RtpPacketizer::SplitAboutEqually(24, limits);
+  // Computed by hand. 4 packets would have capacity 4*7-5=23 (max length -
+  // for each packet minus last packet reduction).
+  // 5 packets is enough for kPayloadSize.
+  EXPECT_THAT(payload_sizes, SizeIs(5));
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8.cc b/modules/rtp_rtcp/source/rtp_format_vp8.cc
index 4a511fc..b219dac 100644
--- a/modules/rtp_rtcp/source/rtp_format_vp8.cc
+++ b/modules/rtp_rtcp/source/rtp_format_vp8.cc
@@ -23,8 +23,15 @@
 namespace webrtc {
 namespace {
 
-// Length of VP8 payload descriptors' fixed part.
-constexpr int kVp8FixedPayloadDescriptorSize = 1;
+constexpr int kXBit = 0x80;
+constexpr int kNBit = 0x20;
+constexpr int kSBit = 0x10;
+constexpr int kKeyIdxField = 0x1F;
+constexpr int kIBit = 0x80;
+constexpr int kLBit = 0x40;
+constexpr int kTBit = 0x20;
+constexpr int kKBit = 0x10;
+constexpr int kYBit = 0x20;
 
 int ParseVP8PictureID(RTPVideoHeaderVP8* vp8,
                       const uint8_t** data,
@@ -165,259 +172,113 @@
 RtpPacketizerVp8::RtpPacketizerVp8(rtc::ArrayView<const uint8_t> payload,
                                    PayloadSizeLimits limits,
                                    const RTPVideoHeaderVP8& hdr_info)
-    : payload_data_(payload.data()), hdr_info_(hdr_info), limits_(limits) {
-  RTC_DCHECK(ValidateHeader(hdr_info));
-  GeneratePackets(payload.size());
+    : hdr_(BuildHeader(hdr_info)), remaining_payload_(payload) {
+  if (limits.max_payload_len - limits.last_packet_reduction_len <
+      hdr_.size() + 1) {
+    // The provided payload length is not long enough for the payload
+    // descriptor and one payload byte in the last packet.
+    current_packet_ = payload_sizes_.begin();
+    return;
+  }
+  limits.max_payload_len -= hdr_.size();
+  payload_sizes_ = SplitAboutEqually(payload.size(), limits);
+  current_packet_ = payload_sizes_.begin();
 }
 
 RtpPacketizerVp8::~RtpPacketizerVp8() = default;
 
 size_t RtpPacketizerVp8::NumPackets() const {
-  return packets_.size();
+  return payload_sizes_.end() - current_packet_;
 }
 
 bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) {
   RTC_DCHECK(packet);
-  if (packets_.empty()) {
+  if (current_packet_ == payload_sizes_.end()) {
     return false;
   }
-  InfoStruct packet_info = packets_.front();
-  packets_.pop();
 
-  size_t packet_payload_len =
-      packets_.empty()
-          ? limits_.max_payload_len - limits_.last_packet_reduction_len
-          : limits_.max_payload_len;
-  uint8_t* buffer = packet->AllocatePayload(packet_payload_len);
-  int bytes = WriteHeaderAndPayload(packet_info, buffer, packet_payload_len);
-  if (bytes < 0) {
-    return false;
-  }
-  packet->SetPayloadSize(bytes);
-  packet->SetMarker(packets_.empty());
+  size_t packet_payload_len = *current_packet_;
+  ++current_packet_;
+
+  uint8_t* buffer = packet->AllocatePayload(hdr_.size() + packet_payload_len);
+  RTC_CHECK(buffer);
+
+  memcpy(buffer, hdr_.data(), hdr_.size());
+  memcpy(buffer + hdr_.size(), remaining_payload_.data(), packet_payload_len);
+
+  remaining_payload_ = remaining_payload_.subview(packet_payload_len);
+  hdr_[0] &= (~kSBit);  //  Clear 'Start of partition' bit.
+  packet->SetMarker(current_packet_ == payload_sizes_.end());
   return true;
 }
 
-void RtpPacketizerVp8::GeneratePackets(size_t payload_len) {
-  if (limits_.max_payload_len - limits_.last_packet_reduction_len <
-      kVp8FixedPayloadDescriptorSize + PayloadDescriptorExtraLength() + 1) {
-    // The provided payload length is not long enough for the payload
-    // descriptor and one payload byte in the last packet.
-    return;
+// Write the VP8 payload descriptor.
+//       0
+//       0 1 2 3 4 5 6 7 8
+//      +-+-+-+-+-+-+-+-+-+
+//      |X| |N|S| PART_ID |
+//      +-+-+-+-+-+-+-+-+-+
+// X:   |I|L|T|K|         | (mandatory if any of the below are used)
+//      +-+-+-+-+-+-+-+-+-+
+// I:   |PictureID   (16b)| (optional)
+//      +-+-+-+-+-+-+-+-+-+
+// L:   |   TL0PIC_IDX    | (optional)
+//      +-+-+-+-+-+-+-+-+-+
+// T/K: |TID:Y|  KEYIDX   | (optional)
+//      +-+-+-+-+-+-+-+-+-+
+RtpPacketizerVp8::RawHeader RtpPacketizerVp8::BuildHeader(
+    const RTPVideoHeaderVP8& header) {
+  RTC_DCHECK(ValidateHeader(header));
+
+  RawHeader result;
+  bool tid_present = header.temporalIdx != kNoTemporalIdx;
+  bool keyid_present = header.keyIdx != kNoKeyIdx;
+  bool tl0_pid_present = header.tl0PicIdx != kNoTl0PicIdx;
+  bool pid_present = header.pictureId != kNoPictureId;
+  uint8_t x_field = 0;
+  if (pid_present)
+    x_field |= kIBit;
+  if (tl0_pid_present)
+    x_field |= kLBit;
+  if (tid_present)
+    x_field |= kTBit;
+  if (keyid_present)
+    x_field |= kKBit;
+
+  uint8_t flags = 0;
+  if (x_field != 0)
+    flags |= kXBit;
+  if (header.nonReference)
+    flags |= kNBit;
+  // Create header as first packet in the frame. NextPacket() will clear it
+  // after first use.
+  flags |= kSBit;
+  result.push_back(flags);
+  if (x_field == 0) {
+    return result;
   }
-
-  size_t capacity = limits_.max_payload_len - (kVp8FixedPayloadDescriptorSize +
-                                               PayloadDescriptorExtraLength());
-
-  // Last packet of the last partition is smaller. Pretend that it's the same
-  // size, but we must write more payload to it.
-  size_t total_bytes = payload_len + limits_.last_packet_reduction_len;
-  // Integer divisions with rounding up.
-  size_t num_packets_left = (total_bytes + capacity - 1) / capacity;
-  size_t bytes_per_packet = total_bytes / num_packets_left;
-  size_t num_larger_packets = total_bytes % num_packets_left;
-  size_t remaining_data = payload_len;
-  while (remaining_data > 0) {
-    // Last num_larger_packets are 1 byte wider than the rest. Increase
-    // per-packet payload size when needed.
-    if (num_packets_left == num_larger_packets)
-      ++bytes_per_packet;
-    size_t current_packet_bytes = bytes_per_packet;
-    if (current_packet_bytes > remaining_data) {
-      current_packet_bytes = remaining_data;
+  result.push_back(x_field);
+  if (pid_present) {
+    const uint16_t pic_id = static_cast<uint16_t>(header.pictureId);
+    result.push_back(0x80 | ((pic_id >> 8) & 0x7F));
+    result.push_back(pic_id & 0xFF);
+  }
+  if (tl0_pid_present) {
+    result.push_back(header.tl0PicIdx);
+  }
+  if (tid_present || keyid_present) {
+    uint8_t data_field = 0;
+    if (tid_present) {
+      data_field |= header.temporalIdx << 6;
+      if (header.layerSync)
+        data_field |= kYBit;
     }
-    // This is not the last packet in the whole payload, but there's no data
-    // left for the last packet. Leave at least one byte for the last packet.
-    if (num_packets_left == 2 && current_packet_bytes == remaining_data) {
-      --current_packet_bytes;
+    if (keyid_present) {
+      data_field |= (header.keyIdx & kKeyIdxField);
     }
-    QueuePacket(payload_len - remaining_data, current_packet_bytes,
-                /*first_packet=*/remaining_data == payload_len);
-    remaining_data -= current_packet_bytes;
-    --num_packets_left;
+    result.push_back(data_field);
   }
-}
-
-void RtpPacketizerVp8::QueuePacket(size_t start_pos,
-                                   size_t packet_size,
-                                   bool first_packet) {
-  // Write info to packet info struct and store in packet info queue.
-  InfoStruct packet_info;
-  packet_info.payload_start_pos = start_pos;
-  packet_info.size = packet_size;
-  packet_info.first_packet = first_packet;
-  packets_.push(packet_info);
-}
-
-int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
-                                            uint8_t* buffer,
-                                            size_t buffer_length) const {
-  // Write the VP8 payload descriptor.
-  //       0
-  //       0 1 2 3 4 5 6 7 8
-  //      +-+-+-+-+-+-+-+-+-+
-  //      |X| |N|S| PART_ID |
-  //      +-+-+-+-+-+-+-+-+-+
-  // X:   |I|L|T|K|         | (mandatory if any of the below are used)
-  //      +-+-+-+-+-+-+-+-+-+
-  // I:   |PictureID (8/16b)| (optional)
-  //      +-+-+-+-+-+-+-+-+-+
-  // L:   |   TL0PIC_IDX    | (optional)
-  //      +-+-+-+-+-+-+-+-+-+
-  // T/K: |TID:Y|  KEYIDX   | (optional)
-  //      +-+-+-+-+-+-+-+-+-+
-
-  RTC_DCHECK_GT(packet_info.size, 0);
-  buffer[0] = 0;
-  if (XFieldPresent())
-    buffer[0] |= kXBit;
-  if (hdr_info_.nonReference)
-    buffer[0] |= kNBit;
-  if (packet_info.first_packet)
-    buffer[0] |= kSBit;
-
-  const int extension_length = WriteExtensionFields(buffer, buffer_length);
-  if (extension_length < 0)
-    return -1;
-
-  memcpy(&buffer[kVp8FixedPayloadDescriptorSize + extension_length],
-         &payload_data_[packet_info.payload_start_pos], packet_info.size);
-
-  // Return total length of written data.
-  return packet_info.size + kVp8FixedPayloadDescriptorSize + extension_length;
-}
-
-int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
-                                           size_t buffer_length) const {
-  size_t extension_length = 0;
-  if (XFieldPresent()) {
-    uint8_t* x_field = buffer + kVp8FixedPayloadDescriptorSize;
-    *x_field = 0;
-    extension_length = 1;  // One octet for the X field.
-    if (PictureIdPresent()) {
-      if (WritePictureIDFields(x_field, buffer, buffer_length,
-                               &extension_length) < 0) {
-        return -1;
-      }
-    }
-    if (TL0PicIdxFieldPresent()) {
-      if (WriteTl0PicIdxFields(x_field, buffer, buffer_length,
-                               &extension_length) < 0) {
-        return -1;
-      }
-    }
-    if (TIDFieldPresent() || KeyIdxFieldPresent()) {
-      if (WriteTIDAndKeyIdxFields(x_field, buffer, buffer_length,
-                                  &extension_length) < 0) {
-        return -1;
-      }
-    }
-    RTC_DCHECK_EQ(extension_length, PayloadDescriptorExtraLength());
-  }
-  return static_cast<int>(extension_length);
-}
-
-int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
-                                           uint8_t* buffer,
-                                           size_t buffer_length,
-                                           size_t* extension_length) const {
-  *x_field |= kIBit;
-  RTC_DCHECK_GE(buffer_length,
-                kVp8FixedPayloadDescriptorSize + *extension_length);
-  const int pic_id_length = WritePictureID(
-      buffer + kVp8FixedPayloadDescriptorSize + *extension_length,
-      buffer_length - kVp8FixedPayloadDescriptorSize - *extension_length);
-  if (pic_id_length < 0)
-    return -1;
-  *extension_length += pic_id_length;
-  return 0;
-}
-
-int RtpPacketizerVp8::WritePictureID(uint8_t* buffer,
-                                     size_t buffer_length) const {
-  const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId);
-  size_t picture_id_len = PictureIdLength();
-  if (picture_id_len > buffer_length)
-    return -1;
-  if (picture_id_len == 2) {
-    buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
-    buffer[1] = pic_id & 0xFF;
-  } else if (picture_id_len == 1) {
-    buffer[0] = pic_id & 0x7F;
-  }
-  return static_cast<int>(picture_id_len);
-}
-
-int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
-                                           uint8_t* buffer,
-                                           size_t buffer_length,
-                                           size_t* extension_length) const {
-  if (buffer_length < kVp8FixedPayloadDescriptorSize + *extension_length + 1) {
-    return -1;
-  }
-  *x_field |= kLBit;
-  buffer[kVp8FixedPayloadDescriptorSize + *extension_length] =
-      hdr_info_.tl0PicIdx;
-  ++*extension_length;
-  return 0;
-}
-
-int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
-                                              uint8_t* buffer,
-                                              size_t buffer_length,
-                                              size_t* extension_length) const {
-  if (buffer_length < kVp8FixedPayloadDescriptorSize + *extension_length + 1) {
-    return -1;
-  }
-  uint8_t* data_field =
-      &buffer[kVp8FixedPayloadDescriptorSize + *extension_length];
-  *data_field = 0;
-  if (TIDFieldPresent()) {
-    *x_field |= kTBit;
-    *data_field |= hdr_info_.temporalIdx << 6;
-    *data_field |= hdr_info_.layerSync ? kYBit : 0;
-  }
-  if (KeyIdxFieldPresent()) {
-    *x_field |= kKBit;
-    *data_field |= (hdr_info_.keyIdx & kKeyIdxField);
-  }
-  ++*extension_length;
-  return 0;
-}
-
-size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
-  size_t length_bytes = PictureIdLength();
-  if (TL0PicIdxFieldPresent())
-    ++length_bytes;
-  if (TIDFieldPresent() || KeyIdxFieldPresent())
-    ++length_bytes;
-  if (length_bytes > 0)
-    ++length_bytes;  // Include the extension field.
-  return length_bytes;
-}
-
-size_t RtpPacketizerVp8::PictureIdLength() const {
-  if (hdr_info_.pictureId == kNoPictureId) {
-    return 0;
-  }
-  return 2;
-}
-
-bool RtpPacketizerVp8::XFieldPresent() const {
-  return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
-          KeyIdxFieldPresent());
-}
-
-bool RtpPacketizerVp8::TIDFieldPresent() const {
-  return (hdr_info_.temporalIdx != kNoTemporalIdx);
-}
-
-bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
-  return (hdr_info_.keyIdx != kNoKeyIdx);
-}
-
-bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
-  return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
+  return result;
 }
 
 //
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8.h b/modules/rtp_rtcp/source/rtp_format_vp8.h
index dd66762..2fdd6c5 100644
--- a/modules/rtp_rtcp/source/rtp_format_vp8.h
+++ b/modules/rtp_rtcp/source/rtp_format_vp8.h
@@ -25,10 +25,11 @@
 #ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
 #define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
 
-#include <queue>
 #include <string>
 #include <vector>
 
+#include "absl/container/inlined_vector.h"
+#include "api/array_view.h"
 #include "modules/include/module_common_types.h"
 #include "modules/rtp_rtcp/source/rtp_format.h"
 #include "rtc_base/constructormagic.h"
@@ -54,88 +55,14 @@
   bool NextPacket(RtpPacketToSend* packet) override;
 
  private:
-  typedef struct {
-    size_t payload_start_pos;
-    size_t size;
-    bool first_packet;
-  } InfoStruct;
-  typedef std::queue<InfoStruct> InfoQueue;
+  // VP8 header can use up to 6 bytes.
+  using RawHeader = absl::InlinedVector<uint8_t, 6>;
+  static RawHeader BuildHeader(const RTPVideoHeaderVP8& header);
 
-  static const int kXBit = 0x80;
-  static const int kNBit = 0x20;
-  static const int kSBit = 0x10;
-  static const int kPartIdField = 0x0F;
-  static const int kKeyIdxField = 0x1F;
-  static const int kIBit = 0x80;
-  static const int kLBit = 0x40;
-  static const int kTBit = 0x20;
-  static const int kKBit = 0x10;
-  static const int kYBit = 0x20;
-
-  // Calculate all packet sizes and load to packet info queue.
-  void GeneratePackets(size_t payload_len);
-
-  // Insert packet into packet queue.
-  void QueuePacket(size_t start_pos, size_t packet_size, bool first_packet);
-
-  // Write the payload header and copy the payload to the buffer.
-  // The info in packet_info determines which part of the payload is written
-  // and what to write in the header fields.
-  int WriteHeaderAndPayload(const InfoStruct& packet_info,
-                            uint8_t* buffer,
-                            size_t buffer_length) const;
-
-  // Write the X field and the appropriate extension fields to buffer.
-  // The function returns the extension length (including X field), or -1
-  // on error.
-  int WriteExtensionFields(uint8_t* buffer, size_t buffer_length) const;
-
-  // Set the I bit in the x_field, and write PictureID to the appropriate
-  // position in buffer. The function returns 0 on success, -1 otherwise.
-  int WritePictureIDFields(uint8_t* x_field,
-                           uint8_t* buffer,
-                           size_t buffer_length,
-                           size_t* extension_length) const;
-
-  // Set the L bit in the x_field, and write Tl0PicIdx to the appropriate
-  // position in buffer. The function returns 0 on success, -1 otherwise.
-  int WriteTl0PicIdxFields(uint8_t* x_field,
-                           uint8_t* buffer,
-                           size_t buffer_length,
-                           size_t* extension_length) const;
-
-  // Set the T and K bits in the x_field, and write TID, Y and KeyIdx to the
-  // appropriate position in buffer. The function returns 0 on success,
-  // -1 otherwise.
-  int WriteTIDAndKeyIdxFields(uint8_t* x_field,
-                              uint8_t* buffer,
-                              size_t buffer_length,
-                              size_t* extension_length) const;
-
-  // Write the PictureID from codec_specific_info_ to buffer. One or two
-  // bytes are written, depending on magnitude of PictureID. The function
-  // returns the number of bytes written.
-  int WritePictureID(uint8_t* buffer, size_t buffer_length) const;
-
-  // Calculate and return length (octets) of the variable header fields in
-  // the next header (i.e., header length in addition to vp8_header_bytes_).
-  size_t PayloadDescriptorExtraLength() const;
-
-  // Calculate and return length (octets) of PictureID field in the next
-  // header. Can be 0, 1, or 2.
-  size_t PictureIdLength() const;
-
-  // Check whether each of the optional fields will be included in the header.
-  bool XFieldPresent() const;
-  bool TIDFieldPresent() const;
-  bool KeyIdxFieldPresent() const;
-  bool TL0PicIdxFieldPresent() const;
-  bool PictureIdPresent() const { return (PictureIdLength() > 0); }
-
-  const uint8_t* payload_data_;
-  const RTPVideoHeaderVP8 hdr_info_;
-  const PayloadSizeLimits limits_;
-  InfoQueue packets_;
+  RawHeader hdr_;
+  rtc::ArrayView<const uint8_t> remaining_payload_;
+  std::vector<size_t> payload_sizes_;
+  std::vector<size_t>::const_iterator current_packet_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp8);
 };