Adding classes for handling multi-frame FEC.

The FEC behavior is unchanged with this commit, we will still be
limited to FEC over one frame for now.

BUG=
TEST=

Review URL: https://webrtc-codereview.appspot.com/450006

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1915 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/interface/module_common_types.h b/src/modules/interface/module_common_types.h
index 2e1beaa..d0bd356 100644
--- a/src/modules/interface/module_common_types.h
+++ b/src/modules/interface/module_common_types.h
@@ -297,6 +297,13 @@
     WebRtc_UWord16    JBabsMax;
 };
 
+// Struct containing forward error correction settings.
+struct FecProtectionParams {
+  int fec_rate;
+  bool use_uep_protection;
+  int max_fec_frames;
+};
+
 // class describing a complete, or parts of an encoded frame.
 class EncodedVideoData
 {
diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp.h b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
index 0293911..8d18dfd 100644
--- a/src/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -1049,32 +1049,9 @@
                                          WebRtc_UWord8& payloadTypeFEC) = 0;
 
 
-    /*
-    *   Set FEC code rate of key and delta frames
-    *   codeRate on a scale of 0 to 255 where 255 is 100% added packets, hence protect up to 50% packet loss
-    *
-    *   return -1 on failure else 0
-    */
-    virtual WebRtc_Word32 SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
-                                       const WebRtc_UWord8 deltaFrameCodeRate) = 0;
-
-
-    /*
-    *   Set FEC unequal protection (UEP) across packets,
-    *   for key and delta frames.
-    *
-    *   If keyUseUepProtection is true UEP is enabled for key frames.
-    *   If deltaUseUepProtection is true UEP is enabled for delta frames.
-    *
-    *   UEP skews the FEC protection towards being spent more on the
-    *   important packets, at the cost of less FEC protection for the
-    *   non-important packets.
-    *
-    *   return -1 on failure else 0
-    */
-    virtual WebRtc_Word32 SetFECUepProtection(const bool keyUseUepProtection,
-                                          const bool deltaUseUepProtection) = 0;
-
+    virtual WebRtc_Word32 SetFecParameters(
+        const FecProtectionParams* delta_params,
+        const FecProtectionParams* key_params) = 0;
 
     /*
     *   Set method for requestion a new key frame
diff --git a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index d3ab74f..e321279 100644
--- a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -280,10 +280,9 @@
       WebRtc_Word32(const bool enable, const WebRtc_UWord8 payloadTypeRED, const WebRtc_UWord8 payloadTypeFEC));
   MOCK_METHOD3(GenericFECStatus,
       WebRtc_Word32(bool& enable, WebRtc_UWord8& payloadTypeRED, WebRtc_UWord8& payloadTypeFEC));
-  MOCK_METHOD2(SetFECCodeRate,
-      WebRtc_Word32(const WebRtc_UWord8 keyFrameCodeRate, const WebRtc_UWord8 deltaFrameCodeRate));
-  MOCK_METHOD2(SetFECUepProtection,
-      WebRtc_Word32(const bool keyUseUepProtection, const bool deltaUseUepProtection));
+  MOCK_METHOD2(SetFecParameters,
+      WebRtc_Word32(const FecProtectionParams* delta_params,
+                    const FecProtectionParams* key_params));
   MOCK_METHOD1(SetKeyFrameRequestMethod,
       WebRtc_Word32(const KeyFrameRequestMethod method));
   MOCK_METHOD0(RequestKeyFrame,
diff --git a/src/modules/rtp_rtcp/source/fec_test_helper.cc b/src/modules/rtp_rtcp/source/fec_test_helper.cc
new file mode 100644
index 0000000..9818015
--- /dev/null
+++ b/src/modules/rtp_rtcp/source/fec_test_helper.cc
@@ -0,0 +1,99 @@
+/*
+ *  Copyright (c) 2012 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/fec_test_helper.h"
+
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+
+namespace webrtc {
+
+FrameGenerator::FrameGenerator()
+    : num_packets_(0),
+      seq_num_(0),
+      timestamp_(0) {}
+
+void FrameGenerator::NewFrame(int num_packets) {
+  num_packets_ = num_packets;
+  timestamp_ += 3000;
+}
+
+uint16_t FrameGenerator::NextSeqNum() {
+  return ++seq_num_;
+}
+
+RtpPacket* FrameGenerator::NextPacket(int offset, size_t length) {
+  RtpPacket* rtp_packet = new RtpPacket;
+  for (size_t i = 0; i < length; ++i)
+    rtp_packet->data[i + kRtpHeaderSize] = offset + i;
+  rtp_packet->length = length + kRtpHeaderSize;
+  memset(&rtp_packet->header, 0, sizeof(WebRtcRTPHeader));
+  rtp_packet->header.frameType = kVideoFrameDelta;
+  rtp_packet->header.header.headerLength = kRtpHeaderSize;
+  rtp_packet->header.header.markerBit = (num_packets_ == 1);
+  rtp_packet->header.header.sequenceNumber = seq_num_;
+  rtp_packet->header.header.timestamp = timestamp_;
+  rtp_packet->header.header.payloadType = kVp8PayloadType;
+  BuildRtpHeader(rtp_packet->data, rtp_packet->header.header);
+  ++seq_num_;
+  --num_packets_;
+  return rtp_packet;
+}
+
+// Creates a new RtpPacket with the RED header added to the packet.
+RtpPacket* FrameGenerator::BuildMediaRedPacket(const RtpPacket* packet) {
+  const int kHeaderLength = packet->header.header.headerLength;
+  RtpPacket* red_packet = new RtpPacket;
+  red_packet->header = packet->header;
+  red_packet->length = packet->length + 1;  // 1 byte RED header.
+  memset(red_packet->data, 0, red_packet->length);
+  // Copy RTP header.
+  memcpy(red_packet->data, packet->data, kHeaderLength);
+  SetRedHeader(red_packet, red_packet->data[1] & 0x7f, kHeaderLength);
+  memcpy(red_packet->data + kHeaderLength + 1, packet->data + kHeaderLength,
+         packet->length - kHeaderLength);
+  return red_packet;
+}
+
+// Creates a new RtpPacket with FEC payload and red header. Does this by
+// creating a new fake media RtpPacket, clears the marker bit and adds a RED
+// header. Finally replaces the payload with the content of |packet->data|.
+RtpPacket* FrameGenerator::BuildFecRedPacket(const Packet* packet) {
+  // Create a fake media packet to get a correct header. 1 byte RED header.
+  ++num_packets_;
+  RtpPacket* red_packet = NextPacket(0, packet->length + 1);
+  red_packet->data[1] &= ~0x80;  // Clear marker bit.
+  const int kHeaderLength = red_packet->header.header.headerLength;
+  SetRedHeader(red_packet, kFecPayloadType, kHeaderLength);
+  memcpy(red_packet->data + kHeaderLength + 1, packet->data,
+         packet->length);
+  red_packet->length = kHeaderLength + 1 + packet->length;
+  return red_packet;
+}
+
+void FrameGenerator::SetRedHeader(Packet* red_packet, uint8_t payload_type,
+                                  int header_length) const {
+  // Replace pltype.
+  red_packet->data[1] &= 0x80;  // Reset.
+  red_packet->data[1] += kRedPayloadType;  // Replace.
+
+  // Add RED header, f-bit always 0.
+  red_packet->data[header_length] = payload_type;
+}
+
+void FrameGenerator::BuildRtpHeader(uint8_t* data, RTPHeader header) {
+  data[0] = 0x80;  // Version 2.
+  data[1] = header.payloadType;
+  data[1] |= (header.markerBit ? kRtpMarkerBitMask : 0);
+  ModuleRTPUtility::AssignUWord16ToBuffer(data+2, header.sequenceNumber);
+  ModuleRTPUtility::AssignUWord32ToBuffer(data+4, header.timestamp);
+  ModuleRTPUtility::AssignUWord32ToBuffer(data+8, header.ssrc);
+}
+
+}  // namespace webrtc
diff --git a/src/modules/rtp_rtcp/source/fec_test_helper.h b/src/modules/rtp_rtcp/source/fec_test_helper.h
new file mode 100644
index 0000000..b84bafb
--- /dev/null
+++ b/src/modules/rtp_rtcp/source/fec_test_helper.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2012 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 WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
+
+#include "modules/interface/module_common_types.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+
+namespace webrtc {
+
+enum { kRtpHeaderSize = 12 };
+enum { kFecPayloadType = 96 };
+enum { kRedPayloadType = 97 };
+enum { kVp8PayloadType = 120 };
+
+typedef ForwardErrorCorrection::Packet Packet;
+
+struct RtpPacket : public Packet {
+  WebRtcRTPHeader header;
+};
+
+class FrameGenerator {
+ public:
+  FrameGenerator();
+
+  void NewFrame(int num_packets);
+
+  uint16_t NextSeqNum();
+
+  RtpPacket* NextPacket(int offset, size_t length);
+
+  // Creates a new RtpPacket with the RED header added to the packet.
+  RtpPacket* BuildMediaRedPacket(const RtpPacket* packet);
+
+  // Creates a new RtpPacket with FEC payload and red header. Does this by
+  // creating a new fake media RtpPacket, clears the marker bit and adds a RED
+  // header. Finally replaces the payload with the content of |packet->data|.
+  RtpPacket* BuildFecRedPacket(const Packet* packet);
+
+  void SetRedHeader(Packet* red_packet, uint8_t payload_type,
+                    int header_length) const;
+
+ private:
+  void BuildRtpHeader(uint8_t* data, RTPHeader header);
+
+  int num_packets_;
+  uint16_t seq_num_;
+  uint32_t timestamp_;
+};
+}
+
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
diff --git a/src/modules/rtp_rtcp/source/producer_fec.cc b/src/modules/rtp_rtcp/source/producer_fec.cc
new file mode 100644
index 0000000..e781436
--- /dev/null
+++ b/src/modules/rtp_rtcp/source/producer_fec.cc
@@ -0,0 +1,203 @@
+/*
+ *  Copyright (c) 2012 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/producer_fec.h"
+
+#include <stdio.h>
+
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+
+namespace webrtc {
+
+// Minimum RTP header size in bytes.
+enum { kRtpHeaderSize = 12 };
+enum { kREDForFECHeaderLength = 1 };
+enum { kMaxOverhead = 60 };  // Q8.
+
+struct RtpPacket {
+  WebRtc_UWord16 rtpHeaderLength;
+  ForwardErrorCorrection::Packet* pkt;
+};
+
+RedPacket::RedPacket(int length)
+    : data_(new uint8_t[length]),
+      length_(length),
+      header_length_(0) {
+}
+
+RedPacket::~RedPacket() {
+  delete [] data_;
+}
+
+void RedPacket::CreateHeader(const uint8_t* rtp_header, int header_length,
+                             int red_pl_type, int pl_type) {
+  assert(header_length + kREDForFECHeaderLength <= length_);
+  memcpy(data_, rtp_header, header_length);
+  // Replace payload type.
+  data_[1] &= 0x80;
+  data_[1] += red_pl_type;
+  // Add RED header
+  // f-bit always 0
+  data_[header_length] = pl_type;
+  header_length_ = header_length + kREDForFECHeaderLength;
+}
+
+void RedPacket::SetSeqNum(int seq_num) {
+  assert(seq_num >= 0 && seq_num < (1<<16));
+  ModuleRTPUtility::AssignUWord16ToBuffer(&data_[2], seq_num);
+}
+
+void RedPacket::AssignPayload(const uint8_t* payload, int length) {
+  assert(header_length_ + length <= length_);
+  memcpy(data_ + header_length_, payload, length);
+}
+
+void RedPacket::ClearMarkerBit() {
+  data_[1] &= 0x7F;
+}
+
+uint8_t* RedPacket::data() const {
+  return data_;
+}
+
+int RedPacket::length() const {
+  return length_;
+}
+
+ProducerFec::ProducerFec(ForwardErrorCorrection* fec)
+    : fec_(fec),
+      media_packets_fec_(),
+      fec_packets_(),
+      num_frames_(0),
+      incomplete_frame_(false),
+      num_first_partition_(0),
+      params_() {
+  memset(&params_, 0, sizeof(params_));
+}
+
+ProducerFec::~ProducerFec() {
+  DeletePackets();
+}
+
+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 >
+      static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) {
+      num_first_partition =
+          ForwardErrorCorrection::kMaxMediaPackets;
+  }
+  params_ = *params;
+  num_first_partition_ = num_first_partition;
+}
+
+RedPacket* ProducerFec::BuildRedPacket(const uint8_t* data_buffer,
+                                       int payload_length,
+                                       int 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,
+                                            int payload_length,
+                                            int rtp_header_length) {
+  assert(fec_packets_.empty());
+  incomplete_frame_ = true;
+  const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
+  ForwardErrorCorrection::Packet* packet = new ForwardErrorCorrection::Packet;
+  packet->length = payload_length + rtp_header_length;
+  memcpy(packet->data, data_buffer, packet->length);
+  // FEC can only protect up to kMaxMediaPackets packets
+  if (media_packets_fec_.size() < ForwardErrorCorrection::kMaxMediaPackets) {
+    media_packets_fec_.push_back(packet);
+  }
+  if (marker_bit) {
+    ++num_frames_;
+    incomplete_frame_ = false;
+  }
+  if (!incomplete_frame_ &&
+      (num_frames_ == params_.max_fec_frames ||
+          (Overhead() - params_.fec_rate) < kMaxOverhead)) {
+    assert(num_first_partition_ <=
+           static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
+    int ret = fec_->GenerateFEC(media_packets_fec_,
+                                params_.fec_rate,
+                                num_first_partition_,
+                                params_.use_uep_protection,
+                                &fec_packets_);
+    if (fec_packets_.empty()) {
+      num_frames_ = 0;
+      DeletePackets();
+    }
+    return ret;
+  }
+  return 0;
+}
+
+bool ProducerFec::FecAvailable() const {
+  return (fec_packets_.size() > 0);
+}
+
+RedPacket* ProducerFec::GetFecPacket(int red_pl_type, int fec_pl_type,
+                                     uint16_t seq_num) {
+  if (fec_packets_.empty())
+    return NULL;
+  // 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();
+  RedPacket* return_packet = new RedPacket(packet_to_send->length +
+                                           kREDForFECHeaderLength +
+                                           kRtpHeaderSize);
+  return_packet->CreateHeader(last_media_packet->data,
+                              kRtpHeaderSize,
+                              red_pl_type,
+                              fec_pl_type);
+  return_packet->SetSeqNum(seq_num);
+  return_packet->ClearMarkerBit();
+  return_packet->AssignPayload(packet_to_send->data, packet_to_send->length);
+  fec_packets_.pop_front();
+  if (fec_packets_.empty()) {
+    // Done with all the FEC packets. Reset for next run.
+    DeletePackets();
+    num_frames_ = 0;
+  }
+  return return_packet;
+}
+
+int ProducerFec::Overhead() const {
+  int num_fec_packets = params_.fec_rate * media_packets_fec_.size();
+  // Ceil.
+  int rounding = (num_fec_packets % (1 << 8) > 0) ? (1 << 8) : 0;
+  num_fec_packets = (num_fec_packets + rounding) >> 8;
+  // Return the overhead in Q8.
+  return (num_fec_packets << 8) /
+      (media_packets_fec_.size() + num_fec_packets);
+}
+
+void ProducerFec::DeletePackets() {
+  while (!media_packets_fec_.empty()) {
+    delete media_packets_fec_.front();
+    media_packets_fec_.pop_front();
+  }
+  assert(media_packets_fec_.empty());
+}
+
+}  // namespace webrtc
diff --git a/src/modules/rtp_rtcp/source/producer_fec.h b/src/modules/rtp_rtcp/source/producer_fec.h
new file mode 100644
index 0000000..4c0b951
--- /dev/null
+++ b/src/modules/rtp_rtcp/source/producer_fec.h
@@ -0,0 +1,76 @@
+/*
+ *  Copyright (c) 2012 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 WEBRTC_MODULES_RTP_RTCP_SOURCE_PRODUCER_FEC_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_PRODUCER_FEC_H_
+
+#include <list>
+
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+
+namespace webrtc {
+
+struct RtpPacket;
+
+class RedPacket {
+ public:
+  explicit RedPacket(int length);
+  ~RedPacket();
+  void CreateHeader(const uint8_t* rtp_header, int header_length,
+                    int red_pl_type, int pl_type);
+  void SetSeqNum(int seq_num);
+  void AssignPayload(const uint8_t* payload, int length);
+  void ClearMarkerBit();
+  uint8_t* data() const;
+  int length() const;
+
+ private:
+  uint8_t* data_;
+  int length_;
+  int header_length_;
+};
+
+class ProducerFec {
+ public:
+  explicit ProducerFec(ForwardErrorCorrection* fec);
+  ~ProducerFec();
+
+  void SetFecParameters(const FecProtectionParams* params,
+                        int max_fec_frames);
+
+  RedPacket* BuildRedPacket(const uint8_t* data_buffer,
+                            int payload_length,
+                            int rtp_header_length,
+                            int red_pl_type);
+
+  int AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
+                                 int payload_length,
+                                 int rtp_header_length);
+
+  bool FecAvailable() const;
+
+  RedPacket* GetFecPacket(int red_pl_type, int fec_pl_type,
+                          uint16_t seq_num);
+
+ private:
+  void DeletePackets();
+  int Overhead() const;
+  ForwardErrorCorrection* fec_;
+  std::list<ForwardErrorCorrection::Packet*> media_packets_fec_;
+  std::list<ForwardErrorCorrection::Packet*> fec_packets_;
+  int num_frames_;
+  bool incomplete_frame_;
+  int num_first_partition_;
+  FecProtectionParams params_;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_PRODUCER_FEC_H_
diff --git a/src/modules/rtp_rtcp/source/producer_fec_unittest.cc b/src/modules/rtp_rtcp/source/producer_fec_unittest.cc
new file mode 100644
index 0000000..fcd8c66
--- /dev/null
+++ b/src/modules/rtp_rtcp/source/producer_fec_unittest.cc
@@ -0,0 +1,143 @@
+/*
+ *  Copyright (c) 2012 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 <list>
+
+#include "gtest/gtest.h"
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/producer_fec.h"
+
+namespace webrtc {
+
+void VerifyHeader(uint16_t seq_num,
+                  uint32_t timestamp,
+                  int red_pltype,
+                  int fec_pltype,
+                  RedPacket* packet,
+                  bool marker_bit) {
+  EXPECT_GT(packet->length(), static_cast<int>(kRtpHeaderSize));
+  EXPECT_TRUE(packet->data() != NULL);
+  uint8_t* data = packet->data();
+  // Marker bit not set.
+  EXPECT_EQ(marker_bit ? 0x80 : 0, data[1] & 0x80);
+  EXPECT_EQ(red_pltype, data[1] & 0x7F);
+  EXPECT_EQ(seq_num, (data[2] << 8) + data[3]);
+  uint32_t parsed_timestamp = (data[4] << 24) + (data[5] << 16) +
+      (data[6] << 8) + data[7];
+  EXPECT_EQ(timestamp, parsed_timestamp);
+  EXPECT_EQ(fec_pltype, data[kRtpHeaderSize]);
+}
+
+class ProducerFecTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    fec_ = new ForwardErrorCorrection(0);
+    producer_ = new ProducerFec(fec_);
+    generator_ = new FrameGenerator;
+  }
+
+  virtual void TearDown() {
+    delete producer_;
+    delete fec_;
+    delete generator_;
+  }
+  ForwardErrorCorrection* fec_;
+  ProducerFec* producer_;
+  FrameGenerator* generator_;
+};
+
+TEST_F(ProducerFecTest, OneFrameFec) {
+  const int kNumPackets = 3;
+  FecProtectionParams params = {5, false, 3};
+  std::list<RtpPacket*> rtp_packets;
+  generator_->NewFrame(kNumPackets);
+  producer_->SetFecParameters(&params, 0);  // Expecting one FEC packet.
+  uint32_t last_timestamp = 0;
+  for (int i = 0; i < kNumPackets; ++i) {
+    RtpPacket* rtp_packet = generator_->NextPacket(i, 10);
+    rtp_packets.push_back(rtp_packet);
+    EXPECT_EQ(0, producer_->AddRtpPacketAndGenerateFec(rtp_packet->data,
+                                                       rtp_packet->length,
+                                                       kRtpHeaderSize));
+    last_timestamp = rtp_packet->header.header.timestamp;
+  }
+  EXPECT_TRUE(producer_->FecAvailable());
+  uint16_t seq_num = generator_->NextSeqNum();
+  RedPacket* packet = producer_->GetFecPacket(kRedPayloadType,
+                                              kFecPayloadType,
+                                              seq_num);
+  EXPECT_FALSE(producer_->FecAvailable());
+  EXPECT_TRUE(packet != NULL);
+  VerifyHeader(seq_num, last_timestamp,
+               kRedPayloadType, kFecPayloadType, packet, false);
+  while (!rtp_packets.empty()) {
+    delete rtp_packets.front();
+    rtp_packets.pop_front();
+  }
+  delete packet;
+}
+
+TEST_F(ProducerFecTest, TwoFrameFec) {
+  const int kNumPackets = 2;
+  const int kNumFrames = 2;
+  FecProtectionParams params = {5, 0, 3};
+  std::list<RtpPacket*> rtp_packets;
+  producer_->SetFecParameters(&params, 0);  // Expecting one FEC packet.
+  uint32_t last_timestamp = 0;
+  for (int i = 0; i < kNumFrames; ++i) {
+    generator_->NewFrame(kNumPackets);
+    for (int j = 0; j < kNumPackets; ++j) {
+      RtpPacket* rtp_packet = generator_->NextPacket(i * kNumPackets + j, 10);
+      rtp_packets.push_back(rtp_packet);
+      EXPECT_EQ(0, producer_->AddRtpPacketAndGenerateFec(rtp_packet->data,
+                                           rtp_packet->length,
+                                           kRtpHeaderSize));
+      last_timestamp = rtp_packet->header.header.timestamp;
+    }
+  }
+  EXPECT_TRUE(producer_->FecAvailable());
+  uint16_t seq_num = generator_->NextSeqNum();
+  RedPacket* packet = producer_->GetFecPacket(kRedPayloadType,
+                                              kFecPayloadType,
+                                              seq_num);
+  EXPECT_FALSE(producer_->FecAvailable());
+  EXPECT_TRUE(packet != NULL);
+  VerifyHeader(seq_num, last_timestamp,
+               kRedPayloadType, kFecPayloadType, packet, false);
+  while (!rtp_packets.empty()) {
+    delete rtp_packets.front();
+    rtp_packets.pop_front();
+  }
+  delete packet;
+}
+
+TEST_F(ProducerFecTest, BuildRedPacket) {
+  generator_->NewFrame(1);
+  RtpPacket* packet = generator_->NextPacket(0, 10);
+  RedPacket* red_packet = producer_->BuildRedPacket(packet->data,
+                                                    packet->length -
+                                                    kRtpHeaderSize,
+                                                    kRtpHeaderSize,
+                                                    kRedPayloadType);
+  EXPECT_EQ(packet->length + 1, red_packet->length());
+  VerifyHeader(packet->header.header.sequenceNumber,
+               packet->header.header.timestamp,
+               kRedPayloadType,
+               packet->header.header.payloadType,
+               red_packet,
+               true);  // Marker bit set.
+  for (int i = 0; i < 10; ++i)
+    EXPECT_EQ(i, red_packet->data()[kRtpHeaderSize + 1 + i]);
+  delete red_packet;
+  delete packet;
+}
+
+}  // namespace webrtc
diff --git a/src/modules/rtp_rtcp/source/receiver_fec_unittest.cc b/src/modules/rtp_rtcp/source/receiver_fec_unittest.cc
index 669018e..c57d54f 100644
--- a/src/modules/rtp_rtcp/source/receiver_fec_unittest.cc
+++ b/src/modules/rtp_rtcp/source/receiver_fec_unittest.cc
@@ -13,6 +13,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
 #include "modules/rtp_rtcp/source/forward_error_correction.h"
 #include "modules/rtp_rtcp/source/mock/mock_rtp_receiver_video.h"
 #include "modules/rtp_rtcp/source/receiver_fec.h"
@@ -24,100 +25,6 @@
 
 namespace webrtc {
 
-typedef ForwardErrorCorrection::Packet Packet;
-
-enum { kRtpHeaderSize = 12 };
-enum { kFecPayloadType = 96 };
-enum { kRedPayloadType = 97 };
-enum { kVp8PayloadType = 120 };
-
-struct RtpPacket : public Packet {
-  WebRtcRTPHeader header;
-};
-
-class FrameGenerator {
- public:
-  FrameGenerator() : num_packets_(0), seq_num_(0), timestamp_(0) {}
-
-  void NewFrame(int num_packets) {
-    num_packets_ = num_packets;
-    timestamp_ += 3000;
-  }
-
-  RtpPacket* NextPacket(int offset, size_t length) {
-    RtpPacket* rtp_packet = new RtpPacket;
-    for (size_t i = 0; i < length; ++i)
-      rtp_packet->data[i] = offset + i;
-    rtp_packet->length = length;
-    memset(&rtp_packet->header, 0, sizeof(WebRtcRTPHeader));
-    rtp_packet->header.frameType = kVideoFrameDelta;
-    rtp_packet->header.header.headerLength = kRtpHeaderSize;
-    rtp_packet->header.header.markerBit = (num_packets_ == 1);
-    rtp_packet->header.header.sequenceNumber = seq_num_;
-    rtp_packet->header.header.timestamp = timestamp_;
-    rtp_packet->header.header.payloadType = kVp8PayloadType;
-    BuildRtpHeader(rtp_packet->data, rtp_packet->header.header);
-    ++seq_num_;
-    --num_packets_;
-    return rtp_packet;
-  }
-
-  // Creates a new RtpPacket with the RED header added to the packet.
-  RtpPacket* BuildMediaRedPacket(const RtpPacket* packet) {
-    const int kHeaderLength = packet->header.header.headerLength;
-    RtpPacket* red_packet = new RtpPacket;
-    red_packet->header = packet->header;
-    red_packet->length = packet->length + 1;  // 1 byte RED header.
-    memset(red_packet->data, 0, red_packet->length);
-    // Copy RTP header.
-    memcpy(red_packet->data, packet->data, kHeaderLength);
-    SetRedHeader(red_packet, red_packet->data[1] & 0x7f, kHeaderLength);
-    memcpy(red_packet->data + kHeaderLength + 1, packet->data + kHeaderLength,
-           packet->length - kHeaderLength);
-    return red_packet;
-  }
-
-  // Creates a new RtpPacket with FEC payload and red header. Does this by
-  // creating a new fake media RtpPacket, clears the marker bit and adds a RED
-  // header. Finally replaces the payload with the content of |packet->data|.
-  RtpPacket* BuildFecRedPacket(const Packet* packet) {
-    // Create a fake media packet to get a correct header. 1 byte RED header.
-    ++num_packets_;
-    RtpPacket* red_packet = NextPacket(0, packet->length + 1);
-    red_packet->data[1] &= ~0x80;  // Clear marker bit.
-    const int kHeaderLength = red_packet->header.header.headerLength;
-    SetRedHeader(red_packet, kFecPayloadType, kHeaderLength);
-    memcpy(red_packet->data + kHeaderLength + 1, packet->data,
-           packet->length);
-    red_packet->length = kHeaderLength + 1 + packet->length;
-    return red_packet;
-  }
-
-  void SetRedHeader(Packet* red_packet, uint8_t payload_type,
-                    int header_length) const {
-    // Replace pltype.
-    red_packet->data[1] &= 0x80;  // Reset.
-    red_packet->data[1] += kRedPayloadType;  // Replace.
-
-    // Add RED header, f-bit always 0.
-    red_packet->data[header_length] = payload_type;
-  }
-
- private:
-  void BuildRtpHeader(uint8_t* data, RTPHeader header) {
-    data[0] = 0x80;  // Version 2.
-    data[1] = header.payloadType;
-    data[1] |= (header.markerBit ? kRtpMarkerBitMask : 0);
-    ModuleRTPUtility::AssignUWord16ToBuffer(data+2, header.sequenceNumber);
-    ModuleRTPUtility::AssignUWord32ToBuffer(data+4, header.timestamp);
-    ModuleRTPUtility::AssignUWord32ToBuffer(data+8, header.ssrc);
-  }
-
-  int num_packets_;
-  uint16_t seq_num_;
-  uint32_t timestamp_;
-};
-
 class ReceiverFecTest : public ::testing::Test {
  protected:
   virtual void SetUp() {
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp.gypi b/src/modules/rtp_rtcp/source/rtp_rtcp.gypi
index 48fc05f..0867d7a 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp.gypi
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp.gypi
@@ -71,6 +71,8 @@
         'forward_error_correction_internal.h',
         'overuse_detector.cc',
         'overuse_detector.h',
+        'producer_fec.cc',
+        'producer_fec.h',
         'remote_rate_control.cc',
         'remote_rate_control.h',
         'rtp_packet_history.cc',
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 6087cc3..81683f6 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -2196,16 +2196,9 @@
   return retVal;
 }
 
-WebRtc_Word32 ModuleRtpRtcpImpl::SetFECCodeRate(
-  const WebRtc_UWord8 keyFrameCodeRate,
-  const WebRtc_UWord8 deltaFrameCodeRate) {
-  WEBRTC_TRACE(kTraceModuleCall,
-               kTraceRtpRtcp,
-               _id,
-               "SetFECCodeRate(%u, %u)",
-               keyFrameCodeRate,
-               deltaFrameCodeRate);
-
+WebRtc_Word32 ModuleRtpRtcpImpl::SetFecParameters(
+    const FecProtectionParams* delta_params,
+    const FecProtectionParams* key_params) {
   const bool defaultInstance(_childModules.empty() ? false : true);
   if (defaultInstance)  {
     // for default we need to update all child modules too
@@ -2215,42 +2208,13 @@
     while (it != _childModules.end()) {
       RtpRtcp* module = *it;
       if (module) {
-        module->SetFECCodeRate(keyFrameCodeRate, deltaFrameCodeRate);
+        module->SetFecParameters(delta_params, key_params);
       }
       it++;
     }
     return 0;
   }
-  return _rtpSender.SetFECCodeRate(keyFrameCodeRate, deltaFrameCodeRate);
-}
-
-WebRtc_Word32 ModuleRtpRtcpImpl::SetFECUepProtection(
-  const bool keyUseUepProtection,
-  const bool deltaUseUepProtection) {
-  WEBRTC_TRACE(kTraceModuleCall,
-               kTraceRtpRtcp, _id,
-               "SetFECUepProtection(%d, %d)",
-               keyUseUepProtection,
-               deltaUseUepProtection);
-
-  const bool defaultInstance(_childModules.empty() ? false : true);
-  if (defaultInstance)  {
-    // for default we need to update all child modules too
-    CriticalSectionScoped lock(_criticalSectionModulePtrs);
-
-    std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin();
-    while (it != _childModules.end()) {
-      RtpRtcp* module = *it;
-      if (module) {
-        module->SetFECUepProtection(keyUseUepProtection,
-                                    deltaUseUepProtection);
-      }
-      it++;
-    }
-    return 0;
-  }
-  return _rtpSender.SetFECUepProtection(keyUseUepProtection,
-                                        deltaUseUepProtection);
+  return _rtpSender.SetFecParameters(delta_params, key_params);
 }
 
 void ModuleRtpRtcpImpl::SetRemoteSSRC(const WebRtc_UWord32 SSRC) {
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 19858d5..8358f4c 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -477,12 +477,9 @@
                                          WebRtc_UWord8& payloadTypeRED,
                                          WebRtc_UWord8& payloadTypeFEC);
 
-
-    virtual WebRtc_Word32 SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
-                                         const WebRtc_UWord8 deltaFrameCodeRate);
-
-    virtual WebRtc_Word32 SetFECUepProtection(const bool keyUseUepProtection,
-                                              const bool deltaUseUepProtection);
+    virtual WebRtc_Word32 SetFecParameters(
+        const FecProtectionParams* delta_params,
+        const FecProtectionParams* key_params);
 
     virtual WebRtc_Word32 LastReceivedNTP(WebRtc_UWord32& NTPsecs,
                                           WebRtc_UWord32& NTPfrac,
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi b/src/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi
index ea705a8..1c66efc 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi
@@ -22,6 +22,9 @@
         '../../../',
       ],
       'sources': [
+        'fec_test_helper.cc',
+        'fec_test_helper.h',
+        'producer_fec_unittest.cc',
         'receiver_fec_unittest.cc',
         'rtp_fec_unittest.cc',
         'rtp_format_vp8_unittest.cc',
diff --git a/src/modules/rtp_rtcp/source/rtp_sender.cc b/src/modules/rtp_rtcp/source/rtp_sender.cc
index 7b0755a..ed87df9 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/src/modules/rtp_rtcp/source/rtp_sender.cc
@@ -1742,27 +1742,12 @@
     return _video->GenericFECStatus(enable, payloadTypeRED, payloadTypeFEC);
 }
 
-WebRtc_Word32
-RTPSender::SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
-                          const WebRtc_UWord8 deltaFrameCodeRate)
-{
-    if(_audioConfigured)
-    {
-        return -1;
-    }
-    return _video->SetFECCodeRate(keyFrameCodeRate, deltaFrameCodeRate);
-}
-
-WebRtc_Word32
-RTPSender::SetFECUepProtection(const bool keyUseUepProtection,
-                               const bool deltaUseUepProtection)
-
-{
-    if(_audioConfigured)
-    {
-        return -1;
-    }
-    return _video->SetFECUepProtection(keyUseUepProtection,
-                                       deltaUseUepProtection);
+WebRtc_Word32 RTPSender::SetFecParameters(
+    const FecProtectionParams* delta_params,
+    const FecProtectionParams* key_params) {
+  if (_audioConfigured) {
+    return -1;
+  }
+  return _video->SetFecParameters(delta_params, key_params);
 }
 } // namespace webrtc
diff --git a/src/modules/rtp_rtcp/source/rtp_sender.h b/src/modules/rtp_rtcp/source/rtp_sender.h
index 1a2cb826..9f81a94 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender.h
+++ b/src/modules/rtp_rtcp/source/rtp_sender.h
@@ -299,11 +299,9 @@
                                  WebRtc_UWord8& payloadTypeRED,
                                  WebRtc_UWord8& payloadTypeFEC) const;
 
-    WebRtc_Word32 SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
-                                 const WebRtc_UWord8 deltaFrameCodeRate);
-
-    WebRtc_Word32 SetFECUepProtection(const bool keyUseUepProtection,
-                                      const bool deltaUseUepProtection);
+    WebRtc_Word32 SetFecParameters(
+        const FecProtectionParams* delta_params,
+        const FecProtectionParams* key_params);
 
 protected:
     WebRtc_Word32 CheckPayloadType(const WebRtc_Word8 payloadType,
diff --git a/src/modules/rtp_rtcp/source/rtp_sender_video.cc b/src/modules/rtp_rtcp/source/rtp_sender_video.cc
index 7a15208..2d30641 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/src/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -19,11 +19,17 @@
 #include <cassert>  // assert
 #include <cstdlib>  // srand
 
+#include "producer_fec.h"
 #include "rtp_format_vp8.h"
 
 namespace webrtc {
 enum { REDForFECHeaderLength = 1 };
 
+struct RtpPacket {
+  WebRtc_UWord16 rtpHeaderLength;
+  ForwardErrorCorrection::Packet* pkt;
+};
+
 RTPSenderVideo::RTPSenderVideo(const WebRtc_Word32 id,
                                RtpRtcpClock* clock,
                                RTPSenderInterface* rtpSender) :
@@ -41,15 +47,15 @@
     _fecEnabled(false),
     _payloadTypeRED(-1),
     _payloadTypeFEC(-1),
-    _codeRateKey(0),
-    _codeRateDelta(0),
-    _useUepProtectionKey(false),
-    _useUepProtectionDelta(false),
-    _fecProtectionFactor(0),
-    _fecUseUepProtection(false),
     _numberFirstPartition(0),
+    delta_fec_params_(),
+    key_fec_params_(),
+    producer_fec_(&_fec),
     _fecOverheadRate(clock),
     _videoBitrate(clock) {
+  memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
+  memset(&key_fec_params_, 0, sizeof(key_fec_params_));
+  delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
 }
 
 RTPSenderVideo::~RTPSenderVideo()
@@ -70,13 +76,10 @@
     _fecEnabled = false;
     _payloadTypeRED = -1;
     _payloadTypeFEC = -1;
-    _codeRateKey = 0;
-    _codeRateDelta = 0;
-    _useUepProtectionKey = false;
-    _useUepProtectionDelta = false;
-    _fecProtectionFactor = 0;
-    _fecUseUepProtection = false;
     _numberFirstPartition = 0;
+    memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
+    memset(&key_fec_params_, 0, sizeof(key_fec_params_));
+    delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
     _fecOverheadRate.Init();
     return 0;
 }
@@ -124,199 +127,77 @@
   return 0;
 }
 
-struct RtpPacket
-{
-    WebRtc_UWord16 rtpHeaderLength;
-    ForwardErrorCorrection::Packet* pkt;
-};
-
 WebRtc_Word32
-RTPSenderVideo::SendVideoPacket(const FrameType frameType,
-                                const WebRtc_UWord8* dataBuffer,
-                                const WebRtc_UWord16 payloadLength,
-                                const WebRtc_UWord16 rtpHeaderLength,
-                                StorageType storage)
-{
-    if(_fecEnabled)
-    {
-        WebRtc_Word32 retVal = 0;
+RTPSenderVideo::SendVideoPacket(const WebRtc_UWord8* data_buffer,
+                                const WebRtc_UWord16 payload_length,
+                                const WebRtc_UWord16 rtp_header_length,
+                                StorageType storage) {
+  if(_fecEnabled) {
+    int ret = 0;
+    int fec_overhead_sent = 0;
+    int video_sent = 0;
 
-        const bool markerBit = (dataBuffer[1] & kRtpMarkerBitMask)?true:false;
-        RtpPacket* ptrGenericFEC = new RtpPacket;
-        ptrGenericFEC->pkt = new ForwardErrorCorrection::Packet;
-        ptrGenericFEC->pkt->length = payloadLength + rtpHeaderLength;
-        ptrGenericFEC->rtpHeaderLength = rtpHeaderLength;
-        memcpy(ptrGenericFEC->pkt->data, dataBuffer,
-               ptrGenericFEC->pkt->length);
+    RedPacket* red_packet = producer_fec_.BuildRedPacket(data_buffer,
+                                                         payload_length,
+                                                         rtp_header_length,
+                                                         _payloadTypeRED);
+    // Sending the media packet with RED header.
+    int packet_success = _rtpSender.SendToNetwork(
+        red_packet->data(),
+        red_packet->length() - rtp_header_length,
+        rtp_header_length,
+        storage);
 
-        // Add packet to FEC list
-        _rtpPacketListFec.push_back(ptrGenericFEC);
-        // FEC can only protect up to kMaxMediaPackets packets
-        if (_mediaPacketListFec.size() <
-            ForwardErrorCorrection::kMaxMediaPackets)
-        {
-            _mediaPacketListFec.push_back(ptrGenericFEC->pkt);
-        }
+    ret |= packet_success;
 
-        // Last packet in frame
-        if (markerBit)
-        {
-
-            // Retain the RTP header of the last media packet to construct FEC
-            // packet RTP headers.
-            ForwardErrorCorrection::Packet lastMediaRtpHeader;
-            memcpy(lastMediaRtpHeader.data,
-                   ptrGenericFEC->pkt->data,
-                   ptrGenericFEC->rtpHeaderLength);
-
-            lastMediaRtpHeader.length = ptrGenericFEC->rtpHeaderLength;
-            // Replace payload and clear marker bit.
-            lastMediaRtpHeader.data[1] = _payloadTypeRED;
-
-            // Number of first partition packets cannot exceed kMaxMediaPackets
-            if (_numberFirstPartition >
-                ForwardErrorCorrection::kMaxMediaPackets)
-            {
-                _numberFirstPartition =
-                    ForwardErrorCorrection::kMaxMediaPackets;
-            }
-
-            std::list<ForwardErrorCorrection::Packet*> fecPacketList;
-            retVal = _fec.GenerateFEC(_mediaPacketListFec,
-                                      _fecProtectionFactor,
-                                      _numberFirstPartition,
-                                      _fecUseUepProtection,
-                                      &fecPacketList);
-
-            int fecOverheadSent = 0;
-            int videoSent = 0;
-
-            while(!_rtpPacketListFec.empty())
-            {
-                WebRtc_UWord8 newDataBuffer[IP_PACKET_SIZE];
-                memset(newDataBuffer, 0, sizeof(newDataBuffer));
-
-                RtpPacket* packetToSend = _rtpPacketListFec.front();
-
-                // Copy RTP header
-                memcpy(newDataBuffer, packetToSend->pkt->data,
-                       packetToSend->rtpHeaderLength);
-
-                // Get codec pltype
-                WebRtc_UWord8 payloadType = newDataBuffer[1] & 0x7f;
-
-                // Replace pltype
-                newDataBuffer[1] &= 0x80;            // reset
-                newDataBuffer[1] += _payloadTypeRED; // replace
-
-                // Add RED header
-                // f-bit always 0
-                newDataBuffer[packetToSend->rtpHeaderLength] = payloadType;
-
-                // Copy payload data
-                memcpy(newDataBuffer + packetToSend->rtpHeaderLength +
-                           REDForFECHeaderLength,
-                       packetToSend->pkt->data + packetToSend->rtpHeaderLength,
-                       packetToSend->pkt->length -
-                           packetToSend->rtpHeaderLength);
-
-                _rtpPacketListFec.pop_front();
-                // Check if _mediaPacketListFec is non-empty.
-                // This list may be smaller than rtpPacketList, if the frame
-                // has more than kMaxMediaPackets.
-                if (!_mediaPacketListFec.empty()) {
-                  _mediaPacketListFec.pop_front();
-                }
-
-                // Send normal packet with RED header
-                int packetSuccess = _rtpSender.SendToNetwork(
-                    newDataBuffer,
-                    packetToSend->pkt->length - packetToSend->rtpHeaderLength +
-                    REDForFECHeaderLength,
-                    packetToSend->rtpHeaderLength,
-                    storage);
-
-                retVal |= packetSuccess;
-
-                if (packetSuccess == 0)
-                {
-                    videoSent += packetToSend->pkt->length +
-                        REDForFECHeaderLength;
-                }
-
-                delete packetToSend->pkt;
-                delete packetToSend;
-                packetToSend = NULL;
-            }
-            assert(_mediaPacketListFec.empty());
-            assert(_rtpPacketListFec.empty());
-
-            while(!fecPacketList.empty())
-            {
-                WebRtc_UWord8 newDataBuffer[IP_PACKET_SIZE];
-
-                // Build FEC packets
-                ForwardErrorCorrection::Packet* packetToSend = fecPacketList.front();
-
-                // The returned FEC packets have no RTP headers.
-                // Copy the last media packet's modified RTP header.
-                memcpy(newDataBuffer, lastMediaRtpHeader.data,
-                       lastMediaRtpHeader.length);
-
-                // Add sequence number
-                ModuleRTPUtility::AssignUWord16ToBuffer(
-                    &newDataBuffer[2], _rtpSender.IncrementSequenceNumber());
-
-                // Add RED header
-                // f-bit always 0
-                newDataBuffer[lastMediaRtpHeader.length] = _payloadTypeFEC;
-
-                // Copy payload data
-                memcpy(newDataBuffer + lastMediaRtpHeader.length +
-                           REDForFECHeaderLength,
-                       packetToSend->data,
-                       packetToSend->length);
-
-                fecPacketList.pop_front();
-
-                // Invalid FEC packet
-                assert(packetToSend->length != 0);
-
-                StorageType storage = kDontRetransmit;
-                if (_retransmissionSettings & kRetransmitFECPackets) {
-                  storage = kAllowRetransmission;
-                }
-
-                // No marker bit on FEC packets, last media packet have the
-                // marker send FEC packet with RED header
-                int packetSuccess = _rtpSender.SendToNetwork(
-                        newDataBuffer,
-                        packetToSend->length + REDForFECHeaderLength,
-                        lastMediaRtpHeader.length,
-                        storage);
-
-                retVal |= packetSuccess;
-
-                if (packetSuccess == 0)
-                {
-                    fecOverheadSent += packetToSend->length +
-                      REDForFECHeaderLength + lastMediaRtpHeader.length;
-                }
-            }
-            _videoBitrate.Update(videoSent);
-            _fecOverheadRate.Update(fecOverheadSent);
-        }
-        return retVal;
+    if (packet_success == 0) {
+      video_sent += red_packet->length();
     }
-    int retVal = _rtpSender.SendToNetwork(dataBuffer,
-                                          payloadLength,
-                                          rtpHeaderLength,
-                                          storage);
-    if (retVal == 0)
-    {
-        _videoBitrate.Update(payloadLength + rtpHeaderLength);
+    delete red_packet;
+    red_packet = NULL;
+
+    ret = producer_fec_.AddRtpPacketAndGenerateFec(data_buffer,
+                                                   payload_length,
+                                                   rtp_header_length);
+    if (ret != 0)
+      return ret;
+
+    while (producer_fec_.FecAvailable()) {
+      red_packet = producer_fec_.GetFecPacket(
+          _payloadTypeRED,
+          _payloadTypeFEC,
+          _rtpSender.IncrementSequenceNumber());
+      StorageType storage = kDontRetransmit;
+      if (_retransmissionSettings & kRetransmitFECPackets) {
+        storage = kAllowRetransmission;
+      }
+      // Sending FEC packet with RED header.
+      int packet_success = _rtpSender.SendToNetwork(
+          red_packet->data(),
+          red_packet->length() - rtp_header_length,
+          rtp_header_length,
+          storage);
+
+      ret |= packet_success;
+
+      if (packet_success == 0) {
+        fec_overhead_sent += red_packet->length();
+      }
+      delete red_packet;
+      red_packet = NULL;
     }
-    return retVal;
+    _videoBitrate.Update(video_sent);
+    _fecOverheadRate.Update(fec_overhead_sent);
+    return ret;
+  }
+  int ret = _rtpSender.SendToNetwork(data_buffer,
+                                     payload_length,
+                                     rtp_header_length,
+                                     storage);
+  if (ret == 0) {
+    _videoBitrate.Update(payload_length + rtp_header_length);
+  }
+  return ret;
 }
 
 WebRtc_Word32
@@ -345,10 +226,9 @@
     _fecEnabled = enable;
     _payloadTypeRED = payloadTypeRED;
     _payloadTypeFEC = payloadTypeFEC;
-    _codeRateKey = 0;
-    _codeRateDelta = 0;
-    _useUepProtectionKey = false;
-    _useUepProtectionDelta = false;
+    memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
+    memset(&key_fec_params_, 0, sizeof(key_fec_params_));
+    delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
     return 0;
 }
 
@@ -374,22 +254,14 @@
     return 0;
 }
 
-WebRtc_Word32
-RTPSenderVideo::SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
-                               const WebRtc_UWord8 deltaFrameCodeRate)
-{
-    _codeRateKey = keyFrameCodeRate;
-    _codeRateDelta = deltaFrameCodeRate;
-    return 0;
-}
-
-WebRtc_Word32
-RTPSenderVideo::SetFECUepProtection(const bool keyUseUepProtection,
-                                    const bool deltaUseUepProtection)
-{
-    _useUepProtectionKey = keyUseUepProtection;
-    _useUepProtectionDelta = deltaUseUepProtection;
-    return 0;
+WebRtc_Word32 RTPSenderVideo::SetFecParameters(
+    const FecProtectionParams* delta_params,
+    const FecProtectionParams* key_params) {
+  assert(delta_params);
+  assert(key_params);
+  delta_fec_params_ = *delta_params;
+  key_fec_params_ = *key_params;
+  return 0;
 }
 
 WebRtc_Word32
@@ -408,19 +280,19 @@
         return -1;
     }
 
-    if (frameType == kVideoFrameKey)
-    {
-        _fecProtectionFactor = _codeRateKey;
-        _fecUseUepProtection = _useUepProtectionKey;
-    } else if (videoType == kRtpVp8Video && rtpTypeHdr->VP8.temporalIdx > 0)
-    {
+    if (frameType == kVideoFrameKey) {
+      producer_fec_.SetFecParameters(&key_fec_params_,
+                                     _numberFirstPartition);
+    } else if (videoType == kRtpVp8Video && rtpTypeHdr->VP8.temporalIdx > 0) {
         // In current version, we only apply FEC on the base layer.
-        _fecProtectionFactor = 0;
-        _fecUseUepProtection = false;
-    } else
-    {
-        _fecProtectionFactor = _codeRateDelta;
-        _fecUseUepProtection = _useUepProtectionDelta;
+      FecProtectionParams params;
+      params.fec_rate = 0;
+      params.max_fec_frames = 0;
+      params.use_uep_protection = false;
+      producer_fec_.SetFecParameters(&params, _numberFirstPartition);
+    } else {
+      producer_fec_.SetFecParameters(&delta_fec_params_,
+                                     _numberFirstPartition);
     }
 
     // Default setting for number of first partition packets:
@@ -498,8 +370,7 @@
                payloadBytesInPacket);
         bytesSent += payloadBytesInPacket;
 
-        if(-1 == SendVideoPacket(kVideoFrameKey,
-                                 dataBuffer,
+        if(-1 == SendVideoPacket(dataBuffer,
                                  payloadBytesInPacket,
                                  rtpHeaderLength,
                                  kAllowRetransmission))
@@ -583,7 +454,7 @@
         // Set marker bit true if this is the last packet in frame.
         _rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
             captureTimeStamp);
-        if (-1 == SendVideoPacket(frameType, dataBuffer, payloadBytesInPacket,
+        if (-1 == SendVideoPacket(dataBuffer, payloadBytesInPacket,
             rtpHeaderLength, storage))
         {
           WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
diff --git a/src/modules/rtp_rtcp/source/rtp_sender_video.h b/src/modules/rtp_rtcp/source/rtp_sender_video.h
index 1bf7142..0765e3f 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender_video.h
+++ b/src/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -24,6 +24,7 @@
 #include "forward_error_correction.h"
 #include "Bitrate.h"
 #include "rtp_sender.h"
+#include "producer_fec.h"
 
 namespace webrtc {
 class CriticalSectionWrapper;
@@ -79,11 +80,8 @@
                                  WebRtc_UWord8& payloadTypeRED,
                                  WebRtc_UWord8& payloadTypeFEC) const;
 
-    WebRtc_Word32 SetFECCodeRate(const WebRtc_UWord8 keyFrameCodeRate,
-                                 const WebRtc_UWord8 deltaFrameCodeRate);
-
-    WebRtc_Word32 SetFECUepProtection(const bool keyUseUepProtection,
-                                      const bool deltaUseUepProtection);
+    WebRtc_Word32 SetFecParameters(const FecProtectionParams* delta_params,
+                                   const FecProtectionParams* key_params);
 
     void ProcessBitrate();
 
@@ -94,8 +92,7 @@
     int SetSelectiveRetransmissions(uint8_t settings);
 
 protected:
-    virtual WebRtc_Word32 SendVideoPacket(const FrameType frameType,
-                                          const WebRtc_UWord8* dataBuffer,
+    virtual WebRtc_Word32 SendVideoPacket(const WebRtc_UWord8* dataBuffer,
                                           const WebRtc_UWord16 payloadLength,
                                           const WebRtc_UWord16 rtpHeaderLength,
                                           StorageType storage);
@@ -129,15 +126,11 @@
     bool                    _fecEnabled;
     WebRtc_Word8              _payloadTypeRED;
     WebRtc_Word8              _payloadTypeFEC;
-    WebRtc_UWord8             _codeRateKey;
-    WebRtc_UWord8             _codeRateDelta;
-    bool                      _useUepProtectionKey;
-    bool                      _useUepProtectionDelta;
-    WebRtc_UWord8             _fecProtectionFactor;
-    bool                      _fecUseUepProtection;
     unsigned int              _numberFirstPartition;
-    std::list<ForwardErrorCorrection::Packet*> _mediaPacketListFec;
-    std::list<RtpPacket*> _rtpPacketListFec;
+    FecProtectionParams delta_fec_params_;
+    FecProtectionParams key_fec_params_;
+    ProducerFec producer_fec_;
+
     // Bitrate used for FEC payload, RED headers, RTP headers for FEC packets
     // and any padding overhead.
     Bitrate                   _fecOverheadRate;
diff --git a/src/modules/video_coding/main/interface/video_coding_defines.h b/src/modules/video_coding/main/interface/video_coding_defines.h
index 3755f6d..bd2a98c 100644
--- a/src/modules/video_coding/main/interface/video_coding_defines.h
+++ b/src/modules/video_coding/main/interface/video_coding_defines.h
@@ -14,8 +14,7 @@
 #include "typedefs.h"
 #include "modules/interface/module_common_types.h"
 
-namespace webrtc
-{
+namespace webrtc {
 
 // Error codes
 #define VCM_FRAME_NOT_READY      3
@@ -41,155 +40,148 @@
 #define VCM_VP8_PAYLOAD_TYPE       120
 #define VCM_I420_PAYLOAD_TYPE      124
 
-enum VCMNackProperties
-{
-    kNackHistoryLength = 450
+enum VCMNackProperties {
+  kNackHistoryLength = 450
 };
 
-enum VCMVideoProtection
-{
-    kProtectionNack,                // Both send-side and receive-side
-    kProtectionNackSender,          // Send-side only
-    kProtectionNackReceiver,        // Receive-side only
-    kProtectionDualDecoder,
-    kProtectionFEC,
-    kProtectionNackFEC,
-    kProtectionKeyOnLoss,
-    kProtectionKeyOnKeyLoss,
-    kProtectionPeriodicKeyFrames
+enum VCMVideoProtection {
+  kProtectionNack,                // Both send-side and receive-side
+  kProtectionNackSender,          // Send-side only
+  kProtectionNackReceiver,        // Receive-side only
+  kProtectionDualDecoder,
+  kProtectionFEC,
+  kProtectionNackFEC,
+  kProtectionKeyOnLoss,
+  kProtectionKeyOnKeyLoss,
+  kProtectionPeriodicKeyFrames
 };
 
-enum VCMTemporalDecimation
-{
-    kBitrateOverUseDecimation,
+enum VCMTemporalDecimation {
+  kBitrateOverUseDecimation,
 };
 
-struct VCMFrameCount
-{
-    WebRtc_UWord32 numKeyFrames;
-    WebRtc_UWord32 numDeltaFrames;
+struct VCMFrameCount {
+  WebRtc_UWord32 numKeyFrames;
+  WebRtc_UWord32 numDeltaFrames;
 };
 
-
 // Callback class used for sending data ready to be packetized
-class VCMPacketizationCallback
-{
-public:
-    virtual WebRtc_Word32 SendData(
-        const FrameType frameType,
-        const WebRtc_UWord8 payloadType,
-        const WebRtc_UWord32 timeStamp,
-        const WebRtc_UWord8* payloadData,
-        const WebRtc_UWord32 payloadSize,
-        const RTPFragmentationHeader& fragmentationHeader,
-        const RTPVideoHeader* rtpVideoHdr) = 0;
-protected:
-    virtual ~VCMPacketizationCallback() {}
+class VCMPacketizationCallback {
+ public:
+  virtual WebRtc_Word32 SendData(
+      const FrameType frameType, const WebRtc_UWord8 payloadType,
+      const WebRtc_UWord32 timeStamp, const WebRtc_UWord8* payloadData,
+      const WebRtc_UWord32 payloadSize,
+      const RTPFragmentationHeader& fragmentationHeader,
+      const RTPVideoHeader* rtpVideoHdr) = 0;
+ protected:
+  virtual ~VCMPacketizationCallback() {
+  }
 };
 
 // Callback class used for passing decoded frames which are ready to be rendered.
-class VCMFrameStorageCallback
-{
-public:
-    virtual WebRtc_Word32 StoreReceivedFrame(const EncodedVideoData& frameToStore) = 0;
+class VCMFrameStorageCallback {
+ public:
+  virtual WebRtc_Word32 StoreReceivedFrame(
+      const EncodedVideoData& frameToStore) = 0;
 
-protected:
-    virtual ~VCMFrameStorageCallback() {}
+ protected:
+  virtual ~VCMFrameStorageCallback() {
+  }
 };
 
 // Callback class used for passing decoded frames which are ready to be rendered.
-class VCMReceiveCallback
-{
-public:
-    virtual WebRtc_Word32 FrameToRender(VideoFrame& videoFrame) = 0;
-    virtual WebRtc_Word32 ReceivedDecodedReferenceFrame(const WebRtc_UWord64 pictureId) {return -1;}
+class VCMReceiveCallback {
+ public:
+  virtual WebRtc_Word32 FrameToRender(VideoFrame& videoFrame) = 0;
+  virtual WebRtc_Word32 ReceivedDecodedReferenceFrame(
+      const WebRtc_UWord64 pictureId) {
+    return -1;
+  }
 
-protected:
-    virtual ~VCMReceiveCallback() {}
+ protected:
+  virtual ~VCMReceiveCallback() {
+  }
 };
 
 // Callback class used for informing the user of the bit rate and frame rate produced by the
 // encoder.
-class VCMSendStatisticsCallback
-{
-public:
-    virtual WebRtc_Word32 SendStatistics(const WebRtc_UWord32 bitRate,
-                                         const WebRtc_UWord32 frameRate) = 0;
+class VCMSendStatisticsCallback {
+ public:
+  virtual WebRtc_Word32 SendStatistics(const WebRtc_UWord32 bitRate,
+                                       const WebRtc_UWord32 frameRate) = 0;
 
-protected:
-    virtual ~VCMSendStatisticsCallback() {}
+ protected:
+  virtual ~VCMSendStatisticsCallback() {
+  }
 };
 
 // Callback class used for informing the user of the incoming bit rate and frame rate.
-class VCMReceiveStatisticsCallback
-{
-public:
-    virtual WebRtc_Word32 ReceiveStatistics(const WebRtc_UWord32 bitRate,
-                                            const WebRtc_UWord32 frameRate) = 0;
+class VCMReceiveStatisticsCallback {
+ public:
+  virtual WebRtc_Word32 ReceiveStatistics(const WebRtc_UWord32 bitRate,
+                                          const WebRtc_UWord32 frameRate) = 0;
 
-protected:
-    virtual ~VCMReceiveStatisticsCallback() {}
+ protected:
+  virtual ~VCMReceiveStatisticsCallback() {
+  }
 };
 
-// Callback class used for telling the user about the requested amount of
-// bit stream protection: FEC rate for key and delta frame;
-// whether the FEC uses unequal protection (UEP) across packets,
-// for key and delta frame;
-// and whether NACK should be on or off.
-class VCMProtectionCallback
-{
-public:
-    virtual int ProtectionRequest(
-        uint8_t delta_fec_rate,
-        uint8_t key_fec_rate,
-        bool delta_use_uep_protection,
-        bool key_use_uep_protection,
-        bool nack_enabled,
-        uint32_t* sent_video_rate_bps,
-        uint32_t* sent_nack_rate_bps,
-        uint32_t* sent_fec_rate_bps) = 0;
+// Callback class used for telling the user about how to configure the FEC,
+// and the rates sent the last second is returned to the VCM.
+class VCMProtectionCallback {
+ public:
+  virtual int ProtectionRequest(const FecProtectionParams* delta_params,
+                                const FecProtectionParams* key_params,
+                                uint32_t* sent_video_rate_bps,
+                                uint32_t* sent_nack_rate_bps,
+                                uint32_t* sent_fec_rate_bps) = 0;
 
-protected:
-    virtual ~VCMProtectionCallback() {}
+ protected:
+  virtual ~VCMProtectionCallback() {
+  }
 };
 
 // Callback class used for telling the user about what frame type needed to continue decoding.
 // Typically a key frame when the stream has been corrupted in some way.
-class VCMFrameTypeCallback
-{
-public:
-    virtual WebRtc_Word32 RequestKeyFrame() = 0;
-    virtual WebRtc_Word32 SliceLossIndicationRequest(const WebRtc_UWord64 pictureId) {return -1;}
+class VCMFrameTypeCallback {
+ public:
+  virtual WebRtc_Word32 RequestKeyFrame() = 0;
+  virtual WebRtc_Word32 SliceLossIndicationRequest(
+      const WebRtc_UWord64 pictureId) {
+    return -1;
+  }
 
-protected:
-    virtual ~VCMFrameTypeCallback() {}
+ protected:
+  virtual ~VCMFrameTypeCallback() {
+  }
 };
 
 // Callback class used for telling the user about which packet sequence numbers are currently
 // missing and need to be resent.
-class VCMPacketRequestCallback
-{
-public:
-    virtual WebRtc_Word32 ResendPackets(const WebRtc_UWord16* sequenceNumbers,
-                                        WebRtc_UWord16 length) = 0;
+class VCMPacketRequestCallback {
+ public:
+  virtual WebRtc_Word32 ResendPackets(const WebRtc_UWord16* sequenceNumbers,
+                                      WebRtc_UWord16 length) = 0;
 
-protected:
-    virtual ~VCMPacketRequestCallback() {}
+ protected:
+  virtual ~VCMPacketRequestCallback() {
+  }
 };
 
 // Callback used to inform the user of the the desired resolution
 // as subscribed by Media Optimization (Quality Modes)
-class VCMQMSettingsCallback
-{
-public:
-    virtual WebRtc_Word32 SetVideoQMSettings(const WebRtc_UWord32 frameRate,
-                                             const WebRtc_UWord32 width,
-                                             const WebRtc_UWord32 height) = 0;
+class VCMQMSettingsCallback {
+ public:
+  virtual WebRtc_Word32 SetVideoQMSettings(const WebRtc_UWord32 frameRate,
+                                           const WebRtc_UWord32 width,
+                                           const WebRtc_UWord32 height) = 0;
 
-protected:
-    virtual ~VCMQMSettingsCallback() {}
+ protected:
+  virtual ~VCMQMSettingsCallback() {
+  }
 };
 
-} // namespace webrtc
+}  // namespace webrtc
 
 #endif // WEBRTC_MODULES_INTERFACE_VIDEO_CODING_DEFINES_H_
diff --git a/src/modules/video_coding/main/source/media_optimization.cc b/src/modules/video_coding/main/source/media_optimization.cc
index a85c05b..a3dd89f 100644
--- a/src/modules/video_coding/main/source/media_optimization.cc
+++ b/src/modules/video_coding/main/source/media_optimization.cc
@@ -9,6 +9,7 @@
  */
 
 #include "media_optimization.h"
