| Index: webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
 | 
| diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
 | 
| index 916561ea876bbc40af46433dca401e7a5519f6b7..f80caeaf7ec2f485dc2cffd0161be3d8dd8afe80 100644
 | 
| --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
 | 
| +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
 | 
| @@ -52,6 +52,7 @@ RTPSenderVideo::RTPSenderVideo(Clock* clock, RTPSender* rtp_sender)
 | 
|        last_rotation_(kVideoRotation_0),
 | 
|        red_payload_type_(-1),
 | 
|        ulpfec_payload_type_(-1),
 | 
| +      flexfec_sender_(nullptr),  // TODO(brandtr): Wire up in future CL.
 | 
|        delta_fec_params_{0, 1, kFecMaskRandom},
 | 
|        key_fec_params_{0, 1, kFecMaskRandom},
 | 
|        fec_bitrate_(1000, RateStatistics::kBpsScale),
 | 
| @@ -111,10 +112,10 @@ void RTPSenderVideo::SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet,
 | 
|                         "seqnum", seq_num);
 | 
|  }
 | 
|  
 | 
| -void RTPSenderVideo::SendVideoPacketAsRed(
 | 
| +void RTPSenderVideo::SendVideoPacketAsRedMaybeWithUlpfec(
 | 
|      std::unique_ptr<RtpPacketToSend> media_packet,
 | 
|      StorageType media_packet_storage,
 | 
| -    bool protect) {
 | 
| +    bool protect_media_packet) {
 | 
|    uint32_t rtp_timestamp = media_packet->Timestamp();
 | 
|    uint16_t media_seq_num = media_packet->SequenceNumber();
 | 
|  
 | 
| @@ -128,21 +129,23 @@ void RTPSenderVideo::SendVideoPacketAsRed(
 | 
|      // Only protect while creating RED and FEC packets, not when sending.
 | 
|      rtc::CritScope cs(&crit_);
 | 
|      red_packet->SetPayloadType(red_payload_type_);
 | 
| -    if (protect) {
 | 
| -      ulpfec_generator_.AddRtpPacketAndGenerateFec(
 | 
| -          media_packet->data(), media_packet->payload_size(),
 | 
| -          media_packet->headers_size());
 | 
| -    }
 | 
| -    uint16_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets();
 | 
| -    if (num_fec_packets > 0) {
 | 
| -      uint16_t first_fec_sequence_number =
 | 
| -          rtp_sender_->AllocateSequenceNumber(num_fec_packets);
 | 
| -      fec_packets = ulpfec_generator_.GetUlpfecPacketsAsRed(
 | 
| -          red_payload_type_, ulpfec_payload_type_, first_fec_sequence_number,
 | 
| -          media_packet->headers_size());
 | 
| -      RTC_DCHECK_EQ(num_fec_packets, fec_packets.size());
 | 
| -      if (retransmission_settings_ & kRetransmitFECPackets)
 | 
| -        fec_storage = kAllowRetransmission;
 | 
| +    if (ulpfec_enabled()) {
 | 
| +      if (protect_media_packet) {
 | 
| +        ulpfec_generator_.AddRtpPacketAndGenerateFec(
 | 
| +            media_packet->data(), media_packet->payload_size(),
 | 
| +            media_packet->headers_size());
 | 
| +      }
 | 
| +      uint16_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets();
 | 
| +      if (num_fec_packets > 0) {
 | 
| +        uint16_t first_fec_sequence_number =
 | 
| +            rtp_sender_->AllocateSequenceNumber(num_fec_packets);
 | 
| +        fec_packets = ulpfec_generator_.GetUlpfecPacketsAsRed(
 | 
| +            red_payload_type_, ulpfec_payload_type_, first_fec_sequence_number,
 | 
| +            media_packet->headers_size());
 | 
| +        RTC_DCHECK_EQ(num_fec_packets, fec_packets.size());
 | 
| +        if (retransmission_settings_ & kRetransmitFECPackets)
 | 
| +          fec_storage = kAllowRetransmission;
 | 
| +      }
 | 
|      }
 | 
|    }
 | 
|    // Send |red_packet| instead of |packet| for allocated sequence number.
 | 
| @@ -170,10 +173,40 @@ void RTPSenderVideo::SendVideoPacketAsRed(
 | 
|        rtc::CritScope cs(&stats_crit_);
 | 
|        fec_bitrate_.Update(fec_packet->length(), clock_->TimeInMilliseconds());
 | 
|        TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
 | 
| -                           "Video::PacketFec", "timestamp", rtp_timestamp,
 | 
| +                           "Video::PacketUlpfec", "timestamp", rtp_timestamp,
 | 
|                             "seqnum", fec_sequence_number);
 | 
|      } else {
 | 
| -      LOG(LS_WARNING) << "Failed to send FEC packet " << fec_sequence_number;
 | 
| +      LOG(LS_WARNING) << "Failed to send ULPFEC packet " << fec_sequence_number;
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void RTPSenderVideo::SendVideoPacketWithFlexfec(
 | 
| +    std::unique_ptr<RtpPacketToSend> media_packet,
 | 
| +    StorageType media_packet_storage,
 | 
| +    bool protect_media_packet) {
 | 
| +  RTC_DCHECK(flexfec_sender_);
 | 
| +
 | 
| +  if (protect_media_packet)
 | 
| +    flexfec_sender_->AddRtpPacketAndGenerateFec(*media_packet);
 | 
| +
 | 
| +  SendVideoPacket(std::move(media_packet), media_packet_storage);
 | 
| +
 | 
| +  if (flexfec_sender_->FecAvailable()) {
 | 
| +    std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
 | 
| +        flexfec_sender_->GetFecPackets();
 | 
| +    for (auto& fec_packet : fec_packets) {
 | 
| +      uint32_t timestamp = fec_packet->Timestamp();
 | 
| +      uint16_t seq_num = fec_packet->SequenceNumber();
 | 
| +      if (rtp_sender_->SendToNetwork(std::move(fec_packet), kDontRetransmit,
 | 
| +                                     RtpPacketSender::kLowPriority)) {
 | 
| +        // TODO(brandtr): Wire up stats here.
 | 
| +        TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
 | 
| +                             "Video::PacketFlexfec", "timestamp", timestamp,
 | 
| +                             "seqnum", seq_num);
 | 
| +      } else {
 | 
| +        LOG(LS_WARNING) << "Failed to send FlexFEC packet " << seq_num;
 | 
| +      }
 | 
|      }
 | 
|    }
 | 
|  }
 | 
| @@ -198,7 +231,7 @@ void RTPSenderVideo::SetUlpfecConfig(int red_payload_type,
 | 
|    // ensure that RED and ULPFEC are only enabled together.
 | 
|    RTC_DCHECK(red_enabled() || !ulpfec_enabled());
 | 
|  
 | 
| -  // Reset FEC rates.
 | 
| +  // Reset FEC parameters.
 | 
|    delta_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom};
 | 
|    key_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom};
 | 
|  }
 | 
