Modified the FEC to allow for option of unequal protection (UEP) across packets.

Added two files under testFec, removed old testFec.cpp, and added two
new files for generating packet masks: _internal.cc/h.
Review URL: http://webrtc-codereview.appspot.com/26003

git-svn-id: http://webrtc.googlecode.com/svn/trunk@93 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
marpan@google.com
2011-06-16 21:44:38 +00:00
parent e25b0148c9
commit ae0ad911a1
10 changed files with 1103 additions and 593 deletions

View File

@@ -13,68 +13,48 @@
#include "rtp_utility.h"
#include "trace.h"
#include <cassert>
#include <cstring>
#define RtpHeaderSize 12 /**> Minimum RTP header size in bytes. */
#define FecHeaderSize 10 /**> FEC header size in bytes. */
#define MaskSizeLBitSet 6 /**> Packet mask size in bytes (L bit is set). */
#define MaskSizeLBitClear 2 /**> Packet mask size in bytes (L bit is cleared). */
#define UlpHeaderSizeLBitSet (2+MaskSizeLBitSet) /**> ULP header size in bytes (L bit is set). */
#define UlpHeaderSizeLBitClear (2 + MaskSizeLBitClear) /**> ULP header size in bytes (L bit is cleared). */
#define TransportOverhead 28 /**> Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. */
#include "forward_error_correction_internal.h"
namespace webrtc {
/**
* Used for internal storage of FEC packets in a list.
*/
// Minimum RTP header size in bytes.
const WebRtc_UWord8 kRtpHeaderSize = 12;
// FEC header size in bytes.
const WebRtc_UWord8 kFecHeaderSize = 10;
// ULP header size in bytes (L bit is set).
const WebRtc_UWord8 kUlpHeaderSizeLBitSet = (2 + kMaskSizeLBitSet);
// ULP header size in bytes (L bit is cleared).
const WebRtc_UWord8 kUlpHeaderSizeLBitClear = (2 + kMaskSizeLBitClear);
//Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
const WebRtc_UWord8 kTransportOverhead = 28;
//
// Used for internal storage of FEC packets in a list.
//
struct FecPacket
{
ListWrapper protectedPktList; /**> List containing #ProtectedPacket types. */
ListWrapper protectedPktList; /**> List containing #ProtectedPacket types.*/
WebRtc_UWord16 seqNum; /**> Sequence number. */
WebRtc_UWord32 ssrc; /**> SSRC of the current frame. */
ForwardErrorCorrection::Packet* pkt; /**> Pointer to the packet storage. */
};
/**
* Used to link media packets to their protecting FEC packets.
*/
//
// Used to link media packets to their protecting FEC packets.
//
struct ProtectedPacket
{
WebRtc_UWord16 seqNum; /**> Sequence number. */
ForwardErrorCorrection::Packet* pkt; /**> Pointer to the packet storage. */
};
namespace // Unnamed namespace gives internal linkage.
{
/**
* Returns an array of packet masks. Every NumMaskBytes-bytes of the array
* corresponds to the mask of a single FEC packet. The mask indicates which
* media packets should be protected by the FEC packet.
*
* \param[out] packetMask A pointer to hold the packet mask array, of size
* numFecPackets * NumMaskBytes;
* \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].
*/
void
GeneratePacketMasks(const WebRtc_UWord8*& packetMask,
const WebRtc_UWord32 numMediaPackets,
const WebRtc_UWord32 numFecPackets)
{
assert(numMediaPackets <= sizeof(packetMaskTbl)/sizeof(*packetMaskTbl) &&
numMediaPackets > 0);
assert(numFecPackets <= numMediaPackets && numFecPackets > 0);
// Retrieve corresponding mask table.
packetMask = packetMaskTbl[numMediaPackets - 1][numFecPackets - 1];
}
}
ForwardErrorCorrection::ForwardErrorCorrection(const WebRtc_Word32 id) :
_id(id),
_generatedFecPackets(NULL),
@@ -112,8 +92,9 @@ ForwardErrorCorrection::~ForwardErrorCorrection()
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
WebRtc_Word32
ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
ListWrapper& fecPacketList,
WebRtc_UWord8 protectionFactor)
WebRtc_UWord8 protectionFactor,
WebRtc_UWord32 numImportantPackets,
ListWrapper& fecPacketList)
{
if (mediaPacketList.Empty())
{
@@ -131,9 +112,12 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
const WebRtc_UWord16 numMediaPackets = mediaPacketList.GetSize();
const WebRtc_UWord8 lBit = numMediaPackets > 16 ? 1 : 0;
const WebRtc_UWord16 numMaskBytes = (lBit == 1)? MaskSizeLBitSet : MaskSizeLBitClear;
const WebRtc_UWord16 ulpHeaderSize = (lBit == 1)? UlpHeaderSizeLBitSet : UlpHeaderSizeLBitClear;
const WebRtc_UWord16 fecRtpOffset = FecHeaderSize + ulpHeaderSize - RtpHeaderSize;
const WebRtc_UWord16 numMaskBytes =
(lBit == 1)? kMaskSizeLBitSet : kMaskSizeLBitClear;
const WebRtc_UWord16 ulpHeaderSize =
(lBit == 1)? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear;
const WebRtc_UWord16 fecRtpOffset =
kFecHeaderSize + ulpHeaderSize - kRtpHeaderSize;
const WebRtc_UWord16 maxMediaPackets = numMaskBytes * 8;
if (numMediaPackets > maxMediaPackets)
@@ -144,6 +128,23 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
return -1;
}
// Error checking on the number of important packets.
// Can't have more important packets than media packets.
if (numImportantPackets > numMediaPackets)
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"Number of Important packet greater than number of Media Packets %d %d",
numImportantPackets, numMediaPackets);
return -1;
}
if (numImportantPackets < 0)
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"Number of Important packets less than zero %d %d",
numImportantPackets, numMediaPackets);
return -1;
}
// Do some error checking on the media packets.
Packet* mediaPacket;
ListItem* mediaListItem = mediaPacketList.First();
@@ -151,7 +152,7 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
{
mediaPacket = static_cast<Packet*>(mediaListItem->GetItem());
if (mediaPacket->length < RtpHeaderSize)
if (mediaPacket->length < kRtpHeaderSize)
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"%s media packet (%d bytes) is smaller than RTP header",
@@ -160,7 +161,7 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
}
// Ensure our FEC packets will fit in a typical MTU.
if (mediaPacket->length + PacketOverhead() + TransportOverhead >
if (mediaPacket->length + PacketOverhead() + kTransportOverhead >
IP_PACKET_SIZE)
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
@@ -197,8 +198,10 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
}
// -- Generate packet masks --
const WebRtc_UWord8* packetMask;
GeneratePacketMasks(packetMask, numMediaPackets, numFecPackets);
WebRtc_UWord8 packetMask[numFecPackets * numMaskBytes];
memset(packetMask, 0, numFecPackets * numMaskBytes);
internal::GeneratePacketMasks(numMediaPackets, numFecPackets,
numImportantPackets, packetMask);
// -- Generate FEC bit strings --
WebRtc_UWord8 mediaPayloadLength[2];
@@ -218,7 +221,7 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
// Assign network-ordered media payload length.
ModuleRTPUtility::AssignUWord16ToBuffer(mediaPayloadLength,
mediaPacket->length - RtpHeaderSize);
mediaPacket->length - kRtpHeaderSize);
fecPacketLength = mediaPacket->length + fecRtpOffset;
// On the first protected packet, we don't need to XOR.
if (_generatedFecPackets[i].length == 0)
@@ -231,9 +234,9 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
memcpy(&_generatedFecPackets[i].data[8], mediaPayloadLength, 2);
// Copy RTP payload, leaving room for the ULP header.
memcpy(&_generatedFecPackets[i].data[FecHeaderSize + ulpHeaderSize],
&mediaPacket->data[RtpHeaderSize],
mediaPacket->length - RtpHeaderSize);
memcpy(&_generatedFecPackets[i].data[kFecHeaderSize + ulpHeaderSize],
&mediaPacket->data[kRtpHeaderSize],
mediaPacket->length - kRtpHeaderSize);
}
else
{
@@ -252,7 +255,7 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
_generatedFecPackets[i].data[9] ^= mediaPayloadLength[1];
// XOR with RTP payload, leaving room for the ULP header.
for (WebRtc_Word32 j = FecHeaderSize + ulpHeaderSize;
for (WebRtc_Word32 j = kFecHeaderSize + ulpHeaderSize;
j < fecPacketLength; j++)
{
_generatedFecPackets[i].data[j] ^=
@@ -278,9 +281,12 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
if (_generatedFecPackets[i].length == 0)
{
// This will occur in the event of an all-zero mask.
// Ensure we still mark the length of the headers.
_generatedFecPackets[i].length = FecHeaderSize + ulpHeaderSize;
//Note: This shouldn't happen: means packet mask is wrong or poorly designed
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"Packet mask has row of zeros %d %d",
numMediaPackets, numFecPackets);
return -1;
}
}
@@ -330,7 +336,7 @@ ForwardErrorCorrection::GenerateFEC(const ListWrapper& mediaPacketList,
// Copy the payload size to the protection length field.
// (We protect the entire packet.)
ModuleRTPUtility::AssignUWord16ToBuffer(&_generatedFecPackets[i].data[10],
_generatedFecPackets[i].length - FecHeaderSize - ulpHeaderSize);
_generatedFecPackets[i].length - kFecHeaderSize - ulpHeaderSize);
// Copy the packet mask.
memcpy(&_generatedFecPackets[i].data[12], &packetMask[i * numMaskBytes],
@@ -517,7 +523,7 @@ ForwardErrorCorrection::DecodeFEC(ListWrapper& receivedPacketList,
// We store this for determining frame completion later.
_seqNumBase = ModuleRTPUtility::BufferToUWord16(&fecPacket->pkt->data[2]);
const WebRtc_UWord16 maskSizeBytes = (fecPacket->pkt->data[0] & 0x40) ?
MaskSizeLBitSet : MaskSizeLBitClear; // L bit set?
kMaskSizeLBitSet : kMaskSizeLBitClear; // L bit set?
for (WebRtc_UWord16 byteIdx = 0; byteIdx < maskSizeBytes; byteIdx++)
{
@@ -617,7 +623,7 @@ ForwardErrorCorrection::DecodeFEC(ListWrapper& receivedPacketList,
// Recovery possible.
WebRtc_UWord8 lengthRecovery[2];
const WebRtc_UWord16 ulpHeaderSize = fecPacket->pkt->data[0] & 0x40 ?
UlpHeaderSizeLBitSet : UlpHeaderSizeLBitClear; // L bit set?
kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; // L bit set?
RecoveredPacket* recPacketToInsert = new RecoveredPacket;
recPacketToInsert->wasRecovered = true;
@@ -641,8 +647,8 @@ ForwardErrorCorrection::DecodeFEC(ListWrapper& receivedPacketList,
memcpy(&lengthRecovery, &fecPacket->pkt->data[8], 2);
// Copy FEC payload, skipping the ULP header.
memcpy(&recPacketToInsert->pkt->data[RtpHeaderSize],
&fecPacket->pkt->data[FecHeaderSize + ulpHeaderSize],
memcpy(&recPacketToInsert->pkt->data[kRtpHeaderSize],
&fecPacket->pkt->data[kFecHeaderSize + ulpHeaderSize],
ModuleRTPUtility::BufferToUWord16(protectionLength));
protectedPacketListItem = fecPacket->protectedPktList.First();
@@ -672,13 +678,13 @@ ForwardErrorCorrection::DecodeFEC(ListWrapper& receivedPacketList,
// XOR with the network-ordered payload size.
ModuleRTPUtility::AssignUWord16ToBuffer(mediaPayloadLength,
protectedPacket->pkt->length - RtpHeaderSize);
protectedPacket->pkt->length - kRtpHeaderSize);
lengthRecovery[0] ^= mediaPayloadLength[0];
lengthRecovery[1] ^= mediaPayloadLength[1];
// XOR with RTP payload.
// TODO: Are we doing more XORs than required here?
for (WebRtc_Word32 i = RtpHeaderSize; i < protectedPacket->pkt->length;
for (WebRtc_Word32 i = kRtpHeaderSize; i < protectedPacket->pkt->length;
i++)
{
recPacketToInsert->pkt->data[i] ^= protectedPacket->pkt->data[i];
@@ -712,7 +718,7 @@ ForwardErrorCorrection::DecodeFEC(ListWrapper& receivedPacketList,
// Recover the packet length.
recPacketToInsert->pkt->length =
ModuleRTPUtility::BufferToUWord16(lengthRecovery) + RtpHeaderSize;
ModuleRTPUtility::BufferToUWord16(lengthRecovery) + kRtpHeaderSize;
// Insert into recovered list in correct position.
recPacketListItem = recoveredPacketList.Last();
@@ -823,6 +829,6 @@ ForwardErrorCorrection::DecodeFEC(ListWrapper& receivedPacketList,
WebRtc_UWord16
ForwardErrorCorrection::PacketOverhead()
{
return FecHeaderSize + UlpHeaderSizeLBitSet;
return kFecHeaderSize + kUlpHeaderSizeLBitSet;
}
} // namespace webrtc

View File

@@ -84,27 +84,35 @@ public:
/**
* Destructor. Before freeing an instance of the class, #DecodeFEC() must be called
* in a particular fashion to free oustanding memory. Refer to #DecodeFEC().
* 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[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().
* \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] 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[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, ListWrapper& fecPacketList,
WebRtc_UWord8 protectionFactor);
WebRtc_Word32 GenerateFEC(const ListWrapper& mediaPacketList,
WebRtc_UWord8 protectionFactor,
WebRtc_UWord32 numImportantPackets,
ListWrapper& fecPacketList);
/**
* Decodes a list of media and FEC packets. It will parse the input received packet

View File

@@ -0,0 +1,340 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "forward_error_correction_internal.h"
#include "fec_private_tables.h"
#include <cassert>
#include <cstring>
namespace {
// This parameter enables/disables unequal protection (UEP) across packets.
// This is not to be confused with protection within packets (referred to as ULP).
// One use case of UEP across packets is for codecs with data partitioning,
// e.g., VP8, H264 XP profile, where important packets would be first partition.
// TODO (marpan): Pass this parameter from MediaOpt (VCM).
const bool kUseUnequalProtection = true;
// Allow for two different modes of protection for residual packets.
// The residual packets are the remaining packets beyond the important ones.
enum ResidualProtectionMode
{
kModeNoOverlap,
kModeOverlap,
};
/**
* 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(const WebRtc_UWord16 numMaskBytes,
const WebRtc_UWord16 numSubMaskBytes,
const WebRtc_UWord16 numRows,
const WebRtc_UWord8* subMask,
WebRtc_UWord8* packetMask)
{
if (numMaskBytes == numSubMaskBytes)
{
memcpy(packetMask,subMask,
numRows * numSubMaskBytes);
}
else
{
for (WebRtc_UWord32 i = 0; i < numRows; i++)
{
WebRtc_UWord32 pktMaskIdx = i * numMaskBytes;
WebRtc_UWord32 pktMaskIdx2 = i * numSubMaskBytes;
for (WebRtc_UWord32 j = 0; j < numSubMaskBytes; j++)
{
packetMask[pktMaskIdx] = subMask[pktMaskIdx2];
pktMaskIdx++;
pktMaskIdx2++;
}
}
}
}
/**
* 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.
*/
// 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(const WebRtc_UWord16 numMaskBytes,
const WebRtc_UWord16 resMaskBytes,
const WebRtc_UWord16 numColumnShift,
const WebRtc_UWord16 endRow,
const WebRtc_UWord8* subMask,
WebRtc_UWord8* packetMask)
{
// Number of bit shifts within a byte
const WebRtc_UWord8 numBitShifts = (numColumnShift % 8);
const WebRtc_UWord8 numByteShifts = numColumnShift >> 3;
// Modify new mask with sub-mask21.
// Loop over the remaining FEC packets.
for (WebRtc_UWord32 i = numColumnShift; i < endRow; i++)
{
// Byte index of new mask, for row i and column resMaskBytes,
// offset by the number of bytes shifts
WebRtc_UWord32 pktMaskIdx = i * numMaskBytes + resMaskBytes - 1
+ numByteShifts;
// Byte index of subMask, for row i and column resMaskBytes
WebRtc_UWord32 pktMaskIdx2 =
(i - numColumnShift) * resMaskBytes + resMaskBytes - 1;
WebRtc_UWord8 shiftRightCurrByte = 0;
WebRtc_UWord8 shiftLeftPrevByte = 0;
WebRtc_UWord8 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 (WebRtc_Word32 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;
}
}
} //namespace
namespace webrtc {
namespace internal {
// Residual protection for remaining packets
void ResidualPacketProtection(const WebRtc_UWord16 numMediaPackets,
const WebRtc_UWord16 numFecPackets,
const WebRtc_UWord16 numImpPackets,
const WebRtc_UWord16 numMaskBytes,
const ResidualProtectionMode mode,
WebRtc_UWord8* packetMask)
{
if (mode == kModeNoOverlap)
{
// subMask21
const WebRtc_UWord8 lBit =
(numMediaPackets - numImpPackets) > 16 ? 1 : 0;
const WebRtc_UWord16 resMaskBytes =
(lBit == 1)? kMaskSizeLBitSet : kMaskSizeLBitClear;
const WebRtc_UWord8* packetMaskSub21 =
packetMaskTbl[numMediaPackets - numImpPackets - 1]
[numFecPackets - numImpPackets - 1];
ShiftFitSubMask(numMaskBytes, resMaskBytes,
numImpPackets, numFecPackets,
packetMaskSub21, packetMask);
}
else if (mode == kModeOverlap)
{
// subMask22
const WebRtc_UWord16 numFecForResidual =
numFecPackets - numImpPackets;
const WebRtc_UWord8* packetMaskSub22 =
packetMaskTbl[numMediaPackets - 1]
[numFecForResidual - 1];
FitSubMask(numMaskBytes, numMaskBytes,
numFecForResidual,
packetMaskSub22,
&packetMask[numImpPackets * numMaskBytes]);
}
else
{
assert(false);
}
}
// Higher protection for numImpPackets
void ImportantPacketProtection(const WebRtc_UWord16 numFecPackets,
const WebRtc_UWord16 numImpPackets,
const WebRtc_UWord16 numMaskBytes,
WebRtc_UWord8* packetMask)
{
const WebRtc_UWord8 lBit = numImpPackets > 16 ? 1 : 0;
const WebRtc_UWord16 numImpMaskBytes =
(lBit == 1)? kMaskSizeLBitSet : kMaskSizeLBitClear;
WebRtc_UWord32 numFecForImpPackets = numImpPackets;
if (numFecPackets < numImpPackets)
{
numFecForImpPackets = numFecPackets;
}
// Get subMask1 from table
const WebRtc_UWord8* packetMaskSub1 =
packetMaskTbl[numImpPackets - 1][numFecForImpPackets - 1];
FitSubMask(numMaskBytes, numImpMaskBytes,
numFecForImpPackets,
packetMaskSub1,
packetMask);
}
// Modification for UEP: reuse the tables (designed for equal protection).
// First version is to build mask from two sub-masks.
// Longer-term, may add another set of tables for UEP cases for more
// flexibility in protection between important and residual packets.
// UEP scheme:
// First subMask is for higher protection for important packets.
// Other subMask is the residual protection for remaining packets.
// Mask is characterized as (#packets_to_protect, #fec_for_protection).
// Protection defined as: (#fec_for_protection / #packets_to_protect).
// So if k = numMediaPackets, n=total#packets, (n-k)=numFecPackets,
// and m=numImpPackets, then we will have the following:
// For important packets:
// subMask1 = (m, t): protection = m/(t), where t=min(m,n-k).
// For the residual protection, we currently have two options:
// Mode 0: subMask21 = (k-m,n-k-m): protection = (n-k-m)/(k-m):
// no protection overlap between the two partitions.
// Mode 1: subMask22 = (k, n-k-m), with protection (n-k-m)/(k):
// some protection overlap between the two partitions.
void UnequalProtectionMask(const WebRtc_UWord16 numMediaPackets,
const WebRtc_UWord16 numFecPackets,
const WebRtc_UWord16 numImpPackets,
const WebRtc_UWord16 numMaskBytes,
const ResidualProtectionMode mode,
WebRtc_UWord8* packetMask)
{
//
// Generate subMask1: higher protection for numImpPackets:
//
ImportantPacketProtection(numFecPackets, numImpPackets,
numMaskBytes, packetMask);
//
// Generate subMask2: left-over protection (for remaining partition data),
// if we still have some some FEC packets
//
if (numFecPackets > numImpPackets)
{
ResidualPacketProtection(numMediaPackets,numFecPackets,
numImpPackets, numMaskBytes,
mode, packetMask);
}
}
void GeneratePacketMasks(const WebRtc_UWord32 numMediaPackets,
const WebRtc_UWord32 numFecPackets,
const WebRtc_UWord32 numImpPackets,
WebRtc_UWord8* packetMask)
{
assert(numMediaPackets <= sizeof(packetMaskTbl)/sizeof(*packetMaskTbl) &&
numMediaPackets > 0);
assert(numFecPackets <= numMediaPackets && numFecPackets > 0);
assert(numImpPackets <= numMediaPackets && numImpPackets >= 0);
WebRtc_UWord8 lBit = numMediaPackets > 16 ? 1 : 0;
const WebRtc_UWord16 numMaskBytes =
(lBit == 1)? kMaskSizeLBitSet : kMaskSizeLBitClear;
// Default: use overlap mode for residual protection.
const ResidualProtectionMode kResidualProtectionMode = kModeOverlap;
// Force equal-protection for these cases.
// Equal protection is also used for: (numImpPackets == 1 && numFecPackets == 1).
// UEP=off would generally be more efficient than the UEP=on for this case.
// TODO (marpan): check/test this condition.
if (!kUseUnequalProtection || numImpPackets == 0 ||
(numImpPackets == 1 && numFecPackets == 1))
{
// 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, packetMaskTbl[numMediaPackets - 1][numFecPackets - 1],
numFecPackets * numMaskBytes);
}
else //UEP case
{
UnequalProtectionMask(numMediaPackets, numFecPackets, numImpPackets,
numMaskBytes, kResidualProtectionMode,
packetMask);
} // End of UEP modification
} //End of GetPacketMasks
} // namespace internal
} // namespace webrtc

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "typedefs.h"
namespace webrtc {
// Packet mask size in bytes (L bit is set).
const WebRtc_UWord8 kMaskSizeLBitSet = 6;
// Packet mask size in bytes (L bit is cleared).
const WebRtc_UWord8 kMaskSizeLBitClear = 2;
namespace internal {
/**
* 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[out] packetMask A pointer to hold the packet mask array, of size
* numFecPackets * "number of mask bytes".
*/
void GeneratePacketMasks(const WebRtc_UWord32 numMediaPackets,
const WebRtc_UWord32 numFecPackets,
const WebRtc_UWord32 numImpPackets,
WebRtc_UWord8* packetMask);
} // namespace internal
} // namespace webrtc

View File

@@ -65,6 +65,8 @@
'fec_private_tables.h',
'forward_error_correction.cc',
'forward_error_correction.h',
'forward_error_correction_internal.cc',
'forward_error_correction_internal.h',
'overuse_detector.cc',
'overuse_detector.h',
'h263_information.cc',

View File

@@ -42,6 +42,7 @@ RTPSenderVideo::RTPSenderVideo(const WebRtc_Word32 id, RTPSenderInterface* rtpSe
_codeRateKey(0),
_codeRateDelta(0),
_fecProtectionFactor(0),
_numberFirstPartition(0),
// H263
_savedByte(0),
@@ -69,6 +70,7 @@ RTPSenderVideo::Init()
_codeRateKey = 0;
_codeRateDelta = 0;
_fecProtectionFactor = 0;
_numberFirstPartition = 0;
return 0;
}
@@ -176,7 +178,8 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
lastMediaRtpHeader.data[1] = _payloadTypeRED; // Replace payload and clear
// marker bit.
retVal = _fec.GenerateFEC(_mediaPacketListFec, fecPacketList,_fecProtectionFactor);
retVal = _fec.GenerateFEC(_mediaPacketListFec, _fecProtectionFactor,
_numberFirstPartition, fecPacketList);
while(!_rtpPacketListFec.Empty())
{
WebRtc_UWord8 newDataBuffer[IP_PACKET_SIZE];
@@ -347,6 +350,10 @@ RTPSenderVideo::SendVideo(const RtpVideoCodecTypes videoType,
_fecProtectionFactor = _codeRateDelta;
}
// Default setting for number of first partition packets:
// Will be extracted in SendVP8 for VP8 codec; other codecs use 0
_numberFirstPartition = 0;
WebRtc_Word32 retVal = -1;
switch(videoType)
{
@@ -1123,6 +1130,9 @@ RTPSenderVideo::SendVP8(const FrameType frameType,
_rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
captureTimeStamp);
// TODO (marpan): Set _numberFirstPartition here:
// Equal to the first packet that contains last fragment of first partition
if (-1 == SendVideoPacket(frameType, dataBuffer, payloadBytesInPacket,
rtpHeaderLength))
{

View File

@@ -152,8 +152,9 @@ private:
WebRtc_UWord8 _codeRateKey;
WebRtc_UWord8 _codeRateDelta;
WebRtc_UWord8 _fecProtectionFactor;
ListWrapper _mediaPacketListFec;
ListWrapper _rtpPacketListFec;
WebRtc_UWord32 _numberFirstPartition;
ListWrapper _mediaPacketListFec;
ListWrapper _rtpPacketListFec;
// H263
WebRtc_UWord8 _savedByte;