+
 #include "content_metrics_processing.h"
 #include "frame_dropper.h"
 #include "qm_select.h"
@@ -206,33 +207,29 @@
     {
         return VCM_OK;
     }
+    FecProtectionParams delta_fec_params;
+    FecProtectionParams key_fec_params;
     // Get the FEC code rate for Key frames (set to 0 when NA)
-    const WebRtc_UWord8
-    codeRateKeyRTP  = selected_method->RequiredProtectionFactorK();
+    key_fec_params.fec_rate = selected_method->RequiredProtectionFactorK();
 
     // Get the FEC code rate for Delta frames (set to 0 when NA)
-    const WebRtc_UWord8
-    codeRateDeltaRTP = selected_method->RequiredProtectionFactorD();
+    delta_fec_params.fec_rate =
+        selected_method->RequiredProtectionFactorD();
 
     // Get the FEC-UEP protection status for Key frames: UEP on/off
-    const bool
-    useUepProtectionKeyRTP  = selected_method->RequiredUepProtectionK();
+    key_fec_params.use_uep_protection =
+        selected_method->RequiredUepProtectionK();
 
     // Get the FEC-UEP protection status for Delta frames: UEP on/off
-    const bool
-    useUepProtectionDeltaRTP = selected_method->RequiredUepProtectionD();
+    delta_fec_params.use_uep_protection =
+        selected_method->RequiredUepProtectionD();
 
