Rename current flexfec implementation flexfec_03

As per the comment in https://webrtc-review.googlesource.com/c/src/+/303240
on the flexfec_header_reader_writer2.h, renaming this file to flexfec_header_reader_writer.h
and renaming the current implementation to flexfec_03_header_reader_writer.h
as it is based on the 03 draft of the RFC.

Change-Id: I80cb2aba6225ec7cd989a134c3204d1db0ac6f7c
Bug: webrtc:15002
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/307600
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40231}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index cab7bec..80c5f6b 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -170,10 +170,10 @@
     "source/fec_private_tables_bursty.h",
     "source/fec_private_tables_random.cc",
     "source/fec_private_tables_random.h",
+    "source/flexfec_03_header_reader_writer.cc",
+    "source/flexfec_03_header_reader_writer.h",
     "source/flexfec_header_reader_writer.cc",
     "source/flexfec_header_reader_writer.h",
-    "source/flexfec_header_reader_writer2.cc",
-    "source/flexfec_header_reader_writer2.h",
     "source/flexfec_receiver.cc",
     "source/flexfec_sender.cc",
     "source/forward_error_correction.cc",
@@ -552,7 +552,7 @@
       "source/byte_io_unittest.cc",
       "source/capture_clock_offset_updater_unittest.cc",
       "source/fec_private_tables_bursty_unittest.cc",
-      "source/flexfec_header_reader_writer2_unittest.cc",
+      "source/flexfec_03_header_reader_writer_unittest.cc",
       "source/flexfec_header_reader_writer_unittest.cc",
       "source/flexfec_receiver_unittest.cc",
       "source/flexfec_sender_unittest.cc",
