637 lines
19 KiB
C++
637 lines
19 KiB
C++
|
/*
|
||
|
* 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 "packet.h"
|
||
|
#include "session_info.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <cassert>
|
||
|
|
||
|
namespace webrtc {
|
||
|
|
||
|
VCMSessionInfo::VCMSessionInfo():
|
||
|
_haveFirstPacket(false),
|
||
|
_markerBit(false),
|
||
|
_sessionNACK(false),
|
||
|
_completeSession(false),
|
||
|
_frameType(kVideoFrameDelta),
|
||
|
_previousFrameLoss(false),
|
||
|
_lowSeqNum(-1),
|
||
|
_highSeqNum(-1),
|
||
|
_highestPacketIndex(0)
|
||
|
{
|
||
|
memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
|
||
|
memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
|
||
|
memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte));
|
||
|
}
|
||
|
|
||
|
VCMSessionInfo::~VCMSessionInfo()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
WebRtc_Word32 VCMSessionInfo::GetLowSeqNum() const
|
||
|
{
|
||
|
return _lowSeqNum;
|
||
|
}
|
||
|
|
||
|
WebRtc_Word32 VCMSessionInfo::GetHighSeqNum() const
|
||
|
{
|
||
|
return _highSeqNum;
|
||
|
}
|
||
|
|
||
|
void VCMSessionInfo::Reset()
|
||
|
{
|
||
|
_lowSeqNum = -1;
|
||
|
_highSeqNum = -1;
|
||
|
_markerBit = false;
|
||
|
_haveFirstPacket = false;
|
||
|
_completeSession = false;
|
||
|
_frameType = kVideoFrameDelta;
|
||
|
_previousFrameLoss = false;
|
||
|
_sessionNACK = false;
|
||
|
_highestPacketIndex = 0;
|
||
|
memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
|
||
|
memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
|
||
|
memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte));
|
||
|
}
|
||
|
|
||
|
WebRtc_UWord32 VCMSessionInfo::GetSessionLength()
|
||
|
{
|
||
|
WebRtc_UWord32 length = 0;
|
||
|
for (WebRtc_Word32 i=0; i<=_highestPacketIndex; ++i)
|
||
|
{
|
||
|
length += _packetSizeBytes[i];
|
||
|
}
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
VCMSessionInfo::SetStartSeqNumber(WebRtc_UWord16 seqNumber)
|
||
|
{
|
||
|
_lowSeqNum = seqNumber;
|
||
|
_highSeqNum = seqNumber;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
VCMSessionInfo::HaveStartSeqNumber()
|
||
|
{
|
||
|
if(_lowSeqNum == -1 || _highSeqNum == -1)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
WebRtc_UWord32 VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer, WebRtc_Word32 packetIndex, const VCMPacket& packet)
|
||
|
{
|
||
|
WebRtc_UWord32 moveLength = 0;
|
||
|
WebRtc_UWord32 returnLength = 0;
|
||
|
int i = 0;
|
||
|
|
||
|
// need to calc offset before updating _packetSizeBytes
|
||
|
WebRtc_UWord32 offset = 0;
|
||
|
WebRtc_UWord32 packetSize = 0;
|
||
|
|
||
|
// Store this packet length. Add length since we could have data present already (e.g. multicall case).
|
||
|
if (packet.bits)
|
||
|
{
|
||
|
packetSize = packet.sizeBytes;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
packetSize = packet.sizeBytes + (packet.insertStartCode?kH264StartCodeLengthBytes:0);
|
||
|
}
|
||
|
|
||
|
_packetSizeBytes[packetIndex] += packetSize;
|
||
|
|
||
|
// count only the one in our layer
|
||
|
for (i=0; i<packetIndex; ++i)
|
||
|
{
|
||
|
offset += _packetSizeBytes[i];
|
||
|
}
|
||
|
for (i=packetIndex+1; i<=_highestPacketIndex; ++i)
|
||
|
{
|
||
|
moveLength += _packetSizeBytes[i];
|
||
|
}
|
||
|
if (moveLength > 0)
|
||
|
{
|
||
|
memmove((void*)(ptrStartOfLayer + offset + packetSize), ptrStartOfLayer + offset, moveLength);
|
||
|
}
|
||
|
|
||
|
if (packet.bits)
|
||
|
{
|
||
|
// Add the packet without ORing end and start bytes together.
|
||
|
// This is done when the frame is fetched for decoding by calling
|
||
|
// GlueTogether().
|
||
|
_ORwithPrevByte[packetIndex] = true;
|
||
|
if (packet.dataPtr != NULL)
|
||
|
{
|
||
|
memcpy((void*)(ptrStartOfLayer + offset), packet.dataPtr, packetSize);
|
||
|
}
|
||
|
returnLength = packetSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_ORwithPrevByte[packetIndex] = false;
|
||
|
if (packet.dataPtr != NULL)
|
||
|
{
|
||
|
const unsigned char startCode[] = {0, 0, 0, 1};
|
||
|
if(packet.insertStartCode)
|
||
|
{
|
||
|
memcpy((void*)(ptrStartOfLayer + offset), startCode, kH264StartCodeLengthBytes);
|
||
|
}
|
||
|
memcpy((void*)(ptrStartOfLayer + offset
|
||
|
+ (packet.insertStartCode?kH264StartCodeLengthBytes:0)),
|
||
|
packet.dataPtr,
|
||
|
packet.sizeBytes);
|
||
|
}
|
||
|
returnLength = packetSize;
|
||
|
}
|
||
|
|
||
|
if (packet.isFirstPacket)
|
||
|
{
|
||
|
_haveFirstPacket = true;
|
||
|
}
|
||
|
if (packet.markerBit)
|
||
|
{
|
||
|
_markerBit = true;
|
||
|
}
|
||
|
// Store information about if the packet is decodable as is or not.
|
||
|
_naluCompleteness[packetIndex]=packet.completeNALU;
|
||
|
|
||
|
UpdateCompleteSession();
|
||
|
|
||
|
return returnLength;
|
||
|
}
|
||
|
|
||
|
void VCMSessionInfo::UpdateCompleteSession()
|
||
|
{
|
||
|
if (_haveFirstPacket && _markerBit)
|
||
|
{
|
||
|
// do we have all packets in this session?
|
||
|
bool completeSession = true;
|
||
|
for (int i=0; i<= _highestPacketIndex; ++i)
|
||
|
{
|
||
|
if (_naluCompleteness[i] == kNaluUnset)
|
||
|
{
|
||
|
completeSession = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
_completeSession = completeSession;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool VCMSessionInfo::IsSessionComplete()
|
||
|
{
|
||
|
return _completeSession;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Find the start and end index of packetIndex packet.
|
||
|
// startIndex -1 if start not found endIndex=-1 if end index not found
|
||
|
void VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,WebRtc_Word32& startIndex, WebRtc_Word32& endIndex)
|
||
|
{
|
||
|
|
||
|
if(_naluCompleteness[packetIndex]==kNaluStart ||
|
||
|
_naluCompleteness[packetIndex]==kNaluComplete)
|
||
|
{
|
||
|
startIndex=packetIndex;
|
||
|
}
|
||
|
else // Need to find the start
|
||
|
{
|
||
|
for(startIndex=packetIndex-1;startIndex>=0;--startIndex)
|
||
|
{
|
||
|
|
||
|
if( (_naluCompleteness[startIndex]==kNaluComplete && _packetSizeBytes[startIndex]>0) ||(_naluCompleteness[startIndex]==kNaluEnd && startIndex>0)) // Found previous NALU.
|
||
|
{
|
||
|
startIndex++;
|
||
|
break;
|
||
|
}
|
||
|
if( _naluCompleteness[startIndex]==kNaluStart) // This is where the NALU start.
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(_naluCompleteness[packetIndex]==kNaluEnd ||
|
||
|
_naluCompleteness[packetIndex]==kNaluComplete)
|
||
|
{
|
||
|
endIndex=packetIndex;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Find the next NALU
|
||
|
for(endIndex=packetIndex+1;endIndex<=_highestPacketIndex;++endIndex)
|
||
|
{
|
||
|
if((_naluCompleteness[endIndex]==kNaluComplete && _packetSizeBytes[endIndex]>0) || _naluCompleteness[endIndex]==kNaluStart) // Found next NALU.
|
||
|
{
|
||
|
endIndex--;
|
||
|
break;
|
||
|
}
|
||
|
if( _naluCompleteness[endIndex]==kNaluEnd) // This is where the NALU end.
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(endIndex>_highestPacketIndex)
|
||
|
endIndex=-1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Deletes all packets between startIndex and endIndex
|
||
|
WebRtc_UWord32 VCMSessionInfo::DeletePackets(WebRtc_UWord8* ptrStartOfLayer,WebRtc_Word32 startIndex,WebRtc_Word32 endIndex)
|
||
|
{
|
||
|
|
||
|
//Get the number of bytes to delete.
|
||
|
//Clear the size of these packets.
|
||
|
WebRtc_UWord32 bytesToDelete=0; /// The number of bytes to delete.
|
||
|
for(int j=startIndex;j<=endIndex;++j)
|
||
|
{
|
||
|
bytesToDelete+=_packetSizeBytes[j];
|
||
|
_packetSizeBytes[j]=0;
|
||
|
}
|
||
|
if (bytesToDelete > 0)
|
||
|
{
|
||
|
// Get the offset we want to move to.
|
||
|
int destOffset=0;
|
||
|
for(int j=0;j<startIndex;j++)
|
||
|
{
|
||
|
destOffset+=_packetSizeBytes[j];
|
||
|
}
|
||
|
|
||
|
//Get the number of bytes to move
|
||
|
WebRtc_UWord32 numberOfBytesToMove=0;
|
||
|
for (int j=endIndex+1; j<=_highestPacketIndex; ++j)
|
||
|
{
|
||
|
numberOfBytesToMove += _packetSizeBytes[j];
|
||
|
}
|
||
|
|
||
|
memmove((void*)(ptrStartOfLayer + destOffset),(void*)(ptrStartOfLayer + destOffset+bytesToDelete), numberOfBytesToMove);
|
||
|
|
||
|
}
|
||
|
|
||
|
return bytesToDelete;
|
||
|
}
|
||
|
|
||
|
// Makes the layer decodable. Ie only contain decodable NALU
|
||
|
// return the number of bytes deleted from the session. -1 if an error occurs
|
||
|
WebRtc_UWord32 VCMSessionInfo::MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer)
|
||
|
{
|
||
|
if(_lowSeqNum<0) // No packets in this session
|
||
|
return 0;
|
||
|
|
||
|
WebRtc_Word32 startIndex=0;
|
||
|
WebRtc_Word32 endIndex=0;
|
||
|
int packetIndex=0;
|
||
|
WebRtc_UWord32 returnLength=0;
|
||
|
for (packetIndex=0; packetIndex<= _highestPacketIndex; ++packetIndex)
|
||
|
{
|
||
|
if (_naluCompleteness[packetIndex] == kNaluUnset) // Found a lost packet
|
||
|
{
|
||
|
FindNaluBorder(packetIndex,startIndex,endIndex);
|
||
|
if(startIndex==-1)
|
||
|
startIndex=0;
|
||
|
if(endIndex==-1)
|
||
|
endIndex=_highestPacketIndex;
|
||
|
|
||
|
returnLength+=DeletePackets(ptrStartOfLayer,packetIndex,endIndex);
|
||
|
packetIndex=endIndex;
|
||
|
}// end lost packet
|
||
|
}
|
||
|
|
||
|
//Make sure the first packet is decodable (Either complete nalu or start of NALU)
|
||
|
if(_packetSizeBytes[0]>0)
|
||
|
{
|
||
|
switch(_naluCompleteness[0])
|
||
|
{
|
||
|
case kNaluComplete: //Packet can be decoded as is.
|
||
|
break;
|
||
|
|
||
|
case kNaluStart: // Packet contain beginning of NALU- No need to do anything.
|
||
|
break;
|
||
|
case kNaluIncomplete: //Packet is not beginning or end of NALU
|
||
|
//Need to find the end of this fua NALU and delete all packets.
|
||
|
FindNaluBorder(0,startIndex,endIndex);
|
||
|
if(endIndex==-1) // No end found. Delete
|
||
|
{
|
||
|
endIndex=_highestPacketIndex;
|
||
|
}
|
||
|
returnLength+=DeletePackets(ptrStartOfLayer,0,endIndex);//Delete this NALU.
|
||
|
break;
|
||
|
case kNaluEnd: // Packet is the end of a NALU
|
||
|
//Need to delete this packet
|
||
|
returnLength+=DeletePackets(ptrStartOfLayer,0,0);//Delete this NALU.
|
||
|
break;
|
||
|
default:
|
||
|
assert(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return returnLength;
|
||
|
}
|
||
|
|
||
|
WebRtc_Word32 VCMSessionInfo::ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num)
|
||
|
{
|
||
|
if ((NULL == list) || (num < 1))
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
if (_lowSeqNum == -1)
|
||
|
{
|
||
|
// no packets in this frame
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Find end point (index of entry that equals _lowSeqNum)
|
||
|
int index = 0;
|
||
|
for (; index <num; index++)
|
||
|
{
|
||
|
if (list[index] == _lowSeqNum)
|
||
|
{
|
||
|
list[index] = -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Zero out between first entry and end point
|
||
|
int i = 0;
|
||
|
while ( i <= _highestPacketIndex && index < num)
|
||
|
{
|
||
|
if (_naluCompleteness[i] != kNaluUnset)
|
||
|
{
|
||
|
list[index] = -1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_sessionNACK = true;
|
||
|
}
|
||
|
i++;
|
||
|
index++;
|
||
|
}
|
||
|
if(!_haveFirstPacket)
|
||
|
{
|
||
|
_sessionNACK = true;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
WebRtc_Word32 VCMSessionInfo::GetHighestPacketIndex()
|
||
|
{
|
||
|
return _highestPacketIndex;
|
||
|
}
|
||
|
|
||
|
bool VCMSessionInfo::HaveLastPacket()
|
||
|
{
|
||
|
return _markerBit;
|
||
|
}
|
||
|
|
||
|
void VCMSessionInfo::ForceSetHaveLastPacket()
|
||
|
{
|
||
|
_markerBit = true;
|
||
|
UpdateCompleteSession();
|
||
|
}
|
||
|
|
||
|
bool VCMSessionInfo::IsRetransmitted()
|
||
|
{
|
||
|
return _sessionNACK;
|
||
|
}
|
||
|
|
||
|
void VCMSessionInfo::UpdatePacketSize(WebRtc_Word32 packetIndex, WebRtc_UWord32 length)
|
||
|
{
|
||
|
// sanity
|
||
|
if(packetIndex >= kMaxPacketsInJitterBuffer || packetIndex < 0)
|
||
|
{
|
||
|
//not allowed
|
||
|
assert(!"SessionInfo::UpdatePacketSize Error: invalid packetIndex");
|
||
|
return;
|
||
|
}
|
||
|
_packetSizeBytes[packetIndex] = length;
|
||
|
}
|
||
|
|
||
|
void VCMSessionInfo::PrependPacketIndices(WebRtc_Word32 numberOfPacketIndices)
|
||
|
{
|
||
|
// sanity
|
||
|
if((numberOfPacketIndices + GetHighestPacketIndex() >= kMaxPacketsInJitterBuffer) || numberOfPacketIndices < 0)
|
||
|
{
|
||
|
//not allowed
|
||
|
assert(!"SessionInfo::PrependPacketIndexes Error: invalid packetIndex");
|
||
|
return;
|
||
|
}
|
||
|
// Works if we have new packets before packetIndex = 0
|
||
|
int numOfPacketsToMove = GetHighestPacketIndex()+1;
|
||
|
memmove(&_packetSizeBytes[numberOfPacketIndices], &_packetSizeBytes[0], (numOfPacketsToMove)*sizeof(WebRtc_UWord16));
|
||
|
memset(&_packetSizeBytes[0], 0, numberOfPacketIndices*sizeof(WebRtc_UWord16));
|
||
|
|
||
|
_highestPacketIndex += (WebRtc_UWord16)numberOfPacketIndices;
|
||
|
}
|
||
|
|
||
|
void VCMSessionInfo::ClearPacketSize(WebRtc_Word32 packetIndex)
|
||
|
{
|
||
|
// sanity
|
||
|
if(packetIndex >= kMaxPacketsInJitterBuffer || packetIndex < 0)
|
||
|
{
|
||
|
//not allowed
|
||
|
assert(!"SessionInfo::ClearPacketSize Error: invalid packetIndex");
|
||
|
return;
|
||
|
}
|
||
|
_packetSizeBytes[packetIndex] =0;
|
||
|
}
|
||
|
|
||
|
WebRtc_UWord32 VCMSessionInfo::GetPacketSize(WebRtc_Word32 packetIndex)
|
||
|
{
|
||
|
// sanity
|
||
|
if(packetIndex >= kMaxPacketsInJitterBuffer || packetIndex < 0)
|
||
|
{
|
||
|
//not allowed
|
||
|
assert(!"SessionInfo::GetPacketSize Error: invalid packetIndex");
|
||
|
return 0;
|
||
|
}
|
||
|
return _packetSizeBytes[packetIndex];
|
||
|
}
|
||
|
|
||
|
WebRtc_Word64
|
||
|
VCMSessionInfo::InsertPacket(const VCMPacket& packet, WebRtc_UWord8* ptrStartOfLayer)
|
||
|
{
|
||
|
//not allowed
|
||
|
assert(!packet.insertStartCode || !packet.bits);
|
||
|
|
||
|
// Check if this is first packet (only valid for some codecs)
|
||
|
if (packet.isFirstPacket)
|
||
|
{
|
||
|
// the first packet in the frame always signals the frametype
|
||
|
_frameType = packet.frameType;
|
||
|
}
|
||
|
|
||
|
// Check sequence number and update highest and lowest sequence numbers received.
|
||
|
// Move data if this seq num is lower than previously lowest.
|
||
|
|
||
|
if (packet.seqNum > _highSeqNum)
|
||
|
{
|
||
|
// This packet's seq num is higher than previously highest seq num; normal case
|
||
|
// if we have a wrap, only update with wrapped values
|
||
|
if (!(_highSeqNum < 0x00ff && packet.seqNum > 0xff00))
|
||
|
{
|
||
|
_highSeqNum = packet.seqNum;
|
||
|
}
|
||
|
} else if (_highSeqNum > 0xff00 && packet.seqNum < 0x00ff)
|
||
|
{
|
||
|
// wrap
|
||
|
_highSeqNum = packet.seqNum;
|
||
|
}
|
||
|
int packetIndex = packet.seqNum - (WebRtc_UWord16)_lowSeqNum;
|
||
|
if(_lowSeqNum < 0x00ff && packet.seqNum > 0xff00)
|
||
|
{
|
||
|
// negative wrap
|
||
|
packetIndex = packet.seqNum - 0x10000 - _lowSeqNum;
|
||
|
}
|
||
|
if (packetIndex < 0)
|
||
|
{
|
||
|
if (_lowSeqNum > 0xff00 && packet.seqNum < 0x00ff)
|
||
|
{
|
||
|
// we have a false detect due to the wrap
|
||
|
packetIndex = (0xffff - (WebRtc_UWord16)_lowSeqNum) + packet.seqNum + (WebRtc_UWord16)1;
|
||
|
} else
|
||
|
{
|
||
|
// This packet's seq num is lower than previously lowest seq num, but no wrap
|
||
|
// We need to move the data in all arrays indexed by packetIndex and insert the new
|
||
|
// packet's info
|
||
|
// How many packets should we leave room for (positions to shift)?
|
||
|
// Example - this seq num is 3 lower than previously lowest seq num
|
||
|
// Before: |--prev packet with lowest seq num--|--|...|
|
||
|
// After: |--new lowest seq num--|--|--|--prev packet with lowest seq num--|--|...|
|
||
|
|
||
|
WebRtc_UWord16 positionsToShift = (WebRtc_UWord16)_lowSeqNum - packet.seqNum;
|
||
|
WebRtc_UWord16 numOfPacketsToMove = _highestPacketIndex + 1;
|
||
|
|
||
|
// sanity, do we have room for the shift?
|
||
|
if ((positionsToShift + numOfPacketsToMove) > kMaxPacketsInJitterBuffer)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// Shift _ORwithPrevByte array
|
||
|
memmove(&_ORwithPrevByte[positionsToShift],
|
||
|
&_ORwithPrevByte[0], numOfPacketsToMove*sizeof(bool));
|
||
|
memset(&_ORwithPrevByte[0], false, positionsToShift*sizeof(bool));
|
||
|
|
||
|
// Shift _packetSizeBytes array
|
||
|
memmove(&_packetSizeBytes[positionsToShift],
|
||
|
&_packetSizeBytes[0], numOfPacketsToMove*sizeof(WebRtc_UWord32));
|
||
|
memset(&_packetSizeBytes[0], 0, positionsToShift*sizeof(WebRtc_UWord32));
|
||
|
|
||
|
//Shift _naluCompleteness
|
||
|
memmove(&_naluCompleteness[positionsToShift],
|
||
|
&_naluCompleteness[0], numOfPacketsToMove*sizeof(WebRtc_UWord8));
|
||
|
memset(&_naluCompleteness[0], kNaluUnset, positionsToShift*sizeof(WebRtc_UWord8));
|
||
|
|
||
|
_highestPacketIndex += positionsToShift;
|
||
|
_lowSeqNum = packet.seqNum;
|
||
|
packetIndex = 0; // (seqNum - _lowSeqNum) = 0
|
||
|
}
|
||
|
} // if (_lowSeqNum > seqNum)
|
||
|
|
||
|
// sanity
|
||
|
if (packetIndex >= kMaxPacketsInJitterBuffer )
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
if (packetIndex < 0 )
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// Check for duplicate packets
|
||
|
if (_packetSizeBytes[packetIndex] != 0)
|
||
|
{
|
||
|
// We have already received a packet with this sequence number, ignore it.
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
// update highest packet index
|
||
|
_highestPacketIndex = packetIndex > _highestPacketIndex ? packetIndex :_highestPacketIndex;
|
||
|
|
||
|
return InsertBuffer(ptrStartOfLayer, packetIndex, packet);
|
||
|
}
|
||
|
|
||
|
WebRtc_UWord32 VCMSessionInfo::PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer, VideoCodecType codec)
|
||
|
{
|
||
|
WebRtc_UWord32 currentPacketOffset = 0;
|
||
|
WebRtc_UWord32 length = GetSessionLength();
|
||
|
WebRtc_UWord32 idSum = 0;
|
||
|
WebRtc_UWord32 realDataBytes = 0;
|
||
|
if (length == 0)
|
||
|
{
|
||
|
return length;
|
||
|
}
|
||
|
bool previousLost = false;
|
||
|
for (int i=0; i <= _highestPacketIndex; i++)
|
||
|
{
|
||
|
if (_ORwithPrevByte[i])
|
||
|
{
|
||
|
if (currentPacketOffset > 0)
|
||
|
{
|
||
|
WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer + currentPacketOffset;
|
||
|
|
||
|
if (_packetSizeBytes[i-1] == 0 || previousLost)
|
||
|
{
|
||
|
// It is be better to throw away this packet if we are missing the
|
||
|
// previous packet.
|
||
|
memset(ptrFirstByte, 0, _packetSizeBytes[i]);
|
||
|
previousLost = true;
|
||
|
}
|
||
|
else if (_packetSizeBytes[i] > 0) // Ignore if empty packet
|
||
|
{
|
||
|
// Glue with previous byte
|
||
|
// Move everything from [this packet start + 1, end of buffer] one byte to the left
|
||
|
WebRtc_UWord8* ptrPrevByte = ptrFirstByte - 1;
|
||
|
*ptrPrevByte = (*ptrPrevByte) | (*ptrFirstByte);
|
||
|
WebRtc_UWord32 lengthToEnd = length - (currentPacketOffset + 1);
|
||
|
memmove((void*)ptrFirstByte, (void*)(ptrFirstByte + 1), lengthToEnd);
|
||
|
_packetSizeBytes[i]--;
|
||
|
length--;
|
||
|
previousLost = false;
|
||
|
realDataBytes += _packetSizeBytes[i];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memset(ptrStartOfLayer, 0, _packetSizeBytes[i]);
|
||
|
previousLost = true;
|
||
|
}
|
||
|
}
|
||
|
else if (_packetSizeBytes[i] == 0 && codec == kVideoCodecH263)
|
||
|
{
|
||
|
WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer + currentPacketOffset;
|
||
|
memmove(ptrFirstByte + 10, ptrFirstByte, length - currentPacketOffset);
|
||
|
memset(ptrFirstByte, 0, 10);
|
||
|
_packetSizeBytes[i] = 10;
|
||
|
length += _packetSizeBytes[i];
|
||
|
previousLost = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
realDataBytes += _packetSizeBytes[i];
|
||
|
previousLost = false;
|
||
|
}
|
||
|
currentPacketOffset += _packetSizeBytes[i];
|
||
|
}
|
||
|
if (realDataBytes == 0)
|
||
|
{
|
||
|
// Drop the frame since all it contains are zeros
|
||
|
length = 0;
|
||
|
memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
|
||
|
}
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
}
|