-    // NACK is on for NACK and NackFec protection method: off for FEC method
-    bool nackStatus = (selected_method->Type() == kNackFec ||
-                       selected_method->Type() == kNack);
+    delta_fec_params.max_fec_frames = 1;
+    key_fec_params.max_fec_frames = 1;
 
     // TODO(Marco): Pass FEC protection values per layer.
-
-    return _videoProtectionCallback->ProtectionRequest(codeRateDeltaRTP,
-                                                       codeRateKeyRTP,
-                                                       useUepProtectionDeltaRTP,
-                                                       useUepProtectionKeyRTP,
-                                                       nackStatus,
+    return _videoProtectionCallback->ProtectionRequest(&delta_fec_params,
+                                                       &key_fec_params,
                                                        video_rate_bps,
                                                        nack_overhead_rate_bps,
                                                        fec_overhead_rate_bps);
diff --git a/src/modules/video_coding/main/test/mt_rx_tx_test.cc b/src/modules/video_coding/main/test/mt_rx_tx_test.cc
index d0a39ad..dc20b32 100644
--- a/src/modules/video_coding/main/test/mt_rx_tx_test.cc
+++ b/src/modules/video_coding/main/test/mt_rx_tx_test.cc
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *  Copyright (c) 2012 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
@@ -235,9 +235,10 @@
     vcm->SetVideoProtection(kProtectionFEC, fecEnabled);
 
     // inform RTP Module of error resilience features
-    rtp->SetFECCodeRate(protectionCallback.FECKeyRate(),
-                        protectionCallback.FECDeltaRate());
-    rtp->SetNACKStatus(protectionCallback.NACKMethod());
+    FecProtectionParams delta_params = protectionCallback.DeltaFecParameters();
+    FecProtectionParams key_params = protectionCallback.KeyFecParameters();
+    rtp->SetFecParameters(&delta_params, &key_params);
+    rtp->SetNACKStatus(nackEnabled ? kNackRtcp : kNackOff);
 
     vcm->SetChannelParameters((WebRtc_UWord32) bitRate,
                               (WebRtc_UWord8) lossRate, rttMS);
diff --git a/src/modules/video_coding/main/test/test_callbacks.cc b/src/modules/video_coding/main/test/test_callbacks.cc
index 1ec0e59..1075aae 100644
--- a/src/modules/video_coding/main/test/test_callbacks.cc
+++ b/src/modules/video_coding/main/test/test_callbacks.cc
@@ -412,13 +412,11 @@
 
 
 VideoProtectionCallback::VideoProtectionCallback():
-_deltaFECRate(0),
-_keyFECRate(0),
-_deltaUseUepProtection(0),
-_keyUseUepProtection(0),
-_nack(kNackOff)
+delta_fec_params_(),
+key_fec_params_()
 {
-    //
+    memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
+    memset(&key_fec_params_, 0, sizeof(key_fec_params_));
 }
 
 VideoProtectionCallback::~VideoProtectionCallback()
@@ -427,72 +425,36 @@
 }
 
 WebRtc_Word32