| @@ -211,29 +244,33 @@ void RTPSenderVideo::GetUlpfecConfig(int* red_payload_type,
 | 
|  }
 | 
|  
 | 
|  size_t RTPSenderVideo::FecPacketOverhead() const {
 | 
| +  if (flexfec_enabled())
 | 
| +    return flexfec_sender_->MaxPacketOverhead();
 | 
| +
 | 
|    rtc::CritScope cs(&crit_);
 | 
|    size_t overhead = 0;
 | 
|    if (red_enabled()) {
 | 
| -    // Overhead is FEC headers plus RED for FEC header plus anything in RTP
 | 
| -    // header beyond the 12 bytes base header (CSRC list, extensions...)
 | 
| +    // The RED overhead is due to a small header.
 | 
| +    overhead += kRedForFecHeaderLength;
 | 
| +  }
 | 
| +  if (ulpfec_enabled()) {
 | 
| +    // For ULPFEC, the overhead is the FEC headers plus RED for FEC header
 | 
| +    // (see above) plus anything in RTP header beyond the 12 bytes base header
 | 
| +    // (CSRC list, extensions...)
 | 
|      // This reason for the header extensions to be included here is that
 | 
|      // from an FEC viewpoint, they are part of the payload to be protected.
 | 
|      // (The base RTP header is already protected by the FEC header.)
 | 
| -    return ulpfec_generator_.MaxPacketOverhead() + kRedForFecHeaderLength +
 | 
| -           (rtp_sender_->RtpHeaderLength() - kRtpHeaderSize);
 | 
| +    overhead += ulpfec_generator_.MaxPacketOverhead() +
 | 
| +                (rtp_sender_->RtpHeaderLength() - kRtpHeaderSize);
 | 
|    }
 | 
| -  if (ulpfec_enabled())
 | 
| -    overhead += ulpfec_generator_.MaxPacketOverhead();
 | 
|    return overhead;
 | 
|  }
 | 
