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(¶ms_, 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(¶ms, 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(¶ms, 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(¶ms, _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);