-VideoProtectionCallback::ProtectionRequest(WebRtc_UWord8 deltaFECRate,
-                                           WebRtc_UWord8 keyFECRate,
-                                           bool deltaUseUepProtection,
-                                           bool keyUseUepProtection,
-                                           bool nack_enabled,
-                                           WebRtc_UWord32* sent_video_rate_bps,
-                                           WebRtc_UWord32* sent_nack_rate_bps,
-                                           WebRtc_UWord32* sent_fec_rate_bps)
+VideoProtectionCallback::ProtectionRequest(
+    const FecProtectionParams* delta_fec_params,
+    const FecProtectionParams* key_fec_params,
+    WebRtc_UWord32* sent_video_rate_bps,
+    WebRtc_UWord32* sent_nack_rate_bps,
+    WebRtc_UWord32* sent_fec_rate_bps)
 {
-    _deltaFECRate = deltaFECRate;
-    _keyFECRate = keyFECRate;
-    _deltaUseUepProtection = deltaUseUepProtection;
-    _keyUseUepProtection = keyUseUepProtection;
-    if (nack_enabled)
-    {
-        _nack = kNackRtcp;
-    }
-    else
-    {
-        _nack = kNackOff;
-    }
+    key_fec_params_ = *key_fec_params;
+    delta_fec_params_ = *delta_fec_params;
 
     // Update RTP
-    if (_rtp->SetFECCodeRate(keyFECRate, deltaFECRate) != 0)
+    if (_rtp->SetFecParameters(&delta_fec_params_,
+                               &key_fec_params_) != 0)
     {
         printf("Error in Setting FEC rate\n");
         return -1;
 
     }
-    if (_rtp->SetFECUepProtection(keyUseUepProtection,
-                                  deltaUseUepProtection) != 0)
-    {
-        printf("Error in Setting FEC UEP protection\n");
-        return -1;
-    }
     return 0;
 
 }