diff --git a/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc
new file mode 100644
index 0000000..ddf8e32
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc
@@ -0,0 +1,319 @@
+/*
+ *  Copyright (c) 2016 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/flexfec_03_header_reader_writer.h"
+
+#include <string.h>
+
+#include "api/scoped_refptr.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+namespace {
+
+// Maximum number of media packets that can be protected in one batch.
+constexpr size_t kMaxMediaPackets = 48;  // Since we are reusing ULPFEC masks.
+
+// Maximum number of media packets tracked by FEC decoder.
+// Maintain a sufficiently larger tracking window than `kMaxMediaPackets`
+// to account for packet reordering in pacer/ network.
+constexpr size_t kMaxTrackedMediaPackets = 4 * kMaxMediaPackets;
+
+// Maximum number of FEC packets stored inside ForwardErrorCorrection.
+constexpr size_t kMaxFecPackets = kMaxMediaPackets;
+
+// Size (in bytes) of packet masks, given number of K bits set.
+constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
+
+// Size (in bytes) of part of header which is not packet mask specific.
+constexpr size_t kBaseHeaderSize = 12;
+
+// Size (in bytes) of part of header which is stream specific.
+constexpr size_t kStreamSpecificHeaderSize = 6;
+
+// Size (in bytes) of header, given the single stream packet mask size, i.e.
+// the number of K-bits set.
+constexpr size_t kHeaderSizes[] = {
+    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[0],
+    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1],
+    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]};
+
+// We currently only support single-stream protection.
+// TODO(brandtr): Update this when we support multistream protection.
+constexpr uint8_t kSsrcCount = 1;
+
+// There are three reserved bytes that MUST be set to zero in the header.
+constexpr uint32_t kReservedBits = 0;
+
+// TODO(brandtr): Update this when we support multistream protection.
+constexpr size_t kPacketMaskOffset =
+    kBaseHeaderSize + kStreamSpecificHeaderSize;
+
+// Here we count the K-bits as belonging to the packet mask.
+// This can be used in conjunction with
+// Flexfec03HeaderWriter::MinPacketMaskSize, which calculates a bound on the
+// needed packet mask size including K-bits, given a packet mask without K-bits.
+size_t FlexfecHeaderSize(size_t packet_mask_size) {
+  RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]);
+  if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) {
+    return kHeaderSizes[0];
+  } else if (packet_mask_size <= kFlexfecPacketMaskSizes[1]) {
+    return kHeaderSizes[1];
+  }
+  return kHeaderSizes[2];
+}
+
+}  // namespace
+
+Flexfec03HeaderReader::Flexfec03HeaderReader()
+    : FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {}
+
+Flexfec03HeaderReader::~Flexfec03HeaderReader() = default;
+
+// TODO(brandtr): Update this function when we support flexible masks,
+// retransmissions, and/or several protected SSRCs.
+bool Flexfec03HeaderReader::ReadFecHeader(
+    ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
+  if (fec_packet->pkt->data.size() <=
+      kBaseHeaderSize + kStreamSpecificHeaderSize) {
+    RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+    return false;
+  }
+  uint8_t* const data = fec_packet->pkt->data.MutableData();
+  bool r_bit = (data[0] & 0x80) != 0;
+  if (r_bit) {
+    RTC_LOG(LS_INFO)
+        << "FlexFEC packet with retransmission bit set. We do not yet "
+           "support this, thus discarding the packet.";
+    return false;
+  }
+  bool f_bit = (data[0] & 0x40) != 0;
+  if (f_bit) {
+    RTC_LOG(LS_INFO)
+        << "FlexFEC packet with inflexible generator matrix. We do "
+           "not yet support this, thus discarding packet.";
+    return false;
+  }
+  uint8_t ssrc_count = ByteReader<uint8_t>::ReadBigEndian(&data[8]);
+  if (ssrc_count != 1) {
+    RTC_LOG(LS_INFO)
+        << "FlexFEC packet protecting multiple media SSRCs. We do not "
+           "yet support this, thus discarding packet.";
+    return false;
+  }
+  uint32_t protected_ssrc = ByteReader<uint32_t>::ReadBigEndian(&data[12]);
+  uint16_t seq_num_base = ByteReader<uint16_t>::ReadBigEndian(&data[16]);
+
+  // Parse the FlexFEC packet mask and remove the interleaved K-bits.
+  // (See FEC header schematic in flexfec_header_reader_writer.h.)
+  // We store the packed packet mask in-band, which "destroys" the standards
+  // compliance of the header. That is fine though, since the code that
+  // reads from the header (from this point and onwards) is aware of this.
+  // TODO(brandtr): When the FEC packet classes have been refactored, store
+  // the packed packet masks out-of-band, thus leaving the FlexFEC header as is.
+  //
+  // We treat the mask parts as unsigned integers with host order endianness
+  // in order to simplify the bit shifting between bytes.
+  if (fec_packet->pkt->data.size() < kHeaderSizes[0]) {
+    RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+    return false;
+  }
+  uint8_t* const packet_mask = data + kPacketMaskOffset;
+  bool k_bit0 = (packet_mask[0] & 0x80) != 0;
+  uint16_t mask_part0 = ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+  // Shift away K-bit 0, implicitly clearing the last bit.
+  mask_part0 <<= 1;
+  ByteWriter<uint16_t>::WriteBigEndian(&packet_mask[0], mask_part0);
+  size_t packet_mask_size;
+  if (k_bit0) {
+    // The first K-bit is set, and the packet mask is thus only 2 bytes long.
+    // We have now read the entire FEC header, and the rest of the packet
+    // is payload.
+    packet_mask_size = kFlexfecPacketMaskSizes[0];
+  } else {
+    if (fec_packet->pkt->data.size() < kHeaderSizes[1]) {
+      return false;
+    }
+    bool k_bit1 = (packet_mask[2] & 0x80) != 0;
+    // We have already shifted the first two bytes of the packet mask one step
+    // to the left, thus removing K-bit 0. We will now shift the next four bytes
+    // of the packet mask two steps to the left. (One step for the removed
+    // K-bit 0, and one step for the to be removed K-bit 1).
+    uint8_t bit15 = (packet_mask[2] >> 6) & 0x01;
+    packet_mask[1] |= bit15;
+    uint32_t mask_part1 = ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
+    // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
+    mask_part1 <<= 2;
+    ByteWriter<uint32_t>::WriteBigEndian(&packet_mask[2], mask_part1);
+    if (k_bit1) {
+      // The first K-bit is clear, but the second K-bit is set. The packet
+      // mask is thus 6 bytes long.  We have now read the entire FEC header,
+      // and the rest of the packet is payload.
+      packet_mask_size = kFlexfecPacketMaskSizes[1];
+    } else {
+      if (fec_packet->pkt->data.size() < kHeaderSizes[2]) {
+        RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+        return false;
+      }
+      bool k_bit2 = (packet_mask[6] & 0x80) != 0;
+      if (k_bit2) {
+        // The first and second K-bits are clear, but the third K-bit is set.
+        // The packet mask is thus 14 bytes long. We have now read the entire
+        // FEC header, and the rest of the packet is payload.
+        packet_mask_size = kFlexfecPacketMaskSizes[2];
+      } else {
+        RTC_LOG(LS_WARNING)
+            << "Discarding FlexFEC packet with malformed header.";
+        return false;
+      }
+      // At this point, K-bits 0 and 1 have been removed, and the front-most
+      // part of the FlexFEC packet mask has been packed accordingly. We will
+      // now shift the remaning part of the packet mask three steps to the left.
+      // This corresponds to the (in total) three K-bits, which have been
+      // removed.
+      uint8_t tail_bits = (packet_mask[6] >> 5) & 0x03;
+      packet_mask[5] |= tail_bits;
+      uint64_t mask_part2 =
+          ByteReader<uint64_t>::ReadBigEndian(&packet_mask[6]);
+      // Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last
+      // three bits.
+      mask_part2 <<= 3;
+      ByteWriter<uint64_t>::WriteBigEndian(&packet_mask[6], mask_part2);
+    }
+  }
+
+  // Store "ULPFECized" packet mask info.
+  fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size);
+  fec_packet->protected_streams = {{.ssrc = protected_ssrc,
+                                    .seq_num_base = seq_num_base,
+                                    .packet_mask_offset = kPacketMaskOffset,
+                                    .packet_mask_size = packet_mask_size}};
+  // In FlexFEC, all media packets are protected in their entirety.
+  fec_packet->protection_length =
+      fec_packet->pkt->data.size() - fec_packet->fec_header_size;
+
+  return true;
+}
+
+Flexfec03HeaderWriter::Flexfec03HeaderWriter()
+    : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
+
+Flexfec03HeaderWriter::~Flexfec03HeaderWriter() = default;
+
+size_t Flexfec03HeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask,
+                                                size_t packet_mask_size) const {
+  if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear &&
+      (packet_mask[1] & 0x01) == 0) {
+    // Packet mask is 16 bits long, with bit 15 clear.
+    // It can be used as is.
+    return kFlexfecPacketMaskSizes[0];
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
+    // Packet mask is 16 bits long, with bit 15 set.
+    // We must expand the packet mask with zeros in the FlexFEC header.
+    return kFlexfecPacketMaskSizes[1];
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet &&
+             (packet_mask[5] & 0x03) == 0) {
+    // Packet mask is 48 bits long, with bits 46 and 47 clear.
+    // It can be used as is.
+    return kFlexfecPacketMaskSizes[1];
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
+    // Packet mask is 48 bits long, with at least one of bits 46 and 47 set.
+    // We must expand it with zeros.
+    return kFlexfecPacketMaskSizes[2];
+  }
+  RTC_DCHECK_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size
+                          << ".";
+  return kFlexfecPacketMaskSizes[2];
+}
+
+size_t Flexfec03HeaderWriter::FecHeaderSize(size_t packet_mask_size) const {
+  return FlexfecHeaderSize(packet_mask_size);
+}
+
+// This function adapts the precomputed ULPFEC packet masks to the
+// FlexFEC header standard. Note that the header size is computed by
+// FecHeaderSize(), so in this function we can be sure that we are
+// writing in space that is intended for the header.
+//
+// TODO(brandtr): Update this function when we support offset-based masks,
+// retransmissions, and protecting multiple SSRCs.
+void Flexfec03HeaderWriter::FinalizeFecHeader(
+    uint32_t media_ssrc,
+    uint16_t seq_num_base,
+    const uint8_t* packet_mask,
+    size_t packet_mask_size,
+    ForwardErrorCorrection::Packet* fec_packet) const {
+  uint8_t* data = fec_packet->data.MutableData();
+  data[0] &= 0x7f;  // Clear R bit.
+  data[0] &= 0xbf;  // Clear F bit.
+  ByteWriter<uint8_t>::WriteBigEndian(&data[8], kSsrcCount);
+  ByteWriter<uint32_t, 3>::WriteBigEndian(&data[9], kReservedBits);
+  ByteWriter<uint32_t>::WriteBigEndian(&data[12], media_ssrc);
+  ByteWriter<uint16_t>::WriteBigEndian(&data[16], seq_num_base);
+  // Adapt ULPFEC packet mask to FlexFEC header.
+  //
+  // We treat the mask parts as unsigned integers with host order endianness
+  // in order to simplify the bit shifting between bytes.
+  uint8_t* const written_packet_mask = data + kPacketMaskOffset;
+  if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
+    // The packet mask is 48 bits long.
+    uint16_t tmp_mask_part0 =
+        ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+    uint32_t tmp_mask_part1 =
+        ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
+
+    tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
+    ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
+                                         tmp_mask_part0);
+    tmp_mask_part1 >>= 2;  // Shift, thus clearing K-bit 1 and bit 15.
+    ByteWriter<uint32_t>::WriteBigEndian(&written_packet_mask[2],
+                                         tmp_mask_part1);
+    bool bit15 = (packet_mask[1] & 0x01) != 0;
+    if (bit15)
+      written_packet_mask[2] |= 0x40;  // Set bit 15.
+    bool bit46 = (packet_mask[5] & 0x02) != 0;
+    bool bit47 = (packet_mask[5] & 0x01) != 0;
+    if (!bit46 && !bit47) {
+      written_packet_mask[2] |= 0x80;  // Set K-bit 1.
+    } else {
+      memset(&written_packet_mask[6], 0, 8);  // Clear all trailing bits.
+      written_packet_mask[6] |= 0x80;         // Set K-bit 2.
+      if (bit46)
+        written_packet_mask[6] |= 0x40;  // Set bit 46.
+      if (bit47)
+        written_packet_mask[6] |= 0x20;  // Set bit 47.
+    }
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
+    // The packet mask is 16 bits long.
+    uint16_t tmp_mask_part0 =
+        ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+
+    tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
+    ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
+                                         tmp_mask_part0);
+    bool bit15 = (packet_mask[1] & 0x01) != 0;
+    if (!bit15) {
+      written_packet_mask[0] |= 0x80;  // Set K-bit 0.
+    } else {
+      memset(&written_packet_mask[2], 0U, 4);  // Clear all trailing bits.
+      written_packet_mask[2] |= 0x80;          // Set K-bit 1.
+      written_packet_mask[2] |= 0x40;          // Set bit 15.
+    }
+  } else {
+    RTC_DCHECK_NOTREACHED()
+        << "Incorrect packet mask size: " << packet_mask_size << ".";
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h
new file mode 100644
index 0000000..c5e965e
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2016 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.
+ */
+
+#ifndef MODULES_RTP_RTCP_SOURCE_FLEXFEC_03_HEADER_READER_WRITER_H_
+#define MODULES_RTP_RTCP_SOURCE_FLEXFEC_03_HEADER_READER_WRITER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+
+namespace webrtc {
+
+// FlexFEC header, minimum 20 bytes.
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |R|F|P|X|  CC   |M| PT recovery |        length recovery        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                          TS recovery                          |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |   SSRCCount   |                    reserved                   |
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// 12 |                             SSRC_i                            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |           SN base_i           |k|          Mask [0-14]        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 |k|                   Mask [15-45] (optional)                   |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 24 |k|                                                             |
+//    +-+                   Mask [46-108] (optional)                  |
+// 28 |                                                               |
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//    :                     ... next in SSRC_i ...                    :
+//
+//
+// FlexFEC header in 'inflexible' mode (F = 1), 20 bytes.
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |0|1|P|X|  CC   |M| PT recovery |        length recovery        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                          TS recovery                          |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |   SSRCCount   |                    reserved                   |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |                             SSRC_i                            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |           SN base_i           |  M (columns)  |    N (rows)   |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class Flexfec03HeaderReader : public FecHeaderReader {
+ public:
+  Flexfec03HeaderReader();
+  ~Flexfec03HeaderReader() override;
+
+  bool ReadFecHeader(
+      ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override;
+};
+
+class Flexfec03HeaderWriter : public FecHeaderWriter {
+ public:
+  Flexfec03HeaderWriter();
+  ~Flexfec03HeaderWriter() override;
+
+  size_t MinPacketMaskSize(const uint8_t* packet_mask,
+                           size_t packet_mask_size) const override;
+
+  size_t FecHeaderSize(size_t packet_mask_row_size) const override;
+
+  void FinalizeFecHeader(
+      uint32_t media_ssrc,
+      uint16_t seq_num_base,
+      const uint8_t* packet_mask,
+      size_t packet_mask_size,
+      ForwardErrorCorrection::Packet* fec_packet) const override;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_FLEXFEC_03_HEADER_READER_WRITER_H_
diff --git a/modules/rtp_rtcp/source/flexfec_03_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer_unittest.cc
new file mode 100644
index 0000000..e58e1b4
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer_unittest.cc
@@ -0,0 +1,565 @@
+/*
+ *  Copyright (c) 2016 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/flexfec_03_header_reader_writer.h"
+
+#include <string.h>
+
+#include <memory>
+#include <utility>
+
+#include "api/scoped_refptr.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/random.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using Packet = ForwardErrorCorrection::Packet;
+using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
+using ::testing::ElementsAreArray;
+using ::testing::make_tuple;
+using ::testing::SizeIs;
+
+// General. Assume single-stream protection.
+constexpr uint32_t kMediaSsrc = 1254983;
+constexpr uint16_t kMediaStartSeqNum = 825;
+constexpr size_t kMediaPacketLength = 1234;
+constexpr uint32_t kFlexfecSsrc = 52142;
+
+constexpr size_t kFlexfecHeaderSizes[] = {20, 24, 32};
+constexpr size_t kFlexfecPacketMaskOffset = 18;
+constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
+constexpr size_t kFlexfecMaxPacketSize = kFlexfecPacketMaskSizes[2];
+
+// Reader tests.
+constexpr uint8_t kNoRBit = 0 << 7;
+constexpr uint8_t kNoFBit = 0 << 6;
+constexpr uint8_t kPtRecovery = 123;
+constexpr uint8_t kLengthRecov[] = {0xab, 0xcd};
+constexpr uint8_t kTsRecovery[] = {0x01, 0x23, 0x45, 0x67};
+constexpr uint8_t kSsrcCount = 1;
+constexpr uint8_t kReservedBits = 0x00;
+constexpr uint8_t kProtSsrc[] = {0x11, 0x22, 0x33, 0x44};
+constexpr uint8_t kSnBase[] = {0xaa, 0xbb};
+constexpr uint8_t kPayloadBits = 0x00;
+
+std::unique_ptr<uint8_t[]> GeneratePacketMask(size_t packet_mask_size,
+                                              uint64_t seed) {
+  Random random(seed);
+  std::unique_ptr<uint8_t[]> packet_mask(new uint8_t[kFlexfecMaxPacketSize]);
+  memset(packet_mask.get(), 0, kFlexfecMaxPacketSize);
+  for (size_t i = 0; i < packet_mask_size; ++i) {
+    packet_mask[i] = random.Rand<uint8_t>();
+  }
+  return packet_mask;
+}
+
+void ClearBit(size_t index, uint8_t* packet_mask) {
+  packet_mask[index / 8] &= ~(1 << (7 - index % 8));
+}
+
+void SetBit(size_t index, uint8_t* packet_mask) {
+  packet_mask[index / 8] |= (1 << (7 - index % 8));
+}
+
+rtc::scoped_refptr<Packet> WriteHeader(const uint8_t* packet_mask,
+                                       size_t packet_mask_size) {
+  Flexfec03HeaderWriter writer;
+  rtc::scoped_refptr<Packet> written_packet(new Packet());
+  written_packet->data.SetSize(kMediaPacketLength);
+  uint8_t* data = written_packet->data.MutableData();
+  for (size_t i = 0; i < written_packet->data.size(); ++i) {
+    data[i] = i;  // Actual content doesn't matter.
+  }
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask,
+                           packet_mask_size, written_packet.get());
+  return written_packet;
+}
+
+std::unique_ptr<ReceivedFecPacket> ReadHeader(const Packet& written_packet) {
+  Flexfec03HeaderReader reader;
+  std::unique_ptr<ReceivedFecPacket> read_packet(new ReceivedFecPacket());
+  read_packet->ssrc = kFlexfecSsrc;
+  read_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
+  read_packet->pkt->data = written_packet.data;
+  EXPECT_TRUE(reader.ReadFecHeader(read_packet.get()));
+  return read_packet;
+}
+
+void VerifyReadHeaders(size_t expected_fec_header_size,
+                       const uint8_t* expected_packet_mask,
+                       size_t expected_packet_mask_size,
+                       const ReceivedFecPacket& read_packet) {
+  EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
+  EXPECT_EQ(ByteReader<uint32_t>::ReadBigEndian(kProtSsrc),
+            read_packet.protected_streams[0].ssrc);
+  EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(kSnBase),
+            read_packet.protected_streams[0].seq_num_base);
+  auto packet_mask_offset = read_packet.protected_streams[0].packet_mask_offset;
+  EXPECT_EQ(kFlexfecPacketMaskOffset, packet_mask_offset);
+  EXPECT_EQ(expected_packet_mask_size,
+            read_packet.protected_streams[0].packet_mask_size);
+  EXPECT_EQ(read_packet.pkt->data.size() - expected_fec_header_size,
+            read_packet.protection_length);
+  // Ensure that the K-bits are removed and the packet mask has been packed.
+  EXPECT_THAT(
+      make_tuple(read_packet.pkt->data.cdata() + packet_mask_offset,
+                 read_packet.protected_streams[0].packet_mask_size),
+      ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
+}
+
+void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask,
+                            size_t expected_packet_mask_size,
+                            const Packet& written_packet) {
+  const uint8_t* packet = written_packet.data.cdata();
+  EXPECT_EQ(0x00, packet[0] & 0x80);  // F bit clear.
+  EXPECT_EQ(0x00, packet[0] & 0x40);  // R bit clear.
+  EXPECT_EQ(0x01, packet[8]);         // SSRCCount = 1.
+  EXPECT_EQ(kMediaSsrc, ByteReader<uint32_t>::ReadBigEndian(packet + 12));
+  EXPECT_EQ(kMediaStartSeqNum,
+            ByteReader<uint16_t>::ReadBigEndian(packet + 16));
+  EXPECT_THAT(
+      make_tuple(packet + kFlexfecPacketMaskOffset, expected_packet_mask_size),
+      ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
+}
+
+void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size,
+                                 const uint8_t* expected_packet_mask,
+                                 size_t expected_packet_mask_size,
+                                 const Packet& written_packet,
+                                 const ReceivedFecPacket& read_packet) {
+  EXPECT_EQ(kFlexfecSsrc, read_packet.ssrc);
+  EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
+  ASSERT_THAT(read_packet.protected_streams, SizeIs(1));
+  EXPECT_EQ(read_packet.protected_streams[0].ssrc, kMediaSsrc);
+  EXPECT_EQ(read_packet.protected_streams[0].seq_num_base, kMediaStartSeqNum);
+  EXPECT_EQ(read_packet.protected_streams[0].packet_mask_offset,
+            kFlexfecPacketMaskOffset);
+  ASSERT_EQ(read_packet.protected_streams[0].packet_mask_size,
+            expected_packet_mask_size);
+  EXPECT_EQ(written_packet.data.size() - expected_fec_header_size,
+            read_packet.protection_length);
+  // Verify that the call to ReadFecHeader did normalize the packet masks.
+  EXPECT_THAT(
+      make_tuple(read_packet.pkt->data.cdata() + kFlexfecPacketMaskOffset,
+                 read_packet.protected_streams[0].packet_mask_size),
+      ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
+  // Verify that the call to ReadFecHeader did not tamper with the payload.
+  EXPECT_THAT(
+      make_tuple(read_packet.pkt->data.cdata() + read_packet.fec_header_size,
+                 read_packet.pkt->data.size() - read_packet.fec_header_size),
+      ElementsAreArray(written_packet.data.cdata() + expected_fec_header_size,
+                       written_packet.data.size() - expected_fec_header_size));
+}
+
+}  // namespace
+
+TEST(Flexfec03HeaderReaderTest, ReadsHeaderWithKBit0Set) {
+  constexpr uint8_t kKBit0 = 1 << 7;
+  constexpr size_t kExpectedPacketMaskSize = 2;
+  constexpr size_t kExpectedFecHeaderSize = 20;
+  // clang-format off
+  constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81};
+  constexpr uint8_t kUlpfecPacketMask[] =        {0x11, 0x02};
+  // clang-format on
+  constexpr uint8_t kPacketData[] = {
+      kNoRBit | kNoFBit, kPtRecovery,    kLengthRecov[0],    kLengthRecov[1],
+      kTsRecovery[0],    kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
+      kSsrcCount,        kReservedBits,  kReservedBits,      kReservedBits,
+      kProtSsrc[0],      kProtSsrc[1],   kProtSsrc[2],       kProtSsrc[3],
+      kSnBase[0],        kSnBase[1],     kFlexfecPktMask[0], kFlexfecPktMask[1],
+      kPayloadBits,      kPayloadBits,   kPayloadBits,       kPayloadBits};
+  const size_t packet_length = sizeof(kPacketData);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  read_packet.pkt->data.SetData(kPacketData, packet_length);
+
+  Flexfec03HeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
+                    kExpectedPacketMaskSize, read_packet);
+}
+
+TEST(Flexfec03HeaderReaderTest, ReadsHeaderWithKBit1Set) {
+  constexpr uint8_t kKBit0 = 0 << 7;
+  constexpr uint8_t kKBit1 = 1 << 7;
+  constexpr size_t kExpectedPacketMaskSize = 6;
+  constexpr size_t kExpectedFecHeaderSize = 24;
+  // clang-format off
+  constexpr uint8_t kFlxfecPktMsk[] = {kKBit0 | 0x48, 0x81,
+                                       kKBit1 | 0x02, 0x11, 0x00, 0x21};
+  constexpr uint8_t kUlpfecPacketMask[] =      {0x91, 0x02,
+                                                0x08, 0x44, 0x00, 0x84};
+  // clang-format on
+  constexpr uint8_t kPacketData[] = {
+      kNoRBit | kNoFBit, kPtRecovery,      kLengthRecov[0],  kLengthRecov[1],
+      kTsRecovery[0],    kTsRecovery[1],   kTsRecovery[2],   kTsRecovery[3],
+      kSsrcCount,        kReservedBits,    kReservedBits,    kReservedBits,
+      kProtSsrc[0],      kProtSsrc[1],     kProtSsrc[2],     kProtSsrc[3],
+      kSnBase[0],        kSnBase[1],       kFlxfecPktMsk[0], kFlxfecPktMsk[1],
+      kFlxfecPktMsk[2],  kFlxfecPktMsk[3], kFlxfecPktMsk[4], kFlxfecPktMsk[5],
+      kPayloadBits,      kPayloadBits,     kPayloadBits,     kPayloadBits};
+  const size_t packet_length = sizeof(kPacketData);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  read_packet.pkt->data.SetData(kPacketData, packet_length);
+
+  Flexfec03HeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
+                    kExpectedPacketMaskSize, read_packet);
+}
+
+TEST(Flexfec03HeaderReaderTest, ReadsHeaderWithKBit2Set) {
+  constexpr uint8_t kKBit0 = 0 << 7;
+  constexpr uint8_t kKBit1 = 0 << 7;
+  constexpr uint8_t kKBit2 = 1 << 7;
+  constexpr size_t kExpectedPacketMaskSize = 14;
+  constexpr size_t kExpectedFecHeaderSize = 32;
+  // clang-format off
+  constexpr uint8_t kFlxfcPktMsk[] = {kKBit0 | 0x48, 0x81,
+                                      kKBit1 | 0x02, 0x11, 0x00, 0x21,
+                                      kKBit2 | 0x01, 0x11, 0x11, 0x11,
+                                               0x11, 0x11, 0x11, 0x11};
+  constexpr uint8_t kUlpfecPacketMask[] =     {0x91, 0x02,
+                                               0x08, 0x44, 0x00, 0x84,
+                                               0x08, 0x88, 0x88, 0x88,
+                                               0x88, 0x88, 0x88, 0x88};
+  // clang-format on
+  constexpr uint8_t kPacketData[] = {
+      kNoRBit | kNoFBit, kPtRecovery,      kLengthRecov[0],  kLengthRecov[1],
+      kTsRecovery[0],    kTsRecovery[1],   kTsRecovery[2],   kTsRecovery[3],
+      kSsrcCount,        kReservedBits,    kReservedBits,    kReservedBits,
+      kProtSsrc[0],      kProtSsrc[1],     kProtSsrc[2],     kProtSsrc[3],
+      kSnBase[0],        kSnBase[1],       kFlxfcPktMsk[0],  kFlxfcPktMsk[1],
+      kFlxfcPktMsk[2],   kFlxfcPktMsk[3],  kFlxfcPktMsk[4],  kFlxfcPktMsk[5],
+      kFlxfcPktMsk[6],   kFlxfcPktMsk[7],  kFlxfcPktMsk[8],  kFlxfcPktMsk[9],
+      kFlxfcPktMsk[10],  kFlxfcPktMsk[11], kFlxfcPktMsk[12], kFlxfcPktMsk[13],
+      kPayloadBits,      kPayloadBits,     kPayloadBits,     kPayloadBits};
+  const size_t packet_length = sizeof(kPacketData);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  read_packet.pkt->data.SetData(kPacketData, packet_length);
+
+  Flexfec03HeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
+                    kExpectedPacketMaskSize, read_packet);
+}
+
+TEST(Flexfec03HeaderReaderTest,
+     ReadPacketWithoutStreamSpecificHeaderShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->data.SetSize(12);
+
+  Flexfec03HeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(Flexfec03HeaderReaderTest, ReadShortPacketWithKBit0SetShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->data.SetSize(18);
+
+  Flexfec03HeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(Flexfec03HeaderReaderTest, ReadShortPacketWithKBit1SetShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(15, packet_mask.get());  // This expands the packet mask "once".
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->data.SetSize(20);
+
+  Flexfec03HeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(Flexfec03HeaderReaderTest, ReadShortPacketWithKBit2SetShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(47, packet_mask.get());  // This expands the packet mask "twice".
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->data.SetSize(24);
+
+  Flexfec03HeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(Flexfec03HeaderWriterTest, FinalizesHeaderWithKBit0Set) {
+  constexpr size_t kExpectedPacketMaskSize = 2;
+  constexpr uint8_t kFlexfecPacketMask[] = {0x88, 0x81};
+  constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
+  Packet written_packet;
+  written_packet.data.SetSize(kMediaPacketLength);
+  uint8_t* data = written_packet.data.MutableData();
+  for (size_t i = 0; i < written_packet.data.size(); ++i) {
+    data[i] = i;
+  }
+
+  Flexfec03HeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
+                           sizeof(kUlpfecPacketMask), &written_packet);
+
+  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
+                         written_packet);
+}
+
+TEST(Flexfec03HeaderWriterTest, FinalizesHeaderWithKBit1Set) {
+  constexpr size_t kExpectedPacketMaskSize = 6;
+  constexpr uint8_t kFlexfecPacketMask[] = {0x48, 0x81, 0x82, 0x11, 0x00, 0x21};
+  constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84};
+  Packet written_packet;
+  written_packet.data.SetSize(kMediaPacketLength);
+  uint8_t* data = written_packet.data.MutableData();
+  for (size_t i = 0; i < written_packet.data.size(); ++i) {
+    data[i] = i;
+  }
+
+  Flexfec03HeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
+                           sizeof(kUlpfecPacketMask), &written_packet);
+
+  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
+                         written_packet);
+}
+
+TEST(Flexfec03HeaderWriterTest, FinalizesHeaderWithKBit2Set) {
+  constexpr size_t kExpectedPacketMaskSize = 14;
+  constexpr uint8_t kFlexfecPacketMask[] = {
+      0x11, 0x11,                                     // K-bit 0 clear.
+      0x11, 0x11, 0x11, 0x10,                         // K-bit 1 clear.
+      0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // K-bit 2 set.
+  };
+  constexpr uint8_t kUlpfecPacketMask[] = {0x22, 0x22, 0x44, 0x44, 0x44, 0x41};
+  Packet written_packet;
+  written_packet.data.SetSize(kMediaPacketLength);
+  uint8_t* data = written_packet.data.MutableData();
+  for (size_t i = 0; i < written_packet.data.size(); ++i) {
+    data[i] = i;
+  }
+
+  Flexfec03HeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
+                           sizeof(kUlpfecPacketMask), &written_packet);
+
+  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
+                         written_packet);
+}
+
+TEST(Flexfec03HeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(15, packet_mask.get());
+
+  Flexfec03HeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[0], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[0], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(Flexfec03HeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(15, packet_mask.get());
+
+  Flexfec03HeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(Flexfec03HeaderWriterTest,
+     ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  Flexfec03HeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(Flexfec03HeaderWriterTest,
+     ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  Flexfec03HeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(Flexfec03HeaderWriterTest,
+     ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  Flexfec03HeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(Flexfec03HeaderWriterTest,
+     ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  Flexfec03HeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(Flexfec03HeaderReaderWriterTest,
+     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(15, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[0], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[0], *written_packet,
+                              *read_packet);
+}
+
+TEST(Flexfec03HeaderReaderWriterTest,
+     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(15, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[1], *written_packet,
+                              *read_packet);
+}
+
+TEST(Flexfec03HeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[1], *written_packet,
+                              *read_packet);
+}
+
+TEST(Flexfec03HeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[2], *written_packet,
+                              *read_packet);
+}
+
+TEST(Flexfec03HeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[2], *written_packet,
+                              *read_packet);
+}
+
+TEST(Flexfec03HeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[2], *written_packet,
+                              *read_packet);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
index 7a7bff7..b659682 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *  Copyright (c) 2023 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
@@ -37,10 +37,10 @@
 constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
 
 // Size (in bytes) of part of header which is not packet mask specific.
-constexpr size_t kBaseHeaderSize = 12;
+constexpr size_t kBaseHeaderSize = 8;
 
 // Size (in bytes) of part of header which is stream specific.
-constexpr size_t kStreamSpecificHeaderSize = 6;
+constexpr size_t kStreamSpecificHeaderSize = 2;
 
 // Size (in bytes) of header, given the single stream packet mask size, i.e.
 // the number of K-bits set.
@@ -82,9 +82,15 @@
 FlexfecHeaderReader::~FlexfecHeaderReader() = default;
 
 // TODO(brandtr): Update this function when we support flexible masks,
-// retransmissions, and/or several protected SSRCs.
+// and retransmissions.
 bool FlexfecHeaderReader::ReadFecHeader(
     ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
+  // Protected ssrcs should already be populated from RTP header.
+  if (fec_packet->protected_streams.empty()) {
+    RTC_LOG(LS_WARNING)
+        << "Discarding FlexFEC packet with no protected sources.";
+    return false;
+  }
   if (fec_packet->pkt->data.size() <=
       kBaseHeaderSize + kStreamSpecificHeaderSize) {
     RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
@@ -105,100 +111,103 @@
            "not yet support this, thus discarding packet.";
     return false;
   }
-  uint8_t ssrc_count = ByteReader<uint8_t>::ReadBigEndian(&data[8]);
-  if (ssrc_count != 1) {
-    RTC_LOG(LS_INFO)
-        << "FlexFEC packet protecting multiple media SSRCs. We do not "
-           "yet support this, thus discarding packet.";
-    return false;
-  }
-  uint32_t protected_ssrc = ByteReader<uint32_t>::ReadBigEndian(&data[12]);
-  uint16_t seq_num_base = ByteReader<uint16_t>::ReadBigEndian(&data[16]);
 
-  // Parse the FlexFEC packet mask and remove the interleaved K-bits.
+  // First seq_num will be in byte index 8
   // (See FEC header schematic in flexfec_header_reader_writer.h.)
-  // We store the packed packet mask in-band, which "destroys" the standards
-  // compliance of the header. That is fine though, since the code that
-  // reads from the header (from this point and onwards) is aware of this.
-  // TODO(brandtr): When the FEC packet classes have been refactored, store
-  // the packed packet masks out-of-band, thus leaving the FlexFEC header as is.
-  //
-  // We treat the mask parts as unsigned integers with host order endianness
-  // in order to simplify the bit shifting between bytes.
-  if (fec_packet->pkt->data.size() < kHeaderSizes[0]) {
-    RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
-    return false;
-  }
-  uint8_t* const packet_mask = data + kPacketMaskOffset;
-  bool k_bit0 = (packet_mask[0] & 0x80) != 0;
-  uint16_t mask_part0 = ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
-  // Shift away K-bit 0, implicitly clearing the last bit.
-  mask_part0 <<= 1;
-  ByteWriter<uint16_t>::WriteBigEndian(&packet_mask[0], mask_part0);
-  size_t packet_mask_size;
-  if (k_bit0) {
-    // The first K-bit is set, and the packet mask is thus only 2 bytes long.
-    // We have now read the entire FEC header, and the rest of the packet
-    // is payload.
-    packet_mask_size = kFlexfecPacketMaskSizes[0];
-  } else {
-    if (fec_packet->pkt->data.size() < kHeaderSizes[1]) {
+  size_t byte_index = 8;
+  for (size_t i = 0; i < fec_packet->protected_streams.size(); ++i) {
+    if (fec_packet->pkt->data.size() < byte_index + kStreamSpecificHeaderSize) {
+      RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
       return false;
     }
-    bool k_bit1 = (packet_mask[2] & 0x80) != 0;
-    // We have already shifted the first two bytes of the packet mask one step
-    // to the left, thus removing K-bit 0. We will now shift the next four bytes
-    // of the packet mask two steps to the left. (One step for the removed
-    // K-bit 0, and one step for the to be removed K-bit 1).
-    uint8_t bit15 = (packet_mask[2] >> 6) & 0x01;
-    packet_mask[1] |= bit15;
-    uint32_t mask_part1 = ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
-    // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
-    mask_part1 <<= 2;
-    ByteWriter<uint32_t>::WriteBigEndian(&packet_mask[2], mask_part1);
-    if (k_bit1) {
-      // The first K-bit is clear, but the second K-bit is set. The packet
-      // mask is thus 6 bytes long.  We have now read the entire FEC header,
-      // and the rest of the packet is payload.
-      packet_mask_size = kFlexfecPacketMaskSizes[1];
+
+    fec_packet->protected_streams[i].seq_num_base =
+        ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
+    byte_index += kStreamSpecificHeaderSize;
+
+    // Parse the FlexFEC packet mask and remove the interleaved K-bits.
+    // (See FEC header schematic in flexfec_header_reader_writer.h.)
+    // We store the packed packet mask in-band, which "destroys" the standards
+    // compliance of the header. That is fine though, since the code that
+    // reads from the header (from this point and onwards) is aware of this.
+    // TODO(brandtr): When the FEC packet classes have been refactored, store
+    // the packed packet masks out-of-band, thus leaving the FlexFEC header as
+    // is.
+    //
+    // We treat the mask parts as unsigned integers with host order endianness
+    // in order to simplify the bit shifting between bytes.
+    if (fec_packet->pkt->data.size() <
+        (byte_index + kFlexfecPacketMaskSizes[0])) {
+      RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+      return false;
+    }
+    fec_packet->protected_streams[i].packet_mask_offset = byte_index;
+    bool k_bit0 = (data[byte_index] & 0x80) != 0;
+    uint16_t mask_part0 =
+        ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
+    // Shift away K-bit 0, implicitly clearing the last bit.
+    mask_part0 <<= 1;
+    ByteWriter<uint16_t>::WriteBigEndian(&data[byte_index], mask_part0);
+    byte_index += kFlexfecPacketMaskSizes[0];
+    if (k_bit0) {
+      // The first K-bit is set, and the packet mask is thus only 2 bytes long.
+      // We have finished reading the properties for current ssrc.
+      fec_packet->protected_streams[i].packet_mask_size =
+          kFlexfecPacketMaskSizes[0];
     } else {
-      if (fec_packet->pkt->data.size() < kHeaderSizes[2]) {
-        RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+      if (fec_packet->pkt->data.size() <
+          (byte_index + kFlexfecPacketMaskSizes[1] -
+           kFlexfecPacketMaskSizes[0])) {
         return false;
       }
-      bool k_bit2 = (packet_mask[6] & 0x80) != 0;
-      if (k_bit2) {
-        // The first and second K-bits are clear, but the third K-bit is set.
-        // The packet mask is thus 14 bytes long. We have now read the entire
-        // FEC header, and the rest of the packet is payload.
-        packet_mask_size = kFlexfecPacketMaskSizes[2];
+      bool k_bit1 = (data[byte_index] & 0x80) != 0;
+      // We have already shifted the first two bytes of the packet mask one step
+      // to the left, thus removing K-bit 0. We will now shift the next four
+      // bytes of the packet mask two steps to the left. (One step for the
+      // removed K-bit 0, and one step for the to be removed K-bit 1).
+      uint8_t bit15 = (data[byte_index] >> 6) & 0x01;
+      data[byte_index - 1] |= bit15;
+      uint32_t mask_part1 =
+          ByteReader<uint32_t>::ReadBigEndian(&data[byte_index]);
+      // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
+      mask_part1 <<= 2;
+      ByteWriter<uint32_t>::WriteBigEndian(&data[byte_index], mask_part1);
+      byte_index += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
+      if (k_bit1) {
+        // The first K-bit is clear, but the second K-bit is set. The packet
+        // mask is thus 6 bytes long. We have finished reading the properties
+        // for current ssrc.
+        fec_packet->protected_streams[i].packet_mask_size =
+            kFlexfecPacketMaskSizes[1];
       } else {
-        RTC_LOG(LS_WARNING)
-            << "Discarding FlexFEC packet with malformed header.";
-        return false;
+        if (fec_packet->pkt->data.size() <
+            (byte_index + kFlexfecPacketMaskSizes[2] -
+             kFlexfecPacketMaskSizes[1])) {
+          RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+          return false;
+        }
+        fec_packet->protected_streams[i].packet_mask_size =
+            kFlexfecPacketMaskSizes[2];
+        // At this point, K-bits 0 and 1 have been removed, and the front-most
+        // part of the FlexFEC packet mask has been packed accordingly. We will
+        // now shift the remaning part of the packet mask two steps to the left.
+        // This corresponds to the (in total) two K-bits, which have been
+        // removed.
+        uint8_t tail_bits = (data[byte_index] >> 6) & 0x03;
+        data[byte_index - 1] |= tail_bits;
+        uint64_t mask_part2 =
+            ByteReader<uint64_t>::ReadBigEndian(&data[byte_index]);
+        // Shift away bit 46, and bit 47, which were copied to the previous
+        // part of the mask, implicitly clearing the last two bits.
+        mask_part2 <<= 2;
+        ByteWriter<uint64_t>::WriteBigEndian(&data[byte_index], mask_part2);
+        byte_index += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1];
       }
-      // At this point, K-bits 0 and 1 have been removed, and the front-most
-      // part of the FlexFEC packet mask has been packed accordingly. We will
-      // now shift the remaning part of the packet mask three steps to the left.
-      // This corresponds to the (in total) three K-bits, which have been
-      // removed.
-      uint8_t tail_bits = (packet_mask[6] >> 5) & 0x03;
-      packet_mask[5] |= tail_bits;
-      uint64_t mask_part2 =
-          ByteReader<uint64_t>::ReadBigEndian(&packet_mask[6]);
-      // Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last
-      // three bits.
-      mask_part2 <<= 3;
-      ByteWriter<uint64_t>::WriteBigEndian(&packet_mask[6], mask_part2);
     }
   }
 
-  // Store "ULPFECized" packet mask info.
-  fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size);
-  fec_packet->protected_streams = {{.ssrc = protected_ssrc,
-                                    .seq_num_base = seq_num_base,
-                                    .packet_mask_offset = kPacketMaskOffset,
-                                    .packet_mask_size = packet_mask_size}};
+  fec_packet->fec_header_size = byte_index;
+
   // In FlexFEC, all media packets are protected in their entirety.
   fec_packet->protection_length =
       fec_packet->pkt->data.size() - fec_packet->fec_header_size;
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.h b/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
index d305c4c..a49702b 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *  Copyright (c) 2023 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
@@ -18,43 +18,25 @@
 
 namespace webrtc {
 
-// FlexFEC header, minimum 20 bytes.
+// FlexFEC header in flexible mode (R=0, F=0), minimum 12 bytes.
+// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
+//
 //     0                   1                   2                   3
 //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  0 |R|F|P|X|  CC   |M| PT recovery |        length recovery        |
+//  0 |0|0|P|X|  CC   |M| PT recovery |        length recovery        |
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //  4 |                          TS recovery                          |
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  8 |   SSRCCount   |                    reserved                   |
-//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-// 12 |                             SSRC_i                            |
+//  8 |           SN base_i           |k|          Mask [0-14]        |
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 16 |           SN base_i           |k|          Mask [0-14]        |
+// 12 |k|                   Mask [15-45] (optional)                   |
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 20 |k|                   Mask [15-45] (optional)                   |
+// 16 |                     Mask [46-109] (optional)                  |
+// 20 |                                                               |
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 24 |k|                                                             |
-//    +-+                   Mask [46-108] (optional)                  |
-// 28 |                                                               |
-//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//    :                     ... next in SSRC_i ...                    :
+//    |   ... next SN base and Mask for CSRC_i in CSRC list ...       |
 //
-//
-// FlexFEC header in 'inflexible' mode (F = 1), 20 bytes.
-//     0                   1                   2                   3
-//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  0 |0|1|P|X|  CC   |M| PT recovery |        length recovery        |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  4 |                          TS recovery                          |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  8 |   SSRCCount   |                    reserved                   |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 12 |                             SSRC_i                            |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 16 |           SN base_i           |  M (columns)  |    N (rows)   |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
 class FlexfecHeaderReader : public FecHeaderReader {
  public:
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc
deleted file mode 100644
index a6ac68b..0000000
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- *  Copyright (c) 2023 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/flexfec_header_reader_writer2.h"
-
-#include <string.h>
-
-#include "api/scoped_refptr.h"
-#include "modules/rtp_rtcp/source/byte_io.h"
-#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-
-namespace webrtc {
-
-namespace {
-
-// Maximum number of media packets that can be protected in one batch.
-constexpr size_t kMaxMediaPackets = 48;  // Since we are reusing ULPFEC masks.
-
-// Maximum number of media packets tracked by FEC decoder.
-// Maintain a sufficiently larger tracking window than `kMaxMediaPackets`
-// to account for packet reordering in pacer/ network.
-constexpr size_t kMaxTrackedMediaPackets = 4 * kMaxMediaPackets;
-
-// Maximum number of FEC packets stored inside ForwardErrorCorrection.
-constexpr size_t kMaxFecPackets = kMaxMediaPackets;
-
-// Size (in bytes) of packet masks, given number of K bits set.
-constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
-
-// Size (in bytes) of part of header which is not packet mask specific.
-constexpr size_t kBaseHeaderSize = 8;
-
-// Size (in bytes) of part of header which is stream specific.
-constexpr size_t kStreamSpecificHeaderSize = 2;
-
-// Size (in bytes) of header, given the single stream packet mask size, i.e.
-// the number of K-bits set.
-constexpr size_t kHeaderSizes[] = {
-    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[0],
-    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1],
-    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]};
-
-// We currently only support single-stream protection.
-// TODO(brandtr): Update this when we support multistream protection.
-constexpr uint8_t kSsrcCount = 1;
-
-// There are three reserved bytes that MUST be set to zero in the header.
-constexpr uint32_t kReservedBits = 0;
-
-// TODO(brandtr): Update this when we support multistream protection.
-constexpr size_t kPacketMaskOffset =
-    kBaseHeaderSize + kStreamSpecificHeaderSize;
-
-// Here we count the K-bits as belonging to the packet mask.
-// This can be used in conjunction with FlexfecHeaderWriter::MinPacketMaskSize,
-// which calculates a bound on the needed packet mask size including K-bits,
-// given a packet mask without K-bits.
-size_t FlexfecHeaderSize(size_t packet_mask_size) {
-  RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]);
-  if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) {
-    return kHeaderSizes[0];
-  } else if (packet_mask_size <= kFlexfecPacketMaskSizes[1]) {
-    return kHeaderSizes[1];
-  }
-  return kHeaderSizes[2];
-}
-
-}  // namespace
-
-FlexfecHeaderReader2::FlexfecHeaderReader2()
-    : FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {}
-
-FlexfecHeaderReader2::~FlexfecHeaderReader2() = default;
-
-// TODO(brandtr): Update this function when we support flexible masks,
-// and retransmissions.
-bool FlexfecHeaderReader2::ReadFecHeader(
-    ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
-  // Protected ssrcs should already be populated from RTP header.
-  if (fec_packet->protected_streams.empty()) {
-    RTC_LOG(LS_WARNING)
-        << "Discarding FlexFEC packet with no protected sources.";
-    return false;
-  }
-  if (fec_packet->pkt->data.size() <=
-      kBaseHeaderSize + kStreamSpecificHeaderSize) {
-    RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
-    return false;
-  }
-  uint8_t* const data = fec_packet->pkt->data.MutableData();
-  bool r_bit = (data[0] & 0x80) != 0;
-  if (r_bit) {
-    RTC_LOG(LS_INFO)
-        << "FlexFEC packet with retransmission bit set. We do not yet "
-           "support this, thus discarding the packet.";
-    return false;
-  }
-  bool f_bit = (data[0] & 0x40) != 0;
-  if (f_bit) {
-    RTC_LOG(LS_INFO)
-        << "FlexFEC packet with inflexible generator matrix. We do "
-           "not yet support this, thus discarding packet.";
-    return false;
-  }
-
-  // First seq_num will be in byte index 8
-  // (See FEC header schematic in flexfec_header_reader_writer.h.)
-  size_t byte_index = 8;
-  for (size_t i = 0; i < fec_packet->protected_streams.size(); ++i) {
-    if (fec_packet->pkt->data.size() < byte_index + kStreamSpecificHeaderSize) {
-      RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
-      return false;
-    }
-
-    fec_packet->protected_streams[i].seq_num_base =
-        ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
-    byte_index += kStreamSpecificHeaderSize;
-
-    // Parse the FlexFEC packet mask and remove the interleaved K-bits.
-    // (See FEC header schematic in flexfec_header_reader_writer.h.)
-    // We store the packed packet mask in-band, which "destroys" the standards
-    // compliance of the header. That is fine though, since the code that
-    // reads from the header (from this point and onwards) is aware of this.
-    // TODO(brandtr): When the FEC packet classes have been refactored, store
-    // the packed packet masks out-of-band, thus leaving the FlexFEC header as
-    // is.
-    //
-    // We treat the mask parts as unsigned integers with host order endianness
-    // in order to simplify the bit shifting between bytes.
-    if (fec_packet->pkt->data.size() <
-        (byte_index + kFlexfecPacketMaskSizes[0])) {
-      RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
-      return false;
-    }
-    fec_packet->protected_streams[i].packet_mask_offset = byte_index;
-    bool k_bit0 = (data[byte_index] & 0x80) != 0;
-    uint16_t mask_part0 =
-        ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
-    // Shift away K-bit 0, implicitly clearing the last bit.
-    mask_part0 <<= 1;
-    ByteWriter<uint16_t>::WriteBigEndian(&data[byte_index], mask_part0);
-    byte_index += kFlexfecPacketMaskSizes[0];
-    if (k_bit0) {
-      // The first K-bit is set, and the packet mask is thus only 2 bytes long.
-      // We have finished reading the properties for current ssrc.
-      fec_packet->protected_streams[i].packet_mask_size =
-          kFlexfecPacketMaskSizes[0];
-    } else {
-      if (fec_packet->pkt->data.size() <
-          (byte_index + kFlexfecPacketMaskSizes[1] -
-           kFlexfecPacketMaskSizes[0])) {
-        return false;
-      }
-      bool k_bit1 = (data[byte_index] & 0x80) != 0;
-      // We have already shifted the first two bytes of the packet mask one step
-      // to the left, thus removing K-bit 0. We will now shift the next four
-      // bytes of the packet mask two steps to the left. (One step for the
-      // removed K-bit 0, and one step for the to be removed K-bit 1).
-      uint8_t bit15 = (data[byte_index] >> 6) & 0x01;
-      data[byte_index - 1] |= bit15;
-      uint32_t mask_part1 =
-          ByteReader<uint32_t>::ReadBigEndian(&data[byte_index]);
-      // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
-      mask_part1 <<= 2;
-      ByteWriter<uint32_t>::WriteBigEndian(&data[byte_index], mask_part1);
-      byte_index += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
-      if (k_bit1) {
-        // The first K-bit is clear, but the second K-bit is set. The packet
-        // mask is thus 6 bytes long. We have finished reading the properties
-        // for current ssrc.
-        fec_packet->protected_streams[i].packet_mask_size =
-            kFlexfecPacketMaskSizes[1];
-      } else {
-        if (fec_packet->pkt->data.size() <
-            (byte_index + kFlexfecPacketMaskSizes[2] -
-             kFlexfecPacketMaskSizes[1])) {
-          RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
-          return false;
-        }
-        fec_packet->protected_streams[i].packet_mask_size =
-            kFlexfecPacketMaskSizes[2];
-        // At this point, K-bits 0 and 1 have been removed, and the front-most
-        // part of the FlexFEC packet mask has been packed accordingly. We will
-        // now shift the remaning part of the packet mask two steps to the left.
-        // This corresponds to the (in total) two K-bits, which have been
-        // removed.
-        uint8_t tail_bits = (data[byte_index] >> 6) & 0x03;
-        data[byte_index - 1] |= tail_bits;
-        uint64_t mask_part2 =
-            ByteReader<uint64_t>::ReadBigEndian(&data[byte_index]);
-        // Shift away bit 46, and bit 47, which were copied to the previous
-        // part of the mask, implicitly clearing the last two bits.
-        mask_part2 <<= 2;
-        ByteWriter<uint64_t>::WriteBigEndian(&data[byte_index], mask_part2);
-        byte_index += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1];
-      }
-    }
-  }
-
-  fec_packet->fec_header_size = byte_index;
-
-  // In FlexFEC, all media packets are protected in their entirety.
-  fec_packet->protection_length =
-      fec_packet->pkt->data.size() - fec_packet->fec_header_size;
-
-  return true;
-}
-
-FlexfecHeaderWriter2::FlexfecHeaderWriter2()
-    : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
-
-FlexfecHeaderWriter2::~FlexfecHeaderWriter2() = default;
-
-size_t FlexfecHeaderWriter2::MinPacketMaskSize(const uint8_t* packet_mask,
-                                               size_t packet_mask_size) const {
-  if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear &&
-      (packet_mask[1] & 0x01) == 0) {
-    // Packet mask is 16 bits long, with bit 15 clear.
-    // It can be used as is.
-    return kFlexfecPacketMaskSizes[0];
-  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
-    // Packet mask is 16 bits long, with bit 15 set.
-    // We must expand the packet mask with zeros in the FlexFEC header.
-    return kFlexfecPacketMaskSizes[1];
-  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet &&
-             (packet_mask[5] & 0x03) == 0) {
-    // Packet mask is 48 bits long, with bits 46 and 47 clear.
-    // It can be used as is.
-    return kFlexfecPacketMaskSizes[1];
-  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
-    // Packet mask is 48 bits long, with at least one of bits 46 and 47 set.
-    // We must expand it with zeros.
-    return kFlexfecPacketMaskSizes[2];
-  }
-  RTC_DCHECK_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size
-                          << ".";
-  return kFlexfecPacketMaskSizes[2];
-}
-
-size_t FlexfecHeaderWriter2::FecHeaderSize(size_t packet_mask_size) const {
-  return FlexfecHeaderSize(packet_mask_size);
-}
-
-// This function adapts the precomputed ULPFEC packet masks to the
-// FlexFEC header standard. Note that the header size is computed by
-// FecHeaderSize(), so in this function we can be sure that we are
-// writing in space that is intended for the header.
-//
-// TODO(brandtr): Update this function when we support offset-based masks,
-// retransmissions, and protecting multiple SSRCs.
-void FlexfecHeaderWriter2::FinalizeFecHeader(
-    uint32_t media_ssrc,
-    uint16_t seq_num_base,
-    const uint8_t* packet_mask,
-    size_t packet_mask_size,
-    ForwardErrorCorrection::Packet* fec_packet) const {
-  uint8_t* data = fec_packet->data.MutableData();
-  data[0] &= 0x7f;  // Clear R bit.
-  data[0] &= 0xbf;  // Clear F bit.
-  ByteWriter<uint8_t>::WriteBigEndian(&data[8], kSsrcCount);
-  ByteWriter<uint32_t, 3>::WriteBigEndian(&data[9], kReservedBits);
-  ByteWriter<uint32_t>::WriteBigEndian(&data[12], media_ssrc);
-  ByteWriter<uint16_t>::WriteBigEndian(&data[16], seq_num_base);
-  // Adapt ULPFEC packet mask to FlexFEC header.
-  //
-  // We treat the mask parts as unsigned integers with host order endianness
-  // in order to simplify the bit shifting between bytes.
-  uint8_t* const written_packet_mask = data + kPacketMaskOffset;
-  if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
-    // The packet mask is 48 bits long.
-    uint16_t tmp_mask_part0 =
-        ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
-    uint32_t tmp_mask_part1 =
-        ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
-
-    tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
-    ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
-                                         tmp_mask_part0);
-    tmp_mask_part1 >>= 2;  // Shift, thus clearing K-bit 1 and bit 15.
-    ByteWriter<uint32_t>::WriteBigEndian(&written_packet_mask[2],
-                                         tmp_mask_part1);
-    bool bit15 = (packet_mask[1] & 0x01) != 0;
-    if (bit15)
-      written_packet_mask[2] |= 0x40;  // Set bit 15.
-    bool bit46 = (packet_mask[5] & 0x02) != 0;
-    bool bit47 = (packet_mask[5] & 0x01) != 0;
-    if (!bit46 && !bit47) {
-      written_packet_mask[2] |= 0x80;  // Set K-bit 1.
-    } else {
-      memset(&written_packet_mask[6], 0, 8);  // Clear all trailing bits.
-      written_packet_mask[6] |= 0x80;         // Set K-bit 2.
-      if (bit46)
-        written_packet_mask[6] |= 0x40;  // Set bit 46.
-      if (bit47)
-        written_packet_mask[6] |= 0x20;  // Set bit 47.
-    }
-  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
-    // The packet mask is 16 bits long.
-    uint16_t tmp_mask_part0 =
-        ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
-
-    tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
-    ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
-                                         tmp_mask_part0);
-    bool bit15 = (packet_mask[1] & 0x01) != 0;
-    if (!bit15) {
-      written_packet_mask[0] |= 0x80;  // Set K-bit 0.
-    } else {
-      memset(&written_packet_mask[2], 0U, 4);  // Clear all trailing bits.
-      written_packet_mask[2] |= 0x80;          // Set K-bit 1.
-      written_packet_mask[2] |= 0x40;          // Set bit 15.
-    }
-  } else {
-    RTC_DCHECK_NOTREACHED()
-        << "Incorrect packet mask size: " << packet_mask_size << ".";
-  }
-}
-
-}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.h b/modules/rtp_rtcp/source/flexfec_header_reader_writer2.h
deleted file mode 100644
index 7b9a052..0000000
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *  Copyright (c) 2023 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.
- */
-
-#ifndef MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER2_H_
-#define MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER2_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "modules/rtp_rtcp/source/forward_error_correction.h"
-
-namespace webrtc {
-
-// FlexFEC header in flexible mode (R=0, F=0), minimum 12 bytes.
-// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
-//
-//     0                   1                   2                   3
-//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  0 |0|0|P|X|  CC   |M| PT recovery |        length recovery        |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  4 |                          TS recovery                          |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  8 |           SN base_i           |k|          Mask [0-14]        |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 12 |k|                   Mask [15-45] (optional)                   |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// 16 |                     Mask [46-109] (optional)                  |
-// 20 |                                                               |
-//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//    |   ... next SN base and Mask for CSRC_i in CSRC list ...       |
-//
-
-class FlexfecHeaderReader2 : public FecHeaderReader {
- public:
-  FlexfecHeaderReader2();
-  ~FlexfecHeaderReader2() override;
-
-  bool ReadFecHeader(
-      ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override;
-};
-
-class FlexfecHeaderWriter2 : public FecHeaderWriter {
- public:
-  FlexfecHeaderWriter2();
-  ~FlexfecHeaderWriter2() override;
-
-  size_t MinPacketMaskSize(const uint8_t* packet_mask,
-                           size_t packet_mask_size) const override;
-
-  size_t FecHeaderSize(size_t packet_mask_row_size) const override;
-
-  void FinalizeFecHeader(
-      uint32_t media_ssrc,
-      uint16_t seq_num_base,
-      const uint8_t* packet_mask,
-      size_t packet_mask_size,
-      ForwardErrorCorrection::Packet* fec_packet) const override;
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER2_H_
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer2_unittest.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer2_unittest.cc
deleted file mode 100644
index 7c83240..0000000
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer2_unittest.cc
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- *  Copyright (c) 2023 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/flexfec_header_reader_writer2.h"
-
-#include <string.h>
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "api/array_view.h"
-#include "api/make_ref_counted.h"
-#include "modules/rtp_rtcp/source/byte_io.h"
-#include "modules/rtp_rtcp/source/forward_error_correction.h"
-#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/random.h"
-#include "test/gmock.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-
-namespace {
-
-using Packet = ForwardErrorCorrection::Packet;
-using ProtectedStream = ForwardErrorCorrection::ProtectedStream;
-using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
-using ::testing::ElementsAreArray;
-
-constexpr uint8_t kMask0[] = {0xAB, 0xCD};              // First K bit is set.
-constexpr uint8_t kMask1[] = {0x12, 0x34,               // First K bit cleared.
-                              0xF6, 0x78, 0x9A, 0xBC};  // Second K bit set.
-constexpr uint8_t kMask2[] = {0x12, 0x34,               //  First K bit cleared.
-                              0x56, 0x78, 0x9A, 0xBC,   // Second K bit cleared.
-                              0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
-
-// Reader tests.
-constexpr uint8_t kFlexible = 0b00 << 6;
-constexpr uint8_t kPtRecovery = 123;
-constexpr uint8_t kLengthRecovery[] = {0xab, 0xcd};
-constexpr uint8_t kTsRecovery[] = {0x01, 0x23, 0x45, 0x67};
-constexpr uint8_t kSnBases[4][2] = {{0x01, 0x02},
-                                    {0x03, 0x04},
-                                    {0x05, 0x06},
-                                    {0x07, 0x08}};
-constexpr uint8_t kPayloadBits = 0x00;
-
-struct FecPacketStreamProperties {
-  ProtectedStream stream;
-  rtc::ArrayView<const uint8_t> mask;
-};
-
-void VerifyReadHeaders(size_t expected_fec_header_size,
-                       const ReceivedFecPacket& read_packet,
-                       std::vector<FecPacketStreamProperties> expected) {
-  EXPECT_EQ(read_packet.fec_header_size, expected_fec_header_size);
-  const size_t protected_streams_num = read_packet.protected_streams.size();
-  EXPECT_EQ(protected_streams_num, expected.size());
-  for (size_t i = 0; i < protected_streams_num; ++i) {
-    SCOPED_TRACE(i);
-    ProtectedStream protected_stream = read_packet.protected_streams[i];
-    EXPECT_EQ(protected_stream.ssrc, expected[i].stream.ssrc);
-    EXPECT_EQ(protected_stream.seq_num_base, expected[i].stream.seq_num_base);
-    EXPECT_EQ(protected_stream.packet_mask_offset,
-              expected[i].stream.packet_mask_offset);
-    EXPECT_EQ(protected_stream.packet_mask_size,
-              expected[i].stream.packet_mask_size);
-    // Ensure that the K-bits are removed and the packet mask has been packed.
-    EXPECT_THAT(rtc::MakeArrayView(read_packet.pkt->data.cdata() +
-                                       protected_stream.packet_mask_offset,
-                                   protected_stream.packet_mask_size),
-                ElementsAreArray(expected[i].mask));
-  }
-  EXPECT_EQ(read_packet.pkt->data.size() - expected_fec_header_size,
-            read_packet.protection_length);
-}
-
-}  // namespace
-
-TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit0SetSingleStream) {
-  constexpr uint8_t kKBit0 = 1 << 7;
-  constexpr size_t kExpectedFecHeaderSize = 12;
-  constexpr uint16_t kSnBase = 0x0102;
-  constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81};
-  constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
-      kSnBase >> 8,   kSnBase & 0xFF, kFlexfecPktMask[0], kFlexfecPktMask[1],
-      kPayloadBits,   kPayloadBits,   kPayloadBits,       kPayloadBits};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {{.ssrc = 0x01}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
-
-  std::vector<FecPacketStreamProperties> expected = {
-      {.stream = {.ssrc = 0x01,
-                  .seq_num_base = kSnBase,
-                  .packet_mask_offset = 10,
-                  .packet_mask_size = std::size(kUlpfecPacketMask)},
-       .mask = kUlpfecPacketMask}};
-
-  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
-}
-
-TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit1SetSingleStream) {
-  constexpr uint8_t kKBit0 = 0 << 7;
-  constexpr uint8_t kKBit1 = 1 << 7;
-  constexpr size_t kExpectedFecHeaderSize = 16;
-  constexpr uint16_t kSnBase = 0x0102;
-  constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x48, 0x81,  //
-                                         kKBit1 | 0x02, 0x11, 0x00, 0x21};
-  constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02,  //
-                                           0x08, 0x44, 0x00, 0x84};
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,          kPtRecovery,        kLengthRecovery[0],
-      kLengthRecovery[1], kTsRecovery[0],     kTsRecovery[1],
-      kTsRecovery[2],     kTsRecovery[3],     kSnBase >> 8,
-      kSnBase & 0xFF,     kFlexfecPktMask[0], kFlexfecPktMask[1],
-      kFlexfecPktMask[2], kFlexfecPktMask[3], kFlexfecPktMask[4],
-      kFlexfecPktMask[5], kPayloadBits,       kPayloadBits,
-      kPayloadBits,       kPayloadBits};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {{.ssrc = 0x01}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
-
-  std::vector<FecPacketStreamProperties> expected = {
-      {.stream = {.ssrc = 0x01,
-                  .seq_num_base = kSnBase,
-                  .packet_mask_offset = 10,
-                  .packet_mask_size = std::size(kUlpfecPacketMask)},
-       .mask = kUlpfecPacketMask}};
-
-  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
-}
-
-TEST(FlexfecHeaderReader2Test, ReadsHeaderWithNoKBitsSetSingleStream) {
-  constexpr uint8_t kKBit0 = 0 << 7;
-  constexpr uint8_t kKBit1 = 0 << 7;
-  constexpr size_t kExpectedFecHeaderSize = 24;
-  constexpr uint16_t kSnBase = 0x0102;
-  constexpr uint8_t kFlexfecPacketMask[] = {kKBit0 | 0x48, 0x81,              //
-                                            kKBit1 | 0x02, 0x11, 0x00, 0x21,  //
-                                            0x01,          0x11, 0x11, 0x11,
-                                            0x11,          0x11, 0x11, 0x11};
-  constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02,              //
-                                           0x08, 0x44, 0x00, 0x84,  //
-                                           0x04, 0x44, 0x44, 0x44,
-                                           0x44, 0x44, 0x44, 0x44};
-  constexpr uint8_t kPacketData[] = {kFlexible,
-                                     kPtRecovery,
-                                     kLengthRecovery[0],
-                                     kLengthRecovery[1],
-                                     kTsRecovery[0],
-                                     kTsRecovery[1],
-                                     kTsRecovery[2],
-                                     kTsRecovery[3],
-                                     kSnBase >> 8,
-                                     kSnBase & 0xFF,
-                                     kFlexfecPacketMask[0],
-                                     kFlexfecPacketMask[1],
-                                     kFlexfecPacketMask[2],
-                                     kFlexfecPacketMask[3],
-                                     kFlexfecPacketMask[4],
-                                     kFlexfecPacketMask[5],
-                                     kFlexfecPacketMask[6],
-                                     kFlexfecPacketMask[7],
-                                     kFlexfecPacketMask[8],
-                                     kFlexfecPacketMask[9],
-                                     kFlexfecPacketMask[10],
-                                     kFlexfecPacketMask[11],
-                                     kFlexfecPacketMask[12],
-                                     kFlexfecPacketMask[13],
-                                     kPayloadBits,
-                                     kPayloadBits,
-                                     kPayloadBits,
-                                     kPayloadBits};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {{.ssrc = 0x01}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
-
-  std::vector<FecPacketStreamProperties> expected = {
-      {.stream = {.ssrc = 0x01,
-                  .seq_num_base = kSnBase,
-                  .packet_mask_offset = 10,
-                  .packet_mask_size = std::size(kUlpfecPacketMask)},
-       .mask = kUlpfecPacketMask}};
-
-  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
-}
-
-TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit0Set2Streams) {
-  constexpr uint8_t kKBit0 = 1 << 7;
-  constexpr size_t kExpectedFecHeaderSize = 16;
-  constexpr uint16_t kSnBase0 = 0x0102;
-  constexpr uint16_t kSnBase1 = 0x0304;
-  constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x08, 0x81};
-  constexpr uint8_t kUlpfecPacketMask1[] = {0x11, 0x02};
-  constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x04, 0x41};
-  constexpr uint8_t kUlpfecPacketMask2[] = {0x08, 0x82};
-
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,     kLengthRecovery[0],  kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1],  kTsRecovery[2],      kTsRecovery[3],
-      kSnBase0 >> 8,  kSnBase0 & 0xFF, kFlexfecPktMask1[0], kFlexfecPktMask1[1],
-      kSnBase1 >> 8,  kSnBase1 & 0xFF, kFlexfecPktMask2[0], kFlexfecPktMask2[1],
-      kPayloadBits,   kPayloadBits,    kPayloadBits,        kPayloadBits};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
-
-  std::vector<FecPacketStreamProperties> expected = {
-      {.stream = {.ssrc = 0x01,
-                  .seq_num_base = kSnBase0,
-                  .packet_mask_offset = 10,
-                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
-       .mask = kUlpfecPacketMask1},
-      {.stream = {.ssrc = 0x02,
-                  .seq_num_base = kSnBase1,
-                  .packet_mask_offset = 14,
-                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
-       .mask = kUlpfecPacketMask2},
-  };
-
-  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
-}
-
-TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit1Set2Streams) {
-  constexpr uint8_t kKBit0 = 0 << 7;
-  constexpr uint8_t kKBit1 = 1 << 7;
-  constexpr size_t kExpectedFecHeaderSize = 24;
-  constexpr uint16_t kSnBase0 = 0x0102;
-  constexpr uint16_t kSnBase1 = 0x0304;
-  constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x48, 0x81,  //
-                                          kKBit1 | 0x02, 0x11, 0x00, 0x21};
-  constexpr uint8_t kUlpfecPacketMask1[] = {0x91, 0x02,  //
-                                            0x08, 0x44, 0x00, 0x84};
-  constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x57, 0x82,  //
-                                          kKBit1 | 0x04, 0x33, 0x00, 0x51};
-  constexpr uint8_t kUlpfecPacketMask2[] = {0xAF, 0x04,  //
-                                            0x10, 0xCC, 0x01, 0x44};
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,           kPtRecovery,         kLengthRecovery[0],
-      kLengthRecovery[1],  kTsRecovery[0],      kTsRecovery[1],
-      kTsRecovery[2],      kTsRecovery[3],      kSnBase0 >> 8,
-      kSnBase0 & 0xFF,     kFlexfecPktMask1[0], kFlexfecPktMask1[1],
-      kFlexfecPktMask1[2], kFlexfecPktMask1[3], kFlexfecPktMask1[4],
-      kFlexfecPktMask1[5], kSnBase1 >> 8,       kSnBase1 & 0xFF,
-      kFlexfecPktMask2[0], kFlexfecPktMask2[1], kFlexfecPktMask2[2],
-      kFlexfecPktMask2[3], kFlexfecPktMask2[4], kFlexfecPktMask2[5],
-      kPayloadBits,        kPayloadBits,        kPayloadBits,
-      kPayloadBits};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
-
-  std::vector<FecPacketStreamProperties> expected = {
-      {.stream = {.ssrc = 0x01,
-                  .seq_num_base = kSnBase0,
-                  .packet_mask_offset = 10,
-                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
-       .mask = kUlpfecPacketMask1},
-      {.stream = {.ssrc = 0x02,
-                  .seq_num_base = kSnBase1,
-                  .packet_mask_offset = 18,
-                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
-       .mask = kUlpfecPacketMask2},
-  };
-
-  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
-}
-
-TEST(FlexfecHeaderReader2Test, ReadsHeaderWithNoKBitsSet2Streams) {
-  constexpr uint8_t kKBit0 = 0 << 7;
-  constexpr uint8_t kKBit1 = 0 << 7;
-  constexpr size_t kExpectedFecHeaderSize = 40;
-  constexpr uint16_t kSnBase0 = 0x0102;
-  constexpr uint16_t kSnBase1 = 0x0304;
-  constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x48, 0x81,              //
-                                          kKBit1 | 0x02, 0x11, 0x00, 0x21,  //
-                                          0x01,          0x11, 0x11, 0x11,
-                                          0x11,          0x11, 0x11, 0x11};
-  constexpr uint8_t kUlpfecPacketMask1[] = {0x91, 0x02,              //
-                                            0x08, 0x44, 0x00, 0x84,  //
-                                            0x04, 0x44, 0x44, 0x44,
-                                            0x44, 0x44, 0x44, 0x44};
-  constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x32, 0x84,              //
-                                          kKBit1 | 0x05, 0x23, 0x00, 0x55,  //
-                                          0xA3,          0x22, 0x22, 0x22,
-                                          0x22,          0x22, 0x22, 0x35};
-  constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x08,              //
-                                            0x14, 0x8C, 0x01, 0x56,  //
-                                            0x8C, 0x88, 0x88, 0x88,
-                                            0x88, 0x88, 0x88, 0xD4};
-
-  constexpr uint8_t kPacketData[] = {kFlexible,
-                                     kPtRecovery,
-                                     kLengthRecovery[0],
-                                     kLengthRecovery[1],
-                                     kTsRecovery[0],
-                                     kTsRecovery[1],
-                                     kTsRecovery[2],
-                                     kTsRecovery[3],
-                                     kSnBase0 >> 8,
-                                     kSnBase0 & 0xFF,
-                                     kFlexfecPktMask1[0],
-                                     kFlexfecPktMask1[1],
-                                     kFlexfecPktMask1[2],
-                                     kFlexfecPktMask1[3],
-                                     kFlexfecPktMask1[4],
-                                     kFlexfecPktMask1[5],
-                                     kFlexfecPktMask1[6],
-                                     kFlexfecPktMask1[7],
-                                     kFlexfecPktMask1[8],
-                                     kFlexfecPktMask1[9],
-                                     kFlexfecPktMask1[10],
-                                     kFlexfecPktMask1[11],
-                                     kFlexfecPktMask1[12],
-                                     kFlexfecPktMask1[13],
-                                     kSnBase1 >> 8,
-                                     kSnBase1 & 0xFF,
-                                     kFlexfecPktMask2[0],
-                                     kFlexfecPktMask2[1],
-                                     kFlexfecPktMask2[2],
-                                     kFlexfecPktMask2[3],
-                                     kFlexfecPktMask2[4],
-                                     kFlexfecPktMask2[5],
-                                     kFlexfecPktMask2[6],
-                                     kFlexfecPktMask2[7],
-                                     kFlexfecPktMask2[8],
-                                     kFlexfecPktMask2[9],
-                                     kFlexfecPktMask2[10],
-                                     kFlexfecPktMask2[11],
-                                     kFlexfecPktMask2[12],
-                                     kFlexfecPktMask2[13],
-                                     kPayloadBits,
-                                     kPayloadBits,
-                                     kPayloadBits,
-                                     kPayloadBits};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
-
-  std::vector<FecPacketStreamProperties> expected = {
-      {.stream = {.ssrc = 0x01,
-                  .seq_num_base = kSnBase0,
-                  .packet_mask_offset = 10,
-                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
-       .mask = kUlpfecPacketMask1},
-      {.stream = {.ssrc = 0x02,
-                  .seq_num_base = kSnBase1,
-                  .packet_mask_offset = 26,
-                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
-       .mask = kUlpfecPacketMask2},
-  };
-
-  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
-}
-
-TEST(FlexfecHeaderReader2Test, ReadsHeaderWithMultipleStreamsMultipleMasks) {
-  constexpr uint8_t kBit0 = 0 << 7;
-  constexpr uint8_t kBit1 = 1 << 7;
-  constexpr size_t kExpectedFecHeaderSize = 44;
-  constexpr uint16_t kSnBase0 = 0x0102;
-  constexpr uint16_t kSnBase1 = 0x0304;
-  constexpr uint16_t kSnBase2 = 0x0506;
-  constexpr uint16_t kSnBase3 = 0x0708;
-  constexpr uint8_t kFlexfecPacketMask1[] = {kBit1 | 0x29, 0x91};
-  constexpr uint8_t kUlpfecPacketMask1[] = {0x53, 0x22};
-  constexpr uint8_t kFlexfecPacketMask2[] = {kBit0 | 0x32, 0xA1,  //
-                                             kBit1 | 0x02, 0x11, 0x00, 0x21};
-  constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x42,  //
-                                            0x08, 0x44, 0x00, 0x84};
-  constexpr uint8_t kFlexfecPacketMask3[] = {kBit0 | 0x48, 0x81,              //
-                                             kBit0 | 0x02, 0x11, 0x00, 0x21,  //
-                                             0x01,         0x11, 0x11, 0x11,
-                                             0x11,         0x11, 0x11, 0x11};
-  constexpr uint8_t kUlpfecPacketMask3[] = {0x91, 0x02,              //
-                                            0x08, 0x44, 0x00, 0x84,  //
-                                            0x04, 0x44, 0x44, 0x44,
-                                            0x44, 0x44, 0x44, 0x44};
-  constexpr uint8_t kFlexfecPacketMask4[] = {kBit0 | 0x32, 0x84,  //
-                                             kBit1 | 0x05, 0x23, 0x00, 0x55};
-  constexpr uint8_t kUlpfecPacketMask4[] = {0x65, 0x08,  //
-                                            0x14, 0x8C, 0x01, 0x54};
-  constexpr uint8_t kPacketData[] = {kFlexible,
-                                     kPtRecovery,
-                                     kLengthRecovery[0],
-                                     kLengthRecovery[1],
-                                     kTsRecovery[0],
-                                     kTsRecovery[1],
-                                     kTsRecovery[2],
-                                     kTsRecovery[3],
-                                     kSnBase0 >> 8,
-                                     kSnBase0 & 0xFF,
-                                     kFlexfecPacketMask1[0],
-                                     kFlexfecPacketMask1[1],
-                                     kSnBase1 >> 8,
-                                     kSnBase1 & 0xFF,
-                                     kFlexfecPacketMask2[0],
-                                     kFlexfecPacketMask2[1],
-                                     kFlexfecPacketMask2[2],
-                                     kFlexfecPacketMask2[3],
-                                     kFlexfecPacketMask2[4],
-                                     kFlexfecPacketMask2[5],
-                                     kSnBase2 >> 8,
-                                     kSnBase2 & 0xFF,
-                                     kFlexfecPacketMask3[0],
-                                     kFlexfecPacketMask3[1],
-                                     kFlexfecPacketMask3[2],
-                                     kFlexfecPacketMask3[3],
-                                     kFlexfecPacketMask3[4],
-                                     kFlexfecPacketMask3[5],
-                                     kFlexfecPacketMask3[6],
-                                     kFlexfecPacketMask3[7],
-                                     kFlexfecPacketMask3[8],
-                                     kFlexfecPacketMask3[9],
-                                     kFlexfecPacketMask3[10],
-                                     kFlexfecPacketMask3[11],
-                                     kFlexfecPacketMask3[12],
-                                     kFlexfecPacketMask3[13],
-                                     kSnBase3 >> 8,
-                                     kSnBase3 & 0xFF,
-                                     kFlexfecPacketMask4[0],
-                                     kFlexfecPacketMask4[1],
-                                     kFlexfecPacketMask4[2],
-                                     kFlexfecPacketMask4[3],
-                                     kFlexfecPacketMask4[4],
-                                     kFlexfecPacketMask4[5],
-                                     kPayloadBits,
-                                     kPayloadBits,
-                                     kPayloadBits,
-                                     kPayloadBits};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {
-      {.ssrc = 0x01}, {.ssrc = 0x02}, {.ssrc = 0x03}, {.ssrc = 0x04}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
-
-  std::vector<FecPacketStreamProperties> expected = {
-      {.stream = {.ssrc = 0x01,
-                  .seq_num_base = kSnBase0,
-                  .packet_mask_offset = 10,
-                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
-       .mask = kUlpfecPacketMask1},
-      {.stream = {.ssrc = 0x02,
-                  .seq_num_base = kSnBase1,
-                  .packet_mask_offset = 14,
-                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
-       .mask = kUlpfecPacketMask2},
-      {.stream = {.ssrc = 0x03,
-                  .seq_num_base = kSnBase2,
-                  .packet_mask_offset = 22,
-                  .packet_mask_size = std::size(kUlpfecPacketMask3)},
-       .mask = kUlpfecPacketMask3},
-      {.stream = {.ssrc = 0x04,
-                  .seq_num_base = kSnBase3,
-                  .packet_mask_offset = 38,
-                  .packet_mask_size = std::size(kUlpfecPacketMask4)},
-       .mask = kUlpfecPacketMask4},
-  };
-
-  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
-}
-
-TEST(FlexfecHeaderReader2Test, ReadPacketWithoutProtectedSsrcsShouldFail) {
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3]};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  // No protected ssrcs.
-  read_packet.protected_streams = {};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
-}
-
-TEST(FlexfecHeaderReader2Test,
-     ReadPacketWithoutStreamSpecificHeaderShouldFail) {
-  // Simulate short received packet.
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3]};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  read_packet.pkt->data.SetData(kPacketData);
-  read_packet.protected_streams = {{.ssrc = 0x01}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
-}
-
-TEST(FlexfecHeaderReader2Test, ReadShortPacketWithKBit0SetShouldFail) {
-  // Simulate short received packet.
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
-      kSnBases[0][0], kSnBases[0][1], kMask0[0],          kMask0[1]};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  // Expected to have 2 bytes of mask but length of packet misses 1 byte.
-  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 1);
-  read_packet.protected_streams = {{.ssrc = 0x01}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
-}
-
-TEST(FlexfecHeaderReader2Test, ReadShortPacketWithKBit1SetShouldFail) {
-  // Simulate short received packet.
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
-      kSnBases[0][0], kSnBases[0][1], kMask1[0],          kMask1[1],
-      kMask1[2],      kMask1[3],      kMask1[4],          kMask1[5]};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  // Expected to have 6 bytes of mask but length of packet misses 2 bytes.
-  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
-  read_packet.protected_streams = {{.ssrc = 0x01}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
-}
-
-TEST(FlexfecHeaderReader2Test, ReadShortPacketWithKBit1ClearedShouldFail) {
-  // Simulate short received packet.
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
-      kSnBases[0][0], kSnBases[0][1], kMask2[0],          kMask2[1],
-      kMask2[2],      kMask2[3],      kMask2[4],          kMask2[5],
-      kMask2[6],      kMask2[7],      kMask2[8],          kMask2[9],
-      kMask2[10],     kMask2[11],     kMask2[12],         kMask2[13]};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  // Expected to have 14 bytes of mask but length of packet misses 2 bytes.
-  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
-  read_packet.protected_streams = {{.ssrc = 0x01}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
-}
-
-TEST(FlexfecHeaderReader2Test, ReadShortPacketMultipleStreamsShouldFail) {
-  // Simulate short received packet with 2 protected ssrcs.
-  constexpr uint8_t kPacketData[] = {
-      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
-      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
-      kSnBases[0][0], kSnBases[0][1], kMask0[0],          kMask0[1],
-      kSnBases[1][0], kSnBases[1][1], kMask2[0],          kMask2[1],
-      kMask2[2],      kMask2[3],      kMask2[4],          kMask2[5],
-      kMask2[6],      kMask2[7],      kMask2[8],          kMask2[9],
-      kMask2[10],     kMask2[11],     kMask2[12],         kMask2[13]};
-  ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::make_ref_counted<Packet>();
-  // Subtract 2 bytes from length, so the read will fail on parsing second
-  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
-  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
-
-  FlexfecHeaderReader2 reader;
-  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
-}
-
-// TODO(bugs.webrtc.org/15002): reimplement and add tests for multi stream cases
-// after updating the Writer code.
-
-TEST(FlexfecHeaderWriter2Test, FinalizesHeaderWithKBit0Set) {}
-
-TEST(FlexfecHeaderWriter2Test, FinalizesHeaderWithKBit1Set) {}
-
-TEST(FlexfecHeaderWriter2Test, FinalizesHeaderWithKBit2Set) {}
-
-TEST(FlexfecHeaderWriter2Test, ContractsShortUlpfecPacketMaskWithBit15Clear) {}
-
-TEST(FlexfecHeaderWriter2Test, ExpandsShortUlpfecPacketMaskWithBit15Set) {}
-
-TEST(FlexfecHeaderWriter2Test,
-     ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {}
-
-TEST(FlexfecHeaderWriter2Test,
-     ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {}
-
-TEST(FlexfecHeaderWriter2Test,
-     ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {}
-
-TEST(FlexfecHeaderWriter2Test,
-     ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) {}
-
-TEST(FlexfecHeaderReaderWriter2Test,
-     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {}
-
-TEST(FlexfecHeaderReaderWriter2Test,
-     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {}
-
-TEST(FlexfecHeaderReaderWriter2Test,
-     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {}
-
-TEST(FlexfecHeaderReaderWriter2Test,
-     WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {}
-
-TEST(FlexfecHeaderReaderWriter2Test,
-     WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {}
-
-TEST(FlexfecHeaderReaderWriter2Test,
-     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {}
-
-}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
index 5487510..16ecbe5 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *  Copyright (c) 2023 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
@@ -14,8 +14,10 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
-#include "api/scoped_refptr.h"
+#include "api/array_view.h"
+#include "api/make_ref_counted.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/forward_error_correction.h"
 #include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
@@ -29,535 +31,613 @@
 namespace {
 
 using Packet = ForwardErrorCorrection::Packet;
+using ProtectedStream = ForwardErrorCorrection::ProtectedStream;
 using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
 using ::testing::ElementsAreArray;
-using ::testing::make_tuple;
-using ::testing::SizeIs;
 
-// General. Assume single-stream protection.
-constexpr uint32_t kMediaSsrc = 1254983;
-constexpr uint16_t kMediaStartSeqNum = 825;
-constexpr size_t kMediaPacketLength = 1234;
-constexpr uint32_t kFlexfecSsrc = 52142;
-
-constexpr size_t kFlexfecHeaderSizes[] = {20, 24, 32};
-constexpr size_t kFlexfecPacketMaskOffset = 18;
-constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
-constexpr size_t kFlexfecMaxPacketSize = kFlexfecPacketMaskSizes[2];
+constexpr uint8_t kMask0[] = {0xAB, 0xCD};              // First K bit is set.
+constexpr uint8_t kMask1[] = {0x12, 0x34,               // First K bit cleared.
+                              0xF6, 0x78, 0x9A, 0xBC};  // Second K bit set.
+constexpr uint8_t kMask2[] = {0x12, 0x34,               //  First K bit cleared.
+                              0x56, 0x78, 0x9A, 0xBC,   // Second K bit cleared.
+                              0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
 
 // Reader tests.
-constexpr uint8_t kNoRBit = 0 << 7;
-constexpr uint8_t kNoFBit = 0 << 6;
+constexpr uint8_t kFlexible = 0b00 << 6;
 constexpr uint8_t kPtRecovery = 123;
-constexpr uint8_t kLengthRecov[] = {0xab, 0xcd};
+constexpr uint8_t kLengthRecovery[] = {0xab, 0xcd};
 constexpr uint8_t kTsRecovery[] = {0x01, 0x23, 0x45, 0x67};
-constexpr uint8_t kSsrcCount = 1;
-constexpr uint8_t kReservedBits = 0x00;
-constexpr uint8_t kProtSsrc[] = {0x11, 0x22, 0x33, 0x44};
-constexpr uint8_t kSnBase[] = {0xaa, 0xbb};
+constexpr uint8_t kSnBases[4][2] = {{0x01, 0x02},
+                                    {0x03, 0x04},
+                                    {0x05, 0x06},
+                                    {0x07, 0x08}};
 constexpr uint8_t kPayloadBits = 0x00;
 
-std::unique_ptr<uint8_t[]> GeneratePacketMask(size_t packet_mask_size,
-                                              uint64_t seed) {
-  Random random(seed);
-  std::unique_ptr<uint8_t[]> packet_mask(new uint8_t[kFlexfecMaxPacketSize]);
-  memset(packet_mask.get(), 0, kFlexfecMaxPacketSize);
-  for (size_t i = 0; i < packet_mask_size; ++i) {
-    packet_mask[i] = random.Rand<uint8_t>();
-  }
-  return packet_mask;
-}
-
-void ClearBit(size_t index, uint8_t* packet_mask) {
-  packet_mask[index / 8] &= ~(1 << (7 - index % 8));
-}
-
-void SetBit(size_t index, uint8_t* packet_mask) {
-  packet_mask[index / 8] |= (1 << (7 - index % 8));
-}
-
-rtc::scoped_refptr<Packet> WriteHeader(const uint8_t* packet_mask,
-                                       size_t packet_mask_size) {
-  FlexfecHeaderWriter writer;
-  rtc::scoped_refptr<Packet> written_packet(new Packet());
-  written_packet->data.SetSize(kMediaPacketLength);
-  uint8_t* data = written_packet->data.MutableData();
-  for (size_t i = 0; i < written_packet->data.size(); ++i) {
-    data[i] = i;  // Actual content doesn't matter.
-  }
-  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask,
-                           packet_mask_size, written_packet.get());
-  return written_packet;
-}
-
-std::unique_ptr<ReceivedFecPacket> ReadHeader(const Packet& written_packet) {
-  FlexfecHeaderReader reader;
-  std::unique_ptr<ReceivedFecPacket> read_packet(new ReceivedFecPacket());
-  read_packet->ssrc = kFlexfecSsrc;
-  read_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
-  read_packet->pkt->data = written_packet.data;
-  EXPECT_TRUE(reader.ReadFecHeader(read_packet.get()));
-  return read_packet;
-}
+struct FecPacketStreamProperties {
+  ProtectedStream stream;
+  rtc::ArrayView<const uint8_t> mask;
+};
 
 void VerifyReadHeaders(size_t expected_fec_header_size,
-                       const uint8_t* expected_packet_mask,
-                       size_t expected_packet_mask_size,
-                       const ReceivedFecPacket& read_packet) {
-  EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
-  EXPECT_EQ(ByteReader<uint32_t>::ReadBigEndian(kProtSsrc),
-            read_packet.protected_streams[0].ssrc);
-  EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(kSnBase),
-            read_packet.protected_streams[0].seq_num_base);
-  auto packet_mask_offset = read_packet.protected_streams[0].packet_mask_offset;
-  EXPECT_EQ(kFlexfecPacketMaskOffset, packet_mask_offset);
-  EXPECT_EQ(expected_packet_mask_size,
-            read_packet.protected_streams[0].packet_mask_size);
+                       const ReceivedFecPacket& read_packet,
+                       std::vector<FecPacketStreamProperties> expected) {
+  EXPECT_EQ(read_packet.fec_header_size, expected_fec_header_size);
+  const size_t protected_streams_num = read_packet.protected_streams.size();
+  EXPECT_EQ(protected_streams_num, expected.size());
+  for (size_t i = 0; i < protected_streams_num; ++i) {
+    SCOPED_TRACE(i);
+    ProtectedStream protected_stream = read_packet.protected_streams[i];
+    EXPECT_EQ(protected_stream.ssrc, expected[i].stream.ssrc);
+    EXPECT_EQ(protected_stream.seq_num_base, expected[i].stream.seq_num_base);
+    EXPECT_EQ(protected_stream.packet_mask_offset,
+              expected[i].stream.packet_mask_offset);
+    EXPECT_EQ(protected_stream.packet_mask_size,
+              expected[i].stream.packet_mask_size);
+    // Ensure that the K-bits are removed and the packet mask has been packed.
+    EXPECT_THAT(rtc::MakeArrayView(read_packet.pkt->data.cdata() +
+                                       protected_stream.packet_mask_offset,
+                                   protected_stream.packet_mask_size),
+                ElementsAreArray(expected[i].mask));
+  }
   EXPECT_EQ(read_packet.pkt->data.size() - expected_fec_header_size,
             read_packet.protection_length);
-  // Ensure that the K-bits are removed and the packet mask has been packed.
-  EXPECT_THAT(
-      make_tuple(read_packet.pkt->data.cdata() + packet_mask_offset,
-                 read_packet.protected_streams[0].packet_mask_size),
-      ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
-}
-
-void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask,
-                            size_t expected_packet_mask_size,
-                            const Packet& written_packet) {
-  const uint8_t* packet = written_packet.data.cdata();
-  EXPECT_EQ(0x00, packet[0] & 0x80);  // F bit clear.
-  EXPECT_EQ(0x00, packet[0] & 0x40);  // R bit clear.
-  EXPECT_EQ(0x01, packet[8]);         // SSRCCount = 1.
-  EXPECT_EQ(kMediaSsrc, ByteReader<uint32_t>::ReadBigEndian(packet + 12));
-  EXPECT_EQ(kMediaStartSeqNum,
-            ByteReader<uint16_t>::ReadBigEndian(packet + 16));
-  EXPECT_THAT(
-      make_tuple(packet + kFlexfecPacketMaskOffset, expected_packet_mask_size),
-      ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
-}
-
-void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size,
-                                 const uint8_t* expected_packet_mask,
-                                 size_t expected_packet_mask_size,
-                                 const Packet& written_packet,
-                                 const ReceivedFecPacket& read_packet) {
-  EXPECT_EQ(kFlexfecSsrc, read_packet.ssrc);
-  EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
-  ASSERT_THAT(read_packet.protected_streams, SizeIs(1));
-  EXPECT_EQ(read_packet.protected_streams[0].ssrc, kMediaSsrc);
-  EXPECT_EQ(read_packet.protected_streams[0].seq_num_base, kMediaStartSeqNum);
-  EXPECT_EQ(read_packet.protected_streams[0].packet_mask_offset,
-            kFlexfecPacketMaskOffset);
-  ASSERT_EQ(read_packet.protected_streams[0].packet_mask_size,
-            expected_packet_mask_size);
-  EXPECT_EQ(written_packet.data.size() - expected_fec_header_size,
-            read_packet.protection_length);
-  // Verify that the call to ReadFecHeader did normalize the packet masks.
-  EXPECT_THAT(
-      make_tuple(read_packet.pkt->data.cdata() + kFlexfecPacketMaskOffset,
-                 read_packet.protected_streams[0].packet_mask_size),
-      ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
-  // Verify that the call to ReadFecHeader did not tamper with the payload.
-  EXPECT_THAT(
-      make_tuple(read_packet.pkt->data.cdata() + read_packet.fec_header_size,
-                 read_packet.pkt->data.size() - read_packet.fec_header_size),
-      ElementsAreArray(written_packet.data.cdata() + expected_fec_header_size,
-                       written_packet.data.size() - expected_fec_header_size));
 }
 
 }  // namespace
 
-TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0Set) {
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0SetSingleStream) {
   constexpr uint8_t kKBit0 = 1 << 7;
-  constexpr size_t kExpectedPacketMaskSize = 2;
-  constexpr size_t kExpectedFecHeaderSize = 20;
-  // clang-format off
+  constexpr size_t kExpectedFecHeaderSize = 12;
+  constexpr uint16_t kSnBase = 0x0102;
   constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81};
-  constexpr uint8_t kUlpfecPacketMask[] =        {0x11, 0x02};
-  // clang-format on
+  constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
   constexpr uint8_t kPacketData[] = {
-      kNoRBit | kNoFBit, kPtRecovery,    kLengthRecov[0],    kLengthRecov[1],
-      kTsRecovery[0],    kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
-      kSsrcCount,        kReservedBits,  kReservedBits,      kReservedBits,
-      kProtSsrc[0],      kProtSsrc[1],   kProtSsrc[2],       kProtSsrc[3],
-      kSnBase[0],        kSnBase[1],     kFlexfecPktMask[0], kFlexfecPktMask[1],
-      kPayloadBits,      kPayloadBits,   kPayloadBits,       kPayloadBits};
-  const size_t packet_length = sizeof(kPacketData);
+      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
+      kSnBase >> 8,   kSnBase & 0xFF, kFlexfecPktMask[0], kFlexfecPktMask[1],
+      kPayloadBits,   kPayloadBits,   kPayloadBits,       kPayloadBits};
   ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
-  read_packet.pkt->data.SetData(kPacketData, packet_length);
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {{.ssrc = 0x01}};
 
   FlexfecHeaderReader reader;
   EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
 
-  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
-                    kExpectedPacketMaskSize, read_packet);
+  std::vector<FecPacketStreamProperties> expected = {
+      {.stream = {.ssrc = 0x01,
+                  .seq_num_base = kSnBase,
+                  .packet_mask_offset = 10,
+                  .packet_mask_size = std::size(kUlpfecPacketMask)},
+       .mask = kUlpfecPacketMask}};
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
 }
 
-TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1Set) {
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1SetSingleStream) {
   constexpr uint8_t kKBit0 = 0 << 7;
   constexpr uint8_t kKBit1 = 1 << 7;
-  constexpr size_t kExpectedPacketMaskSize = 6;
-  constexpr size_t kExpectedFecHeaderSize = 24;
-  // clang-format off
-  constexpr uint8_t kFlxfecPktMsk[] = {kKBit0 | 0x48, 0x81,
-                                       kKBit1 | 0x02, 0x11, 0x00, 0x21};
-  constexpr uint8_t kUlpfecPacketMask[] =      {0x91, 0x02,
-                                                0x08, 0x44, 0x00, 0x84};
-  // clang-format on
+  constexpr size_t kExpectedFecHeaderSize = 16;
+  constexpr uint16_t kSnBase = 0x0102;
+  constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x48, 0x81,  //
+                                         kKBit1 | 0x02, 0x11, 0x00, 0x21};
+  constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02,  //
+                                           0x08, 0x44, 0x00, 0x84};
   constexpr uint8_t kPacketData[] = {
-      kNoRBit | kNoFBit, kPtRecovery,      kLengthRecov[0],  kLengthRecov[1],
-      kTsRecovery[0],    kTsRecovery[1],   kTsRecovery[2],   kTsRecovery[3],
-      kSsrcCount,        kReservedBits,    kReservedBits,    kReservedBits,
-      kProtSsrc[0],      kProtSsrc[1],     kProtSsrc[2],     kProtSsrc[3],
-      kSnBase[0],        kSnBase[1],       kFlxfecPktMsk[0], kFlxfecPktMsk[1],
-      kFlxfecPktMsk[2],  kFlxfecPktMsk[3], kFlxfecPktMsk[4], kFlxfecPktMsk[5],
-      kPayloadBits,      kPayloadBits,     kPayloadBits,     kPayloadBits};
-  const size_t packet_length = sizeof(kPacketData);
+      kFlexible,          kPtRecovery,        kLengthRecovery[0],
+      kLengthRecovery[1], kTsRecovery[0],     kTsRecovery[1],
+      kTsRecovery[2],     kTsRecovery[3],     kSnBase >> 8,
+      kSnBase & 0xFF,     kFlexfecPktMask[0], kFlexfecPktMask[1],
+      kFlexfecPktMask[2], kFlexfecPktMask[3], kFlexfecPktMask[4],
+      kFlexfecPktMask[5], kPayloadBits,       kPayloadBits,
+      kPayloadBits,       kPayloadBits};
   ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
-  read_packet.pkt->data.SetData(kPacketData, packet_length);
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {{.ssrc = 0x01}};
 
   FlexfecHeaderReader reader;
   EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
 
-  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
-                    kExpectedPacketMaskSize, read_packet);
+  std::vector<FecPacketStreamProperties> expected = {
+      {.stream = {.ssrc = 0x01,
+                  .seq_num_base = kSnBase,
+                  .packet_mask_offset = 10,
+                  .packet_mask_size = std::size(kUlpfecPacketMask)},
+       .mask = kUlpfecPacketMask}};
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
 }
 
-TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit2Set) {
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithNoKBitsSetSingleStream) {
   constexpr uint8_t kKBit0 = 0 << 7;
   constexpr uint8_t kKBit1 = 0 << 7;
-  constexpr uint8_t kKBit2 = 1 << 7;
-  constexpr size_t kExpectedPacketMaskSize = 14;
-  constexpr size_t kExpectedFecHeaderSize = 32;
-  // clang-format off
-  constexpr uint8_t kFlxfcPktMsk[] = {kKBit0 | 0x48, 0x81,
-                                      kKBit1 | 0x02, 0x11, 0x00, 0x21,
-                                      kKBit2 | 0x01, 0x11, 0x11, 0x11,
-                                               0x11, 0x11, 0x11, 0x11};
-  constexpr uint8_t kUlpfecPacketMask[] =     {0x91, 0x02,
-                                               0x08, 0x44, 0x00, 0x84,
-                                               0x08, 0x88, 0x88, 0x88,
-                                               0x88, 0x88, 0x88, 0x88};
-  // clang-format on
-  constexpr uint8_t kPacketData[] = {
-      kNoRBit | kNoFBit, kPtRecovery,      kLengthRecov[0],  kLengthRecov[1],
-      kTsRecovery[0],    kTsRecovery[1],   kTsRecovery[2],   kTsRecovery[3],
-      kSsrcCount,        kReservedBits,    kReservedBits,    kReservedBits,
-      kProtSsrc[0],      kProtSsrc[1],     kProtSsrc[2],     kProtSsrc[3],
-      kSnBase[0],        kSnBase[1],       kFlxfcPktMsk[0],  kFlxfcPktMsk[1],
-      kFlxfcPktMsk[2],   kFlxfcPktMsk[3],  kFlxfcPktMsk[4],  kFlxfcPktMsk[5],
-      kFlxfcPktMsk[6],   kFlxfcPktMsk[7],  kFlxfcPktMsk[8],  kFlxfcPktMsk[9],
-      kFlxfcPktMsk[10],  kFlxfcPktMsk[11], kFlxfcPktMsk[12], kFlxfcPktMsk[13],
-      kPayloadBits,      kPayloadBits,     kPayloadBits,     kPayloadBits};
-  const size_t packet_length = sizeof(kPacketData);
+  constexpr size_t kExpectedFecHeaderSize = 24;
+  constexpr uint16_t kSnBase = 0x0102;
+  constexpr uint8_t kFlexfecPacketMask[] = {kKBit0 | 0x48, 0x81,              //
+                                            kKBit1 | 0x02, 0x11, 0x00, 0x21,  //
+                                            0x01,          0x11, 0x11, 0x11,
+                                            0x11,          0x11, 0x11, 0x11};
+  constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02,              //
+                                           0x08, 0x44, 0x00, 0x84,  //
+                                           0x04, 0x44, 0x44, 0x44,
+                                           0x44, 0x44, 0x44, 0x44};
+  constexpr uint8_t kPacketData[] = {kFlexible,
+                                     kPtRecovery,
+                                     kLengthRecovery[0],
+                                     kLengthRecovery[1],
+                                     kTsRecovery[0],
+                                     kTsRecovery[1],
+                                     kTsRecovery[2],
+                                     kTsRecovery[3],
+                                     kSnBase >> 8,
+                                     kSnBase & 0xFF,
+                                     kFlexfecPacketMask[0],
+                                     kFlexfecPacketMask[1],
+                                     kFlexfecPacketMask[2],
+                                     kFlexfecPacketMask[3],
+                                     kFlexfecPacketMask[4],
+                                     kFlexfecPacketMask[5],
+                                     kFlexfecPacketMask[6],
+                                     kFlexfecPacketMask[7],
+                                     kFlexfecPacketMask[8],
+                                     kFlexfecPacketMask[9],
+                                     kFlexfecPacketMask[10],
+                                     kFlexfecPacketMask[11],
+                                     kFlexfecPacketMask[12],
+                                     kFlexfecPacketMask[13],
+                                     kPayloadBits,
+                                     kPayloadBits,
+                                     kPayloadBits,
+                                     kPayloadBits};
   ReceivedFecPacket read_packet;