|  
 | 
|  void RTPSenderVideo::SetFecParameters(const FecProtectionParams& delta_params,
 | 
|                                        const FecProtectionParams& key_params) {
 | 
|    rtc::CritScope cs(&crit_);
 | 
| -  if (ulpfec_enabled()) {
 | 
| -    delta_fec_params_ = delta_params;
 | 
| -    key_fec_params_ = key_params;
 | 
| -  }
 | 
| +  delta_fec_params_ = delta_params;
 | 
| +  key_fec_params_ = key_params;
 | 
|  }
 | 
|  
 | 
|  bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type,
 | 
| @@ -290,11 +327,18 @@ bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type,
 | 
|    bool first_frame = first_frame_sent_();
 | 
|    {
 | 
|      rtc::CritScope cs(&crit_);
 | 
| +
 | 
| +    // Media packet storage.
 | 
| +    storage = packetizer->GetStorageType(retransmission_settings_);
 | 
| +
 | 
| +    // FEC settings.
 | 
|      const FecProtectionParams& fec_params =
 | 
|          frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_;
 | 
| -    ulpfec_generator_.SetFecParameters(fec_params);
 | 
| -    storage = packetizer->GetStorageType(retransmission_settings_);
 | 
| +    if (flexfec_enabled())
 | 
| +      flexfec_sender_->SetFecParameters(fec_params);
 | 
|      red_enabled = this->red_enabled();
 | 
| +    if (ulpfec_enabled())
 | 
| +      ulpfec_generator_.SetFecParameters(fec_params);
 | 
|    }
 | 
|  
 | 
|    // TODO(changbin): we currently don't support to configure the codec to
 | 
| @@ -321,9 +365,15 @@ bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type,
 | 
|      if (!rtp_sender_->AssignSequenceNumber(packet.get()))
 | 
|        return false;
 | 
|  
 | 
| -    if (red_enabled) {
 | 
| -      SendVideoPacketAsRed(std::move(packet), storage,
 | 
| -                           packetizer->GetProtectionType() == kProtectedPacket);
 | 
| +    const bool protect_packet =
 | 
| +        (packetizer->GetProtectionType() == kProtectedPacket);
 | 
| +    if (flexfec_enabled()) {
 | 
| +      // TODO(brandtr): Remove the FlexFEC code path when FlexfecSender
 | 
| +      // is wired up to PacedSender instead.
 | 
| +      SendVideoPacketWithFlexfec(std::move(packet), storage, protect_packet);
 | 
| +    } else if (red_enabled) {
 | 
| +      SendVideoPacketAsRedMaybeWithUlpfec(std::move(packet), storage,
 | 
| +                                          protect_packet);
 | 
|      } else {
 | 
|        SendVideoPacket(std::move(packet), storage);
 | 
|      }
 | 
| 
 |