-NACKMethod
-VideoProtectionCallback::NACKMethod()
+
+FecProtectionParams VideoProtectionCallback::DeltaFecParameters() const
 {
-    return _nack;
+    return delta_fec_params_;
 }
 
-WebRtc_UWord8
-VideoProtectionCallback::FECDeltaRate()
+FecProtectionParams VideoProtectionCallback::KeyFecParameters() const
 {
-    return _deltaFECRate;
-}
-
-WebRtc_UWord8
-VideoProtectionCallback::FECKeyRate()
-{
-    return _keyFECRate;
-}
-
-bool
-VideoProtectionCallback::FECDeltaUepProtection()
-{
-    return _deltaUseUepProtection;
-}
-
-bool
-VideoProtectionCallback::FECKeyUepProtection()
-{
-    return _keyUseUepProtection;
+    return key_fec_params_;
 }
 
 void
diff --git a/src/modules/video_coding/main/test/test_callbacks.h b/src/modules/video_coding/main/test/test_callbacks.h
index 07820bb..5c67c4c 100644
--- a/src/modules/video_coding/main/test/test_callbacks.h
+++ b/src/modules/video_coding/main/test/test_callbacks.h
@@ -235,26 +235,18 @@
     VideoProtectionCallback();
     virtual ~VideoProtectionCallback();
     void RegisterRtpModule(RtpRtcp* rtp) {_rtp = rtp;}
