| Index: webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
 | 
| diff --git a/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc b/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..d317f01dd940baeeccf9bc51346324c10706b8c0
 | 
| --- /dev/null
 | 
| +++ b/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
 | 
| @@ -0,0 +1,283 @@
 | 
| +/*
 | 
| + *  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 "webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
 | 
| +
 | 
| +#include <string.h>
 | 
| +
 | 
| +#include <utility>
 | 
| +
 | 
| +#include "webrtc/base/checks.h"
 | 
| +#include "webrtc/base/logging.h"
 | 
| +#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 | 
| +#include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.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 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]};
 | 
| +
 | 
| +// 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
 | 
| +
 | 
| +FlexfecHeaderReader::FlexfecHeaderReader()
 | 
| +    : FecHeaderReader(kMaxMediaPackets, kMaxFecPackets) {}
 | 
| +
 | 
| +FlexfecHeaderReader::~FlexfecHeaderReader() = default;
 | 
| +
 | 
| +// TODO(brandtr): Update this function when we support flexible masks,
 | 
| +// retransmissions, and/or several protected SSRCs.
 | 
| +bool FlexfecHeaderReader::ReadFecHeader(
 | 
| +    ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
 | 
| +  if (fec_packet->pkt->length <= kBaseHeaderSize + kStreamSpecificHeaderSize) {
 | 
| +    LOG(LS_INFO) << "Discarding truncated FlexFEC packet.";
 | 
| +    return false;
 | 
| +  }
 | 
| +  bool f_bit = (fec_packet->pkt->data[0] & 0x80) != 0;
 | 
| +  if (f_bit) {
 | 
| +    return false;
 | 
| +  }
 | 
| +  bool r_bit = (fec_packet->pkt->data[0] & 0x40) != 0;
 | 
| +  if (r_bit) {
 | 
| +    return false;
 | 
| +  }
 | 
| +  uint8_t ssrc_count =
 | 
| +      ByteReader<uint8_t>::ReadBigEndian(&fec_packet->pkt->data[8]);
 | 
| +  if (ssrc_count != 1) {
 | 
| +    return false;
 | 
| +  }
 | 
| +  uint32_t protected_ssrc =
 | 
| +      ByteReader<uint32_t>::ReadBigEndian(&fec_packet->pkt->data[12]);
 | 
| +  uint16_t seq_num_base =
 | 
| +      ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[16]);
 | 
| +
 | 
| +  // Read packet mask and adapt it by removing the interleaved K bits.
 | 
| +  // This destroys the FlexFEC standards compliance of the packet masks,
 | 
| +  // but makes it compatible with the ULPFEC masks.
 | 
| +  // TODO(brandtr): Store the adapted pack mask out-of-band, when the
 | 
| +  // FEC packet classes have been refactored.
 | 
| +  //
 | 
| +  // 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->length < kHeaderSizes[0]) {
 | 
| +    LOG(LS_INFO) << "Discarding truncated FlexFEC packet.";
 | 
| +    return false;
 | 
| +  }
 | 
| +  uint8_t* const packet_mask = fec_packet->pkt->data + kPacketMaskOffset;
 | 
| +  bool k_bit0 = (packet_mask[0] & 0x80) != 0;
 | 
| +  uint16_t mask_part0 = ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
 | 
| +  mask_part0 <<= 1;  // Shift away K-bit 0 from adapted mask.
 | 
| +  ByteWriter<uint16_t>::WriteBigEndian(&packet_mask[0], mask_part0);
 | 
| +  size_t packet_mask_size;
 | 
| +  if (k_bit0) {
 | 
| +    packet_mask_size = kFlexfecPacketMaskSizes[0];
 | 
| +  } else {
 | 
| +    if (fec_packet->pkt->length < kHeaderSizes[1]) {
 | 
| +      return false;
 | 
| +    }
 | 
| +    bool k_bit1 = (packet_mask[2] & 0x80) != 0;
 | 
| +    bool bit15 = (packet_mask[2] & 0x40) != 0;
 | 
| +    if (bit15) {
 | 
| +      packet_mask[1] |= 0x01;  // Set bit 15 in adapted mask.
 | 
| +    }
 | 
| +    uint32_t mask_part1 = ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
 | 
| +    mask_part1 <<= 2;  // Shift away K-bit 1 and bit 15 from adapted mask.
 | 
| +    ByteWriter<uint32_t>::WriteBigEndian(&packet_mask[2], mask_part1);
 | 
| +    if (k_bit1) {
 | 
| +      packet_mask_size = kFlexfecPacketMaskSizes[1];
 | 
| +    } else {
 | 
| +      if (fec_packet->pkt->length < kHeaderSizes[2]) {
 | 
| +        LOG(LS_INFO) << "Discarding truncated FlexFEC packet.";
 | 
| +        return false;
 | 
| +      }
 | 
| +      bool k_bit2 = (packet_mask[6] & 0x80) != 0;
 | 
| +      if (k_bit2) {
 | 
| +        packet_mask_size = kFlexfecPacketMaskSizes[2];
 | 
| +      } else {
 | 
| +        LOG(LS_INFO) << "Discarding FlexFEC packet with malformed header.";
 | 
| +        return false;
 | 
| +      }
 | 
| +      // Copy bits 46 and 47.
 | 
| +      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 from adapted mask.
 | 
| +      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_ssrc = protected_ssrc;
 | 
| +  fec_packet->seq_num_base = seq_num_base;
 | 
| +  fec_packet->packet_mask_offset = kPacketMaskOffset;
 | 
| +  fec_packet->packet_mask_size = packet_mask_size;
 | 
| +
 | 
| +  // In FlexFEC, all media packets are protected in their entirety.
 | 
| +  fec_packet->protection_length =
 | 
| +      fec_packet->pkt->length - fec_packet->fec_header_size;
 | 
| +
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +FlexfecHeaderWriter::FlexfecHeaderWriter()
 | 
| +    : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
 | 
| +
 | 
| +FlexfecHeaderWriter::~FlexfecHeaderWriter() = default;
 | 
| +
 | 
| +size_t FlexfecHeaderWriter::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_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size << ".";
 | 
| +  return kFlexfecPacketMaskSizes[2];
 | 
| +}
 | 
| +
 | 
| +size_t FlexfecHeaderWriter::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 FlexfecHeaderWriter::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 {
 | 
| +  fec_packet->data[0] &= 0x7f;  // Clear F bit.
 | 
| +  fec_packet->data[0] &= 0xbf;  // Clear R bit.
 | 
| +  // Write SSRC count, reserved bits, protected media SSRC, and sequence number
 | 
| +  // base.
 | 
| +  ByteWriter<uint8_t>::WriteBigEndian(&fec_packet->data[8], 1U);
 | 
| +  memset(&fec_packet->data[9], 0, 3);
 | 
| +  ByteWriter<uint32_t>::WriteBigEndian(&fec_packet->data[12], media_ssrc);
 | 
| +  ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->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 = fec_packet->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_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size
 | 
| +                     << ".";
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +}  // namespace webrtc
 | 
| 
 |