-  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
-  read_packet.pkt->data.SetData(kPacketData, packet_length);
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {{.ssrc = 0x01}};
 
   FlexfecHeaderReader reader;
   EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
 
-  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
-                    kExpectedPacketMaskSize, read_packet);
+  std::vector<FecPacketStreamProperties> expected = {
+      {.stream = {.ssrc = 0x01,
+                  .seq_num_base = kSnBase,
+                  .packet_mask_offset = 10,
+                  .packet_mask_size = std::size(kUlpfecPacketMask)},
+       .mask = kUlpfecPacketMask}};
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0Set2Streams) {
+  constexpr uint8_t kKBit0 = 1 << 7;
+  constexpr size_t kExpectedFecHeaderSize = 16;
+  constexpr uint16_t kSnBase0 = 0x0102;
+  constexpr uint16_t kSnBase1 = 0x0304;
+  constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x08, 0x81};
+  constexpr uint8_t kUlpfecPacketMask1[] = {0x11, 0x02};
+  constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x04, 0x41};
+  constexpr uint8_t kUlpfecPacketMask2[] = {0x08, 0x82};
+
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,      kPtRecovery,     kLengthRecovery[0],  kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1],  kTsRecovery[2],      kTsRecovery[3],
+      kSnBase0 >> 8,  kSnBase0 & 0xFF, kFlexfecPktMask1[0], kFlexfecPktMask1[1],
+      kSnBase1 >> 8,  kSnBase1 & 0xFF, kFlexfecPktMask2[0], kFlexfecPktMask2[1],
+      kPayloadBits,   kPayloadBits,    kPayloadBits,        kPayloadBits};
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
+
+  FlexfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  std::vector<FecPacketStreamProperties> expected = {
+      {.stream = {.ssrc = 0x01,
+                  .seq_num_base = kSnBase0,
+                  .packet_mask_offset = 10,
+                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
+       .mask = kUlpfecPacketMask1},
+      {.stream = {.ssrc = 0x02,
+                  .seq_num_base = kSnBase1,
+                  .packet_mask_offset = 14,
+                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
+       .mask = kUlpfecPacketMask2},
+  };
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1Set2Streams) {
+  constexpr uint8_t kKBit0 = 0 << 7;
+  constexpr uint8_t kKBit1 = 1 << 7;
+  constexpr size_t kExpectedFecHeaderSize = 24;
+  constexpr uint16_t kSnBase0 = 0x0102;
+  constexpr uint16_t kSnBase1 = 0x0304;
+  constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x48, 0x81,  //
+                                          kKBit1 | 0x02, 0x11, 0x00, 0x21};
+  constexpr uint8_t kUlpfecPacketMask1[] = {0x91, 0x02,  //
+                                            0x08, 0x44, 0x00, 0x84};
+  constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x57, 0x82,  //
+                                          kKBit1 | 0x04, 0x33, 0x00, 0x51};
+  constexpr uint8_t kUlpfecPacketMask2[] = {0xAF, 0x04,  //
+                                            0x10, 0xCC, 0x01, 0x44};
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,           kPtRecovery,         kLengthRecovery[0],
+      kLengthRecovery[1],  kTsRecovery[0],      kTsRecovery[1],
+      kTsRecovery[2],      kTsRecovery[3],      kSnBase0 >> 8,
+      kSnBase0 & 0xFF,     kFlexfecPktMask1[0], kFlexfecPktMask1[1],
+      kFlexfecPktMask1[2], kFlexfecPktMask1[3], kFlexfecPktMask1[4],
+      kFlexfecPktMask1[5], kSnBase1 >> 8,       kSnBase1 & 0xFF,
+      kFlexfecPktMask2[0], kFlexfecPktMask2[1], kFlexfecPktMask2[2],
+      kFlexfecPktMask2[3], kFlexfecPktMask2[4], kFlexfecPktMask2[5],
+      kPayloadBits,        kPayloadBits,        kPayloadBits,
+      kPayloadBits};
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
+
+  FlexfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  std::vector<FecPacketStreamProperties> expected = {
+      {.stream = {.ssrc = 0x01,
+                  .seq_num_base = kSnBase0,
+                  .packet_mask_offset = 10,
+                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
+       .mask = kUlpfecPacketMask1},
+      {.stream = {.ssrc = 0x02,
+                  .seq_num_base = kSnBase1,
+                  .packet_mask_offset = 18,
+                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
+       .mask = kUlpfecPacketMask2},
+  };
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithNoKBitsSet2Streams) {
+  constexpr uint8_t kKBit0 = 0 << 7;
+  constexpr uint8_t kKBit1 = 0 << 7;
+  constexpr size_t kExpectedFecHeaderSize = 40;
+  constexpr uint16_t kSnBase0 = 0x0102;
+  constexpr uint16_t kSnBase1 = 0x0304;
+  constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x48, 0x81,              //
+                                          kKBit1 | 0x02, 0x11, 0x00, 0x21,  //
+                                          0x01,          0x11, 0x11, 0x11,
+                                          0x11,          0x11, 0x11, 0x11};
+  constexpr uint8_t kUlpfecPacketMask1[] = {0x91, 0x02,              //
+                                            0x08, 0x44, 0x00, 0x84,  //
+                                            0x04, 0x44, 0x44, 0x44,
+                                            0x44, 0x44, 0x44, 0x44};
+  constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x32, 0x84,              //
+                                          kKBit1 | 0x05, 0x23, 0x00, 0x55,  //
+                                          0xA3,          0x22, 0x22, 0x22,
+                                          0x22,          0x22, 0x22, 0x35};
+  constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x08,              //
+                                            0x14, 0x8C, 0x01, 0x56,  //
+                                            0x8C, 0x88, 0x88, 0x88,
+                                            0x88, 0x88, 0x88, 0xD4};
+
+  constexpr uint8_t kPacketData[] = {kFlexible,
+                                     kPtRecovery,
+                                     kLengthRecovery[0],
+                                     kLengthRecovery[1],
+                                     kTsRecovery[0],
+                                     kTsRecovery[1],
+                                     kTsRecovery[2],
+                                     kTsRecovery[3],
+                                     kSnBase0 >> 8,
+                                     kSnBase0 & 0xFF,
+                                     kFlexfecPktMask1[0],
+                                     kFlexfecPktMask1[1],
+                                     kFlexfecPktMask1[2],
+                                     kFlexfecPktMask1[3],
+                                     kFlexfecPktMask1[4],
+                                     kFlexfecPktMask1[5],
+                                     kFlexfecPktMask1[6],
+                                     kFlexfecPktMask1[7],
+                                     kFlexfecPktMask1[8],
+                                     kFlexfecPktMask1[9],
+                                     kFlexfecPktMask1[10],
+                                     kFlexfecPktMask1[11],
+                                     kFlexfecPktMask1[12],
+                                     kFlexfecPktMask1[13],
+                                     kSnBase1 >> 8,
+                                     kSnBase1 & 0xFF,
+                                     kFlexfecPktMask2[0],
+                                     kFlexfecPktMask2[1],
+                                     kFlexfecPktMask2[2],
+                                     kFlexfecPktMask2[3],
+                                     kFlexfecPktMask2[4],
+                                     kFlexfecPktMask2[5],
+                                     kFlexfecPktMask2[6],
+                                     kFlexfecPktMask2[7],
+                                     kFlexfecPktMask2[8],
+                                     kFlexfecPktMask2[9],
+                                     kFlexfecPktMask2[10],
+                                     kFlexfecPktMask2[11],
+                                     kFlexfecPktMask2[12],
+                                     kFlexfecPktMask2[13],
+                                     kPayloadBits,
+                                     kPayloadBits,
+                                     kPayloadBits,
+                                     kPayloadBits};
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
+
+  FlexfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  std::vector<FecPacketStreamProperties> expected = {
+      {.stream = {.ssrc = 0x01,
+                  .seq_num_base = kSnBase0,
+                  .packet_mask_offset = 10,
+                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
+       .mask = kUlpfecPacketMask1},
+      {.stream = {.ssrc = 0x02,
+                  .seq_num_base = kSnBase1,
+                  .packet_mask_offset = 26,
+                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
+       .mask = kUlpfecPacketMask2},
+  };
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithMultipleStreamsMultipleMasks) {
+  constexpr uint8_t kBit0 = 0 << 7;
+  constexpr uint8_t kBit1 = 1 << 7;
+  constexpr size_t kExpectedFecHeaderSize = 44;
+  constexpr uint16_t kSnBase0 = 0x0102;
+  constexpr uint16_t kSnBase1 = 0x0304;
+  constexpr uint16_t kSnBase2 = 0x0506;
+  constexpr uint16_t kSnBase3 = 0x0708;
+  constexpr uint8_t kFlexfecPacketMask1[] = {kBit1 | 0x29, 0x91};
+  constexpr uint8_t kUlpfecPacketMask1[] = {0x53, 0x22};
+  constexpr uint8_t kFlexfecPacketMask2[] = {kBit0 | 0x32, 0xA1,  //
+                                             kBit1 | 0x02, 0x11, 0x00, 0x21};
+  constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x42,  //
+                                            0x08, 0x44, 0x00, 0x84};
+  constexpr uint8_t kFlexfecPacketMask3[] = {kBit0 | 0x48, 0x81,              //
+                                             kBit0 | 0x02, 0x11, 0x00, 0x21,  //
+                                             0x01,         0x11, 0x11, 0x11,
+                                             0x11,         0x11, 0x11, 0x11};
+  constexpr uint8_t kUlpfecPacketMask3[] = {0x91, 0x02,              //
+                                            0x08, 0x44, 0x00, 0x84,  //
+                                            0x04, 0x44, 0x44, 0x44,
+                                            0x44, 0x44, 0x44, 0x44};
+  constexpr uint8_t kFlexfecPacketMask4[] = {kBit0 | 0x32, 0x84,  //
+                                             kBit1 | 0x05, 0x23, 0x00, 0x55};
+  constexpr uint8_t kUlpfecPacketMask4[] = {0x65, 0x08,  //
+                                            0x14, 0x8C, 0x01, 0x54};
+  constexpr uint8_t kPacketData[] = {kFlexible,
+                                     kPtRecovery,
+                                     kLengthRecovery[0],
+                                     kLengthRecovery[1],
+                                     kTsRecovery[0],
+                                     kTsRecovery[1],
+                                     kTsRecovery[2],
+                                     kTsRecovery[3],
+                                     kSnBase0 >> 8,
+                                     kSnBase0 & 0xFF,
+                                     kFlexfecPacketMask1[0],
+                                     kFlexfecPacketMask1[1],
+                                     kSnBase1 >> 8,
+                                     kSnBase1 & 0xFF,
+                                     kFlexfecPacketMask2[0],
+                                     kFlexfecPacketMask2[1],
+                                     kFlexfecPacketMask2[2],
+                                     kFlexfecPacketMask2[3],
+                                     kFlexfecPacketMask2[4],
+                                     kFlexfecPacketMask2[5],
+                                     kSnBase2 >> 8,
+                                     kSnBase2 & 0xFF,
+                                     kFlexfecPacketMask3[0],
+                                     kFlexfecPacketMask3[1],
+                                     kFlexfecPacketMask3[2],
+                                     kFlexfecPacketMask3[3],
+                                     kFlexfecPacketMask3[4],
+                                     kFlexfecPacketMask3[5],
+                                     kFlexfecPacketMask3[6],
+                                     kFlexfecPacketMask3[7],
+                                     kFlexfecPacketMask3[8],
+                                     kFlexfecPacketMask3[9],
+                                     kFlexfecPacketMask3[10],
+                                     kFlexfecPacketMask3[11],
+                                     kFlexfecPacketMask3[12],
+                                     kFlexfecPacketMask3[13],
+                                     kSnBase3 >> 8,
+                                     kSnBase3 & 0xFF,
+                                     kFlexfecPacketMask4[0],
+                                     kFlexfecPacketMask4[1],
+                                     kFlexfecPacketMask4[2],
+                                     kFlexfecPacketMask4[3],
+                                     kFlexfecPacketMask4[4],
+                                     kFlexfecPacketMask4[5],
+                                     kPayloadBits,
+                                     kPayloadBits,
+                                     kPayloadBits,
+                                     kPayloadBits};
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {
+      {.ssrc = 0x01}, {.ssrc = 0x02}, {.ssrc = 0x03}, {.ssrc = 0x04}};
+
+  FlexfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  std::vector<FecPacketStreamProperties> expected = {
+      {.stream = {.ssrc = 0x01,
+                  .seq_num_base = kSnBase0,
+                  .packet_mask_offset = 10,
+                  .packet_mask_size = std::size(kUlpfecPacketMask1)},
+       .mask = kUlpfecPacketMask1},
+      {.stream = {.ssrc = 0x02,
+                  .seq_num_base = kSnBase1,
+                  .packet_mask_offset = 14,
+                  .packet_mask_size = std::size(kUlpfecPacketMask2)},
+       .mask = kUlpfecPacketMask2},
+      {.stream = {.ssrc = 0x03,
+                  .seq_num_base = kSnBase2,
+                  .packet_mask_offset = 22,
+                  .packet_mask_size = std::size(kUlpfecPacketMask3)},
+       .mask = kUlpfecPacketMask3},
+      {.stream = {.ssrc = 0x04,
+                  .seq_num_base = kSnBase3,
+                  .packet_mask_offset = 38,
+                  .packet_mask_size = std::size(kUlpfecPacketMask4)},
+       .mask = kUlpfecPacketMask4},
+  };
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadPacketWithoutProtectedSsrcsShouldFail) {
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3]};
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  // No protected ssrcs.
+  read_packet.protected_streams = {};
+
+  FlexfecHeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
 }
 
 TEST(FlexfecHeaderReaderTest, ReadPacketWithoutStreamSpecificHeaderShouldFail) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-
   // Simulate short received packet.
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3]};
   ReceivedFecPacket read_packet;