-    WebRtc_Word32 ProtectionRequest(WebRtc_UWord8 deltaFECRate,
-                                    WebRtc_UWord8 keyFECRate,
-                                    bool deltaUseUepProtection,
-                                    bool keyUseUepProtection,
-                                    bool nack_enabled,
-                                    WebRtc_UWord32* sent_video_rate_bps,
-                                    WebRtc_UWord32* sent_nack_rate_bps,
-                                    WebRtc_UWord32* sent_fec_rate_bps);
-    enum NACKMethod   NACKMethod();
-    WebRtc_UWord8     FECDeltaRate();
-    WebRtc_UWord8     FECKeyRate();
-    bool              FECDeltaUepProtection();
-    bool              FECKeyUepProtection();
+    WebRtc_Word32 ProtectionRequest(
+        const FecProtectionParams* delta_fec_params,
+        const FecProtectionParams* key_fec_params,
+        WebRtc_UWord32* sent_video_rate_bps,
+        WebRtc_UWord32* sent_nack_rate_bps,
+        WebRtc_UWord32* sent_fec_rate_bps);
+    FecProtectionParams DeltaFecParameters() const;
+    FecProtectionParams KeyFecParameters() const;
 private:
-    RtpRtcp*             _rtp;
-    WebRtc_UWord8        _deltaFECRate;
-    WebRtc_UWord8        _keyFECRate;
-    bool                 _deltaUseUepProtection;
-    bool                 _keyUseUepProtection;
-    enum NACKMethod      _nack;
+    RtpRtcp* _rtp;
+    FecProtectionParams delta_fec_params_;
+    FecProtectionParams key_fec_params_;
 };
 
 // Feed back from the RTP Module callback
