Remove list wrapper from FEC code.

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1489 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pwestin@webrtc.org 2012-01-20 06:59:06 +00:00
parent 9165f1fe91
commit 95cf47932d
7 changed files with 1596 additions and 1799 deletions

File diff suppressed because it is too large Load Diff

View File

@ -11,178 +11,222 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
#include <list>
#include <vector>
#include "typedefs.h"
#include "rtp_rtcp_defines.h"
#include "list_wrapper.h"
namespace webrtc {
// Forward declaration.
struct 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).
*/
class ForwardErrorCorrection
{
public:
class ForwardErrorCorrection {
public:
// Maximum number of media packets we can protect
static const int kMaxMediaPackets = 48;
// Maximum number of media packets we can protect
static const int kMaxMediaPackets = 48;
struct Packet {
uint16_t length; /**> Length of packet in bytes. */
uint8_t data[IP_PACKET_SIZE]; /**> Packet data. */
};
/**
* The ListWrapper parameters of #GenerateFEC() should reference structs of this type.
*/
struct Packet
{
WebRtc_UWord16 length; /**> Length of packet in bytes. */
WebRtc_UWord8 data[IP_PACKET_SIZE]; /**> Packet data. */
};
/**
* 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.
*/
struct ReceivedPacket {
uint16_t seqNum; /**> Sequence number of packet. */
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 lastMediaPktInFrame; /**> Set to true to mark the last media packet in
the frame and false otherwise. */
Packet* pkt; /**> Pointer to the packet storage. */
};
/**
* 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.
*/
struct ReceivedPacket
{
WebRtc_UWord16 seqNum; /**> Sequence number of packet. */
WebRtc_UWord32 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 lastMediaPktInFrame; /**> Set to true to mark the last media packet in the
frame and false otherwise. */
Packet* pkt; /**> Pointer to the packet storage. */
};
/**
* The recovered list parameter of #DecodeFEC() will reference structs of
* this type.
*/
struct RecoveredPacket {
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. */
uint16_t seqNum; /**> Sequence number of the packet. This is mostly for
implementation convenience but could be utilized
by the user if so desired. */
Packet* pkt; /**> Pointer to the packet storage. */
};
/**
* The recovered list parameter of #DecodeFEC() will reference structs of this type.
*/
struct RecoveredPacket
{
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. */
WebRtc_UWord16 seqNum; /**> Sequence number of the packet. This is mostly for
implementation convenience but could be utilized by the
user if so desired. */
Packet* pkt; /**> Pointer to the packet storage. */
};
/**
* \param[in] id Module ID
*/
ForwardErrorCorrection(int32_t id);
/**
* Constructor.
*
* \param[in] id Module ID
*/
ForwardErrorCorrection(WebRtc_Word32 id);
virtual ~ForwardErrorCorrection();
/**
* Destructor. Before freeing an instance of the class, #DecodeFEC() must be called
* in a particular fashion to free outstanding memory. Refer to #DecodeFEC().
*/
virtual ~ForwardErrorCorrection();
/**
* Generates a list of FEC packets from supplied media packets.
*
* \param[in] mediaPacketList List of media packets to protect, of type
* #Packet. All packets must belong to the
* same frame and the list must not be empty.
* \param[in] protectionFactor FEC protection overhead in the [0, 255]
* domain. To obtain 100% overhead, or an
* equal number of FEC packets as media
* packets, use 255.
* \param[in] numImportantPackets The number of "important" packets in the
* frame. These packets may receive greater
* protection than the remaining packets. The
* important packets must be located at the
* start of the media packet list. For codecs
* with data partitioning, the important
* packets may correspond to first partition
* packets.
* \param[in] useUnequalProtection Parameter to enable/disable unequal
* protection (UEP) across packets. Enabling
* UEP will allocate more protection to the
* numImportantPackets from the start of the
* mediaPacketList.
* \param[out] fecPacketList List of FEC packets, of type #Packet. Must
* be empty on entry. The memory available
* through the list will be valid until the
* next call to GenerateFEC().
*
* \return 0 on success, -1 on failure.
*/
int32_t GenerateFEC(const std::list<Packet*>& mediaPacketList,
uint8_t protectionFactor,
int numImportantPackets,
bool useUnequalProtection,
std::list<Packet*>* fecPacketList);
/**
* Generates a list of FEC packets from supplied media packets.
*
* \param[in] mediaPacketList List of media packets to protect, of type #Packet.
* All packets must belong to the same frame and the
* list must not be empty.
* \param[in] protectionFactor FEC protection overhead in the [0, 255] domain. To
* obtain 100% overhead, or an equal number of FEC
* packets as media packets, use 255.
* \param[in] numImportantPackets The number of "important" packets in the frame.
* These packets may receive greater protection than
* the remaining packets. The important packets must
* be located at the start of the media packet list.
* For codecs with data partitioning, the important
* packets may correspond to first partition packets.
* \param[in] useUnequalProtection Parameter to enable/disable unequal protection
* (UEP) across packets. Enabling UEP will allocate more
* protection to the numImportantPackets from
* the start of the mediaPacketList.
* \param[out] fecPacketList List of FEC packets, of type #Packet. Must be empty
* on entry. The memory available through the list
* will be valid until the next call to GenerateFEC().
*
* \return 0 on success, -1 on failure.
*/
WebRtc_Word32 GenerateFEC(const ListWrapper& mediaPacketList,
WebRtc_UWord8 protectionFactor,
int numImportantPackets,
bool useUnequalProtection,
ListWrapper& fecPacketList);
/**
* Decodes a list of media and FEC packets. It will parse the input received
* packet list, storing FEC packets internally and inserting media packets to
* the output recovered packet list. The recovered list will be sorted by
* as cending sequence number and have duplicates removed. The function
* should be called as new packets arrive, with the recovered list being
* progressively assembled with each call. The received packet list will be
* empty at output.\n
*
* The user will allocate packets submitted through the received list. The
* function will handle allocation of recovered packets and optionally
* deleting of all packet memory. The user may delete the recovered list
* packets, in which case they must remove deleted packets from the
* recovered list.\n
*
* Before deleting an instance of the class, call the function with an empty
* received packet list and the completion parameter set to true. This will
* free any outstanding memory.
*
* \param[in] receivedPacketList List of new received packets, of type
* #ReceivedPacket, beloning to a single
* frame. At output the list will be empty,
* with packets either stored internally,
* or accessible through the recovered list.
* \param[out] recoveredPacketList List of recovered media packets, of type
* #RecoveredPacket, belonging to a single
* frame. The memory available through the
* list will be valid until the next call to
* DecodeFEC() in which the completion
* parameter is set to true.
* \param[in] lastFECSeqNum Estimated last seqNumber before this frame.
* \param[in,out] frameComplete Set to true on input to indicate the start
* of a new frame. On output, this will be
* set to true if all media packets in the
* frame have been recovered. Note that the
* frame may be complete without this
* parameter having been set, as it may not
* always be possible to determine frame
* completion.
*
* \return 0 on success, -1 on failure.
*/
int32_t DecodeFEC(std::list<ReceivedPacket*>* receivedPacketList,
std::list<RecoveredPacket*>* recoveredPacketList,
uint16_t lastFECSeqNum,
bool& frameComplete);
/**
* 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();
/**
* Decodes a list of media and FEC packets. It will parse the input received packet
* list, storing FEC packets internally and inserting media packets to the output
* recovered packet list. The recovered list will be sorted by ascending sequence
* number and have duplicates removed. The function should be called as new packets
* arrive, with the recovered list being progressively assembled with each call.
* The received packet list will be empty at output.\n
*
* The user will allocate packets submitted through the received list. The function
* will handle allocation of recovered packets and optionally deleting of all packet
* memory. The user may delete the recovered list packets, in which case they must
* remove deleted packets from the recovered list.\n
*
* Before deleting an instance of the class, call the function with an empty received
* packet list and the completion parameter set to true. This will free any
* outstanding memory.
*
* \param[in] receivedPacketList List of new received packets, of type
* #ReceivedPacket, beloning to a single frame. At
* output the list will be empty, with packets
* either stored internally, or accessible through
* the recovered list.
* \param[out] recoveredPacketList List of recovered media packets, of type
* #RecoveredPacket, belonging to a single frame.
* The memory available through the list will be
* valid until the next call to DecodeFEC() in which
* the completion parameter is set to true.
* \param[in] lastFECSeqNum Estimated last seqNumber before this frame
* \param[in,out] frameComplete Set to true on input to indicate the start of a
* new frame. On output, this will be set to true if
* all media packets in the frame have been
* recovered. Note that the frame may be complete
* without this parameter having been set, as it may
* not always be possible to determine frame
* completion.
*
* \return 0 on success, -1 on failure.
*/
WebRtc_Word32 DecodeFEC(ListWrapper& receivedPacketList,
ListWrapper& recoveredPacketList,
WebRtc_UWord16 lastFECSeqNum,
bool& frameComplete);
/**
* Gets the size in bytes of the FEC/ULP headers, which must be accounted for as
* packet overhead.
* \return Packet overhead in bytes.
*/
static WebRtc_UWord16 PacketOverhead();
private:
// True if first is <= than second.
static bool CompareRecoveredPackets(RecoveredPacket* first,
RecoveredPacket* second);
private:
WebRtc_Word32 _id;
Packet* _generatedFecPackets;
ListWrapper _fecPacketList;
WebRtc_UWord16 _seqNumBase;
bool _lastMediaPacketReceived;
bool _fecPacketReceived;
void GenerateFecUlpHeaders(const std::list<Packet*>& mediaPacketList,
uint8_t* packetMask,
uint32_t numFecPackets);
void GenerateFecBitStrings(const std::list<Packet*>& mediaPacketList,
uint8_t* packetMask,
uint32_t numFecPackets);
// Reset internal states from last frame and clear the recoveredPacketList.
void ResetState(std::list<RecoveredPacket*>* recoveredPacketList);
// Insert received packets into FEC or recovered list.
void InsertPackets(std::list<ReceivedPacket*>* receivedPacketList,
std::list<RecoveredPacket*>* recoveredPacketList);
// Insert media packet into recovered packet list. We delete duplicates.
void InsertMediaPacket(ReceivedPacket* rxPacket,
std::list<RecoveredPacket*>* recoveredPacketList);
// Insert packet into FEC list. We delete duplicates.
void InsertFECPacket(ReceivedPacket* rxPacket);
// Insert into recovered list in correct position.
void InsertRecoveredPacket(
RecoveredPacket* recPacketToInsert,
std::list<RecoveredPacket*>* recoveredPacketList);
// Attempt to recover missing packets.
void AttemptRecover(std::list<RecoveredPacket*>* recoveredPacketList);
// Recover a missing packet.
void RecoverPacket(const FecPacket& fecPacket,
RecoveredPacket* recPacketToInsert);
// Get number of protected packet in the fecPacket.
uint32_t NumberOfProtectedPackets(
const FecPacket& fecPacket,
std::list<RecoveredPacket*>* recoveredPacketList);
int32_t _id;
std::vector<Packet> _generatedFecPackets;
std::list<FecPacket*> _fecPacketList;
uint16_t _seqNumBase;
bool _lastMediaPacketReceived;
bool _fecPacketReceived;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_

View File

@ -16,42 +16,35 @@
// RFC 5109
namespace webrtc {
ReceiverFEC::ReceiverFEC(const WebRtc_Word32 id, RTPReceiverVideo* owner) :
_owner(owner),
_fec(new ForwardErrorCorrection(id)),
_payloadTypeFEC(-1),
_lastFECSeqNum(0),
_frameComplete(true)
{
ReceiverFEC::ReceiverFEC(const WebRtc_Word32 id, RTPReceiverVideo* owner)
: _owner(owner),
_fec(new ForwardErrorCorrection(id)),
_payloadTypeFEC(-1),
_lastFECSeqNum(0),
_frameComplete(true) {
}
ReceiverFEC::~ReceiverFEC()
{
// Clean up DecodeFEC()
while (_receivedPacketList.First() != NULL)
{
ForwardErrorCorrection::ReceivedPacket* receivedPacket =
static_cast<ForwardErrorCorrection::ReceivedPacket*>(
_receivedPacketList.First()->GetItem());
delete receivedPacket->pkt;
delete receivedPacket;
receivedPacket = NULL;
_receivedPacketList.PopFront();
}
assert(_receivedPacketList.Empty());
ReceiverFEC::~ReceiverFEC() {
// Clean up DecodeFEC()
while (!_receivedPacketList.empty()){
ForwardErrorCorrection::ReceivedPacket* receivedPacket =
_receivedPacketList.front();
delete receivedPacket->pkt;
delete receivedPacket;
_receivedPacketList.pop_front();
}
assert(_receivedPacketList.empty());
if (_fec != NULL)
{
bool frameComplete = true;
_fec->DecodeFEC(_receivedPacketList, _recoveredPacketList,_lastFECSeqNum, frameComplete);
delete _fec;
}
if (_fec != NULL) {
bool frameComplete = true;
_fec->DecodeFEC(&_receivedPacketList, &_recoveredPacketList,_lastFECSeqNum,
frameComplete);
delete _fec;
}
}
void
ReceiverFEC::SetPayloadTypeFEC(const WebRtc_Word8 payloadType)
{
_payloadTypeFEC = payloadType;
void ReceiverFEC::SetPayloadTypeFEC(const WebRtc_Word8 payloadType) {
_payloadTypeFEC = payloadType;
}
/*
@ -84,279 +77,242 @@ RFC 2198 RTP Payload for Redundant Audio Data September 1997
block excluding header.
*/
WebRtc_Word32
ReceiverFEC::AddReceivedFECPacket(const WebRtcRTPHeader* rtpHeader,
const WebRtc_UWord8* incomingRtpPacket,
const WebRtc_UWord16 payloadDataLength,
bool& FECpacket,
bool oldPacket)
{
if (_payloadTypeFEC == -1)
{
return -1;
WebRtc_Word32 ReceiverFEC::AddReceivedFECPacket(
const WebRtcRTPHeader* rtpHeader,
const WebRtc_UWord8* incomingRtpPacket,
const WebRtc_UWord16 payloadDataLength,
bool& FECpacket,
bool oldPacket) {
if (_payloadTypeFEC == -1) {
return -1;
}
WebRtc_UWord8 REDHeaderLength = 1;
// Add to list without RED header, aka a virtual RTP packet
// we remove the RED header
ForwardErrorCorrection::ReceivedPacket* receivedPacket =
new ForwardErrorCorrection::ReceivedPacket;
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
// get payload type from RED header
WebRtc_UWord8 payloadType =
incomingRtpPacket[rtpHeader->header.headerLength] & 0x7f;
// use the payloadType to decide if it's FEC or coded data
if(_payloadTypeFEC == payloadType) {
receivedPacket->isFec = true;
FECpacket = true;
// We don't need to parse old FEC packets.
// Old FEC packets are sent to jitter buffer as empty packets in the
// callback in rtp_receiver_video.
if (oldPacket) return 0;
} else {
receivedPacket->isFec = false;
FECpacket = false;
}
receivedPacket->lastMediaPktInFrame = rtpHeader->header.markerBit;
receivedPacket->seqNum = rtpHeader->header.sequenceNumber;
WebRtc_UWord16 blockLength = 0;
if(incomingRtpPacket[rtpHeader->header.headerLength] & 0x80) {
// f bit set in RED header
REDHeaderLength = 4;
WebRtc_UWord16 timestampOffset =
(incomingRtpPacket[rtpHeader->header.headerLength + 1]) << 8;
timestampOffset += incomingRtpPacket[rtpHeader->header.headerLength+2];
timestampOffset = timestampOffset >> 2;
if(timestampOffset != 0) {
// sanity timestampOffset must be 0
assert(false);
return -1;
}
blockLength =
(0x03 & incomingRtpPacket[rtpHeader->header.headerLength + 2]) << 8;
blockLength += (incomingRtpPacket[rtpHeader->header.headerLength + 3]);
// check next RED header
if(incomingRtpPacket[rtpHeader->header.headerLength+4] & 0x80) {
// more than 2 blocks in packet not supported
assert(false);
return -1;
}
if(blockLength > payloadDataLength - REDHeaderLength) {
// block length longer than packet
assert(false);
return -1;
}
}
ForwardErrorCorrection::ReceivedPacket* secondReceivedPacket = 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);
// replace the RED payload type
receivedPacket->pkt->data[1] &= 0x80; // reset the payload
receivedPacket->pkt->data[1] += payloadType; // set the media payload type
// copy the payload data
memcpy(receivedPacket->pkt->data + rtpHeader->header.headerLength,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength,
blockLength);
receivedPacket->pkt->length = blockLength;
secondReceivedPacket = new ForwardErrorCorrection::ReceivedPacket;
secondReceivedPacket->pkt = new ForwardErrorCorrection::Packet;
secondReceivedPacket->isFec = true;
secondReceivedPacket->lastMediaPktInFrame = false;
secondReceivedPacket->seqNum = rtpHeader->header.sequenceNumber;
// copy the FEC payload data
memcpy(secondReceivedPacket->pkt->data,
incomingRtpPacket + rtpHeader->header.headerLength +
REDHeaderLength + blockLength,
payloadDataLength - REDHeaderLength - blockLength);
secondReceivedPacket->pkt->length = payloadDataLength - REDHeaderLength -
blockLength;
} else if(receivedPacket->isFec) {
// 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]);
} else {
// copy the RTP header
memcpy(receivedPacket->pkt->data,
incomingRtpPacket,
rtpHeader->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
// copy the media payload data
memcpy(receivedPacket->pkt->data + rtpHeader->header.headerLength,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength,
payloadDataLength - REDHeaderLength);
receivedPacket->pkt->length = rtpHeader->header.headerLength +
payloadDataLength - REDHeaderLength;
}
if(receivedPacket->isFec) {
AddReceivedFECInfo(rtpHeader, NULL, FECpacket);
}
if(receivedPacket->pkt->length == 0) {
delete receivedPacket->pkt;
delete receivedPacket;
return 0;
}
// Send any old media packets to jitter buffer, don't push them onto
// received list for FEC decoding (we don't do FEC decoding on old packets).
if (oldPacket && receivedPacket->isFec == false) {
if (ParseAndReceivePacket(receivedPacket->pkt) != 0) {
return -1;
}
WebRtc_UWord8 REDHeaderLength = 1;
delete receivedPacket->pkt;
delete receivedPacket;
} else {
_receivedPacketList.push_back(receivedPacket);
if (secondReceivedPacket) {
_receivedPacketList.push_back(secondReceivedPacket);
}
}
return 0;
}
// Add to list without RED header, aka a virtual RTP packet
// we remove the RED header
ForwardErrorCorrection::ReceivedPacket* receivedPacket = new ForwardErrorCorrection::ReceivedPacket;
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
void ReceiverFEC::AddReceivedFECInfo(const WebRtcRTPHeader* rtpHeader,
const WebRtc_UWord8* incomingRtpPacket,
bool& FECpacket) {
// store the highest FEC seq num received
if (_lastFECSeqNum >= rtpHeader->header.sequenceNumber) {
if (_lastFECSeqNum > 0xff00 && rtpHeader->header.sequenceNumber < 0x0ff ) {
// wrap
_lastFECSeqNum = rtpHeader->header.sequenceNumber;
} else {
// old seqNum
}
} else {
// check for a wrap
if(rtpHeader->header.sequenceNumber > 0xff00 && _lastFECSeqNum < 0x0ff ) {
// old seqNum
} else {
_lastFECSeqNum = rtpHeader->header.sequenceNumber;
}
}
if (incomingRtpPacket) {
// get payload type from RED header
WebRtc_UWord8 payloadType = incomingRtpPacket[rtpHeader->header.headerLength] & 0x7f;
WebRtc_UWord8 payloadType =
incomingRtpPacket[rtpHeader->header.headerLength] & 0x7f;
// use the payloadType to decide if it's FEC or coded data
if(_payloadTypeFEC == payloadType)
{
receivedPacket->isFec = true;
FECpacket = true;
// We don't need to parse old FEC packets.
// Old FEC packets are sent to jitter buffer as empty packets in the
// callback in rtp_receiver_video.
if (oldPacket)
return 0;
} else
{
receivedPacket->isFec = false;
FECpacket = false;
if(_payloadTypeFEC == payloadType) {
FECpacket = true;
} else {
FECpacket = false;
}
receivedPacket->lastMediaPktInFrame = rtpHeader->header.markerBit;
receivedPacket->seqNum = rtpHeader->header.sequenceNumber;
WebRtc_UWord16 blockLength = 0;
if(incomingRtpPacket[rtpHeader->header.headerLength] & 0x80)
{
// f bit set in RED header
REDHeaderLength = 4;
WebRtc_UWord16 timestampOffset = (incomingRtpPacket[rtpHeader->header.headerLength + 1]) << 8;
timestampOffset += incomingRtpPacket[rtpHeader->header.headerLength+2];
timestampOffset = timestampOffset >> 2;
if(timestampOffset != 0)
{
// sanity timestampOffset must be 0
assert(false);
return -1;
}
blockLength = (0x03 & incomingRtpPacket[rtpHeader->header.headerLength + 2]) << 8;
blockLength += (incomingRtpPacket[rtpHeader->header.headerLength + 3]);
// check next RED header
if(incomingRtpPacket[rtpHeader->header.headerLength+4] & 0x80)
{
// more than 2 blocks in packet not supported
assert(false);
return -1;
}
if(blockLength > payloadDataLength - REDHeaderLength)
{
// block length longer than packet
assert(false);
return -1;
}
}
ForwardErrorCorrection::ReceivedPacket* secondReceivedPacket = 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);
// replace the RED payload type
receivedPacket->pkt->data[1] &= 0x80; // reset the payload
receivedPacket->pkt->data[1] += payloadType; // set the media payload type
// copy the payload data
memcpy(receivedPacket->pkt->data + rtpHeader->header.headerLength,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength,
blockLength);
receivedPacket->pkt->length = blockLength;
secondReceivedPacket = new ForwardErrorCorrection::ReceivedPacket;
secondReceivedPacket->pkt = new ForwardErrorCorrection::Packet;
secondReceivedPacket->isFec = true;
secondReceivedPacket->lastMediaPktInFrame = false;
secondReceivedPacket->seqNum = rtpHeader->header.sequenceNumber;
// copy the FEC payload data
memcpy(secondReceivedPacket->pkt->data,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength +
blockLength, payloadDataLength - REDHeaderLength - blockLength);
secondReceivedPacket->pkt->length = payloadDataLength - REDHeaderLength -
blockLength;
} else if(receivedPacket->isFec)
{
// 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]);
}else
{
// copy the RTP header
memcpy(receivedPacket->pkt->data,
incomingRtpPacket,
rtpHeader->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
// copy the media payload data
memcpy(receivedPacket->pkt->data + rtpHeader->header.headerLength,
incomingRtpPacket + rtpHeader->header.headerLength + REDHeaderLength,
payloadDataLength - REDHeaderLength);
receivedPacket->pkt->length = rtpHeader->header.headerLength +
payloadDataLength - REDHeaderLength;
}
if(receivedPacket->isFec)
{
AddReceivedFECInfo(rtpHeader, NULL, FECpacket);
}
if(receivedPacket->pkt->length == 0)
{
delete receivedPacket->pkt;
delete receivedPacket;
return 0;
}
// Send any old media packets to jitter buffer, don't push them onto
// received list for FEC decoding (we don't do FEC decoding on old packets).
if (oldPacket && receivedPacket->isFec == false)
{
if (ParseAndReceivePacket(receivedPacket->pkt) != 0) {
return -1;
}
delete receivedPacket->pkt;
delete receivedPacket;
}
else
{
_receivedPacketList.PushBack(receivedPacket);
if (secondReceivedPacket)
{
_receivedPacketList.PushBack(secondReceivedPacket);
}
}
return 0;
}
}
void
ReceiverFEC::AddReceivedFECInfo(const WebRtcRTPHeader* rtpHeader,
const WebRtc_UWord8* incomingRtpPacket,
bool& FECpacket)
{
// store the highest FEC seq num received
if(_lastFECSeqNum >= rtpHeader->header.sequenceNumber)
{
if(_lastFECSeqNum > 0xff00 && rtpHeader->header.sequenceNumber < 0x0ff ) //detect wrap around
{
// wrap
_lastFECSeqNum = rtpHeader->header.sequenceNumber;
} else
{
// old seqNum
}
}else
{
// check for a wrap
if(rtpHeader->header.sequenceNumber > 0xff00 && _lastFECSeqNum < 0x0ff ) //detect wrap around
{
// old seqNum
}else
{
_lastFECSeqNum = rtpHeader->header.sequenceNumber;
}
WebRtc_Word32 ReceiverFEC::ProcessReceivedFEC(const bool forceFrameDecode) {
if (!_receivedPacketList.empty()) {
if (_fec->DecodeFEC(&_receivedPacketList, &_recoveredPacketList,
_lastFECSeqNum, _frameComplete) != 0) {
return -1;
}
assert(_receivedPacketList.empty());
}
if (forceFrameDecode) {
_frameComplete = true;
}
if (_frameComplete) {
while (!_recoveredPacketList.empty()) {
ForwardErrorCorrection::RecoveredPacket* recoveredPacket =
_recoveredPacketList.front();
if(incomingRtpPacket)
{
// get payload type from RED header
WebRtc_UWord8 payloadType = incomingRtpPacket[rtpHeader->header.headerLength] & 0x7f;
// use the payloadType to decide if it's FEC or coded data
if(_payloadTypeFEC == payloadType)
{
FECpacket = true;
} else
{
FECpacket = false;
}
if (ParseAndReceivePacket(recoveredPacket->pkt) != 0) {
return -1;
}
delete recoveredPacket->pkt;
delete recoveredPacket;
_recoveredPacketList.pop_front();
}
}
WebRtc_Word32
ReceiverFEC::ProcessReceivedFEC(const bool forceFrameDecode)
{
if (!_receivedPacketList.Empty())
{
if (_fec->DecodeFEC(_receivedPacketList,
_recoveredPacketList,
_lastFECSeqNum,
_frameComplete) != 0)
{
return -1;
}
assert(_receivedPacketList.Empty());
}
if (forceFrameDecode)
{
_frameComplete = true;
}
if (_frameComplete)
{
while (_recoveredPacketList.First() != NULL)
{
ForwardErrorCorrection::RecoveredPacket* recoveredPacket =
static_cast<ForwardErrorCorrection::RecoveredPacket*>(_recoveredPacketList.First()->GetItem());
if (ParseAndReceivePacket(recoveredPacket->pkt) != 0) {
return -1;
}
delete recoveredPacket->pkt;
delete recoveredPacket;
recoveredPacket = NULL;
_recoveredPacketList.PopFront();
}
assert(_recoveredPacketList.Empty());
}
return 0;
assert(_recoveredPacketList.empty());
}
return 0;
}
int ReceiverFEC::ParseAndReceivePacket(
const ForwardErrorCorrection::Packet* packet) {
WebRtcRTPHeader header;
memset(&header, 0, sizeof(header));
ModuleRTPUtility::RTPHeaderParser parser(packet->data,
packet->length);
packet->length);
if (!parser.Parse(header)) {
return -1;
}
if (_owner->ReceiveRecoveredPacketCallback(
&header,
&packet->data[header.header.headerLength],
packet->length - header.header.headerLength) != 0) {
&header,
&packet->data[header.header.headerLength],
packet->length - header.header.headerLength) != 0) {
return -1;
}
return 0;

View File

@ -11,12 +11,13 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVER_FEC_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVER_FEC_H_
#include <list>
#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 "list_wrapper.h"
namespace webrtc {
class RTPReceiverVideo;
@ -45,8 +46,8 @@ private:
int ParseAndReceivePacket(const ForwardErrorCorrection::Packet* packet);
RTPReceiverVideo* _owner;
ForwardErrorCorrection* _fec;
ListWrapper _receivedPacketList;
ListWrapper _recoveredPacketList;
std::list<ForwardErrorCorrection::ReceivedPacket*> _receivedPacketList;
std::list<ForwardErrorCorrection::RecoveredPacket*> _recoveredPacketList;
WebRtc_Word8 _payloadTypeFEC;
WebRtc_UWord16 _lastFECSeqNum;
bool _frameComplete;

View File

@ -100,34 +100,29 @@ RTPSenderVideo::VideoCodecType() const
return _videoType;
}
WebRtc_Word32
RTPSenderVideo::RegisterVideoPayload(
const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 maxBitRate,
ModuleRTPUtility::Payload*& payload)
{
CriticalSectionScoped cs(_sendVideoCritsect);
WebRtc_Word32 RTPSenderVideo::RegisterVideoPayload(
const char payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 maxBitRate,
ModuleRTPUtility::Payload*& payload) {
CriticalSectionScoped cs(_sendVideoCritsect);
RtpVideoCodecTypes videoType = kRtpNoVideo;
if (ModuleRTPUtility::StringCompare(payloadName, "VP8",3))
{
videoType = kRtpVp8Video;
} else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4))
{
videoType = kRtpNoVideo;
}else
{
videoType = kRtpNoVideo;
return -1;
}
payload = new ModuleRTPUtility::Payload;
strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE);
payload->typeSpecific.Video.videoCodecType = videoType;
payload->typeSpecific.Video.maxRate = maxBitRate;
payload->audio = false;
return 0;
RtpVideoCodecTypes videoType = kRtpNoVideo;
if (ModuleRTPUtility::StringCompare(payloadName, "VP8",3)) {
videoType = kRtpVp8Video;
} else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) {
videoType = kRtpNoVideo;
} else {
videoType = kRtpNoVideo;
return -1;
}
payload = new ModuleRTPUtility::Payload;
strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; // Null terminate string.
payload->typeSpecific.Video.videoCodecType = videoType;
payload->typeSpecific.Video.maxRate = maxBitRate;
payload->audio = false;
return 0;
}
struct RtpPacket
@ -156,19 +151,17 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
ptrGenericFEC->pkt->length);
// Add packet to FEC list
_rtpPacketListFec.PushBack(ptrGenericFEC);
_rtpPacketListFec.push_back(ptrGenericFEC);
// FEC can only protect up to kMaxMediaPackets packets
if (static_cast<int>(_mediaPacketListFec.GetSize()) <
if (static_cast<int>(_mediaPacketListFec.size()) <
ForwardErrorCorrection::kMaxMediaPackets)
{
_mediaPacketListFec.PushBack(ptrGenericFEC->pkt);
_mediaPacketListFec.push_back(ptrGenericFEC->pkt);
}
// Last packet in frame
if (markerBit)
{
// Interface for FEC
ListWrapper fecPacketList;
// Retain the RTP header of the last media packet to construct FEC
// packet RTP headers.
@ -189,23 +182,22 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
ForwardErrorCorrection::kMaxMediaPackets;
}
std::list<ForwardErrorCorrection::Packet*> fecPacketList;
retVal = _fec.GenerateFEC(_mediaPacketListFec,
_fecProtectionFactor,
_numberFirstPartition,
_fecUseUepProtection,
fecPacketList);
&fecPacketList);
int fecOverheadSent = 0;
int videoSent = 0;
while(!_rtpPacketListFec.Empty())
while(!_rtpPacketListFec.empty())
{
WebRtc_UWord8 newDataBuffer[IP_PACKET_SIZE];
memset(newDataBuffer, 0, sizeof(newDataBuffer));
ListItem* item = _rtpPacketListFec.First();
RtpPacket* packetToSend =
static_cast<RtpPacket*>(item->GetItem());
RtpPacket* packetToSend = _rtpPacketListFec.front();
// Copy RTP header
memcpy(newDataBuffer, packetToSend->pkt->data,
@ -229,8 +221,8 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
packetToSend->pkt->length -
packetToSend->rtpHeaderLength);
_rtpPacketListFec.PopFront();
_mediaPacketListFec.PopFront();
_rtpPacketListFec.pop_front();
_mediaPacketListFec.pop_front();
// Send normal packet with RED header
int packetSuccess = _rtpSender.SendToNetwork(
@ -252,19 +244,15 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
delete packetToSend;
packetToSend = NULL;
}
assert(_mediaPacketListFec.Empty());
assert(_rtpPacketListFec.Empty());
assert(_mediaPacketListFec.empty());
assert(_rtpPacketListFec.empty());
while(!fecPacketList.Empty())
while(!fecPacketList.empty())
{
WebRtc_UWord8 newDataBuffer[IP_PACKET_SIZE];
ListItem* item = fecPacketList.First();
// Build FEC packets
ForwardErrorCorrection::Packet* packetToSend =
static_cast<ForwardErrorCorrection::Packet*>
(item->GetItem());
ForwardErrorCorrection::Packet* packetToSend = fecPacketList.front();
// The returned FEC packets have no RTP headers.
// Copy the last media packet's modified RTP header.
@ -285,7 +273,7 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
packetToSend->data,
packetToSend->length);
fecPacketList.PopFront();
fecPacketList.pop_front();
// Invalid FEC packet
assert(packetToSend->length != 0);

View File

@ -11,22 +11,24 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_
#include <list>
#include "typedefs.h"
#include "common_types.h" // Transport
#include "rtp_rtcp_config.h"
#include "rtp_rtcp_defines.h"
#include "rtp_utility.h"
#include "list_wrapper.h"
#include "video_codec_information.h"
#include "forward_error_correction.h"
#include "Bitrate.h"
#include "rtp_sender.h"
namespace webrtc {
class CriticalSectionWrapper;
struct RtpPacket;
class RTPSenderVideo
{
public:
@ -42,10 +44,11 @@ public:
WebRtc_UWord16 FECPacketOverhead() const;
WebRtc_Word32 RegisterVideoPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 maxBitRate,
ModuleRTPUtility::Payload*& payload);
WebRtc_Word32 RegisterVideoPayload(
const char payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 maxBitRate,
ModuleRTPUtility::Payload*& payload);
WebRtc_Word32 SendVideo(const RtpVideoCodecTypes videoType,
const FrameType frameType,
@ -133,8 +136,8 @@ private:
WebRtc_UWord8 _fecProtectionFactor;
bool _fecUseUepProtection;
int _numberFirstPartition;
ListWrapper _mediaPacketListFec;
ListWrapper _rtpPacketListFec;
std::list<ForwardErrorCorrection::Packet*> _mediaPacketListFec;
std::list<RtpPacket*> _rtpPacketListFec;
// Bitrate used for FEC payload, RED headers, RTP headers for FEC packets
// and any padding overhead.
Bitrate _fecOverheadRate;

File diff suppressed because it is too large Load Diff