-  read_packet.ssrc = kFlexfecSsrc;
-  read_packet.pkt = std::move(written_packet);
-  read_packet.pkt->data.SetSize(12);
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  read_packet.pkt->data.SetData(kPacketData);
+  read_packet.protected_streams = {{.ssrc = 0x01}};
 
   FlexfecHeaderReader reader;
   EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
 }
 
 TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit0SetShouldFail) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-
   // Simulate short received packet.
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
+      kSnBases[0][0], kSnBases[0][1], kMask0[0],          kMask0[1]};
   ReceivedFecPacket read_packet;
-  read_packet.ssrc = kFlexfecSsrc;
-  read_packet.pkt = std::move(written_packet);
-  read_packet.pkt->data.SetSize(18);
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  // Expected to have 2 bytes of mask but length of packet misses 1 byte.
+  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 1);
+  read_packet.protected_streams = {{.ssrc = 0x01}};
 
   FlexfecHeaderReader reader;
   EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
 }
 
 TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit1SetShouldFail) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(15, packet_mask.get());  // This expands the packet mask "once".
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-
   // Simulate short received packet.
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
+      kSnBases[0][0], kSnBases[0][1], kMask1[0],          kMask1[1],
+      kMask1[2],      kMask1[3],      kMask1[4],          kMask1[5]};
   ReceivedFecPacket read_packet;