diff --git a/src/video_engine/vie_encoder.cc b/src/video_engine/vie_encoder.cc
index 20d8dac..22895e5 100644
--- a/src/video_engine/vie_encoder.cc
+++ b/src/video_engine/vie_encoder.cc
@@ -684,11 +684,8 @@
 }
 
 WebRtc_Word32 ViEEncoder::ProtectionRequest(
-    WebRtc_UWord8 delta_fecrate,
-    WebRtc_UWord8 key_fecrate,
-    bool delta_use_uep_protection,
-    bool key_use_uep_protection,
-    bool nack_enabled,
+    const FecProtectionParams* delta_fec_params,
+    const FecProtectionParams* key_fec_params,
     WebRtc_UWord32* sent_video_rate_bps,
     WebRtc_UWord32* sent_nack_rate_bps,
     WebRtc_UWord32* sent_fec_rate_bps) {
@@ -696,19 +693,17 @@
                ViEId(engine_id_, channel_id_),
                "%s, deltaFECRate: %u, key_fecrate: %u, "
                "delta_use_uep_protection: %d, key_use_uep_protection: %d, ",
-               __FUNCTION__, delta_fecrate, key_fecrate,
-               delta_use_uep_protection, key_use_uep_protection);
+               __FUNCTION__,
+               delta_fec_params->fec_rate,
+               key_fec_params->fec_rate,
+               delta_fec_params->use_uep_protection,
+               key_fec_params->use_uep_protection);
 
