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:
parent
5c1948dfaf
commit
9919ad5caf
File diff suppressed because it is too large
Load Diff
@ -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_
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user