-  read_packet.ssrc = kFlexfecSsrc;
-  read_packet.pkt = std::move(written_packet);
-  read_packet.pkt->data.SetSize(20);
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  // Expected to have 6 bytes of mask but length of packet misses 2 bytes.
+  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
+  read_packet.protected_streams = {{.ssrc = 0x01}};
 
   FlexfecHeaderReader reader;
   EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
 }
 
-TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit2SetShouldFail) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(47, packet_mask.get());  // This expands the packet mask "twice".
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-
+TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit1ClearedShouldFail) {
   // Simulate short received packet.
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
+      kSnBases[0][0], kSnBases[0][1], kMask2[0],          kMask2[1],
+      kMask2[2],      kMask2[3],      kMask2[4],          kMask2[5],
+      kMask2[6],      kMask2[7],      kMask2[8],          kMask2[9],
+      kMask2[10],     kMask2[11],     kMask2[12],         kMask2[13]};
   ReceivedFecPacket read_packet;
-  read_packet.ssrc = kFlexfecSsrc;
-  read_packet.pkt = std::move(written_packet);
-  read_packet.pkt->data.SetSize(24);
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  // Expected to have 14 bytes of mask but length of packet misses 2 bytes.
+  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
+  read_packet.protected_streams = {{.ssrc = 0x01}};
 
   FlexfecHeaderReader reader;
   EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
 }
 
-TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0Set) {
-  constexpr size_t kExpectedPacketMaskSize = 2;
-  constexpr uint8_t kFlexfecPacketMask[] = {0x88, 0x81};
-  constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
-  Packet written_packet;
-  written_packet.data.SetSize(kMediaPacketLength);
-  uint8_t* data = written_packet.data.MutableData();
-  for (size_t i = 0; i < written_packet.data.size(); ++i) {
-    data[i] = i;
-  }
+TEST(FlexfecHeaderReaderTest, ReadShortPacketMultipleStreamsShouldFail) {
+  // Simulate short received packet with 2 protected ssrcs.
+  constexpr uint8_t kPacketData[] = {
+      kFlexible,      kPtRecovery,    kLengthRecovery[0], kLengthRecovery[1],
+      kTsRecovery[0], kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
+      kSnBases[0][0], kSnBases[0][1], kMask0[0],          kMask0[1],
+      kSnBases[1][0], kSnBases[1][1], kMask2[0],          kMask2[1],
+      kMask2[2],      kMask2[3],      kMask2[4],          kMask2[5],
+      kMask2[6],      kMask2[7],      kMask2[8],          kMask2[9],
+      kMask2[10],     kMask2[11],     kMask2[12],         kMask2[13]};
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::make_ref_counted<Packet>();
+  // Subtract 2 bytes from length, so the read will fail on parsing second
+  read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
+  read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
 
-  FlexfecHeaderWriter writer;
-  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
-                           sizeof(kUlpfecPacketMask), &written_packet);
-
-  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
-                         written_packet);
+  FlexfecHeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
 }
 
-TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1Set) {
-  constexpr size_t kExpectedPacketMaskSize = 6;
-  constexpr uint8_t kFlexfecPacketMask[] = {0x48, 0x81, 0x82, 0x11, 0x00, 0x21};
-  constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84};
-  Packet written_packet;
-  written_packet.data.SetSize(kMediaPacketLength);
-  uint8_t* data = written_packet.data.MutableData();
-  for (size_t i = 0; i < written_packet.data.size(); ++i) {
-    data[i] = i;
-  }
+// TODO(bugs.webrtc.org/15002): reimplement and add tests for multi stream cases
+// after updating the Writer code.
 
-  FlexfecHeaderWriter writer;
-  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
-                           sizeof(kUlpfecPacketMask), &written_packet);
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0Set) {}
 
-  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
-                         written_packet);
-}
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1Set) {}
 
-TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit2Set) {
-  constexpr size_t kExpectedPacketMaskSize = 14;
-  constexpr uint8_t kFlexfecPacketMask[] = {
-      0x11, 0x11,                                     // K-bit 0 clear.
-      0x11, 0x11, 0x11, 0x10,                         // K-bit 1 clear.
-      0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // K-bit 2 set.
-  };
-  constexpr uint8_t kUlpfecPacketMask[] = {0x22, 0x22, 0x44, 0x44, 0x44, 0x41};
-  Packet written_packet;
-  written_packet.data.SetSize(kMediaPacketLength);
-  uint8_t* data = written_packet.data.MutableData();
-  for (size_t i = 0; i < written_packet.data.size(); ++i) {
-    data[i] = i;
-  }
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit2Set) {}
 
-  FlexfecHeaderWriter writer;
-  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
-                           sizeof(kUlpfecPacketMask), &written_packet);
+TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {}
 
-  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
-                         written_packet);
-}
-
-TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  ClearBit(15, packet_mask.get());
-
-  FlexfecHeaderWriter writer;
-  size_t min_packet_mask_size =
-      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
-
-  EXPECT_EQ(kFlexfecPacketMaskSizes[0], min_packet_mask_size);
-  EXPECT_EQ(kFlexfecHeaderSizes[0], writer.FecHeaderSize(min_packet_mask_size));
-}
-
-TEST(FlexfecHeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(15, packet_mask.get());
-
-  FlexfecHeaderWriter writer;
-  size_t min_packet_mask_size =
-      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
-
-  EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
-  EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
-}
+TEST(FlexfecHeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {}
 
 TEST(FlexfecHeaderWriterTest,
-     ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  ClearBit(46, packet_mask.get());
-  ClearBit(47, packet_mask.get());
-
-  FlexfecHeaderWriter writer;
-  size_t min_packet_mask_size =
-      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
-
-  EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
-  EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
-}
+     ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {}
 
 TEST(FlexfecHeaderWriterTest,
-     ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(46, packet_mask.get());
-  ClearBit(47, packet_mask.get());
-
-  FlexfecHeaderWriter writer;
-  size_t min_packet_mask_size =
-      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
-
-  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
-  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
-}
+     ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {}
 
 TEST(FlexfecHeaderWriterTest,
-     ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  ClearBit(46, packet_mask.get());
-  SetBit(47, packet_mask.get());
-
-  FlexfecHeaderWriter writer;
-  size_t min_packet_mask_size =
-      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
-
-  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
-  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
-}
+     ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {}
 
 TEST(FlexfecHeaderWriterTest, ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(46, packet_mask.get());
-  SetBit(47, packet_mask.get());
-
-  FlexfecHeaderWriter writer;
-  size_t min_packet_mask_size =
-      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
-
-  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
-  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
 }
 
 TEST(FlexfecHeaderReaderWriterTest,
-     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  ClearBit(15, packet_mask.get());
-
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-  auto read_packet = ReadHeader(*written_packet);
-
-  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[0], packet_mask.get(),
-                              kFlexfecPacketMaskSizes[0], *written_packet,
-                              *read_packet);
-}
+     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {}
 
 TEST(FlexfecHeaderReaderWriterTest,
-     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(15, packet_mask.get());
-
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-  auto read_packet = ReadHeader(*written_packet);
-
-  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
-                              kFlexfecPacketMaskSizes[1], *written_packet,
-                              *read_packet);
-}
+     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {}
 
 TEST(FlexfecHeaderReaderWriterTest,
-     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  ClearBit(46, packet_mask.get());
-  ClearBit(47, packet_mask.get());
-
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-  auto read_packet = ReadHeader(*written_packet);
-
-  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
-                              kFlexfecPacketMaskSizes[1], *written_packet,
-                              *read_packet);
-}
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {}
 
 TEST(FlexfecHeaderReaderWriterTest,
-     WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(46, packet_mask.get());
-  ClearBit(47, packet_mask.get());
-
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-  auto read_packet = ReadHeader(*written_packet);
-
-  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
-                              kFlexfecPacketMaskSizes[2], *written_packet,
-                              *read_packet);
-}
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {}
 
 TEST(FlexfecHeaderReaderWriterTest,
-     WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  ClearBit(46, packet_mask.get());
-  SetBit(47, packet_mask.get());
-
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-  auto read_packet = ReadHeader(*written_packet);
-
-  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
-                              kFlexfecPacketMaskSizes[2], *written_packet,
-                              *read_packet);
-}
+     WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {}
 
 TEST(FlexfecHeaderReaderWriterTest,
-     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {
-  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
-  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
-  SetBit(46, packet_mask.get());
-  SetBit(47, packet_mask.get());
-
-  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
-  auto read_packet = ReadHeader(*written_packet);
-
-  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
-                              kFlexfecPacketMaskSizes[2], *written_packet,
-                              *read_packet);
-}
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {}
 
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/forward_error_correction.cc b/modules/rtp_rtcp/source/forward_error_correction.cc
index ada9742..750c800 100644
--- a/modules/rtp_rtcp/source/forward_error_correction.cc
+++ b/modules/rtp_rtcp/source/forward_error_correction.cc
@@ -19,7 +19,7 @@
 #include "modules/include/module_common_types_public.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
-#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
+#include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h"
 #include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
 #include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
 #include "rtc_base/checks.h"
@@ -99,8 +99,10 @@
 std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateFlexfec(
     uint32_t ssrc,
     uint32_t protected_media_ssrc) {
-  std::unique_ptr<FecHeaderReader> fec_header_reader(new FlexfecHeaderReader());
-  std::unique_ptr<FecHeaderWriter> fec_header_writer(new FlexfecHeaderWriter());
+  std::unique_ptr<FecHeaderReader> fec_header_reader(
+      new Flexfec03HeaderReader());
+  std::unique_ptr<FecHeaderWriter> fec_header_writer(
+      new Flexfec03HeaderWriter());
   return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection(
       std::move(fec_header_reader), std::move(fec_header_writer), ssrc,
       protected_media_ssrc));
diff --git a/modules/rtp_rtcp/source/rtp_fec_unittest.cc b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
index 2c01a0d..7e5aef7 100644
--- a/modules/rtp_rtcp/source/rtp_fec_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
@@ -14,7 +14,7 @@
 #include "absl/algorithm/container.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/fec_test_helper.h"
-#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
+#include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h"
 #include "modules/rtp_rtcp/source/forward_error_correction.h"
 #include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
 #include "rtc_base/random.h"
@@ -177,8 +177,8 @@
 
   FlexfecForwardErrorCorrection()
       : ForwardErrorCorrection(
-            std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()),
-            std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()),
+            std::unique_ptr<FecHeaderReader>(new Flexfec03HeaderReader()),
+            std::unique_ptr<FecHeaderWriter>(new Flexfec03HeaderWriter()),
             kFecSsrc,
             kMediaSsrc) {}