-  if (default_rtp_rtcp_.SetFECCodeRate(key_fecrate, delta_fecrate) != 0) {
+  if (default_rtp_rtcp_.SetFecParameters(delta_fec_params,
+                                         key_fec_params) != 0) {
     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
                  ViEId(engine_id_, channel_id_),
-                 "%s: Could not update FEC code rate", __FUNCTION__);
-  }
-  if (default_rtp_rtcp_.SetFECUepProtection(key_use_uep_protection,
-                                            delta_use_uep_protection) != 0) {
-    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
-                 ViEId(engine_id_, channel_id_),
-                 "%s: Could not update FEC-UEP protection", __FUNCTION__);
+                 "%s: Could not update FEC parameters", __FUNCTION__);
   }
   default_rtp_rtcp_.BitrateSent(NULL,
                                 sent_video_rate_bps,
diff --git a/src/video_engine/vie_encoder.h b/src/video_engine/vie_encoder.h
index f2e7f9e..79d8fef 100644
--- a/src/video_engine/vie_encoder.h
+++ b/src/video_engine/vie_encoder.h
@@ -108,12 +108,9 @@
     const RTPVideoHeader* rtp_video_hdr);
 
   // Implements VideoProtectionCallback.
-  virtual WebRtc_Word32 ProtectionRequest(
-      WebRtc_UWord8 delta_fecrate,
-      WebRtc_UWord8 key_fecrate,
-      bool delta_use_uep_protection,
-      bool key_use_uep_protection,
-      bool nack_enabled,
+  virtual int ProtectionRequest(
+      const FecProtectionParams* delta_fec_params,
+      const FecProtectionParams* key_fec_params,
       WebRtc_UWord32* sent_video_rate_bps,
       WebRtc_UWord32* sent_nack_rate_bps,
       WebRtc_UWord32* sent_fec_rate_bps);