Formatted FEC stuff.

Unfortunately I had to pull in quite a bit of stuff due to use of unencapsulated public member variables.

BUG=
R=stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4047 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
phoglund@webrtc.org 2013-05-16 15:06:28 +00:00
parent 5c1948dfaf
commit 9919ad5caf
9 changed files with 1025 additions and 1211 deletions

File diff suppressed because it is too large Load Diff

View File

@ -14,22 +14,20 @@
#include <list>
#include <vector>
#include "modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "system_wrappers/interface/ref_count.h"
#include "system_wrappers/interface/scoped_refptr.h"
#include "typedefs.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/system_wrappers/interface/ref_count.h"
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
#include "webrtc/typedefs.h"
namespace webrtc {
// Forward declaration.
class FecPacket;
/**
* Performs codec-independent forward error correction (FEC), based on RFC 5109.
* Option exists to enable unequal protection (UEP) across packets.
* This is not to be confused with protection within packets
* (referred to as uneven level protection (ULP) in RFC 5109).
*/
// Performs codec-independent forward error correction (FEC), based on RFC 5109.
// Option exists to enable unequal protection (UEP) across packets.
// This is not to be confused with protection within packets
// (referred to as uneven level protection (ULP) in RFC 5109).
class ForwardErrorCorrection {
public:
// Maximum number of media packets we can protect
@ -45,21 +43,18 @@ class ForwardErrorCorrection {
virtual ~Packet() {}
// Add a reference.
virtual int32_t AddRef() {
return ++ref_count_;
}
virtual int32_t AddRef() { return ++ref_count_; }
// Release a reference. Will delete the object if the reference count
// reaches zero.
virtual int32_t Release() {
int32_t ref_count;
ref_count = --ref_count_;
if (ref_count == 0)
delete this;
if (ref_count == 0) delete this;
return ref_count;
}
uint16_t length; // Length of packet in bytes.
uint16_t length; // Length of packet in bytes.
uint8_t data[IP_PACKET_SIZE]; // Packet data.
private:
@ -73,61 +68,55 @@ class ForwardErrorCorrection {
static bool LessThan(const SortablePacket* first,
const SortablePacket* second);
uint16_t seqNum;
uint16_t seq_num;
};
/**
* The received list parameter of #DecodeFEC() must reference structs of this
* type. The lastMediaPktInFrame is not required to be used for correct
* recovery, but will reduce delay by allowing #DecodeFEC() to pre-emptively
* determine frame completion. If set, we assume a FEC stream, and the
* following assumptions must hold:\n
*
* 1. The media packets in a frame have contiguous sequence numbers, i.e. the
* frame's FEC packets have sequence numbers either lower than the first
* media packet or higher than the last media packet.\n
* 2. All FEC packets have a sequence number base equal to the first media
* packet in the corresponding frame.\n
*
* The ssrc member is needed to ensure we can restore the SSRC field of
* recovered packets. In most situations this could be retrieved from other
* media packets, but in the case of an FEC packet protecting a single
* missing media packet, we have no other means of obtaining it.
*/
// The received list parameter of #DecodeFEC() must reference structs of this
// type. The last_media_pkt_in_frame is not required to be used for correct
// recovery, but will reduce delay by allowing #DecodeFEC() to pre-emptively
// determine frame completion. If set, we assume a FEC stream, and the
// following assumptions must hold:\n
//
// 1. The media packets in a frame have contiguous sequence numbers, i.e. the
// frame's FEC packets have sequence numbers either lower than the first
// media packet or higher than the last media packet.\n
// 2. All FEC packets have a sequence number base equal to the first media
// packet in the corresponding frame.\n
//
// The ssrc member is needed to ensure we can restore the SSRC field of
// recovered packets. In most situations this could be retrieved from other
// media packets, but in the case of an FEC packet protecting a single
// missing media packet, we have no other means of obtaining it.
// TODO(holmer): Refactor into a proper class.
class ReceivedPacket : public SortablePacket {
public:
uint32_t ssrc; // SSRC of the current frame. Must be set for FEC
// packets, but not required for media packets.
bool isFec; // Set to true if this is an FEC packet and false
// otherwise.
bool is_fec; // Set to true if this is an FEC packet and false
// otherwise.
scoped_refptr<Packet> pkt; // Pointer to the packet storage.
};
/**
* The recovered list parameter of #DecodeFEC() will reference structs of
* this type.
*/
// The recovered list parameter of #DecodeFEC() will reference structs of
// this type.
// TODO(holmer): Refactor into a proper class.
class RecoveredPacket : public SortablePacket {
public:
bool wasRecovered; // Will be true if this packet was recovered by
// the FEC. Otherwise it was a media packet passed in
// through the received packet list.
bool was_recovered; // Will be true if this packet was recovered by
// the FEC. Otherwise it was a media packet passed in
// through the received packet list.
bool returned; // True when the packet already has been returned to the
// caller through the callback.
uint8_t length_recovery[2]; // Two bytes used for recovering the packet
// length with XOR operations.
scoped_refptr<Packet> pkt; // Pointer to the packet storage.
scoped_refptr<Packet> pkt; // Pointer to the packet storage.
};
typedef std::list<Packet*> PacketList;
typedef std::list<ReceivedPacket*> ReceivedPacketList;
typedef std::list<RecoveredPacket*> RecoveredPacketList;
/**
* \param[in] id Module ID
*/
// \param[in] id Module ID
ForwardErrorCorrection(int32_t id);
virtual ~ForwardErrorCorrection();
@ -168,12 +157,10 @@ class ForwardErrorCorrection {
*
* \return 0 on success, -1 on failure.
*/
int32_t GenerateFEC(const PacketList& mediaPacketList,
uint8_t protectionFactor,
int numImportantPackets,
bool useUnequalProtection,
FecMaskType fec_mask_type,
PacketList* fecPacketList);
int32_t GenerateFEC(const PacketList& media_packet_list,
uint8_t protection_factor, int num_important_packets,
bool use_unequal_protection, FecMaskType fec_mask_type,
PacketList* fec_packet_list);
/**
* Decodes a list of media and FEC packets. It will parse the input received
@ -203,32 +190,28 @@ class ForwardErrorCorrection {
*
* \return 0 on success, -1 on failure.
*/
int32_t DecodeFEC(ReceivedPacketList* receivedPacketList,
RecoveredPacketList* recoveredPacketList);
int32_t DecodeFEC(ReceivedPacketList* received_packet_list,
RecoveredPacketList* recovered_packet_list);
// Get the number of FEC packets, given the number of media packets and the
// protection factor.
int GetNumberOfFecPackets(int numMediaPackets,
int protectionFactor);
int GetNumberOfFecPackets(int num_media_packets, int protection_factor);
/**
* Gets the size in bytes of the FEC/ULP headers, which must be accounted for
* as packet overhead.
* \return Packet overhead in bytes.
*/
// Gets the size in bytes of the FEC/ULP headers, which must be accounted for
// as packet overhead.
// \return Packet overhead in bytes.
static uint16_t PacketOverhead();
// Reset internal states from last frame and clear the recoveredPacketList.
// Reset internal states from last frame and clear the recovered_packet_list.
// Frees all memory allocated by this class.
void ResetState(RecoveredPacketList* recoveredPacketList);
void ResetState(RecoveredPacketList* recovered_packet_list);
private:
typedef std::list<FecPacket*> FecPacketList;
void GenerateFecUlpHeaders(const PacketList& mediaPacketList,
uint8_t* packetMask,
bool lBit,
int numFecPackets);
void GenerateFecUlpHeaders(const PacketList& media_packet_list,
uint8_t* packet_mask, bool l_bit,
int num_fec_packets);
// Analyzes |media_packets| for holes in the sequence and inserts zero columns
// into the |packet_mask| where those holes are found. Zero columns means that
@ -237,18 +220,15 @@ class ForwardErrorCorrection {
// Requires that |packet_mask| has at least 6 * |num_fec_packets| bytes
// allocated.
int InsertZerosInBitMasks(const PacketList& media_packets,
uint8_t* packet_mask,
int num_mask_bytes,
uint8_t* packet_mask, int num_mask_bytes,
int num_fec_packets);
// Inserts |num_zeros| zero columns into |new_mask| at position
// |new_bit_index|. If the current byte of |new_mask| can't fit all zeros, the
// byte will be filled with zeros from |new_bit_index|, but the next byte will
// be untouched.
static void InsertZeroColumns(int num_zeros,
uint8_t* new_mask,
int new_mask_bytes,
int num_fec_packets,
static void InsertZeroColumns(int num_zeros, uint8_t* new_mask,
int new_mask_bytes, int num_fec_packets,
int new_bit_index);
// Copies the left most bit column from the byte pointed to by
@ -259,26 +239,22 @@ class ForwardErrorCorrection {
// The copied bit is shifted out from |old_mask| and is shifted one step to
// the left in |new_mask|. |new_mask| will contain "xxxx xxn0" after this
// operation, where x are previously inserted bits and n is the new bit.
static void CopyColumn(uint8_t* new_mask,
int new_mask_bytes,
uint8_t* old_mask,
int old_mask_bytes,
int num_fec_packets,
int new_bit_index,
static void CopyColumn(uint8_t* new_mask, int new_mask_bytes,
uint8_t* old_mask, int old_mask_bytes,
int num_fec_packets, int new_bit_index,
int old_bit_index);
void GenerateFecBitStrings(const PacketList& mediaPacketList,
uint8_t* packetMask,
int numFecPackets,
bool lBit);
void GenerateFecBitStrings(const PacketList& media_packet_list,
uint8_t* packet_mask, int num_fec_packets,
bool l_bit);
// Insert received packets into FEC or recovered list.
void InsertPackets(ReceivedPacketList* receivedPacketList,
RecoveredPacketList* recoveredPacketList);
void InsertPackets(ReceivedPacketList* received_packet_list,
RecoveredPacketList* recovered_packet_list);
// Insert media packet into recovered packet list. We delete duplicates.
void InsertMediaPacket(ReceivedPacket* rxPacket,
RecoveredPacketList* recoveredPacketList);
void InsertMediaPacket(ReceivedPacket* rx_packet,
RecoveredPacketList* recovered_packet_list);
// Assigns pointers to the recovered packet from all FEC packets which cover
// it.
@ -288,37 +264,34 @@ class ForwardErrorCorrection {
void UpdateCoveringFECPackets(RecoveredPacket* packet);
// Insert packet into FEC list. We delete duplicates.
void InsertFECPacket(ReceivedPacket* rxPacket,
const RecoveredPacketList* recoveredPacketList);
void InsertFECPacket(ReceivedPacket* rx_packet,
const RecoveredPacketList* recovered_packet_list);
// Assigns pointers to already recovered packets covered by this FEC packet.
static void AssignRecoveredPackets(
FecPacket* fec_packet,
const RecoveredPacketList* recovered_packets);
FecPacket* fec_packet, const RecoveredPacketList* recovered_packets);
// Insert into recovered list in correct position.
void InsertRecoveredPacket(
RecoveredPacket* recPacketToInsert,
RecoveredPacketList* recoveredPacketList);
void InsertRecoveredPacket(RecoveredPacket* rec_packet_to_insert,
RecoveredPacketList* recovered_packet_list);
// Attempt to recover missing packets.
void AttemptRecover(RecoveredPacketList* recoveredPacketList);
void AttemptRecover(RecoveredPacketList* recovered_packet_list);
// Initializes the packet recovery using the FEC packet.
static void InitRecovery(const FecPacket* fec_packet,
RecoveredPacket* recovered);
static void InitRecovery(const FecPacket* fec_packet,
RecoveredPacket* recovered);
// Performs XOR between |src_packet| and |dst_packet| and stores the result
// in |dst_packet|.
static void XorPackets(const Packet* src_packet,
RecoveredPacket* dst_packet);
static void XorPackets(const Packet* src_packet, RecoveredPacket* dst_packet);
// Finish up the recovery of a packet.
static void FinishRecovery(RecoveredPacket* recovered);
static void FinishRecovery(RecoveredPacket* recovered);
// Recover a missing packet.
void RecoverPacket(const FecPacket* fecPacket,
RecoveredPacket* recPacketToInsert);
void RecoverPacket(const FecPacket* fec_packet,
RecoveredPacket* rec_packet_to_insert);
// Get the number of missing media packets which are covered by this
// FEC packet. An FEC packet can recover at most one packet, and if zero
@ -327,13 +300,13 @@ class ForwardErrorCorrection {
static int NumCoveredPacketsMissing(const FecPacket* fec_packet);
static void DiscardFECPacket(FecPacket* fec_packet);
static void DiscardOldPackets(RecoveredPacketList* recoveredPacketList);
static void DiscardOldPackets(RecoveredPacketList* recovered_packet_list);
static uint16_t ParseSequenceNumber(uint8_t* packet);
int32_t _id;
std::vector<Packet> _generatedFecPackets;
FecPacketList _fecPacketList;
bool _fecPacketReceived;
int32_t id_;
std::vector<Packet> generated_fec_packets_;
FecPacketList fec_packet_list_;
bool fec_packet_received_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_

View File

@ -8,148 +8,128 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include <cassert>
#include <cstring>
#include "modules/rtp_rtcp/source/fec_private_tables_random.h"
#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h"
#include "webrtc/modules/rtp_rtcp/source/fec_private_tables_bursty.h"
#include "webrtc/modules/rtp_rtcp/source/fec_private_tables_random.h"
namespace {
// Allow for different modes of protection for packets in UEP case.
enum ProtectionMode
{
kModeNoOverlap,
kModeOverlap,
kModeBiasFirstPacket,
enum ProtectionMode {
kModeNoOverlap,
kModeOverlap,
kModeBiasFirstPacket,
};
/**
* Fits an input mask (subMask) to an output mask.
* The mask is a matrix where the rows are the FEC packets,
* and the columns are the source packets the FEC is applied to.
* Each row of the mask is represented by a number of mask bytes.
*
* \param[in] numMaskBytes The number of mask bytes of output mask.
* \param[in] numSubMaskBytes The number of mask bytes of input mask.
* \param[in] numRows The number of rows of the input mask.
* \param[in] subMask A pointer to hold the input mask, of size
* [0, numRows * numSubMaskBytes]
* \param[out] packetMask A pointer to hold the output mask, of size
* [0, x * numMaskBytes], where x >= numRows.
*/
void FitSubMask(int numMaskBytes,
int numSubMaskBytes,
int numRows,
const uint8_t* subMask,
uint8_t* packetMask)
{
if (numMaskBytes == numSubMaskBytes)
{
memcpy(packetMask, subMask, numRows * numSubMaskBytes);
}
else
{
for (int i = 0; i < numRows; i++)
{
int pktMaskIdx = i * numMaskBytes;
int pktMaskIdx2 = i * numSubMaskBytes;
for (int j = 0; j < numSubMaskBytes; j++)
{
packetMask[pktMaskIdx] = subMask[pktMaskIdx2];
pktMaskIdx++;
pktMaskIdx2++;
}
}
// Fits an input mask (sub_mask) to an output mask.
// The mask is a matrix where the rows are the FEC packets,
// and the columns are the source packets the FEC is applied to.
// Each row of the mask is represented by a number of mask bytes.
//
// \param[in] num_mask_bytes The number of mask bytes of output mask.
// \param[in] num_sub_mask_bytes The number of mask bytes of input mask.
// \param[in] num_rows The number of rows of the input mask.
// \param[in] sub_mask A pointer to hold the input mask, of size
// [0, num_rows * num_sub_mask_bytes]
// \param[out] packet_mask A pointer to hold the output mask, of size
// [0, x * num_mask_bytes], where x >= num_rows.
void FitSubMask(int num_mask_bytes, int num_sub_mask_bytes, int num_rows,
const uint8_t* sub_mask, uint8_t* packet_mask) {
if (num_mask_bytes == num_sub_mask_bytes) {
memcpy(packet_mask, sub_mask, num_rows * num_sub_mask_bytes);
} else {
for (int i = 0; i < num_rows; ++i) {
int pkt_mask_idx = i * num_mask_bytes;
int pkt_mask_idx2 = i * num_sub_mask_bytes;
for (int j = 0; j < num_sub_mask_bytes; ++j) {
packet_mask[pkt_mask_idx] = sub_mask[pkt_mask_idx2];
pkt_mask_idx++;
pkt_mask_idx2++;
}
}
}
}
/**
* Shifts a mask by number of columns (bits), and fits it to an output mask.
* The mask is a matrix where the rows are the FEC packets,
* and the columns are the source packets the FEC is applied to.
* Each row of the mask is represented by a number of mask bytes.
*
* \param[in] numMaskBytes The number of mask bytes of output mask.
* \param[in] numSubMaskBytes The number of mask bytes of input mask.
* \param[in] numColumnShift The number columns to be shifted, and
* the starting row for the output mask.
* \param[in] endRow The ending row for the output mask.
* \param[in] subMask A pointer to hold the input mask, of size
* [0, (endRowFEC - startRowFec) * numSubMaskBytes]
* \param[out] packetMask A pointer to hold the output mask, of size
* [0, x * numMaskBytes], where x >= endRowFEC.
*/
// Shifts a mask by number of columns (bits), and fits it to an output mask.
// The mask is a matrix where the rows are the FEC packets,
// and the columns are the source packets the FEC is applied to.
// Each row of the mask is represented by a number of mask bytes.
//
// \param[in] num_mask_bytes The number of mask bytes of output mask.
// \param[in] num_sub_mask_bytes The number of mask bytes of input mask.
// \param[in] num_column_shift The number columns to be shifted, and
// the starting row for the output mask.
// \param[in] end_row The ending row for the output mask.
// \param[in] sub_mask A pointer to hold the input mask, of size
// [0, (end_row_fec - start_row_fec) *
// num_sub_mask_bytes]
// \param[out] packet_mask A pointer to hold the output mask, of size
// [0, x * num_mask_bytes],
// where x >= end_row_fec.
// TODO (marpan): This function is doing three things at the same time:
// shift within a byte, byte shift and resizing.
// Split up into subroutines.
void ShiftFitSubMask(int numMaskBytes,
int resMaskBytes,
int numColumnShift,
int endRow,
const uint8_t* subMask,
uint8_t* packetMask)
{
void ShiftFitSubMask(int num_mask_bytes, int res_mask_bytes,
int num_column_shift, int end_row, const uint8_t* sub_mask,
uint8_t* packet_mask) {
// Number of bit shifts within a byte
const int numBitShifts = (numColumnShift % 8);
const int numByteShifts = numColumnShift >> 3;
// Number of bit shifts within a byte
const int num_bit_shifts = (num_column_shift % 8);
const int num_byte_shifts = num_column_shift >> 3;
// Modify new mask with sub-mask21.
// Modify new mask with sub-mask21.
// Loop over the remaining FEC packets.
for (int i = numColumnShift; i < endRow; i++)
{
// Byte index of new mask, for row i and column resMaskBytes,
// offset by the number of bytes shifts
int pktMaskIdx = i * numMaskBytes + resMaskBytes - 1 + numByteShifts;
// Byte index of subMask, for row i and column resMaskBytes
int pktMaskIdx2 =
(i - numColumnShift) * resMaskBytes + resMaskBytes - 1;
// Loop over the remaining FEC packets.
for (int i = num_column_shift; i < end_row; ++i) {
// Byte index of new mask, for row i and column res_mask_bytes,
// offset by the number of bytes shifts
int pkt_mask_idx =
i * num_mask_bytes + res_mask_bytes - 1 + num_byte_shifts;
// Byte index of sub_mask, for row i and column res_mask_bytes
int pkt_mask_idx2 =
(i - num_column_shift) * res_mask_bytes + res_mask_bytes - 1;
uint8_t shiftRightCurrByte = 0;
uint8_t shiftLeftPrevByte = 0;
uint8_t combNewByte = 0;
// Handle case of numMaskBytes > resMaskBytes:
// For a given row, copy the rightmost "numBitShifts" bits
// of the last byte of subMask into output mask.
if (numMaskBytes > resMaskBytes)
{
shiftLeftPrevByte =
(subMask[pktMaskIdx2] << (8 - numBitShifts));
packetMask[pktMaskIdx + 1] = shiftLeftPrevByte;
}
// For each row i (FEC packet), shift the bit-mask of the subMask.
// Each row of the mask contains "resMaskBytes" of bytes.
// We start from the last byte of the subMask and move to first one.
for (int j = resMaskBytes - 1; j > 0; j--)
{
// Shift current byte of sub21 to the right by "numBitShifts".
shiftRightCurrByte =
subMask[pktMaskIdx2] >> numBitShifts;
// Fill in shifted bits with bits from the previous (left) byte:
// First shift the previous byte to the left by "8-numBitShifts".
shiftLeftPrevByte =
(subMask[pktMaskIdx2 - 1] << (8 - numBitShifts));
// Then combine both shifted bytes into new mask byte.
combNewByte = shiftRightCurrByte | shiftLeftPrevByte;
// Assign to new mask.
packetMask[pktMaskIdx] = combNewByte;
pktMaskIdx--;
pktMaskIdx2--;
}
// For the first byte in the row (j=0 case).
shiftRightCurrByte = subMask[pktMaskIdx2] >> numBitShifts;
packetMask[pktMaskIdx] = shiftRightCurrByte;
uint8_t shift_right_curr_byte = 0;
uint8_t shift_left_prev_byte = 0;
uint8_t comb_new_byte = 0;
// Handle case of num_mask_bytes > res_mask_bytes:
// For a given row, copy the rightmost "numBitShifts" bits
// of the last byte of sub_mask into output mask.
if (num_mask_bytes > res_mask_bytes) {
shift_left_prev_byte = (sub_mask[pkt_mask_idx2] << (8 - num_bit_shifts));
packet_mask[pkt_mask_idx + 1] = shift_left_prev_byte;
}
// For each row i (FEC packet), shift the bit-mask of the sub_mask.
// Each row of the mask contains "resMaskBytes" of bytes.
// We start from the last byte of the sub_mask and move to first one.
for (int j = res_mask_bytes - 1; j > 0; j--) {
// Shift current byte of sub21 to the right by "numBitShifts".
shift_right_curr_byte = sub_mask[pkt_mask_idx2] >> num_bit_shifts;
// Fill in shifted bits with bits from the previous (left) byte:
// First shift the previous byte to the left by "8-numBitShifts".
shift_left_prev_byte =
(sub_mask[pkt_mask_idx2 - 1] << (8 - num_bit_shifts));
// Then combine both shifted bytes into new mask byte.
comb_new_byte = shift_right_curr_byte | shift_left_prev_byte;
// Assign to new mask.
packet_mask[pkt_mask_idx] = comb_new_byte;
pkt_mask_idx--;
pkt_mask_idx2--;
}
// For the first byte in the row (j=0 case).
shift_right_curr_byte = sub_mask[pkt_mask_idx2] >> num_bit_shifts;
packet_mask[pkt_mask_idx] = shift_right_curr_byte;
}
}
} // namespace
@ -159,12 +139,11 @@ namespace internal {
PacketMaskTable::PacketMaskTable(FecMaskType fec_mask_type,
int num_media_packets)
: fec_mask_type_(InitMaskType(fec_mask_type, num_media_packets)),
fec_packet_mask_table_(InitMaskTable(fec_mask_type_)) {
}
fec_packet_mask_table_(InitMaskTable(fec_mask_type_)) {}
// Sets |fec_mask_type_| to the type of packet mask selected. The type of
// packet mask selected is based on |fec_mask_type| and |numMediaPackets|.
// If |numMediaPackets| is larger than the maximum allowed by |fec_mask_type|
// packet mask selected is based on |fec_mask_type| and |num_media_packets|.
// If |num_media_packets| is larger than the maximum allowed by |fec_mask_type|
// for the bursty type, then the random type is selected.
FecMaskType PacketMaskTable::InitMaskType(FecMaskType fec_mask_type,
int num_media_packets) {
@ -172,9 +151,7 @@ FecMaskType PacketMaskTable::InitMaskType(FecMaskType fec_mask_type,
assert(num_media_packets <= static_cast<int>(sizeof(kPacketMaskRandomTbl) /
sizeof(*kPacketMaskRandomTbl)));
switch (fec_mask_type) {
case kFecMaskRandom: {
return kFecMaskRandom;
}
case kFecMaskRandom: { return kFecMaskRandom; }
case kFecMaskBursty: {
int max_media_packets = static_cast<int>(sizeof(kPacketMaskBurstyTbl) /
sizeof(*kPacketMaskBurstyTbl));
@ -193,118 +170,95 @@ FecMaskType PacketMaskTable::InitMaskType(FecMaskType fec_mask_type,
// |fec_mask_type|.
const uint8_t*** PacketMaskTable::InitMaskTable(FecMaskType fec_mask_type) {
switch (fec_mask_type) {
case kFecMaskRandom: {
return kPacketMaskRandomTbl;
}
case kFecMaskBursty: {
return kPacketMaskBurstyTbl;
}
case kFecMaskRandom: { return kPacketMaskRandomTbl; }
case kFecMaskBursty: { return kPacketMaskBurstyTbl; }
}
assert(false);
return kPacketMaskRandomTbl;
}
// Remaining protection after important (first partition) packet protection
void RemainingPacketProtection(int numMediaPackets,
int numFecRemaining,
int numFecForImpPackets,
int numMaskBytes,
ProtectionMode mode,
uint8_t* packetMask,
const PacketMaskTable& mask_table)
{
if (mode == kModeNoOverlap)
{
// subMask21
void RemainingPacketProtection(int num_media_packets, int num_fec_remaining,
int num_fec_for_imp_packets, int num_mask_bytes,
ProtectionMode mode, uint8_t* packet_mask,
const PacketMaskTable& mask_table) {
if (mode == kModeNoOverlap) {
// sub_mask21
const int lBit =
(numMediaPackets - numFecForImpPackets) > 16 ? 1 : 0;
const int l_bit =
(num_media_packets - num_fec_for_imp_packets) > 16 ? 1 : 0;
const int resMaskBytes =
(lBit == 1) ? kMaskSizeLBitSet : kMaskSizeLBitClear;
const int res_mask_bytes =
(l_bit == 1) ? kMaskSizeLBitSet : kMaskSizeLBitClear;
const uint8_t* packetMaskSub21 =
mask_table.fec_packet_mask_table()
[numMediaPackets - numFecForImpPackets - 1]
[numFecRemaining - 1];
const uint8_t* packet_mask_sub_21 = mask_table.fec_packet_mask_table()[
num_media_packets - num_fec_for_imp_packets - 1][num_fec_remaining - 1];
ShiftFitSubMask(numMaskBytes, resMaskBytes, numFecForImpPackets,
(numFecForImpPackets + numFecRemaining),
packetMaskSub21, packetMask);
ShiftFitSubMask(num_mask_bytes, res_mask_bytes, num_fec_for_imp_packets,
(num_fec_for_imp_packets + num_fec_remaining),
packet_mask_sub_21, packet_mask);
} else if (mode == kModeOverlap || mode == kModeBiasFirstPacket) {
// sub_mask22
const uint8_t* packet_mask_sub_22 = mask_table
.fec_packet_mask_table()[num_media_packets - 1][num_fec_remaining - 1];
FitSubMask(num_mask_bytes, num_mask_bytes, num_fec_remaining,
packet_mask_sub_22,
&packet_mask[num_fec_for_imp_packets * num_mask_bytes]);
if (mode == kModeBiasFirstPacket) {
for (int i = 0; i < num_fec_remaining; ++i) {
int pkt_mask_idx = i * num_mask_bytes;
packet_mask[pkt_mask_idx] = packet_mask[pkt_mask_idx] | (1 << 7);
}
}
else if (mode == kModeOverlap || mode == kModeBiasFirstPacket)
{
// subMask22
const uint8_t* packetMaskSub22 =
mask_table.fec_packet_mask_table()
[numMediaPackets - 1][numFecRemaining - 1];
FitSubMask(numMaskBytes, numMaskBytes, numFecRemaining, packetMaskSub22,
&packetMask[numFecForImpPackets * numMaskBytes]);
if (mode == kModeBiasFirstPacket)
{
for (int i = 0; i < numFecRemaining; i++)
{
int pktMaskIdx = i * numMaskBytes;
packetMask[pktMaskIdx] = packetMask[pktMaskIdx] | (1 << 7);
}
}
}
else
{
assert(false);
}
} else {
assert(false);
}
}
// Protection for important (first partition) packets
void ImportantPacketProtection(int numFecForImpPackets,
int numImpPackets,
int numMaskBytes,
uint8_t* packetMask,
const PacketMaskTable& mask_table)
{
const int lBit = numImpPackets > 16 ? 1 : 0;
const int numImpMaskBytes =
(lBit == 1) ? kMaskSizeLBitSet : kMaskSizeLBitClear;
void ImportantPacketProtection(int num_fec_for_imp_packets, int num_imp_packets,
int num_mask_bytes, uint8_t* packet_mask,
const PacketMaskTable& mask_table) {
const int l_bit = num_imp_packets > 16 ? 1 : 0;
const int num_imp_mask_bytes =
(l_bit == 1) ? kMaskSizeLBitSet : kMaskSizeLBitClear;
// Get subMask1 from table
const uint8_t* packetMaskSub1 =
mask_table.fec_packet_mask_table()
[numImpPackets - 1][numFecForImpPackets - 1];
// Get sub_mask1 from table
const uint8_t* packet_mask_sub_1 = mask_table.fec_packet_mask_table()[
num_imp_packets - 1][num_fec_for_imp_packets - 1];
FitSubMask(numMaskBytes, numImpMaskBytes,
numFecForImpPackets, packetMaskSub1, packetMask);
FitSubMask(num_mask_bytes, num_imp_mask_bytes, num_fec_for_imp_packets,
packet_mask_sub_1, packet_mask);
}
// This function sets the protection allocation: i.e., how many FEC packets
// to use for numImp (1st partition) packets, given the: number of media
// to use for num_imp (1st partition) packets, given the: number of media
// packets, number of FEC packets, and number of 1st partition packets.
int SetProtectionAllocation(int numMediaPackets,
int numFecPackets,
int numImpPackets)
{
int SetProtectionAllocation(int num_media_packets, int num_fec_packets,
int num_imp_packets) {
// TODO (marpan): test different cases for protection allocation:
// TODO (marpan): test different cases for protection allocation:
// Use at most (allocPar * numFecPackets) for important packets.
float allocPar = 0.5;
int maxNumFecForImp = allocPar * numFecPackets;
// Use at most (alloc_par * num_fec_packets) for important packets.
float alloc_par = 0.5;
int max_num_fec_for_imp = alloc_par * num_fec_packets;
int numFecForImpPackets = (numImpPackets < maxNumFecForImp) ?
numImpPackets : maxNumFecForImp;
int num_fec_for_imp_packets =
(num_imp_packets < max_num_fec_for_imp) ? num_imp_packets
: max_num_fec_for_imp;
// Fall back to equal protection in this case
if (numFecPackets == 1 && (numMediaPackets > 2 * numImpPackets))
{
numFecForImpPackets = 0;
}
// Fall back to equal protection in this case
if (num_fec_packets == 1 && (num_media_packets > 2 * num_imp_packets)) {
num_fec_for_imp_packets = 0;
}
return numFecForImpPackets;
return num_fec_for_imp_packets;
}
// Modification for UEP: reuse the off-line tables for the packet masks.
@ -319,28 +273,28 @@ int SetProtectionAllocation(int numMediaPackets,
// Mask is characterized as (#packets_to_protect, #fec_for_protection).
// Protection factor defined as: (#fec_for_protection / #packets_to_protect).
// Let k=numMediaPackets, n=total#packets, (n-k)=numFecPackets, m=numImpPackets.
// Let k=num_media_packets, n=total#packets, (n-k)=num_fec_packets,
// m=num_imp_packets.
// For ProtectionMode 0 and 1:
// one mask (subMask1) is used for 1st partition packets,
// the other mask (subMask21/22, for 0/1) is for the remaining FEC packets.
// one mask (sub_mask1) is used for 1st partition packets,
// the other mask (sub_mask21/22, for 0/1) is for the remaining FEC packets.
// In both mode 0 and 1, the packets of 1st partition (numImpPackets) are
// In both mode 0 and 1, the packets of 1st partition (num_imp_packets) are
// treated equally important, and are afforded more protection than the
// residual partition packets.
// For numImpPackets:
// subMask1 = (m, t): protection = t/(m), where t=F(k,n-k,m).
// For num_imp_packets:
// sub_mask1 = (m, t): protection = t/(m), where t=F(k,n-k,m).
// t=F(k,n-k,m) is the number of packets used to protect first partition in
// subMask1. This is determined from the function SetProtectionAllocation().
// sub_mask1. This is determined from the function SetProtectionAllocation().
// For the left-over protection:
// Mode 0: subMask21 = (k-m,n-k-t): protection = (n-k-t)/(k-m)
// Mode 0: sub_mask21 = (k-m,n-k-t): protection = (n-k-t)/(k-m)
// mode 0 has no protection overlap between the two partitions.
// For mode 0, we would typically set t = min(m, n-k).
// Mode 1: subMask22 = (k, n-k-t), with protection (n-k-t)/(k)
// Mode 1: sub_mask22 = (k, n-k-t), with protection (n-k-t)/(k)
// mode 1 has protection overlap between the two partitions (preferred).
// For ProtectionMode 2:
@ -352,85 +306,71 @@ int SetProtectionAllocation(int numMediaPackets,
// Protection Mode 2 may be extended for a sort of sliding protection
// (i.e., vary the number/density of "1s" across columns) across packets.
void UnequalProtectionMask(int numMediaPackets,
int numFecPackets,
int numImpPackets,
int numMaskBytes,
uint8_t* packetMask,
const PacketMaskTable& mask_table)
{
void UnequalProtectionMask(int num_media_packets, int num_fec_packets,
int num_imp_packets, int num_mask_bytes,
uint8_t* packet_mask,
const PacketMaskTable& mask_table) {
// Set Protection type and allocation
// TODO (marpan): test/update for best mode and some combinations thereof.
// Set Protection type and allocation
// TODO (marpan): test/update for best mode and some combinations thereof.
ProtectionMode mode = kModeOverlap;
int numFecForImpPackets = 0;
ProtectionMode mode = kModeOverlap;
int num_fec_for_imp_packets = 0;
if (mode != kModeBiasFirstPacket)
{
numFecForImpPackets = SetProtectionAllocation(numMediaPackets,
numFecPackets,
numImpPackets);
}
if (mode != kModeBiasFirstPacket) {
num_fec_for_imp_packets = SetProtectionAllocation(
num_media_packets, num_fec_packets, num_imp_packets);
}
int numFecRemaining = numFecPackets - numFecForImpPackets;
// Done with setting protection type and allocation
int num_fec_remaining = num_fec_packets - num_fec_for_imp_packets;
// Done with setting protection type and allocation
//
// Generate subMask1
//
if (numFecForImpPackets > 0)
{
ImportantPacketProtection(numFecForImpPackets, numImpPackets,
numMaskBytes, packetMask,
mask_table);
}
//
// Generate sub_mask1
//
if (num_fec_for_imp_packets > 0) {
ImportantPacketProtection(num_fec_for_imp_packets, num_imp_packets,
num_mask_bytes, packet_mask, mask_table);
}
//
// Generate subMask2
//
if (numFecRemaining > 0)
{
RemainingPacketProtection(numMediaPackets, numFecRemaining,
numFecForImpPackets, numMaskBytes,
mode, packetMask, mask_table);
}
//
// Generate sub_mask2
//
if (num_fec_remaining > 0) {
RemainingPacketProtection(num_media_packets, num_fec_remaining,
num_fec_for_imp_packets, num_mask_bytes, mode,
packet_mask, mask_table);
}
}
void GeneratePacketMasks(int numMediaPackets,
int numFecPackets,
int numImpPackets,
bool useUnequalProtection,
void GeneratePacketMasks(int num_media_packets, int num_fec_packets,
int num_imp_packets, bool use_unequal_protection,
const PacketMaskTable& mask_table,
uint8_t* packetMask)
{
assert(numMediaPackets > 0);
assert(numFecPackets <= numMediaPackets && numFecPackets > 0);
assert(numImpPackets <= numMediaPackets && numImpPackets >= 0);
uint8_t* packet_mask) {
assert(num_media_packets > 0);
assert(num_fec_packets <= num_media_packets && num_fec_packets > 0);
assert(num_imp_packets <= num_media_packets && num_imp_packets >= 0);
int lBit = numMediaPackets > 16 ? 1 : 0;
const int numMaskBytes =
(lBit == 1) ? kMaskSizeLBitSet : kMaskSizeLBitClear;
int l_bit = num_media_packets > 16 ? 1 : 0;
const int num_mask_bytes =
(l_bit == 1) ? kMaskSizeLBitSet : kMaskSizeLBitClear;
// Equal-protection for these cases
if (!useUnequalProtection || numImpPackets == 0)
{
// Retrieve corresponding mask table directly:for equal-protection case.
// Mask = (k,n-k), with protection factor = (n-k)/k,
// where k = numMediaPackets, n=total#packets, (n-k)=numFecPackets.
memcpy(packetMask,
mask_table.fec_packet_mask_table()[numMediaPackets - 1]
[numFecPackets - 1],
numFecPackets * numMaskBytes);
}
else //UEP case
{
UnequalProtectionMask(numMediaPackets, numFecPackets, numImpPackets,
numMaskBytes, packetMask, mask_table);
// Equal-protection for these cases.
if (!use_unequal_protection || num_imp_packets == 0) {
// Retrieve corresponding mask table directly:for equal-protection case.
// Mask = (k,n-k), with protection factor = (n-k)/k,
// where k = num_media_packets, n=total#packets, (n-k)=num_fec_packets.
memcpy(packet_mask, mask_table.fec_packet_mask_table()[
num_media_packets - 1][num_fec_packets - 1],
num_fec_packets * num_mask_bytes);
} else //UEP case
{
UnequalProtectionMask(num_media_packets, num_fec_packets, num_imp_packets,
num_mask_bytes, packet_mask, mask_table);
} // End of UEP modification
} //End of GetPacketMasks
} // End of UEP modification
} //End of GetPacketMasks
} // namespace internal
} // namespace webrtc

View File

@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/forward_error_correction.h"
#include "typedefs.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
#include "webrtc/typedefs.h"
namespace webrtc {
@ -23,49 +23,44 @@ namespace internal {
class PacketMaskTable {
public:
PacketMaskTable(FecMaskType fec_mask_type, int num_media_packets);
~PacketMaskTable() {
}
~PacketMaskTable() {}
FecMaskType fec_mask_type() const { return fec_mask_type_; }
const uint8_t*** fec_packet_mask_table() const {
return fec_packet_mask_table_;
}
private:
FecMaskType InitMaskType(FecMaskType fec_mask_type,
int num_media_packets);
FecMaskType InitMaskType(FecMaskType fec_mask_type, int num_media_packets);
const uint8_t*** InitMaskTable(FecMaskType fec_mask_type_);
const FecMaskType fec_mask_type_;
const uint8_t*** fec_packet_mask_table_;
};
/**
* Returns an array of packet masks. The mask of a single FEC packet
* corresponds to a number of mask bytes. The mask indicates which
* media packets should be protected by the FEC packet.
// Returns an array of packet masks. The mask of a single FEC packet
// corresponds to a number of mask bytes. The mask indicates which
// media packets should be protected by the FEC packet.
* \param[in] numMediaPackets The number of media packets to protect.
* [1, maxMediaPackets].
* \param[in] numFecPackets The number of FEC packets which will
* be generated. [1, numMediaPackets].
* \param[in] numImpPackets The number of important packets.
* [0, numMediaPackets].
* numImpPackets = 0 is the equal
* protection scenario.
* \param[in] useUnequalProtection Enables unequal protection: allocates
* more protection to the numImpPackets.
* \param[in] mask_table An instance of the |PacketMaskTable|
* class, which contains the type of FEC
* packet mask used, and a pointer to the
* corresponding packet masks.
* \param[out] packetMask A pointer to hold the packet mask array,
* of size:
* numFecPackets * "number of mask bytes".
*/
void GeneratePacketMasks(int numMediaPackets,
int numFecPackets,
int numImpPackets,
bool useUnequalProtection,
// \param[in] num_media_packets The number of media packets to protect.
// [1, max_media_packets].
// \param[in] num_fec_packets The number of FEC packets which will
// be generated. [1, num_media_packets].
// \param[in] num_imp_packets The number of important packets.
// [0, num_media_packets].
// num_imp_packets = 0 is the equal
// protection scenario.
// \param[in] use_unequal_protection Enables unequal protection: allocates
// more protection to the num_imp_packets.
// \param[in] mask_table An instance of the |PacketMaskTable|
// class, which contains the type of FEC
// packet mask used, and a pointer to the
// corresponding packet masks.
// \param[out] packet_mask A pointer to hold the packet mask array,
// of size: num_fec_packets *
// "number of mask bytes".
void GeneratePacketMasks(int num_media_packets, int num_fec_packets,
int num_imp_packets, bool use_unequal_protection,
const PacketMaskTable& mask_table,
uint8_t* packetMask);
uint8_t* packet_mask);
} // namespace internal
} // namespace webrtc
} // namespace internal
} // namespace webrtc

View File

@ -8,80 +8,75 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/receiver_fec.h"
#include "webrtc/modules/rtp_rtcp/source/receiver_fec.h"
#include <cassert>
#include "modules/rtp_rtcp/source/rtp_receiver_video.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "system_wrappers/interface/scoped_ptr.h"
#include "system_wrappers/interface/trace.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/trace.h"
// RFC 5109
namespace webrtc {
ReceiverFEC::ReceiverFEC(const int32_t id, RTPReceiverVideo* owner)
: _id(id),
_owner(owner),
_fec(new ForwardErrorCorrection(id)),
_payloadTypeFEC(-1) {
}
: id_(id),
owner_(owner),
fec_(new ForwardErrorCorrection(id)),
payload_type_fec_(-1) {}
ReceiverFEC::~ReceiverFEC() {
// Clean up DecodeFEC()
while (!_receivedPacketList.empty()){
ForwardErrorCorrection::ReceivedPacket* receivedPacket =
_receivedPacketList.front();
delete receivedPacket;
_receivedPacketList.pop_front();
while (!received_packet_list_.empty()) {
ForwardErrorCorrection::ReceivedPacket* received_packet =
received_packet_list_.front();
delete received_packet;
received_packet_list_.pop_front();
}
assert(_receivedPacketList.empty());
assert(received_packet_list_.empty());
if (_fec != NULL) {
_fec->ResetState(&_recoveredPacketList);
delete _fec;
if (fec_ != NULL) {
fec_->ResetState(&recovered_packet_list_);
delete fec_;
}
}
void ReceiverFEC::SetPayloadTypeFEC(const int8_t payloadType) {
_payloadTypeFEC = payloadType;
void ReceiverFEC::SetPayloadTypeFEC(const int8_t payload_type) {
payload_type_fec_ = payload_type;
}
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |F| block PT | timestamp offset | block length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//
// RFC 2198 RTP Payload for Redundant Audio Data September 1997
//
// The bits in the header are specified as follows:
//
// F: 1 bit First bit in header indicates whether another header block
// follows. If 1 further header blocks follow, if 0 this is the
// last header block.
// If 0 there is only 1 byte RED header
//
// block PT: 7 bits RTP payload type for this block.
//
// timestamp offset: 14 bits Unsigned offset of timestamp of this block
// relative to timestamp given in RTP header. The use of an unsigned
// offset implies that redundant data must be sent after the primary
// data, and is hence a time to be subtracted from the current
// timestamp to determine the timestamp of the data for which this
// block is the redundancy.
//
// block length: 10 bits Length in bytes of the corresponding data
// block excluding header.
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F| block PT | timestamp offset | block length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
RFC 2198 RTP Payload for Redundant Audio Data September 1997
The bits in the header are specified as follows:
F: 1 bit First bit in header indicates whether another header block
follows. If 1 further header blocks follow, if 0 this is the
last header block.
If 0 there is only 1 byte RED header
block PT: 7 bits RTP payload type for this block.
timestamp offset: 14 bits Unsigned offset of timestamp of this block
relative to timestamp given in RTP header. The use of an unsigned
offset implies that redundant data must be sent after the primary
data, and is hence a time to be subtracted from the current
timestamp to determine the timestamp of the data for which this
block is the redundancy.
block length: 10 bits Length in bytes of the corresponding data
block excluding header.
*/
int32_t ReceiverFEC::AddReceivedFECPacket(
const WebRtcRTPHeader* rtpHeader,
const uint8_t* incomingRtpPacket,
const uint16_t payloadDataLength,
bool& FECpacket) {
if (_payloadTypeFEC == -1) {
int32_t ReceiverFEC::AddReceivedFECPacket(const WebRtcRTPHeader* rtp_header,
const uint8_t* incoming_rtp_packet,
const uint16_t payload_data_length,
bool& FECpacket) {
if (payload_type_fec_ == -1) {
return -1;
}
@ -90,154 +85,158 @@ int32_t ReceiverFEC::AddReceivedFECPacket(
// Add to list without RED header, aka a virtual RTP packet
// we remove the RED header
ForwardErrorCorrection::ReceivedPacket* receivedPacket =
ForwardErrorCorrection::ReceivedPacket* received_packet =
new ForwardErrorCorrection::ReceivedPacket;
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
received_packet->pkt = new ForwardErrorCorrection::Packet;
// get payload type from RED header
uint8_t payloadType =
incomingRtpPacket[rtpHeader->header.headerLength] & 0x7f;
uint8_t payload_type =
incoming_rtp_packet[rtp_header->header.headerLength] & 0x7f;
// use the payloadType to decide if it's FEC or coded data
if (_payloadTypeFEC == payloadType) {
receivedPacket->isFec = true;
// use the payload_type to decide if it's FEC or coded data
if (payload_type_fec_ == payload_type) {
received_packet->is_fec = true;
FECpacket = true;
} else {
receivedPacket->isFec = false;
received_packet->is_fec = false;
FECpacket = false;
}
receivedPacket->seqNum = rtpHeader->header.sequenceNumber;
received_packet->seq_num = rtp_header->header.sequenceNumber;
uint16_t blockLength = 0;
if(incomingRtpPacket[rtpHeader->header.headerLength] & 0x80) {
if (incoming_rtp_packet[rtp_header->header.headerLength] & 0x80) {
// f bit set in RED header
REDHeaderLength = 4;
uint16_t timestampOffset =
(incomingRtpPacket[rtpHeader->header.headerLength + 1]) << 8;
timestampOffset += incomingRtpPacket[rtpHeader->header.headerLength+2];
timestampOffset = timestampOffset >> 2;
if(timestampOffset != 0) {
uint16_t timestamp_offset =
(incoming_rtp_packet[rtp_header->header.headerLength + 1]) << 8;
timestamp_offset +=
incoming_rtp_packet[rtp_header->header.headerLength + 2];
timestamp_offset = timestamp_offset >> 2;
if (timestamp_offset != 0) {
// |timestampOffset| should be 0. However, it's possible this is the first
// location a corrupt payload can be caught, so don't assert.
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_,
"Corrupt payload found in %s", __FUNCTION__);
delete receivedPacket;
delete received_packet;
return -1;
}
blockLength =
(0x03 & incomingRtpPacket[rtpHeader->header.headerLength + 2]) << 8;
blockLength += (incomingRtpPacket[rtpHeader->header.headerLength + 3]);
(0x03 & incoming_rtp_packet[rtp_header->header.headerLength + 2]) << 8;
blockLength += (incoming_rtp_packet[rtp_header->header.headerLength + 3]);
// check next RED header
if(incomingRtpPacket[rtpHeader->header.headerLength+4] & 0x80) {
if (incoming_rtp_packet[rtp_header->header.headerLength + 4] & 0x80) {
// more than 2 blocks in packet not supported
delete receivedPacket;
delete received_packet;
assert(false);
return -1;
}
if(blockLength > payloadDataLength - REDHeaderLength) {
if (blockLength > payload_data_length - REDHeaderLength) {
// block length longer than packet
delete receivedPacket;
delete received_packet;
assert(false);
return -1;
}
}
ForwardErrorCorrection::ReceivedPacket* secondReceivedPacket = NULL;
ForwardErrorCorrection::ReceivedPacket* second_received_packet = NULL;
if (blockLength > 0) {
// handle block length, split into 2 packets
REDHeaderLength = 5;
// copy the RTP header
memcpy(receivedPacket->pkt->data,
incomingRtpPacket,
rtpHeader->header.headerLength);
memcpy(received_packet->pkt->data, incoming_rtp_packet,
rtp_header->header.headerLength);
// replace the RED payload type
receivedPacket->pkt->data[1] &= 0x80; // reset the payload
receivedPacket->pkt->data[1] += payloadType; // set the media payload type
received_packet->pkt->data[1] &= 0x80; // reset the payload
received_packet->pkt->data[1] +=
payload_type; // set the media payload type
// copy the payload data
memcpy(receivedPacket->pkt->data + rtpHeader->header.headerLength,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength,
blockLength);
memcpy(
received_packet->pkt->data + rtp_header->header.headerLength,
incoming_rtp_packet + rtp_header->header.headerLength + REDHeaderLength,
blockLength);
receivedPacket->pkt->length = blockLength;
received_packet->pkt->length = blockLength;
secondReceivedPacket = new ForwardErrorCorrection::ReceivedPacket;
secondReceivedPacket->pkt = new ForwardErrorCorrection::Packet;
second_received_packet = new ForwardErrorCorrection::ReceivedPacket;
second_received_packet->pkt = new ForwardErrorCorrection::Packet;
secondReceivedPacket->isFec = true;
secondReceivedPacket->seqNum = rtpHeader->header.sequenceNumber;
second_received_packet->is_fec = true;
second_received_packet->seq_num = rtp_header->header.sequenceNumber;
// copy the FEC payload data
memcpy(secondReceivedPacket->pkt->data,
incomingRtpPacket + rtpHeader->header.headerLength +
memcpy(second_received_packet->pkt->data,
incoming_rtp_packet + rtp_header->header.headerLength +
REDHeaderLength + blockLength,
payloadDataLength - REDHeaderLength - blockLength);
payload_data_length - REDHeaderLength - blockLength);
secondReceivedPacket->pkt->length = payloadDataLength - REDHeaderLength -
blockLength;
second_received_packet->pkt->length =
payload_data_length - REDHeaderLength - blockLength;
} else if(receivedPacket->isFec) {
} else if (received_packet->is_fec) {
// everything behind the RED header
memcpy(receivedPacket->pkt->data,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength,
payloadDataLength - REDHeaderLength);
receivedPacket->pkt->length = payloadDataLength - REDHeaderLength;
receivedPacket->ssrc =
ModuleRTPUtility::BufferToUWord32(&incomingRtpPacket[8]);
memcpy(
received_packet->pkt->data,
incoming_rtp_packet + rtp_header->header.headerLength + REDHeaderLength,
payload_data_length - REDHeaderLength);
received_packet->pkt->length = payload_data_length - REDHeaderLength;
received_packet->ssrc =
ModuleRTPUtility::BufferToUWord32(&incoming_rtp_packet[8]);
} else {
// copy the RTP header
memcpy(receivedPacket->pkt->data,
incomingRtpPacket,
rtpHeader->header.headerLength);
memcpy(received_packet->pkt->data, incoming_rtp_packet,
rtp_header->header.headerLength);
// replace the RED payload type
receivedPacket->pkt->data[1] &= 0x80; // reset the payload
receivedPacket->pkt->data[1] += payloadType; // set the media payload type
received_packet->pkt->data[1] &= 0x80; // reset the payload
received_packet->pkt->data[1] +=
payload_type; // set the media payload type
// copy the media payload data
memcpy(receivedPacket->pkt->data + rtpHeader->header.headerLength,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength,
payloadDataLength - REDHeaderLength);
memcpy(
received_packet->pkt->data + rtp_header->header.headerLength,
incoming_rtp_packet + rtp_header->header.headerLength + REDHeaderLength,
payload_data_length - REDHeaderLength);
receivedPacket->pkt->length = rtpHeader->header.headerLength +
payloadDataLength - REDHeaderLength;
received_packet->pkt->length =
rtp_header->header.headerLength + payload_data_length - REDHeaderLength;
}
if(receivedPacket->pkt->length == 0) {
delete secondReceivedPacket;
delete receivedPacket;
if (received_packet->pkt->length == 0) {
delete second_received_packet;
delete received_packet;
return 0;
}
_receivedPacketList.push_back(receivedPacket);
if (secondReceivedPacket) {
_receivedPacketList.push_back(secondReceivedPacket);
received_packet_list_.push_back(received_packet);
if (second_received_packet) {
received_packet_list_.push_back(second_received_packet);
}
return 0;
}
int32_t ReceiverFEC::ProcessReceivedFEC() {
if (!_receivedPacketList.empty()) {
if (!received_packet_list_.empty()) {
// Send received media packet to VCM.
if (!_receivedPacketList.front()->isFec) {
if (ParseAndReceivePacket(_receivedPacketList.front()->pkt) != 0) {
if (!received_packet_list_.front()->is_fec) {
if (ParseAndReceivePacket(received_packet_list_.front()->pkt) != 0) {
return -1;
}
}
if (_fec->DecodeFEC(&_receivedPacketList, &_recoveredPacketList) != 0) {
if (fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_) != 0) {
return -1;
}
assert(_receivedPacketList.empty());
assert(received_packet_list_.empty());
}
// Send any recovered media packets to VCM.
ForwardErrorCorrection::RecoveredPacketList::iterator it =
_recoveredPacketList.begin();
for (; it != _recoveredPacketList.end(); ++it) {
recovered_packet_list_.begin();
for (; it != recovered_packet_list_.end(); ++it) {
if ((*it)->returned) // Already sent to the VCM and the jitter buffer.
continue;
if (ParseAndReceivePacket((*it)->pkt) != 0) {
@ -252,18 +251,16 @@ int ReceiverFEC::ParseAndReceivePacket(
const ForwardErrorCorrection::Packet* packet) {
WebRtcRTPHeader header;
memset(&header, 0, sizeof(header));
ModuleRTPUtility::RTPHeaderParser parser(packet->data,
packet->length);
ModuleRTPUtility::RTPHeaderParser parser(packet->data, packet->length);
if (!parser.Parse(header)) {
return -1;
}
if (_owner->ReceiveRecoveredPacketCallback(
&header,
&packet->data[header.header.headerLength],
packet->length - header.header.headerLength) != 0) {
if (owner_->ReceiveRecoveredPacketCallback(
&header, &packet->data[header.header.headerLength],
packet->length - header.header.headerLength) != 0) {
return -1;
}
return 0;
}
} // namespace webrtc
} // namespace webrtc

View File

@ -11,43 +11,42 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVER_FEC_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVER_FEC_H_
#include "rtp_rtcp_defines.h"
// This header is included to get the nested declaration of Packet structure.
#include "forward_error_correction.h"
#include "typedefs.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class RTPReceiverVideo;
class ReceiverFEC
{
public:
ReceiverFEC(const int32_t id, RTPReceiverVideo* owner);
virtual ~ReceiverFEC();
class ReceiverFEC {
public:
ReceiverFEC(const int32_t id, RTPReceiverVideo* owner);
virtual ~ReceiverFEC();
int32_t AddReceivedFECPacket(const WebRtcRTPHeader* rtpHeader,
const uint8_t* incomingRtpPacket,
const uint16_t payloadDataLength,
bool& FECpacket);
int32_t AddReceivedFECPacket(const WebRtcRTPHeader* rtp_header,
const uint8_t* incoming_rtp_packet,
const uint16_t payload_data_length,
bool& FECpacket);
int32_t ProcessReceivedFEC();
int32_t ProcessReceivedFEC();
void SetPayloadTypeFEC(const int8_t payloadType);
void SetPayloadTypeFEC(const int8_t payload_type);
private:
int ParseAndReceivePacket(const ForwardErrorCorrection::Packet* packet);
private:
int ParseAndReceivePacket(const ForwardErrorCorrection::Packet* packet);
int _id;
RTPReceiverVideo* _owner;
ForwardErrorCorrection* _fec;
// TODO(holmer): In the current version _receivedPacketList is never more
// than one packet, since we process FEC every time a new packet
// arrives. We should remove the list.
ForwardErrorCorrection::ReceivedPacketList _receivedPacketList;
ForwardErrorCorrection::RecoveredPacketList _recoveredPacketList;
int8_t _payloadTypeFEC;
int id_;
RTPReceiverVideo* owner_;
ForwardErrorCorrection* fec_;
// TODO(holmer): In the current version received_packet_list_ is never more
// than one packet, since we process FEC every time a new packet
// arrives. We should remove the list.
ForwardErrorCorrection::ReceivedPacketList received_packet_list_;
ForwardErrorCorrection::RecoveredPacketList recovered_packet_list_;
int8_t payload_type_fec_;
};
} // namespace webrtc
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVER_FEC_H_
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVER_FEC_H_

View File

@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string.h>
#include <list>
#include <string.h>
#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"
#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/mock/mock_rtp_receiver_video.h"
#include "webrtc/modules/rtp_rtcp/source/receiver_fec.h"
using ::testing::_;
using ::testing::Args;
@ -42,24 +42,19 @@ class ReceiverFecTest : public ::testing::Test {
void GenerateFEC(std::list<Packet*>* media_packets,
std::list<Packet*>* fec_packets,
unsigned int num_fec_packets) {
EXPECT_EQ(0, fec_->GenerateFEC(
*media_packets,
num_fec_packets * 255 / media_packets->size(),
0,
false,
kFecMaskBursty,
fec_packets));
uint8_t protection_factor = num_fec_packets * 255 / media_packets->size();
EXPECT_EQ(0, fec_->GenerateFEC(*media_packets, protection_factor,
0, false, kFecMaskBursty, fec_packets));
ASSERT_EQ(num_fec_packets, fec_packets->size());
}
void GenerateFrame(int num_media_packets,
int frame_offset,
void GenerateFrame(int num_media_packets, int frame_offset,
std::list<RtpPacket*>* media_rtp_packets,
std::list<Packet*>* media_packets) {
generator_->NewFrame(num_media_packets);
for (int i = 0; i < num_media_packets; ++i) {
media_rtp_packets->push_back(generator_->NextPacket(frame_offset + i,
kRtpHeaderSize + 10));
media_rtp_packets->push_back(
generator_->NextPacket(frame_offset + i, kRtpHeaderSize + 10));
media_packets->push_back(media_rtp_packets->back());
}
}
@ -68,9 +63,8 @@ class ReceiverFecTest : public ::testing::Test {
// Verify that the content of the reconstructed packet is equal to the
// content of |packet|, and that the same content is received |times| number
// of times in a row.
EXPECT_CALL(rtp_receiver_video_,
ReceiveRecoveredPacketCallback(_, _,
packet->length - kRtpHeaderSize))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(
_, _, packet->length - kRtpHeaderSize))
.With(Args<1, 2>(ElementsAreArray(packet->data + kRtpHeaderSize,
packet->length - kRtpHeaderSize)))
.Times(times);
@ -79,11 +73,9 @@ class ReceiverFecTest : public ::testing::Test {
void BuildAndAddRedMediaPacket(RtpPacket* packet) {
RtpPacket* red_packet = generator_->BuildMediaRedPacket(packet);
bool is_fec = false;
EXPECT_EQ(0, receiver_fec_->AddReceivedFECPacket(&red_packet->header,
red_packet->data,
red_packet->length -
kRtpHeaderSize,
is_fec));
EXPECT_EQ(0, receiver_fec_->AddReceivedFECPacket(
&red_packet->header, red_packet->data,
red_packet->length - kRtpHeaderSize, is_fec));
delete red_packet;
EXPECT_FALSE(is_fec);
}
@ -91,11 +83,9 @@ class ReceiverFecTest : public ::testing::Test {
void BuildAndAddRedFecPacket(Packet* packet) {
RtpPacket* red_packet = generator_->BuildFecRedPacket(packet);
bool is_fec = false;
EXPECT_EQ(0, receiver_fec_->AddReceivedFECPacket(&red_packet->header,
red_packet->data,
red_packet->length -
kRtpHeaderSize,
is_fec));
EXPECT_EQ(0, receiver_fec_->AddReceivedFECPacket(
&red_packet->header, red_packet->data,
red_packet->length - kRtpHeaderSize, is_fec));
delete red_packet;
EXPECT_TRUE(is_fec);
}
@ -244,11 +234,8 @@ TEST_F(ReceiverFecTest, TooManyFrames) {
}
std::list<Packet*> fec_packets;
EXPECT_EQ(-1, fec_->GenerateFEC(media_packets,
kNumFecPackets * 255 / kNumMediaPackets,
0,
false,
kFecMaskBursty,
&fec_packets));
kNumFecPackets * 255 / kNumMediaPackets, 0,
false, kFecMaskBursty, &fec_packets));
DeletePackets(&media_packets);
}
@ -267,7 +254,7 @@ TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) {
GenerateFEC(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front());
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(1);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());
delayed_fec = fec_packets.front();
@ -280,16 +267,16 @@ TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) {
GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2);
}
for (std::list<RtpPacket*>::iterator it = media_rtp_packets_batch2.begin();
it != media_rtp_packets_batch2.end(); ++it) {
it != media_rtp_packets_batch2.end(); ++it) {
BuildAndAddRedMediaPacket(*it);
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(1);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());
}
// Add the delayed FEC packet. One packet should be reconstructed.
BuildAndAddRedFecPacket(delayed_fec);
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(1);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());
@ -311,7 +298,7 @@ TEST_F(ReceiverFecTest, PacketDroppedWhenTooOld) {
GenerateFEC(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front());
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(1);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());
delayed_fec = fec_packets.front();
@ -324,9 +311,9 @@ TEST_F(ReceiverFecTest, PacketDroppedWhenTooOld) {
GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2);
}
for (std::list<RtpPacket*>::iterator it = media_rtp_packets_batch2.begin();
it != media_rtp_packets_batch2.end(); ++it) {
it != media_rtp_packets_batch2.end(); ++it) {
BuildAndAddRedMediaPacket(*it);
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(1);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());
}
@ -334,7 +321,7 @@ TEST_F(ReceiverFecTest, PacketDroppedWhenTooOld) {
// Add the delayed FEC packet. No packet should be reconstructed since the
// first media packet of that frame has been dropped due to being too old.
BuildAndAddRedFecPacket(delayed_fec);
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(0);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());
@ -355,15 +342,14 @@ TEST_F(ReceiverFecTest, OldFecPacketDropped) {
GenerateFrame(2, 0, &frame_media_rtp_packets, &frame_media_packets);
GenerateFEC(&frame_media_packets, &fec_packets, 1);
for (std::list<Packet*>::iterator it = fec_packets.begin();
it != fec_packets.end(); ++it) {
it != fec_packets.end(); ++it) {
// Only FEC packets inserted. No packets recoverable at this time.
BuildAndAddRedFecPacket(*it);
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(0);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());
}
media_packets.insert(media_packets.end(),
frame_media_packets.begin(),
media_packets.insert(media_packets.end(), frame_media_packets.begin(),
frame_media_packets.end());
media_rtp_packets.insert(media_rtp_packets.end(),
frame_media_rtp_packets.begin(),
@ -373,7 +359,7 @@ TEST_F(ReceiverFecTest, OldFecPacketDropped) {
// and should've been dropped. Only the media packet we inserted will be
// returned.
BuildAndAddRedMediaPacket(media_rtp_packets.front());
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_,_,_))
EXPECT_CALL(rtp_receiver_video_, ReceiveRecoveredPacketCallback(_, _, _))
.Times(1);
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFEC());

View File

@ -8,12 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/forward_error_correction.h"
#include <gtest/gtest.h>
#include <list>
#include "rtp_utility.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
using webrtc::ForwardErrorCorrection;
@ -30,7 +29,7 @@ typedef std::list<ForwardErrorCorrection::Packet*> PacketList;
typedef std::list<ForwardErrorCorrection::ReceivedPacket*> ReceivedPacketList;
typedef std::list<ForwardErrorCorrection::RecoveredPacket*> RecoveredPacketList;
template<typename T> void ClearList(std::list<T*>* my_list) {
template <typename T> void ClearList(std::list<T*>* my_list) {
T* packet = NULL;
while (!my_list->empty()) {
packet = my_list->front();
@ -42,10 +41,7 @@ template<typename T> void ClearList(std::list<T*>* my_list) {
class RtpFecTest : public ::testing::Test {
protected:
RtpFecTest()
: fec_(new ForwardErrorCorrection(0)),
ssrc_(rand()),
fec_seq_num_(0) {
}
: fec_(new ForwardErrorCorrection(0)), ssrc_(rand()), fec_seq_num_(0) {}
ForwardErrorCorrection* fec_;
int ssrc_;
@ -67,8 +63,7 @@ class RtpFecTest : public ::testing::Test {
// Construct the media packet list, up to |num_media_packets| packets.
// Returns the next sequence number after the last media packet.
// (this will be the sequence of the first FEC packet)
int ConstructMediaPacketsSeqNum(int num_media_packets,
int start_seq_num);
int ConstructMediaPacketsSeqNum(int num_media_packets, int start_seq_num);
int ConstructMediaPackets(int num_media_packets);
// Construct the received packet list: a subset of the media and FEC packets.
@ -78,10 +73,8 @@ class RtpFecTest : public ::testing::Test {
// |loss_mask|.
// The |packet_list| may be a media packet list (is_fec = false), or a
// FEC packet list (is_fec = true).
void ReceivedPackets(
const PacketList& packet_list,
int* loss_mask,
bool is_fec);
void ReceivedPackets(const PacketList& packet_list, int* loss_mask,
bool is_fec);
// Check for complete recovery after FEC decoding.
bool IsRecoveryComplete();
@ -97,65 +90,50 @@ class RtpFecTest : public ::testing::Test {
TEST_F(RtpFecTest, HandleIncorrectInputs) {
int kNumImportantPackets = 0;
bool kUseUnequalProtection = false;
bool kUseUnequalProtection = false;
uint8_t kProtectionFactor = 60;
// Media packet list is empty.
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
int num_media_packets = 10;
ConstructMediaPackets(num_media_packets);
kNumImportantPackets = -1;
// Number of important packets below 0.
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
kNumImportantPackets = 12;
// Number of important packets greater than number of media packets.
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
num_media_packets = kMaxNumberMediaPackets + 1;
ConstructMediaPackets(num_media_packets);
kNumImportantPackets = 0;
// Number of media packet is above maximum allowed (kMaxNumberMediaPackets).
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
}
TEST_F(RtpFecTest, FecRecoveryNoLoss) {
const int kNumImportantPackets = 0;
const bool kUseUnequalProtection = false;
const bool kUseUnequalProtection = false;
const int kNumMediaPackets = 4;
uint8_t kProtectionFactor = 60;
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 1 FEC packet.
EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
@ -165,7 +143,7 @@ TEST_F(RtpFecTest, FecRecoveryNoLoss) {
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// No packets lost, expect complete recovery.
@ -180,12 +158,9 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 1 FEC packet.
EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
@ -196,8 +171,8 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
&recovered_packet_list_));
EXPECT_EQ(0,
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
// One packet lost, one FEC packet, expect complete recovery.
EXPECT_TRUE(IsRecoveryComplete());
@ -210,7 +185,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// 2 packets lost, one FEC packet, cannot get complete recovery.
@ -222,7 +197,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
// consecutive loss which cannot be fully recovered.
TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
const int kNumImportantPackets = 0;
const bool kUseUnequalProtection = false;
const bool kUseUnequalProtection = false;
const int kNumMediaPackets = 4;
const uint8_t kProtectionFactor = 255;
@ -238,12 +213,9 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskRandom,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskRandom, &fec_packet_list_));
// Expect 4 FEC packets.
EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
@ -257,8 +229,8 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
&recovered_packet_list_));
EXPECT_EQ(0,
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
// With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
EXPECT_TRUE(IsRecoveryComplete());
@ -273,7 +245,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// Cannot get complete recovery for this loss configuration with random mask.
@ -285,7 +257,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
// non-consecutive which cannot be fully recovered.
TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
const int kNumImportantPackets = 0;
const bool kUseUnequalProtection = false;
const bool kUseUnequalProtection = false;
const int kNumMediaPackets = 4;
const uint8_t kProtectionFactor = 255;
@ -301,12 +273,9 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 4 FEC packets.
EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
@ -336,7 +305,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// Expect complete recovery for consecutive packet loss <= 50%.
@ -352,7 +321,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// Cannot get complete recovery for this loss configuration.
@ -361,18 +330,15 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
const int kNumImportantPackets = 2;
const bool kUseUnequalProtection = true;
const bool kUseUnequalProtection = true;
const int kNumMediaPackets = 4;
const uint8_t kProtectionFactor = 60;
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 1 FEC packet.
EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
@ -382,8 +348,8 @@ TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
&recovered_packet_list_));
EXPECT_EQ(0,
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
// No packets lost, expect complete recovery.
EXPECT_TRUE(IsRecoveryComplete());
@ -391,18 +357,15 @@ TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
const int kNumImportantPackets = 2;
const bool kUseUnequalProtection = true;
const bool kUseUnequalProtection = true;
const int kNumMediaPackets = 4;
const uint8_t kProtectionFactor = 60;
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 1 FEC packet.
EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
@ -413,7 +376,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// One packet lost, one FEC packet, expect complete recovery.
@ -427,7 +390,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// 2 packets lost, one FEC packet, cannot get complete recovery.
@ -437,7 +400,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
// Test 50% protection with random mask type for UEP on.
TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
const int kNumImportantPackets = 1;
const bool kUseUnequalProtection = true;
const bool kUseUnequalProtection = true;
const int kNumMediaPackets = 4;
const uint8_t kProtectionFactor = 255;
@ -453,12 +416,9 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskRandom,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskRandom, &fec_packet_list_));
// Expect 4 FEC packets.
EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
@ -472,7 +432,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
@ -489,7 +449,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
media_loss_mask_[3] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// Cannot get complete recovery for this loss configuration.
@ -509,17 +469,13 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
PacketList protected_media_packets;
int i = 0;
for (PacketList::iterator it = media_packet_list_.begin();
it != media_packet_list_.end(); ++it, ++i) {
if (i % 2 == 0)
protected_media_packets.push_back(*it);
it != media_packet_list_.end(); ++it, ++i) {
if (i % 2 == 0) protected_media_packets.push_back(*it);
}
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 1 FEC packet.
EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
@ -530,7 +486,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
media_loss_mask_[2] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// One packet lost, one FEC packet, expect complete recovery.
@ -543,7 +499,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
media_loss_mask_[1] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// Unprotected packet lost. Recovery not possible.
@ -557,7 +513,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
media_loss_mask_[2] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// 2 protected packets lost, one FEC packet, cannot get complete recovery.
@ -577,20 +533,16 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
PacketList protected_media_packets;
int i = 0;
for (PacketList::iterator it = media_packet_list_.begin();
it != media_packet_list_.end(); ++it, ++i) {
if (i % 2 == 0)
protected_media_packets.push_back(*it);
it != media_packet_list_.end(); ++it, ++i) {
if (i % 2 == 0) protected_media_packets.push_back(*it);
}
// Zero column insertion will have to extend the size of the packet
// mask since the number of actual packets are 21, while the number
// of protected packets are 11.
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 5 FEC packet.
EXPECT_EQ(5, static_cast<int>(fec_packet_list_.size()));
@ -601,7 +553,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
media_loss_mask_[kNumMediaPackets - 1] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// One packet lost, one FEC packet, expect complete recovery.
@ -614,7 +566,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
media_loss_mask_[kNumMediaPackets - 2] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// Unprotected packet lost. Recovery not possible.
@ -632,7 +584,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
media_loss_mask_[kNumMediaPackets - 1] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// 5 protected packets lost, one FEC packet, cannot get complete recovery.
@ -652,20 +604,16 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
PacketList protected_media_packets;
int i = 0;
for (PacketList::iterator it = media_packet_list_.begin();
it != media_packet_list_.end(); ++it, ++i) {
if (i % 2 == 0)
protected_media_packets.push_back(*it);
it != media_packet_list_.end(); ++it, ++i) {
if (i % 2 == 0) protected_media_packets.push_back(*it);
}
// Zero column insertion will have to extend the size of the packet
// mask since the number of actual packets are 21, while the number
// of protected packets are 11.
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets,
kProtectionFactor,
kNumImportantPackets,
kUseUnequalProtection,
webrtc::kFecMaskBursty,
&fec_packet_list_));
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
kNumImportantPackets, kUseUnequalProtection,
webrtc::kFecMaskBursty, &fec_packet_list_));
// Expect 5 FEC packet.
EXPECT_EQ(5, static_cast<int>(fec_packet_list_.size()));
@ -676,7 +624,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
media_loss_mask_[kNumMediaPackets - 1] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// One packet lost, one FEC packet, expect complete recovery.
@ -689,7 +637,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
media_loss_mask_[kNumMediaPackets - 2] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// Unprotected packet lost. Recovery not possible.
@ -707,7 +655,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
media_loss_mask_[kNumMediaPackets - 1] = 1;
NetworkReceivedPackets();
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
&recovered_packet_list_));
// 5 protected packets lost, one FEC packet, cannot get complete recovery.
@ -739,10 +687,9 @@ bool RtpFecTest::IsRecoveryComplete() {
bool recovery = true;
PacketList::iterator
media_packet_list_item = media_packet_list_.begin();
RecoveredPacketList::iterator
recovered_packet_list_item = recovered_packet_list_.begin();
PacketList::iterator media_packet_list_item = media_packet_list_.begin();
RecoveredPacketList::iterator recovered_packet_list_item =
recovered_packet_list_.begin();
while (media_packet_list_item != media_packet_list_.end()) {
if (recovered_packet_list_item == recovered_packet_list_.end()) {
return false;
@ -768,17 +715,14 @@ void RtpFecTest::NetworkReceivedPackets() {
ReceivedPackets(fec_packet_list_, fec_loss_mask_, kFecPacket);
}
void RtpFecTest:: ReceivedPackets(
const PacketList& packet_list,
int* loss_mask,
bool is_fec) {
void RtpFecTest::ReceivedPackets(const PacketList& packet_list, int* loss_mask,
bool is_fec) {
ForwardErrorCorrection::Packet* packet;
ForwardErrorCorrection::ReceivedPacket* received_packet;
int seq_num = fec_seq_num_;
int packet_idx = 0;
PacketList::const_iterator
packet_list_item = packet_list.begin();
PacketList::const_iterator packet_list_item = packet_list.begin();
while (packet_list_item != packet_list.end()) {
packet = *packet_list_item;
@ -787,28 +731,26 @@ void RtpFecTest:: ReceivedPackets(
received_packet->pkt = new ForwardErrorCorrection::Packet;
received_packet_list_.push_back(received_packet);
received_packet->pkt->length = packet->length;
memcpy(received_packet->pkt->data, packet->data,
packet->length);
received_packet->isFec = is_fec;
memcpy(received_packet->pkt->data, packet->data, packet->length);
received_packet->is_fec = is_fec;
if (!is_fec) {
// For media packets, the sequence number and marker bit is
// obtained from RTP header. These were set in ConstructMediaPackets().
received_packet->seqNum =
received_packet->seq_num =
webrtc::ModuleRTPUtility::BufferToUWord16(&packet->data[2]);
}
else {
} else {
// The sequence number, marker bit, and ssrc number are defined in the
// RTP header of the FEC packet, which is not constructed in this test.
// So we set these values below based on the values generated in
// ConstructMediaPackets().
received_packet->seqNum = seq_num;
received_packet->seq_num = seq_num;
// The ssrc value for FEC packets is set to the one used for the
// media packets in ConstructMediaPackets().
received_packet->ssrc = ssrc_;
}
}
packet_idx++;
packet_list_item ++;
packet_list_item++;
// Sequence number of FEC packets are defined as increment by 1 from
// last media packet in frame.
if (is_fec) seq_num++;
@ -822,13 +764,13 @@ int RtpFecTest::ConstructMediaPacketsSeqNum(int num_media_packets,
int sequence_number = start_seq_num;
int time_stamp = rand();
for (int i = 0; i < num_media_packets; i++) {
for (int i = 0; i < num_media_packets; ++i) {
media_packet = new ForwardErrorCorrection::Packet;
media_packet_list_.push_back(media_packet);
media_packet->length =
static_cast<uint16_t>((static_cast<float>(rand()) / RAND_MAX) *
media_packet->length = static_cast<uint16_t>(
(static_cast<float>(rand()) / RAND_MAX) *
(IP_PACKET_SIZE - kRtpHeaderSize - kTransportOverhead -
ForwardErrorCorrection::PacketOverhead()));
ForwardErrorCorrection::PacketOverhead()));
if (media_packet->length < kRtpHeaderSize) {
media_packet->length = kRtpHeaderSize;
@ -858,8 +800,8 @@ int RtpFecTest::ConstructMediaPacketsSeqNum(int num_media_packets,
ssrc_);
// Generate random values for payload.
for (int j = 12; j < media_packet->length; j++) {
media_packet->data[j] = static_cast<uint8_t> (rand() % 256);
for (int j = 12; j < media_packet->length; ++j) {
media_packet->data[j] = static_cast<uint8_t>(rand() % 256);
}
sequence_number++;
}

View File

@ -38,8 +38,12 @@ void ReceivePackets(
int main() {
// TODO(marpan): Split this function into subroutines/helper functions.
enum { kMaxNumberMediaPackets = 48 };
enum { kMaxNumberFecPackets = 48 };
enum {
kMaxNumberMediaPackets = 48
};
enum {
kMaxNumberFecPackets = 48
};
const uint32_t kNumMaskBytesL0 = 2;
const uint32_t kNumMaskBytesL1 = 6;
@ -48,7 +52,7 @@ int main() {
const bool kUseUnequalProtection = true;
// FEC mask types.
const FecMaskType kMaskTypes[] = {kFecMaskRandom, kFecMaskBursty};
const FecMaskType kMaskTypes[] = { kFecMaskRandom, kFecMaskBursty };
const int kNumFecMaskTypes = sizeof(kMaskTypes) / sizeof(*kMaskTypes);
// TODO(pbos): Fix this. Hack to prevent a warning
@ -76,8 +80,8 @@ int main() {
ForwardErrorCorrection::Packet* mediaPacket = NULL;
// Running over only one loss rate to limit execution time.
const float lossRate[] = {0.5f};
const uint32_t lossRateSize = sizeof(lossRate)/sizeof(*lossRate);
const float lossRate[] = { 0.5f };
const uint32_t lossRateSize = sizeof(lossRate) / sizeof(*lossRate);
const float reorderRate = 0.1f;
const float duplicateRate = 0.1f;
@ -101,40 +105,35 @@ int main() {
// Loop over the mask types: random and bursty.
for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes;
++mask_type_idx) {
++mask_type_idx) {
for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize;
++lossRateIdx) {
for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize; ++lossRateIdx) {
printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx],
mask_type_idx);
const uint32_t packetMaskMax = kMaxMediaPackets[mask_type_idx];
uint8_t* packetMask =
new uint8_t[packetMaskMax * kNumMaskBytesL1];
uint8_t* packetMask = new uint8_t[packetMaskMax * kNumMaskBytesL1];
FecMaskType fec_mask_type = kMaskTypes[mask_type_idx];
for (uint32_t numMediaPackets = 1;
numMediaPackets <= packetMaskMax;
numMediaPackets++) {
for (uint32_t numMediaPackets = 1; numMediaPackets <= packetMaskMax;
numMediaPackets++) {
internal::PacketMaskTable mask_table(fec_mask_type, numMediaPackets);
for (uint32_t numFecPackets = 1;
numFecPackets <= numMediaPackets &&
numFecPackets <= packetMaskMax;
numFecPackets++) {
numFecPackets <= numMediaPackets && numFecPackets <= packetMaskMax;
numFecPackets++) {
// Loop over numImpPackets: usually <= (0.3*numMediaPackets).
// For this test we check up to ~ (0.5*numMediaPackets).
uint32_t maxNumImpPackets = numMediaPackets / 2 + 1;
for (uint32_t numImpPackets = 0;
numImpPackets <= maxNumImpPackets &&
numImpPackets <= packetMaskMax;
numImpPackets++) {
for (uint32_t numImpPackets = 0; numImpPackets <= maxNumImpPackets &&
numImpPackets <= packetMaskMax;
numImpPackets++) {
uint8_t protectionFactor = static_cast<uint8_t>
(numFecPackets * 255 / numMediaPackets);
uint8_t protectionFactor =
static_cast<uint8_t>(numFecPackets * 255 / numMediaPackets);
const uint32_t maskBytesPerFecPacket =
(numMediaPackets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
@ -142,18 +141,15 @@ int main() {
memset(packetMask, 0, numMediaPackets * maskBytesPerFecPacket);
// Transfer packet masks from bit-mask to byte-mask.
internal::GeneratePacketMasks(numMediaPackets,
numFecPackets,
numImpPackets,
kUseUnequalProtection,
mask_table,
packetMask);
internal::GeneratePacketMasks(numMediaPackets, numFecPackets,
numImpPackets, kUseUnequalProtection,
mask_table, packetMask);
#ifdef VERBOSE_OUTPUT
printf("%u media packets, %u FEC packets, %u numImpPackets, "
"loss rate = %.2f \n",
numMediaPackets, numFecPackets, numImpPackets,
lossRate[lossRateIdx]);
"loss rate = %.2f \n",
numMediaPackets, numFecPackets, numImpPackets,
lossRate[lossRateIdx]);
printf("Packet mask matrix \n");
#endif
@ -199,13 +195,13 @@ int main() {
}
// Construct media packets.
for (uint32_t i = 0; i < numMediaPackets; ++i) {
for (uint32_t i = 0; i < numMediaPackets; ++i) {
mediaPacket = new ForwardErrorCorrection::Packet;
mediaPacketList.push_back(mediaPacket);
mediaPacket->length =
static_cast<uint16_t>((static_cast<float>(rand()) /
RAND_MAX) * (IP_PACKET_SIZE - 12 -
28 - ForwardErrorCorrection::PacketOverhead()));
mediaPacket->length = static_cast<uint16_t>(
(static_cast<float>(rand()) / RAND_MAX) *
(IP_PACKET_SIZE - 12 - 28 -
ForwardErrorCorrection::PacketOverhead()));
if (mediaPacket->length < 12) {
mediaPacket->length = 12;
}
@ -236,9 +232,8 @@ int main() {
ModuleRTPUtility::AssignUWord32ToBuffer(&mediaPacket->data[8],
ssrc);
// Generate random values for payload
for (int32_t j = 12; j < mediaPacket->length; ++j) {
mediaPacket->data[j] =
static_cast<uint8_t> (rand() % 256);
for (int32_t j = 12; j < mediaPacket->length; ++j) {
mediaPacket->data[j] = static_cast<uint8_t>(rand() % 256);
}
seqNum++;
}
@ -253,43 +248,42 @@ int main() {
if (fecPacketList.size() != numFecPackets) {
printf("Error: we requested %u FEC packets, "
"but GenerateFEC() produced %u\n",
numFecPackets,
static_cast<uint32_t>(fecPacketList.size()));
"but GenerateFEC() produced %u\n",
numFecPackets,
static_cast<uint32_t>(fecPacketList.size()));
return -1;
}
memset(mediaLossMask, 0, sizeof(mediaLossMask));
ForwardErrorCorrection::PacketList::iterator
mediaPacketListItem = mediaPacketList.begin();
ForwardErrorCorrection::PacketList::iterator mediaPacketListItem =
mediaPacketList.begin();
ForwardErrorCorrection::ReceivedPacket* receivedPacket;
uint32_t mediaPacketIdx = 0;
while (mediaPacketListItem != mediaPacketList.end()) {
mediaPacket = *mediaPacketListItem;
// We want a value between 0 and 1.
const float lossRandomVariable = (static_cast<float>(rand()) /
(RAND_MAX));
const float lossRandomVariable =
(static_cast<float>(rand()) / (RAND_MAX));
if (lossRandomVariable >= lossRate[lossRateIdx]) {
mediaLossMask[mediaPacketIdx] = 1;
receivedPacket =
new ForwardErrorCorrection::ReceivedPacket;
receivedPacket = new ForwardErrorCorrection::ReceivedPacket;
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
receivedPacketList.push_back(receivedPacket);
receivedPacket->pkt->length = mediaPacket->length;
memcpy(receivedPacket->pkt->data, mediaPacket->data,
mediaPacket->length);
receivedPacket->seqNum =
receivedPacket->seq_num =
ModuleRTPUtility::BufferToUWord16(&mediaPacket->data[2]);
receivedPacket->isFec = false;
receivedPacket->is_fec = false;
}
mediaPacketIdx++;
++mediaPacketListItem;
}
memset(fecLossMask, 0, sizeof(fecLossMask));
ForwardErrorCorrection::PacketList::iterator
fecPacketListItem = fecPacketList.begin();
ForwardErrorCorrection::PacketList::iterator fecPacketListItem =
fecPacketList.begin();
ForwardErrorCorrection::Packet* fecPacket;
uint32_t fecPacketIdx = 0;
while (fecPacketListItem != fecPacketList.end()) {
@ -298,8 +292,7 @@ int main() {
(static_cast<float>(rand()) / (RAND_MAX));
if (lossRandomVariable >= lossRate[lossRateIdx]) {
fecLossMask[fecPacketIdx] = 1;
receivedPacket =
new ForwardErrorCorrection::ReceivedPacket;
receivedPacket = new ForwardErrorCorrection::ReceivedPacket;
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
receivedPacketList.push_back(receivedPacket);
@ -308,8 +301,8 @@ int main() {
memcpy(receivedPacket->pkt->data, fecPacket->data,
fecPacket->length);
receivedPacket->seqNum = seqNum;
receivedPacket->isFec = true;
receivedPacket->seq_num = seqNum;
receivedPacket->is_fec = true;
receivedPacket->ssrc = ssrc;
fecMaskList.push_back(fecPacketMasks[fecPacketIdx]);
@ -352,7 +345,7 @@ int main() {
// Recovery possible. Restart search.
mediaLossMask[recoveryPosition] = 1;
fecMaskIt = fecMaskList.begin();
} else if (hammingDist == 0) {
} else if (hammingDist == 0) {
// FEC packet cannot provide further recovery.
fecMaskList.erase(itemToDelete);
}
@ -367,9 +360,9 @@ int main() {
// For error-checking frame completion.
bool fecPacketReceived = false;
while (!receivedPacketList.empty()) {
uint32_t numPacketsToDecode = static_cast<uint32_t>
((static_cast<float>(rand()) / RAND_MAX) *
receivedPacketList.size() + 0.5);
uint32_t numPacketsToDecode = static_cast<uint32_t>(
(static_cast<float>(rand()) / RAND_MAX) *
receivedPacketList.size() + 0.5);
if (numPacketsToDecode < 1) {
numPacketsToDecode = 1;
}
@ -378,17 +371,16 @@ int main() {
if (fecPacketReceived == false) {
ForwardErrorCorrection::ReceivedPacketList::iterator
toDecodeIt = toDecodeList.begin();
toDecodeIt = toDecodeList.begin();
while (toDecodeIt != toDecodeList.end()) {
receivedPacket = *toDecodeIt;
if (receivedPacket->isFec) {
if (receivedPacket->is_fec) {
fecPacketReceived = true;
}
++toDecodeIt;
}
}
if (fec.DecodeFEC(&toDecodeList, &recoveredPacketList)
!= 0) {
if (fec.DecodeFEC(&toDecodeList, &recoveredPacketList) != 0) {
printf("Error: DecodeFEC() failed\n");
return -1;
}
@ -403,7 +395,7 @@ int main() {
if (mediaLossMask[mediaPacketIdx] == 1) {
// Should have recovered this packet.
ForwardErrorCorrection::RecoveredPacketList::iterator
recoveredPacketListItem = recoveredPacketList.begin();
recoveredPacketListItem = recoveredPacketList.begin();
if (recoveredPacketListItem == recoveredPacketList.end()) {
printf("Error: insufficient number of recovered packets.\n");
@ -415,13 +407,13 @@ int main() {
if (recoveredPacket->pkt->length != mediaPacket->length) {
printf("Error: recovered packet length not identical to "
"original media packet\n");
"original media packet\n");
return -1;
}
if (memcmp(recoveredPacket->pkt->data, mediaPacket->data,
mediaPacket->length) != 0) {
printf("Error: recovered packet payload not identical to "
"original media packet\n");
"original media packet\n");
return -1;
}
delete recoveredPacket;
@ -455,7 +447,7 @@ int main() {
// Delete received packets we didn't pass to DecodeFEC(), due to
// early frame completion.
ForwardErrorCorrection::ReceivedPacketList::iterator
receivedPacketIt = receivedPacketList.begin();
receivedPacketIt = receivedPacketList.begin();
while (receivedPacketIt != receivedPacketList.end()) {
receivedPacket = *receivedPacketIt;
delete receivedPacket;
@ -469,11 +461,11 @@ int main() {
}
timeStamp += 90000 / 30;
} // loop over numImpPackets
} // loop over FecPackets
} // loop over numMediaPackets
delete [] packetMask;
} // loop over FecPackets
} // loop over numMediaPackets
delete[] packetMask;
} // loop over loss rates
} // loop over mask types
} // loop over mask types
// Have DecodeFEC free allocated memory.
fec.ResetState(&recoveredPacketList);