Generalize FEC unit tests and rename GenerateFec.

- Rename GenerateFec -> EncodeFec in ForwardErrorCorrection. This naming
  is more consistent with DecodeFec.
- Add appropriate using directives, to reduce clutter in tests.
- Move ConstructMediaPackets to fec_test_helper.{h,cc}. This will help
  future tests of ULPFEC/FlexFEC header formatters.
- Generalize tests in rtp_fec_unittest.cc to typed tests. This will help
  testing ForwardErrorCorrection with both ULPFEC and FlexFEC.

This CL should not impact functionality or performance.

BUG=webrtc:5654

Review-Url: https://codereview.webrtc.org/2267393002
Cr-Commit-Position: refs/heads/master@{#14314}
This commit is contained in:
brandtr
2016-09-20 23:16:28 -07:00
committed by Commit bot
parent 3548357e1b
commit ece4aba64e
10 changed files with 681 additions and 552 deletions

View File

@ -22,46 +22,48 @@
#include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h" #include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
namespace webrtc {
namespace {
constexpr uint8_t kFecPayloadType = 96;
} // namespace
using ::testing::_; using ::testing::_;
using ::testing::Args; using ::testing::Args;
using ::testing::ElementsAreArray; using ::testing::ElementsAreArray;
using ::testing::Return; using ::testing::Return;
using Packet = webrtc::ForwardErrorCorrection::Packet;
namespace webrtc { using ::webrtc::test::fec::FrameGenerator;
using Packet = ::webrtc::ForwardErrorCorrection::Packet;
using ::webrtc::test::fec::RawRtpPacket;
class ReceiverFecTest : public ::testing::Test { class ReceiverFecTest : public ::testing::Test {
protected: protected:
virtual void SetUp() { ReceiverFecTest() : receiver_fec_(FecReceiver::Create(&rtp_data_callback_)) {}
fec_.reset(new ForwardErrorCorrection());
receiver_fec_.reset(FecReceiver::Create(&rtp_data_callback_));
generator_.reset(new FrameGenerator());
}
void GenerateFec(ForwardErrorCorrection::PacketList* media_packets, void EncodeFec(ForwardErrorCorrection::PacketList* media_packets,
std::list<ForwardErrorCorrection::Packet*>* fec_packets, std::list<ForwardErrorCorrection::Packet*>* fec_packets,
unsigned int num_fec_packets) { unsigned int num_fec_packets) {
uint8_t protection_factor = num_fec_packets * 255 / media_packets->size(); uint8_t protection_factor = num_fec_packets * 255 / media_packets->size();
EXPECT_EQ(0, fec_->GenerateFec(*media_packets, protection_factor, EXPECT_EQ(0, fec_.EncodeFec(*media_packets, protection_factor, 0, false,
0, false, kFecMaskBursty, fec_packets)); kFecMaskBursty, fec_packets));
ASSERT_EQ(num_fec_packets, fec_packets->size()); ASSERT_EQ(num_fec_packets, fec_packets->size());
} }
void GenerateFrame(int num_media_packets, void GenerateFrame(int num_media_packets,
int frame_offset, int frame_offset,
std::list<test::RawRtpPacket*>* media_rtp_packets, std::list<RawRtpPacket*>* media_rtp_packets,
ForwardErrorCorrection::PacketList* media_packets) { ForwardErrorCorrection::PacketList* media_packets) {
generator_->NewFrame(num_media_packets); generator_.NewFrame(num_media_packets);
for (int i = 0; i < num_media_packets; ++i) { for (int i = 0; i < num_media_packets; ++i) {
std::unique_ptr<test::RawRtpPacket> next_packet( std::unique_ptr<RawRtpPacket> next_packet(
generator_->NextPacket(frame_offset + i, kRtpHeaderSize + 10)); generator_.NextPacket(frame_offset + i, kRtpHeaderSize + 10));
media_rtp_packets->push_back(next_packet.get()); media_rtp_packets->push_back(next_packet.get());
media_packets->push_back(std::move(next_packet)); media_packets->push_back(std::move(next_packet));
} }
} }
void VerifyReconstructedMediaPacket(const test::RawRtpPacket* packet, void VerifyReconstructedMediaPacket(const RawRtpPacket* packet, int times) {
int times) {
// Verify that the content of the reconstructed packet is equal to the // Verify that the content of the reconstructed packet is equal to the
// content of |packet|, and that the same content is received |times| number // content of |packet|, and that the same content is received |times| number
// of times in a row. // of times in a row.
@ -71,17 +73,17 @@ class ReceiverFecTest : public ::testing::Test {
.Times(times).WillRepeatedly(Return(true)); .Times(times).WillRepeatedly(Return(true));
} }
void BuildAndAddRedMediaPacket(test::RawRtpPacket* packet) { void BuildAndAddRedMediaPacket(RawRtpPacket* packet) {
std::unique_ptr<test::RawRtpPacket> red_packet( std::unique_ptr<RawRtpPacket> red_packet(
generator_->BuildMediaRedPacket(packet)); generator_.BuildMediaRedPacket(packet));
EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket( EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
red_packet->header.header, red_packet->data, red_packet->header.header, red_packet->data,
red_packet->length, kFecPayloadType)); red_packet->length, kFecPayloadType));
} }
void BuildAndAddRedFecPacket(Packet* packet) { void BuildAndAddRedFecPacket(Packet* packet) {
std::unique_ptr<test::RawRtpPacket> red_packet( std::unique_ptr<RawRtpPacket> red_packet(
generator_->BuildFecRedPacket(packet)); generator_.BuildFecRedPacket(packet));
EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket( EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
red_packet->header.header, red_packet->data, red_packet->header.header, red_packet->data,
red_packet->length, kFecPayloadType)); red_packet->length, kFecPayloadType));
@ -93,18 +95,18 @@ class ReceiverFecTest : public ::testing::Test {
uint8_t ulpfec_payload_type); uint8_t ulpfec_payload_type);
MockRtpData rtp_data_callback_; MockRtpData rtp_data_callback_;
std::unique_ptr<ForwardErrorCorrection> fec_; ForwardErrorCorrection fec_;
std::unique_ptr<FecReceiver> receiver_fec_; std::unique_ptr<FecReceiver> receiver_fec_;
std::unique_ptr<FrameGenerator> generator_; FrameGenerator generator_;
}; };
TEST_F(ReceiverFecTest, TwoMediaOneFec) { TEST_F(ReceiverFecTest, TwoMediaOneFec) {
const unsigned int kNumFecPackets = 1u; const unsigned int kNumFecPackets = 1u;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
GenerateFrame(2, 0, &media_rtp_packets, &media_packets); GenerateFrame(2, 0, &media_rtp_packets, &media_packets);
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets, &fec_packets, kNumFecPackets); EncodeFec(&media_packets, &fec_packets, kNumFecPackets);
// Recovery // Recovery
auto it = media_rtp_packets.begin(); auto it = media_rtp_packets.begin();
@ -129,11 +131,11 @@ void ReceiverFecTest::InjectGarbagePacketLength(size_t fec_garbage_offset) {
.WillRepeatedly(Return(true)); .WillRepeatedly(Return(true));
const unsigned int kNumFecPackets = 1u; const unsigned int kNumFecPackets = 1u;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
GenerateFrame(2, 0, &media_rtp_packets, &media_packets); GenerateFrame(2, 0, &media_rtp_packets, &media_packets);
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets, &fec_packets, kNumFecPackets); EncodeFec(&media_packets, &fec_packets, kNumFecPackets);
ByteWriter<uint16_t>::WriteBigEndian( ByteWriter<uint16_t>::WriteBigEndian(
&fec_packets.front()->data[fec_garbage_offset], 0x4711); &fec_packets.front()->data[fec_garbage_offset], 0x4711);
@ -162,11 +164,11 @@ TEST_F(ReceiverFecTest, InjectGarbageFecLevelHeaderProtectionLength) {
TEST_F(ReceiverFecTest, TwoMediaTwoFec) { TEST_F(ReceiverFecTest, TwoMediaTwoFec) {
const unsigned int kNumFecPackets = 2u; const unsigned int kNumFecPackets = 2u;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
GenerateFrame(2, 0, &media_rtp_packets, &media_packets); GenerateFrame(2, 0, &media_rtp_packets, &media_packets);
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets, &fec_packets, kNumFecPackets); EncodeFec(&media_packets, &fec_packets, kNumFecPackets);
// Recovery // Recovery
// Drop both media packets. // Drop both media packets.
@ -184,12 +186,12 @@ TEST_F(ReceiverFecTest, TwoMediaTwoFec) {
TEST_F(ReceiverFecTest, TwoFramesOneFec) { TEST_F(ReceiverFecTest, TwoFramesOneFec) {
const unsigned int kNumFecPackets = 1u; const unsigned int kNumFecPackets = 1u;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
GenerateFrame(1, 0, &media_rtp_packets, &media_packets); GenerateFrame(1, 0, &media_rtp_packets, &media_packets);
GenerateFrame(1, 1, &media_rtp_packets, &media_packets); GenerateFrame(1, 1, &media_rtp_packets, &media_packets);
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets, &fec_packets, kNumFecPackets); EncodeFec(&media_packets, &fec_packets, kNumFecPackets);
// Recovery // Recovery
auto it = media_rtp_packets.begin(); auto it = media_rtp_packets.begin();
@ -205,13 +207,13 @@ TEST_F(ReceiverFecTest, TwoFramesOneFec) {
TEST_F(ReceiverFecTest, OneCompleteOneUnrecoverableFrame) { TEST_F(ReceiverFecTest, OneCompleteOneUnrecoverableFrame) {
const unsigned int kNumFecPackets = 1u; const unsigned int kNumFecPackets = 1u;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
GenerateFrame(1, 0, &media_rtp_packets, &media_packets); GenerateFrame(1, 0, &media_rtp_packets, &media_packets);
GenerateFrame(2, 1, &media_rtp_packets, &media_packets); GenerateFrame(2, 1, &media_rtp_packets, &media_packets);
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets, &fec_packets, kNumFecPackets); EncodeFec(&media_packets, &fec_packets, kNumFecPackets);
// Recovery // Recovery
auto it = media_rtp_packets.begin(); auto it = media_rtp_packets.begin();
@ -227,13 +229,13 @@ TEST_F(ReceiverFecTest, OneCompleteOneUnrecoverableFrame) {
TEST_F(ReceiverFecTest, MaxFramesOneFec) { TEST_F(ReceiverFecTest, MaxFramesOneFec) {
const unsigned int kNumFecPackets = 1u; const unsigned int kNumFecPackets = 1u;
const unsigned int kNumMediaPackets = 48u; const unsigned int kNumMediaPackets = 48u;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
for (unsigned int i = 0; i < kNumMediaPackets; ++i) { for (unsigned int i = 0; i < kNumMediaPackets; ++i) {
GenerateFrame(1, i, &media_rtp_packets, &media_packets); GenerateFrame(1, i, &media_rtp_packets, &media_packets);
} }
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets, &fec_packets, kNumFecPackets); EncodeFec(&media_packets, &fec_packets, kNumFecPackets);
// Recovery // Recovery
auto it = media_rtp_packets.begin(); auto it = media_rtp_packets.begin();
@ -252,15 +254,15 @@ TEST_F(ReceiverFecTest, MaxFramesOneFec) {
TEST_F(ReceiverFecTest, TooManyFrames) { TEST_F(ReceiverFecTest, TooManyFrames) {
const unsigned int kNumFecPackets = 1u; const unsigned int kNumFecPackets = 1u;
const unsigned int kNumMediaPackets = 49u; const unsigned int kNumMediaPackets = 49u;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
for (unsigned int i = 0; i < kNumMediaPackets; ++i) { for (unsigned int i = 0; i < kNumMediaPackets; ++i) {
GenerateFrame(1, i, &media_rtp_packets, &media_packets); GenerateFrame(1, i, &media_rtp_packets, &media_packets);
} }
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
EXPECT_EQ(-1, fec_->GenerateFec(media_packets, EXPECT_EQ(
kNumFecPackets * 255 / kNumMediaPackets, 0, -1, fec_.EncodeFec(media_packets, kNumFecPackets * 255 / kNumMediaPackets,
false, kFecMaskBursty, &fec_packets)); 0, false, kFecMaskBursty, &fec_packets));
} }
TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) { TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) {
@ -269,12 +271,12 @@ TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) {
Packet* delayed_fec = NULL; Packet* delayed_fec = NULL;
const unsigned int kNumFecPacketsBatch1 = 1u; const unsigned int kNumFecPacketsBatch1 = 1u;
const unsigned int kNumMediaPacketsBatch1 = 2u; const unsigned int kNumMediaPacketsBatch1 = 2u;
std::list<test::RawRtpPacket*> media_rtp_packets_batch1; std::list<RawRtpPacket*> media_rtp_packets_batch1;
ForwardErrorCorrection::PacketList media_packets_batch1; ForwardErrorCorrection::PacketList media_packets_batch1;
GenerateFrame(kNumMediaPacketsBatch1, 0, &media_rtp_packets_batch1, GenerateFrame(kNumMediaPacketsBatch1, 0, &media_rtp_packets_batch1,
&media_packets_batch1); &media_packets_batch1);
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1); EncodeFec(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front()); BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front());
EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _)) EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
@ -284,7 +286,7 @@ TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) {
// Fill the FEC decoder. No packets should be dropped. // Fill the FEC decoder. No packets should be dropped.
const unsigned int kNumMediaPacketsBatch2 = 46u; const unsigned int kNumMediaPacketsBatch2 = 46u;
std::list<test::RawRtpPacket*> media_rtp_packets_batch2; std::list<RawRtpPacket*> media_rtp_packets_batch2;
ForwardErrorCorrection::PacketList media_packets_batch2; ForwardErrorCorrection::PacketList media_packets_batch2;
for (unsigned int i = 0; i < kNumMediaPacketsBatch2; ++i) { for (unsigned int i = 0; i < kNumMediaPacketsBatch2; ++i) {
GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2); GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2);
@ -310,12 +312,12 @@ TEST_F(ReceiverFecTest, PacketDroppedWhenTooOld) {
Packet* delayed_fec = NULL; Packet* delayed_fec = NULL;
const unsigned int kNumFecPacketsBatch1 = 1u; const unsigned int kNumFecPacketsBatch1 = 1u;
const unsigned int kNumMediaPacketsBatch1 = 2u; const unsigned int kNumMediaPacketsBatch1 = 2u;
std::list<test::RawRtpPacket*> media_rtp_packets_batch1; std::list<RawRtpPacket*> media_rtp_packets_batch1;
ForwardErrorCorrection::PacketList media_packets_batch1; ForwardErrorCorrection::PacketList media_packets_batch1;
GenerateFrame(kNumMediaPacketsBatch1, 0, &media_rtp_packets_batch1, GenerateFrame(kNumMediaPacketsBatch1, 0, &media_rtp_packets_batch1,
&media_packets_batch1); &media_packets_batch1);
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFec(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1); EncodeFec(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front()); BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front());
EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _)) EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
@ -325,7 +327,7 @@ TEST_F(ReceiverFecTest, PacketDroppedWhenTooOld) {
// Fill the FEC decoder and force the last packet to be dropped. // Fill the FEC decoder and force the last packet to be dropped.
const unsigned int kNumMediaPacketsBatch2 = 48u; const unsigned int kNumMediaPacketsBatch2 = 48u;
std::list<test::RawRtpPacket*> media_rtp_packets_batch2; std::list<RawRtpPacket*> media_rtp_packets_batch2;
ForwardErrorCorrection::PacketList media_packets_batch2; ForwardErrorCorrection::PacketList media_packets_batch2;
for (unsigned int i = 0; i < kNumMediaPacketsBatch2; ++i) { for (unsigned int i = 0; i < kNumMediaPacketsBatch2; ++i) {
GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2); GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2);
@ -350,14 +352,14 @@ TEST_F(ReceiverFecTest, OldFecPacketDropped) {
// 49 frames with 2 media packets and one FEC packet. All media packets // 49 frames with 2 media packets and one FEC packet. All media packets
// missing. // missing.
const unsigned int kNumMediaPackets = 49 * 2; const unsigned int kNumMediaPackets = 49 * 2;
std::list<test::RawRtpPacket*> media_rtp_packets; std::list<RawRtpPacket*> media_rtp_packets;
ForwardErrorCorrection::PacketList media_packets; ForwardErrorCorrection::PacketList media_packets;
for (unsigned int i = 0; i < kNumMediaPackets / 2; ++i) { for (unsigned int i = 0; i < kNumMediaPackets / 2; ++i) {
std::list<test::RawRtpPacket*> frame_media_rtp_packets; std::list<RawRtpPacket*> frame_media_rtp_packets;
ForwardErrorCorrection::PacketList frame_media_packets; ForwardErrorCorrection::PacketList frame_media_packets;
std::list<ForwardErrorCorrection::Packet*> fec_packets; std::list<ForwardErrorCorrection::Packet*> fec_packets;
GenerateFrame(2, 0, &frame_media_rtp_packets, &frame_media_packets); GenerateFrame(2, 0, &frame_media_rtp_packets, &frame_media_packets);
GenerateFec(&frame_media_packets, &fec_packets, 1); EncodeFec(&frame_media_packets, &fec_packets, 1);
for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) { for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) {
// Only FEC packets inserted. No packets recoverable at this time. // Only FEC packets inserted. No packets recoverable at this time.
BuildAndAddRedFecPacket(*it); BuildAndAddRedFecPacket(*it);

View File

@ -10,10 +10,21 @@
#include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h" #include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h"
#include <memory>
#include <utility>
#include "webrtc/modules/rtp_rtcp/source/byte_io.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
namespace webrtc { namespace webrtc {
namespace test {
namespace fec {
namespace {
constexpr uint8_t kFecPayloadType = 96;
constexpr uint8_t kRedPayloadType = 97;
constexpr uint8_t kVp8PayloadType = 120;
} // namespace
FrameGenerator::FrameGenerator() FrameGenerator::FrameGenerator()
: num_packets_(0), seq_num_(0), timestamp_(0) {} : num_packets_(0), seq_num_(0), timestamp_(0) {}
@ -25,8 +36,8 @@ void FrameGenerator::NewFrame(int num_packets) {
uint16_t FrameGenerator::NextSeqNum() { return ++seq_num_; } uint16_t FrameGenerator::NextSeqNum() { return ++seq_num_; }
test::RawRtpPacket* FrameGenerator::NextPacket(int offset, size_t length) { RawRtpPacket* FrameGenerator::NextPacket(int offset, size_t length) {
test::RawRtpPacket* rtp_packet = new test::RawRtpPacket; RawRtpPacket* rtp_packet = new RawRtpPacket;
for (size_t i = 0; i < length; ++i) for (size_t i = 0; i < length; ++i)
rtp_packet->data[i + kRtpHeaderSize] = offset + i; rtp_packet->data[i + kRtpHeaderSize] = offset + i;
rtp_packet->length = length + kRtpHeaderSize; rtp_packet->length = length + kRtpHeaderSize;
@ -44,10 +55,9 @@ test::RawRtpPacket* FrameGenerator::NextPacket(int offset, size_t length) {
} }
// Creates a new RtpPacket with the RED header added to the packet. // Creates a new RtpPacket with the RED header added to the packet.
test::RawRtpPacket* FrameGenerator::BuildMediaRedPacket( RawRtpPacket* FrameGenerator::BuildMediaRedPacket(const RawRtpPacket* packet) {
const test::RawRtpPacket* packet) {
const size_t kHeaderLength = packet->header.header.headerLength; const size_t kHeaderLength = packet->header.header.headerLength;
test::RawRtpPacket* red_packet = new test::RawRtpPacket; RawRtpPacket* red_packet = new RawRtpPacket;
red_packet->header = packet->header; red_packet->header = packet->header;
red_packet->length = packet->length + 1; // 1 byte RED header. red_packet->length = packet->length + 1; // 1 byte RED header.
memset(red_packet->data, 0, red_packet->length); memset(red_packet->data, 0, red_packet->length);
@ -59,14 +69,14 @@ test::RawRtpPacket* FrameGenerator::BuildMediaRedPacket(
return red_packet; return red_packet;
} }
// Creates a new RtpPacket with FEC payload and red header. Does this by // 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 // 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|. // header. Finally replaces the payload with the content of |packet->data|.
test::RawRtpPacket* FrameGenerator::BuildFecRedPacket( RawRtpPacket* FrameGenerator::BuildFecRedPacket(
const ForwardErrorCorrection::Packet* packet) { const ForwardErrorCorrection::Packet* packet) {
// Create a fake media packet to get a correct header. 1 byte RED header. // Create a fake media packet to get a correct header. 1 byte RED header.
++num_packets_; ++num_packets_;
test::RawRtpPacket* red_packet = NextPacket(0, packet->length + 1); RawRtpPacket* red_packet = NextPacket(0, packet->length + 1);
red_packet->data[1] &= ~0x80; // Clear marker bit. red_packet->data[1] &= ~0x80; // Clear marker bit.
const size_t kHeaderLength = red_packet->header.header.headerLength; const size_t kHeaderLength = red_packet->header.header.headerLength;
SetRedHeader(red_packet, kFecPayloadType, kHeaderLength); SetRedHeader(red_packet, kFecPayloadType, kHeaderLength);
@ -95,4 +105,69 @@ void FrameGenerator::BuildRtpHeader(uint8_t* data, const RTPHeader* header) {
ByteWriter<uint32_t>::WriteBigEndian(data + 8, header->ssrc); ByteWriter<uint32_t>::WriteBigEndian(data + 8, header->ssrc);
} }
ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets(
int num_media_packets,
uint16_t start_seq_num) {
RTC_DCHECK_GT(num_media_packets, 0);
uint16_t seq_num = start_seq_num;
int time_stamp = random_->Rand<int>();
ForwardErrorCorrection::PacketList media_packets;
for (int i = 0; i < num_media_packets; ++i) {
std::unique_ptr<ForwardErrorCorrection::Packet> media_packet(
new ForwardErrorCorrection::Packet());
media_packet->length = random_->Rand(min_packet_size_, max_packet_size_);
// Generate random values for the first 2 bytes
media_packet->data[0] = random_->Rand<uint8_t>();
media_packet->data[1] = random_->Rand<uint8_t>();
// The first two bits are assumed to be 10 by the FEC encoder.
// In fact the FEC decoder will set the two first bits to 10 regardless of
// what they actually were. Set the first two bits to 10 so that a memcmp
// can be performed for the whole restored packet.
media_packet->data[0] |= 0x80;
media_packet->data[0] &= 0xbf;
// FEC is applied to a whole frame.
// A frame is signaled by multiple packets without the marker bit set
// followed by the last packet of the frame for which the marker bit is set.
// Only push one (fake) frame to the FEC.
media_packet->data[1] &= 0x7f;
webrtc::ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2],
seq_num);
webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4],
time_stamp);
webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], ssrc_);
// Generate random values for payload.
for (size_t j = 12; j < media_packet->length; ++j) {
media_packet->data[j] = random_->Rand<uint8_t>();
}
seq_num++;
media_packets.push_back(std::move(media_packet));
}
// Last packet, set marker bit.
ForwardErrorCorrection::Packet* media_packet = media_packets.back().get();
RTC_DCHECK(media_packet);
media_packet->data[1] |= 0x80;
fec_seq_num_ = seq_num;
return media_packets;
}
ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets(
int num_media_packets) {
return ConstructMediaPackets(num_media_packets, random_->Rand<uint16_t>());
}
uint16_t MediaPacketGenerator::GetFecSeqNum() {
return fec_seq_num_;
}
} // namespace fec
} // namespace test
} // namespace webrtc } // namespace webrtc

View File

@ -11,19 +11,20 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_ #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
#include "webrtc/base/basictypes.h"
#include "webrtc/base/random.h"
#include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
namespace webrtc { namespace webrtc {
namespace test { namespace test {
// Needed to not clash with another webrtc::FrameGenerator.
namespace fec {
struct RawRtpPacket : public ForwardErrorCorrection::Packet { struct RawRtpPacket : public ForwardErrorCorrection::Packet {
WebRtcRTPHeader header; WebRtcRTPHeader header;
}; };
} // namespace test
const uint8_t kFecPayloadType = 96;
const uint8_t kRedPayloadType = 97;
const uint8_t kVp8PayloadType = 120;
class FrameGenerator { class FrameGenerator {
public: public:
@ -33,16 +34,15 @@ class FrameGenerator {
uint16_t NextSeqNum(); uint16_t NextSeqNum();
test::RawRtpPacket* NextPacket(int offset, size_t length); RawRtpPacket* NextPacket(int offset, size_t length);
// Creates a new RtpPacket with the RED header added to the packet. // Creates a new RtpPacket with the RED header added to the packet.
test::RawRtpPacket* BuildMediaRedPacket(const test::RawRtpPacket* packet); RawRtpPacket* BuildMediaRedPacket(const RawRtpPacket* packet);
// Creates a new RtpPacket with FEC payload and red header. Does this by // 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 // 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|. // header. Finally replaces the payload with the content of |packet->data|.
test::RawRtpPacket* BuildFecRedPacket( RawRtpPacket* BuildFecRedPacket(const ForwardErrorCorrection::Packet* packet);
const ForwardErrorCorrection::Packet* packet);
void SetRedHeader(ForwardErrorCorrection::Packet* red_packet, void SetRedHeader(ForwardErrorCorrection::Packet* red_packet,
uint8_t payload_type, uint8_t payload_type,
@ -55,6 +55,39 @@ class FrameGenerator {
uint16_t seq_num_; uint16_t seq_num_;
uint32_t timestamp_; uint32_t timestamp_;
}; };
class MediaPacketGenerator {
public:
MediaPacketGenerator(uint32_t min_packet_size,
uint32_t max_packet_size,
uint32_t ssrc,
Random* random)
: min_packet_size_(min_packet_size),
max_packet_size_(max_packet_size),
ssrc_(ssrc),
random_(random) {}
// Construct the media packets, up to |num_media_packets| packets.
ForwardErrorCorrection::PacketList ConstructMediaPackets(
int num_media_packets,
uint16_t start_seq_num);
ForwardErrorCorrection::PacketList ConstructMediaPackets(
int num_media_packets);
uint16_t GetFecSeqNum();
private:
uint32_t min_packet_size_;
uint32_t max_packet_size_;
uint32_t ssrc_;
Random* random_;
ForwardErrorCorrection::PacketList media_packets_;
uint16_t fec_seq_num_;
};
} // namespace fec
} // namespace test
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_ #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_

View File

@ -94,19 +94,18 @@ ForwardErrorCorrection::~ForwardErrorCorrection() {}
// | | // | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// //
// Note that any potential RED headers are added/removed before calling int ForwardErrorCorrection::EncodeFec(const PacketList& media_packets,
// GenerateFec() or DecodeFec().
int ForwardErrorCorrection::GenerateFec(const PacketList& media_packets,
uint8_t protection_factor, uint8_t protection_factor,
int num_important_packets, int num_important_packets,
bool use_unequal_protection, bool use_unequal_protection,
FecMaskType fec_mask_type, FecMaskType fec_mask_type,
std::list<Packet*>* fec_packets) { std::list<Packet*>* fec_packets) {
const uint16_t num_media_packets = media_packets.size(); const size_t num_media_packets = media_packets.size();
// Sanity check arguments. // Sanity check arguments.
RTC_DCHECK_GT(num_media_packets, 0); RTC_DCHECK_GT(num_media_packets, 0u);
RTC_DCHECK_GE(num_important_packets, 0); RTC_DCHECK_GE(num_important_packets, 0);
RTC_DCHECK_LE(num_important_packets, num_media_packets); RTC_DCHECK_LE(static_cast<size_t>(num_important_packets), num_media_packets);
RTC_DCHECK(fec_packets->empty()); RTC_DCHECK(fec_packets->empty());
if (num_media_packets > kMaxMediaPackets) { if (num_media_packets > kMaxMediaPackets) {

View File

@ -147,13 +147,15 @@ class ForwardErrorCorrection {
// of type Packet. Must be empty on entry. // of type Packet. Must be empty on entry.
// The memory available through the list will // The memory available through the list will
// be valid until the next call to // be valid until the next call to
// GenerateFec(). // EncodeFec().
// //
// Returns 0 on success, -1 on failure. // Returns 0 on success, -1 on failure.
// //
int GenerateFec(const PacketList& media_packets, int EncodeFec(const PacketList& media_packets,
uint8_t protection_factor, int num_important_packets, uint8_t protection_factor,
bool use_unequal_protection, FecMaskType fec_mask_type, int num_important_packets,
bool use_unequal_protection,
FecMaskType fec_mask_type,
std::list<Packet*>* fec_packets); std::list<Packet*>* fec_packets);
// //

View File

@ -24,12 +24,12 @@ namespace webrtc {
constexpr size_t kRedForFecHeaderLength = 1; constexpr size_t kRedForFecHeaderLength = 1;
// This controls the maximum amount of excess overhead (actual - target) // This controls the maximum amount of excess overhead (actual - target)
// allowed in order to trigger GenerateFec(), before |params_.max_fec_frames| // allowed in order to trigger EncodeFec(), before |params_.max_fec_frames|
// is reached. Overhead here is defined as relative to number of media packets. // is reached. Overhead here is defined as relative to number of media packets.
constexpr int kMaxExcessOverhead = 50; // Q8. constexpr int kMaxExcessOverhead = 50; // Q8.
// This is the minimum number of media packets required (above some protection // This is the minimum number of media packets required (above some protection
// level) in order to trigger GenerateFec(), before |params_.max_fec_frames| is // level) in order to trigger EncodeFec(), before |params_.max_fec_frames| is
// reached. // reached.
constexpr size_t kMinMediaPackets = 4; constexpr size_t kMinMediaPackets = 4;
@ -175,7 +175,7 @@ int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
// Since unequal protection is disabled, the value of // Since unequal protection is disabled, the value of
// |num_important_packets_| has no importance when calling GenerateFec(). // |num_important_packets_| has no importance when calling GenerateFec().
constexpr bool kUseUnequalProtection = false; constexpr bool kUseUnequalProtection = false;
int ret = fec_.GenerateFec(media_packets_, params_.fec_rate, int ret = fec_.EncodeFec(media_packets_, params_.fec_rate,
num_important_packets_, kUseUnequalProtection, num_important_packets_, kUseUnequalProtection,
params_.fec_mask_type, &generated_fec_packets_); params_.fec_mask_type, &generated_fec_packets_);
if (generated_fec_packets_.empty()) { if (generated_fec_packets_.empty()) {

View File

@ -20,6 +20,14 @@
namespace webrtc { namespace webrtc {
namespace {
constexpr uint8_t kFecPayloadType = 96;
constexpr uint8_t kRedPayloadType = 97;
} // namespace
using ::webrtc::test::fec::FrameGenerator;
using ::webrtc::test::fec::RawRtpPacket;
void VerifyHeader(uint16_t seq_num, void VerifyHeader(uint16_t seq_num,
uint32_t timestamp, uint32_t timestamp,
int red_payload_type, int red_payload_type,
@ -97,12 +105,12 @@ TEST_F(ProducerFecTest, OneFrameFec) {
// media packets for 1 frame is at least |minimum_media_packets_fec_|. // media packets for 1 frame is at least |minimum_media_packets_fec_|.
const int kNumPackets = 4; const int kNumPackets = 4;
FecProtectionParams params = {15, 3, kFecMaskRandom}; FecProtectionParams params = {15, 3, kFecMaskRandom};
std::list<test::RawRtpPacket*> rtp_packets; std::list<RawRtpPacket*> rtp_packets;
generator_.NewFrame(kNumPackets); generator_.NewFrame(kNumPackets);
producer_.SetFecParameters(&params, 0); // Expecting one FEC packet. producer_.SetFecParameters(&params, 0); // Expecting one FEC packet.
uint32_t last_timestamp = 0; uint32_t last_timestamp = 0;
for (int i = 0; i < kNumPackets; ++i) { for (int i = 0; i < kNumPackets; ++i) {
test::RawRtpPacket* rtp_packet = generator_.NextPacket(i, 10); RawRtpPacket* rtp_packet = generator_.NextPacket(i, 10);
rtp_packets.push_back(rtp_packet); rtp_packets.push_back(rtp_packet);
EXPECT_EQ(0, producer_.AddRtpPacketAndGenerateFec( EXPECT_EQ(0, producer_.AddRtpPacketAndGenerateFec(
rtp_packet->data, rtp_packet->length, kRtpHeaderSize)); rtp_packet->data, rtp_packet->length, kRtpHeaderSize));
@ -135,14 +143,13 @@ TEST_F(ProducerFecTest, TwoFrameFec) {
const int kNumFrames = 2; const int kNumFrames = 2;
FecProtectionParams params = {15, 3, kFecMaskRandom}; FecProtectionParams params = {15, 3, kFecMaskRandom};
std::list<test::RawRtpPacket*> rtp_packets; std::list<RawRtpPacket*> rtp_packets;
producer_.SetFecParameters(&params, 0); // Expecting one FEC packet. producer_.SetFecParameters(&params, 0); // Expecting one FEC packet.
uint32_t last_timestamp = 0; uint32_t last_timestamp = 0;
for (int i = 0; i < kNumFrames; ++i) { for (int i = 0; i < kNumFrames; ++i) {
generator_.NewFrame(kNumPackets); generator_.NewFrame(kNumPackets);
for (int j = 0; j < kNumPackets; ++j) { for (int j = 0; j < kNumPackets; ++j) {
test::RawRtpPacket* rtp_packet = RawRtpPacket* rtp_packet = generator_.NextPacket(i * kNumPackets + j, 10);
generator_.NextPacket(i * kNumPackets + j, 10);
rtp_packets.push_back(rtp_packet); rtp_packets.push_back(rtp_packet);
EXPECT_EQ(0, producer_.AddRtpPacketAndGenerateFec( EXPECT_EQ(0, producer_.AddRtpPacketAndGenerateFec(
rtp_packet->data, rtp_packet->length, kRtpHeaderSize)); rtp_packet->data, rtp_packet->length, kRtpHeaderSize));
@ -166,16 +173,14 @@ TEST_F(ProducerFecTest, TwoFrameFec) {
TEST_F(ProducerFecTest, BuildRedPacket) { TEST_F(ProducerFecTest, BuildRedPacket) {
generator_.NewFrame(1); generator_.NewFrame(1);
test::RawRtpPacket* packet = generator_.NextPacket(0, 10); RawRtpPacket* packet = generator_.NextPacket(0, 10);
std::unique_ptr<RedPacket> red_packet = std::unique_ptr<RedPacket> red_packet =
ProducerFec::BuildRedPacket(packet->data, packet->length - kRtpHeaderSize, ProducerFec::BuildRedPacket(packet->data, packet->length - kRtpHeaderSize,
kRtpHeaderSize, kRedPayloadType); kRtpHeaderSize, kRedPayloadType);
EXPECT_EQ(packet->length + 1, red_packet->length()); EXPECT_EQ(packet->length + 1, red_packet->length());
VerifyHeader(packet->header.header.sequenceNumber, VerifyHeader(packet->header.header.sequenceNumber,
packet->header.header.timestamp, packet->header.header.timestamp, kRedPayloadType,
kRedPayloadType, packet->header.header.payloadType, red_packet.get(),
packet->header.header.payloadType,
red_packet.get(),
true); // Marker bit set. true); // Marker bit set.
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
EXPECT_EQ(i, red_packet->data()[kRtpHeaderSize + 1 + i]); EXPECT_EQ(i, red_packet->data()[kRtpHeaderSize + 1 + i]);
@ -188,7 +193,7 @@ TEST_F(ProducerFecTest, BuildRedPacketWithEmptyPayload) {
constexpr size_t kRedForFecHeaderLength = 1; constexpr size_t kRedForFecHeaderLength = 1;
generator_.NewFrame(kNumFrames); generator_.NewFrame(kNumFrames);
std::unique_ptr<test::RawRtpPacket> packet( std::unique_ptr<RawRtpPacket> packet(
generator_.NextPacket(0, kPayloadLength)); generator_.NextPacket(0, kPayloadLength));
std::unique_ptr<RedPacket> red_packet = std::unique_ptr<RedPacket> red_packet =
ProducerFec::BuildRedPacket(packet->data, packet->length - kRtpHeaderSize, ProducerFec::BuildRedPacket(packet->data, packet->length - kRtpHeaderSize,

File diff suppressed because it is too large Load Diff

View File

@ -277,14 +277,14 @@ TEST(FecTest, MAYBE_FecTest) {
} }
media_packet_list.back()->data[1] |= 0x80; media_packet_list.back()->data[1] |= 0x80;
ASSERT_EQ(0, fec.GenerateFec(media_packet_list, protection_factor, ASSERT_EQ(0, fec.EncodeFec(media_packet_list, protection_factor,
num_imp_packets, kUseUnequalProtection, num_imp_packets, kUseUnequalProtection,
fec_mask_type, &fec_packet_list)) fec_mask_type, &fec_packet_list))
<< "GenerateFec() failed"; << "EncodeFec() failed";
ASSERT_EQ(num_fec_packets, fec_packet_list.size()) ASSERT_EQ(num_fec_packets, fec_packet_list.size())
<< "We requested " << num_fec_packets << " FEC packets, but " << "We requested " << num_fec_packets << " FEC packets, but "
<< "GenerateFec() produced " << fec_packet_list.size(); << "EncodeFec() produced " << fec_packet_list.size();
memset(media_loss_mask, 0, sizeof(media_loss_mask)); memset(media_loss_mask, 0, sizeof(media_loss_mask));
uint32_t media_packet_idx = 0; uint32_t media_packet_idx = 0;
@ -392,8 +392,8 @@ TEST(FecTest, MAYBE_FecTest) {
} }
} }
} }
ASSERT_EQ(0, fec.DecodeFec(&to_decode_list, ASSERT_EQ(0,
&recovered_packet_list)) fec.DecodeFec(&to_decode_list, &recovered_packet_list))
<< "DecodeFec() failed"; << "DecodeFec() failed";
ASSERT_TRUE(to_decode_list.empty()) ASSERT_TRUE(to_decode_list.empty())
<< "Received packet list is not empty."; << "Received packet list is not empty.";

View File

@ -17,6 +17,11 @@
namespace webrtc { namespace webrtc {
namespace {
constexpr uint8_t kFecPayloadType = 96;
constexpr uint8_t kRedPayloadType = 97;
} // namespace
void FuzzOneInput(const uint8_t* data, size_t size) { void FuzzOneInput(const uint8_t* data, size_t size) {
ProducerFec producer; ProducerFec producer;
size_t i = 0; size_t i = 0;