| Index: webrtc/modules/rtp_rtcp/source/producer_fec.cc
 | 
| diff --git a/webrtc/modules/rtp_rtcp/source/producer_fec.cc b/webrtc/modules/rtp_rtcp/source/producer_fec.cc
 | 
| index c27472bfaf264532352041b25762328ea38ef418..b928020df3211d33c7a9be5c838b39f49708faa9 100644
 | 
| --- a/webrtc/modules/rtp_rtcp/source/producer_fec.cc
 | 
| +++ b/webrtc/modules/rtp_rtcp/source/producer_fec.cc
 | 
| @@ -13,27 +13,39 @@
 | 
|  #include <memory>
 | 
|  #include <utility>
 | 
|  
 | 
| +#include "webrtc/base/basictypes.h"
 | 
| +#include "webrtc/base/checks.h"
 | 
|  #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 | 
|  #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
 | 
|  #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 | 
|  
 | 
|  namespace webrtc {
 | 
|  
 | 
| -enum { kREDForFECHeaderLength = 1 };
 | 
| +constexpr size_t kRedForFecHeaderLength = 1;
 | 
| +
 | 
|  // This controls the maximum amount of excess overhead (actual - target)
 | 
|  // allowed in order to trigger GenerateFec(), before |params_.max_fec_frames|
 | 
|  // is reached. Overhead here is defined as relative to number of media packets.
 | 
| -enum { kMaxExcessOverhead = 50 };  // Q8.
 | 
| +constexpr int kMaxExcessOverhead = 50;  // Q8.
 | 
| +
 | 
|  // This is the minimum number of media packets required (above some protection
 | 
|  // level) in order to trigger GenerateFec(), before |params_.max_fec_frames| is
 | 
|  // reached.
 | 
| -enum { kMinimumMediaPackets = 4 };
 | 
| +constexpr size_t kMinMediaPackets = 4;
 | 
| +
 | 
|  // Threshold on the received FEC protection level, above which we enforce at
 | 
| -// least |kMinimumMediaPackets| packets for the FEC code. Below this
 | 
| -// threshold |kMinimumMediaPackets| is set to default value of 1.
 | 
| -enum { kHighProtectionThreshold = 80 };  // Corresponds to ~30 overhead, range
 | 
| -// is 0 to 255, where 255 corresponds to 100% overhead (relative to number of
 | 
| -// media packets).
 | 
| +// least |kMinMediaPackets| packets for the FEC code. Below this
 | 
| +// threshold |kMinMediaPackets| is set to default value of 1.
 | 
| +//
 | 
| +// The range is between 0 and 255, where 255 corresponds to 100% overhead
 | 
| +// (relative to the number of protected media packets).
 | 
| +constexpr uint8_t kHighProtectionThreshold = 80;
 | 
| +
 | 
| +// This threshold is used to adapt the |kMinMediaPackets| threshold, based
 | 
| +// on the average number of packets per frame seen so far. When there are few
 | 
| +// packets per frame (as given by this threshold), at least
 | 
| +// |kMinMediaPackets| + 1 packets are sent to the FEC code.
 | 
| +constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f;
 | 
|  
 | 
|  RedPacket::RedPacket(size_t length)
 | 
|      : data_(new uint8_t[length]),
 | 
| @@ -41,32 +53,31 @@ RedPacket::RedPacket(size_t length)
 | 
|        header_length_(0) {
 | 
|  }
 | 
|  
 | 
| -RedPacket::~RedPacket() {
 | 
| -  delete [] data_;
 | 
| -}
 | 
| -
 | 
| -void RedPacket::CreateHeader(const uint8_t* rtp_header, size_t header_length,
 | 
| -                             int red_pl_type, int pl_type) {
 | 
| -  assert(header_length + kREDForFECHeaderLength <= length_);
 | 
| -  memcpy(data_, rtp_header, header_length);
 | 
| +void RedPacket::CreateHeader(const uint8_t* rtp_header,
 | 
| +                             size_t header_length,
 | 
| +                             int red_payload_type,
 | 
| +                             int payload_type) {
 | 
| +  RTC_DCHECK_LT(header_length + kRedForFecHeaderLength, length_);
 | 
| +  memcpy(data_.get(), rtp_header, header_length);
 | 
|    // Replace payload type.
 | 
|    data_[1] &= 0x80;
 | 
| -  data_[1] += red_pl_type;
 | 
| +  data_[1] += red_payload_type;
 | 
|    // Add RED header
 | 
|    // f-bit always 0
 | 
| -  data_[header_length] = static_cast<uint8_t>(pl_type);
 | 
| -  header_length_ = header_length + kREDForFECHeaderLength;
 | 
| +  data_[header_length] = static_cast<uint8_t>(payload_type);
 | 
| +  header_length_ = header_length + kRedForFecHeaderLength;
 | 
|  }
 | 
|  
 | 
|  void RedPacket::SetSeqNum(int seq_num) {
 | 
| -  assert(seq_num >= 0 && seq_num < (1<<16));
 | 
| +  RTC_DCHECK_GE(seq_num, 0);
 | 
| +  RTC_DCHECK_LT(seq_num, 1 << 16);
 | 
|  
 | 
|    ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num);
 | 
|  }
 | 
|  
 | 
|  void RedPacket::AssignPayload(const uint8_t* payload, size_t length) {
 | 
| -  assert(header_length_ + length <= length_);
 | 
| -  memcpy(data_ + header_length_, payload, length);
 | 
| +  RTC_DCHECK_LE(header_length_ + length, length_);
 | 
| +  memcpy(data_.get() + header_length_, payload, length);
 | 
|  }
 | 
|  
 | 
|  void RedPacket::ClearMarkerBit() {
 | 
| @@ -74,7 +85,7 @@ void RedPacket::ClearMarkerBit() {
 | 
|  }
 | 
|  
 | 
|  uint8_t* RedPacket::data() const {
 | 
| -  return data_;
 | 
| +  return data_.get();
 | 
|  }
 | 
|  
 | 
|  size_t RedPacket::length() const {
 | 
| @@ -83,11 +94,11 @@ size_t RedPacket::length() const {
 | 
|  
 | 
|  ProducerFec::ProducerFec(ForwardErrorCorrection* fec)
 | 
|      : fec_(fec),
 | 
| -      media_packets_fec_(),
 | 
| -      fec_packets_(),
 | 
| -      num_frames_(0),
 | 
| -      num_first_partition_(0),
 | 
| -      minimum_media_packets_fec_(1),
 | 
| +      media_packets_(),
 | 
| +      generated_fec_packets_(),
 | 
| +      num_protected_frames_(0),
 | 
| +      num_important_packets_(0),
 | 
| +      min_num_media_packets_(1),
 | 
|        params_(),
 | 
|        new_params_() {
 | 
|    memset(¶ms_, 0, sizeof(params_));
 | 
| @@ -95,166 +106,165 @@ ProducerFec::ProducerFec(ForwardErrorCorrection* fec)
 | 
|  }
 | 
|  
 | 
|  ProducerFec::~ProducerFec() {
 | 
| -  DeletePackets();
 | 
| +  DeleteMediaPackets();
 | 
| +}
 | 
| +
 | 
| +std::unique_ptr<RedPacket> ProducerFec::BuildRedPacket(
 | 
| +    const uint8_t* data_buffer,
 | 
| +    size_t payload_length,
 | 
| +    size_t rtp_header_length,
 | 
| +    int red_payload_type) {
 | 
| +  std::unique_ptr<RedPacket> red_packet(new RedPacket(
 | 
| +      payload_length + kRedForFecHeaderLength + rtp_header_length));
 | 
| +  int payload_type = data_buffer[1] & 0x7f;
 | 
| +  red_packet->CreateHeader(data_buffer, rtp_header_length, red_payload_type,
 | 
| +                           payload_type);
 | 
| +  red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
 | 
| +  return red_packet;
 | 
|  }
 | 
|  
 | 
|  void ProducerFec::SetFecParameters(const FecProtectionParams* params,
 | 
| -                                   int num_first_partition) {
 | 
| -  // Number of first partition packets cannot exceed kMaxMediaPackets
 | 
| -  assert(params->fec_rate >= 0 && params->fec_rate < 256);
 | 
| -  if (num_first_partition >
 | 
| +                                   int num_important_packets) {
 | 
| +  // Number of important packets (i.e. number of packets receiving additional
 | 
| +  // protection in 'unequal protection mode') cannot exceed kMaxMediaPackets.
 | 
| +  RTC_DCHECK_GE(params->fec_rate, 0);
 | 
| +  RTC_DCHECK_LE(params->fec_rate, 255);
 | 
| +  if (num_important_packets >
 | 
|        static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) {
 | 
| -      num_first_partition =
 | 
| -          ForwardErrorCorrection::kMaxMediaPackets;
 | 
| +    num_important_packets = ForwardErrorCorrection::kMaxMediaPackets;
 | 
|    }
 | 
|    // Store the new params and apply them for the next set of FEC packets being
 | 
|    // produced.
 | 
|    new_params_ = *params;
 | 
| -  num_first_partition_ = num_first_partition;
 | 
| +  num_important_packets_ = num_important_packets;
 | 
|    if (params->fec_rate > kHighProtectionThreshold) {
 | 
| -    minimum_media_packets_fec_ = kMinimumMediaPackets;
 | 
| +    min_num_media_packets_ = kMinMediaPackets;
 | 
|    } else {
 | 
| -    minimum_media_packets_fec_ = 1;
 | 
| +    min_num_media_packets_ = 1;
 | 
|    }
 | 
|  }
 | 
|  
 | 
| -RedPacket* ProducerFec::BuildRedPacket(const uint8_t* data_buffer,
 | 
| -                                       size_t payload_length,
 | 
| -                                       size_t rtp_header_length,
 | 
| -                                       int red_pl_type) {
 | 
| -  RedPacket* red_packet = new RedPacket(
 | 
| -      payload_length + kREDForFECHeaderLength + rtp_header_length);
 | 
| -  int pl_type = data_buffer[1] & 0x7f;
 | 
| -  red_packet->CreateHeader(data_buffer, rtp_header_length,
 | 
| -                           red_pl_type, pl_type);
 | 
| -  red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
 | 
| -  return red_packet;
 | 
| -}
 | 
| -
 | 
|  int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
 | 
|                                              size_t payload_length,
 | 
|                                              size_t rtp_header_length) {
 | 
| -  assert(fec_packets_.empty());
 | 
| -  if (media_packets_fec_.empty()) {
 | 
| +  RTC_DCHECK(generated_fec_packets_.empty());
 | 
| +  if (media_packets_.empty()) {
 | 
|      params_ = new_params_;
 | 
|    }
 | 
|    bool complete_frame = false;
 | 
|    const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
 | 
| -  if (media_packets_fec_.size() < ForwardErrorCorrection::kMaxMediaPackets) {
 | 
| -    // Generic FEC can only protect up to kMaxMediaPackets packets.
 | 
| +  if (media_packets_.size() < ForwardErrorCorrection::kMaxMediaPackets) {
 | 
| +    // Generic FEC can only protect up to |kMaxMediaPackets| packets.
 | 
|      std::unique_ptr<ForwardErrorCorrection::Packet> packet(
 | 
|          new ForwardErrorCorrection::Packet());
 | 
|      packet->length = payload_length + rtp_header_length;
 | 
|      memcpy(packet->data, data_buffer, packet->length);
 | 
| -    media_packets_fec_.push_back(std::move(packet));
 | 
| +    media_packets_.push_back(std::move(packet));
 | 
|    }
 | 
|    if (marker_bit) {
 | 
| -    ++num_frames_;
 | 
| +    ++num_protected_frames_;
 | 
|      complete_frame = true;
 | 
|    }
 | 
|    // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as:
 | 
|    // (1) the excess overhead (actual overhead - requested/target overhead) is
 | 
|    // less than |kMaxExcessOverhead|, and
 | 
| -  // (2) at least |minimum_media_packets_fec_| media packets is reached.
 | 
| +  // (2) at least |min_num_media_packets_| media packets is reached.
 | 
|    if (complete_frame &&
 | 
| -      (num_frames_ == params_.max_fec_frames ||
 | 
| -          (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
 | 
| -    assert(num_first_partition_ <=
 | 
| -           static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
 | 
| +      (num_protected_frames_ == params_.max_fec_frames ||
 | 
| +       (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
 | 
| +    RTC_DCHECK_LE(num_important_packets_,
 | 
| +                  static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
 | 
|      // TODO(pbos): Consider whether unequal protection should be enabled or not,
 | 
|      // it is currently always disabled.
 | 
| -    int ret = fec_->GenerateFec(media_packets_fec_, params_.fec_rate,
 | 
| -                                num_first_partition_, false,
 | 
| -                                params_.fec_mask_type, &fec_packets_);
 | 
| -    if (fec_packets_.empty()) {
 | 
| -      num_frames_ = 0;
 | 
| -      DeletePackets();
 | 
| +    //
 | 
| +    // Since unequal protection is disabled, the value of
 | 
| +    // |num_important_packets_| has no importance when calling GenerateFec().
 | 
| +    constexpr bool kUseUnequalProtection = false;
 | 
| +    int ret = fec_->GenerateFec(media_packets_, params_.fec_rate,
 | 
| +                                num_important_packets_, kUseUnequalProtection,
 | 
| +                                params_.fec_mask_type, &generated_fec_packets_);
 | 
| +    if (generated_fec_packets_.empty()) {
 | 
| +      num_protected_frames_ = 0;
 | 
| +      DeleteMediaPackets();
 | 
|      }
 | 
|      return ret;
 | 
|    }
 | 
|    return 0;
 | 
|  }
 | 
|  
 | 
| -// Returns true if the excess overhead (actual - target) for the FEC is below
 | 
| -// the amount |kMaxExcessOverhead|. This effects the lower protection level
 | 
| -// cases and low number of media packets/frame. The target overhead is given by
 | 
| -// |params_.fec_rate|, and is only achievable in the limit of large number of
 | 
| -// media packets.
 | 
| -bool ProducerFec::ExcessOverheadBelowMax() {
 | 
| +bool ProducerFec::ExcessOverheadBelowMax() const {
 | 
|    return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead);
 | 
|  }
 | 
|  
 | 
| -// Returns true if the media packet list for the FEC is at least
 | 
| -// |minimum_media_packets_fec_|. This condition tries to capture the effect
 | 
| -// that, for the same amount of protection/overhead, longer codes
 | 
| -// (e.g. (2k,2m) vs (k,m)) are generally more effective at recovering losses.
 | 
| -bool ProducerFec::MinimumMediaPacketsReached() {
 | 
| -  float avg_num_packets_frame = static_cast<float>(media_packets_fec_.size()) /
 | 
| -                                num_frames_;
 | 
| -  if (avg_num_packets_frame < 2.0f) {
 | 
| -  return (static_cast<int>(media_packets_fec_.size()) >=
 | 
| -      minimum_media_packets_fec_);
 | 
| +bool ProducerFec::MinimumMediaPacketsReached() const {
 | 
| +  float average_num_packets_per_frame =
 | 
| +      static_cast<float>(media_packets_.size()) / num_protected_frames_;
 | 
| +  int num_media_packets = static_cast<int>(media_packets_.size());
 | 
| +  if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) {
 | 
| +    return num_media_packets >= min_num_media_packets_;
 | 
|    } else {
 | 
|      // For larger rates (more packets/frame), increase the threshold.
 | 
| -    return (static_cast<int>(media_packets_fec_.size()) >=
 | 
| -        minimum_media_packets_fec_ + 1);
 | 
| +    // TODO(brandtr): Investigate what impact this adaptation has.
 | 
| +    return num_media_packets >= min_num_media_packets_ + 1;
 | 
|    }
 | 
|  }
 | 
|  
 | 
|  bool ProducerFec::FecAvailable() const {
 | 
| -  return !fec_packets_.empty();
 | 
| +  return !generated_fec_packets_.empty();
 | 
|  }
 | 
|  
 | 
|  size_t ProducerFec::NumAvailableFecPackets() const {
 | 
| -  return fec_packets_.size();
 | 
| +  return generated_fec_packets_.size();
 | 
|  }
 | 
|  
 | 
| -std::vector<RedPacket*> ProducerFec::GetFecPackets(int red_pl_type,
 | 
| -                                                   int fec_pl_type,
 | 
| -                                                   uint16_t first_seq_num,
 | 
| -                                                   size_t rtp_header_length) {
 | 
| -  std::vector<RedPacket*> fec_packets;
 | 
| -  fec_packets.reserve(fec_packets_.size());
 | 
| -  uint16_t sequence_number = first_seq_num;
 | 
| -  while (!fec_packets_.empty()) {
 | 
| -    // Build FEC packet. The FEC packets in |fec_packets_| doesn't
 | 
| -    // have RTP headers, so we're reusing the header from the last
 | 
| -    // media packet.
 | 
| -    ForwardErrorCorrection::Packet* packet_to_send = fec_packets_.front();
 | 
| -    ForwardErrorCorrection::Packet* last_media_packet =
 | 
| -        media_packets_fec_.back().get();
 | 
| -
 | 
| -    RedPacket* red_packet = new RedPacket(
 | 
| -        packet_to_send->length + kREDForFECHeaderLength + rtp_header_length);
 | 
| +std::vector<std::unique_ptr<RedPacket>> ProducerFec::GetFecPacketsAsRed(
 | 
| +    int red_payload_type,
 | 
| +    int ulpfec_payload_type,
 | 
| +    uint16_t first_seq_num,
 | 
| +    size_t rtp_header_length) {
 | 
| +  std::vector<std::unique_ptr<RedPacket>> red_packets;
 | 
| +  red_packets.reserve(generated_fec_packets_.size());
 | 
| +  RTC_DCHECK(!media_packets_.empty());
 | 
| +  ForwardErrorCorrection::Packet* last_media_packet =
 | 
| +      media_packets_.back().get();
 | 
| +  uint16_t seq_num = first_seq_num;
 | 
| +  for (const auto& fec_packet : generated_fec_packets_) {
 | 
| +    // Wrap FEC packet (including FEC headers) in a RED packet. Since the
 | 
| +    // FEC packets in |generated_fec_packets_| don't have RTP headers, we
 | 
| +    // reuse the header from the last media packet.
 | 
| +    std::unique_ptr<RedPacket> red_packet(new RedPacket(
 | 
| +        fec_packet->length + kRedForFecHeaderLength + rtp_header_length));
 | 
|      red_packet->CreateHeader(last_media_packet->data, rtp_header_length,
 | 
| -                             red_pl_type, fec_pl_type);
 | 
| -    red_packet->SetSeqNum(sequence_number++);
 | 
| +                             red_payload_type, ulpfec_payload_type);
 | 
| +    red_packet->SetSeqNum(seq_num++);
 | 
|      red_packet->ClearMarkerBit();
 | 
| -    red_packet->AssignPayload(packet_to_send->data, packet_to_send->length);
 | 
| -
 | 
| -    fec_packets.push_back(red_packet);
 | 
| +    red_packet->AssignPayload(fec_packet->data, fec_packet->length);
 | 
|  
 | 
| -    fec_packets_.pop_front();
 | 
| +    red_packets.push_back(std::move(red_packet));
 | 
|    }
 | 
| -  DeletePackets();
 | 
| -  num_frames_ = 0;
 | 
| -  return fec_packets;
 | 
| +
 | 
| +  // Reset state.
 | 
| +  DeleteMediaPackets();
 | 
| +  generated_fec_packets_.clear();
 | 
| +  num_protected_frames_ = 0;
 | 
| +
 | 
| +  return red_packets;
 | 
|  }
 | 
|  
 | 
|  int ProducerFec::Overhead() const {
 | 
|    // Overhead is defined as relative to the number of media packets, and not
 | 
| -  // relative to total number of packets. This definition is inhereted from the
 | 
| +  // relative to total number of packets. This definition is inherited from the
 | 
|    // protection factor produced by video_coding module and how the FEC
 | 
|    // generation is implemented.
 | 
| -  assert(!media_packets_fec_.empty());
 | 
| -  int num_fec_packets = fec_->GetNumberOfFecPackets(media_packets_fec_.size(),
 | 
| -                                                    params_.fec_rate);
 | 
| +  RTC_DCHECK(!media_packets_.empty());
 | 
| +  int num_fec_packets =
 | 
| +      fec_->GetNumberOfFecPackets(media_packets_.size(), params_.fec_rate);
 | 
|    // Return the overhead in Q8.
 | 
| -  return (num_fec_packets << 8) / media_packets_fec_.size();
 | 
| +  return (num_fec_packets << 8) / media_packets_.size();
 | 
|  }
 | 
|  
 | 
| -void ProducerFec::DeletePackets() {
 | 
| -  media_packets_fec_.clear();
 | 
| +void ProducerFec::DeleteMediaPackets() {
 | 
| +  media_packets_.clear();
 | 
|  }
 | 
|  
 | 
|  }  // namespace webrtc
 | 
| 
 |