VCM: 1. Updating handling of empty packets. 2. Updating JB test. 3. Removing un-used code.
Review URL: http://webrtc-codereview.appspot.com/59001 git-svn-id: http://webrtc.googlecode.com/svn/trunk@142 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
c13708271a
commit
cdc943e2d5
@ -113,8 +113,9 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sanity checks
|
// sanity checks
|
||||||
if (_size + packet.sizeBytes + (packet.insertStartCode?kH264StartCodeLengthBytes:0) >
|
if (_size + packet.sizeBytes +
|
||||||
kMaxJBFrameSizeBytes)
|
(packet.insertStartCode ? kH264StartCodeLengthBytes : 0 )
|
||||||
|
> kMaxJBFrameSizeBytes)
|
||||||
{
|
{
|
||||||
return kSizeError;
|
return kSizeError;
|
||||||
}
|
}
|
||||||
@ -122,7 +123,8 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs)
|
|||||||
{
|
{
|
||||||
return kSizeError;
|
return kSizeError;
|
||||||
}
|
}
|
||||||
if(!_sessionInfo.HaveStartSeqNumber())
|
if ((packet.frameType != kFrameEmpty) &&
|
||||||
|
(!_sessionInfo.HaveStartSeqNumber()))
|
||||||
{
|
{
|
||||||
_sessionInfo.SetStartSeqNumber(packet.seqNum);
|
_sessionInfo.SetStartSeqNumber(packet.seqNum);
|
||||||
}
|
}
|
||||||
@ -133,13 +135,13 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs)
|
|||||||
|
|
||||||
if (kStateEmpty == _state)
|
if (kStateEmpty == _state)
|
||||||
{
|
{
|
||||||
// This is the first packet (empty and/or data) inserted into this frame.
|
// First packet (empty and/or media) inserted into this frame.
|
||||||
// store some info and set some initial values.
|
// store some info and set some initial values.
|
||||||
_timeStamp = packet.timestamp;
|
_timeStamp = packet.timestamp;
|
||||||
_codec = packet.codec;
|
_codec = packet.codec;
|
||||||
// for the first media packet
|
|
||||||
if (packet.frameType != kFrameEmpty)
|
if (packet.frameType != kFrameEmpty)
|
||||||
{
|
{
|
||||||
|
// first media packet
|
||||||
SetState(kStateIncomplete);
|
SetState(kStateIncomplete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,9 +150,12 @@ VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs)
|
|||||||
(packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
|
(packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
|
||||||
if (requiredSizeBytes >= _size)
|
if (requiredSizeBytes >= _size)
|
||||||
{
|
{
|
||||||
const WebRtc_UWord32 increments = requiredSizeBytes / kBufferIncStepSizeBytes +
|
const WebRtc_UWord32 increments = requiredSizeBytes /
|
||||||
(requiredSizeBytes % kBufferIncStepSizeBytes > 0);
|
kBufferIncStepSizeBytes +
|
||||||
const WebRtc_UWord32 newSize = _size + increments * kBufferIncStepSizeBytes;
|
(requiredSizeBytes %
|
||||||
|
kBufferIncStepSizeBytes > 0);
|
||||||
|
const WebRtc_UWord32 newSize = _size +
|
||||||
|
increments * kBufferIncStepSizeBytes;
|
||||||
if (newSize > kMaxJBFrameSizeBytes)
|
if (newSize > kMaxJBFrameSizeBytes)
|
||||||
{
|
{
|
||||||
return kSizeError;
|
return kSizeError;
|
||||||
|
@ -666,7 +666,7 @@ VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
|
|||||||
// Verify that we have received the first packet of the next frame.
|
// Verify that we have received the first packet of the next frame.
|
||||||
// This is the only way we can be sure we're not missing the last packet.
|
// This is the only way we can be sure we're not missing the last packet.
|
||||||
if (nextFrame != NULL && nextFrame->GetLowSeqNum() ==
|
if (nextFrame != NULL && nextFrame->GetLowSeqNum() ==
|
||||||
static_cast<WebRtc_UWord16>(oldestFrame->GetHighSeqNum()+1)) // Sequence number is only 16 bit
|
static_cast<WebRtc_UWord16>(oldestFrame->GetHighSeqNum() + 1))
|
||||||
{
|
{
|
||||||
_missingMarkerBits = true;
|
_missingMarkerBits = true;
|
||||||
bool completeSession = oldestFrame->ForceSetHaveLastPacket();
|
bool completeSession = oldestFrame->ForceSetHaveLastPacket();
|
||||||
@ -800,7 +800,8 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
|
|||||||
_critSect.Leave();
|
_critSect.Leave();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const WebRtc_Word64 endWaitTimeMs = VCMTickTime::MillisecondTimestamp() + maxWaitTimeMS;
|
const WebRtc_Word64 endWaitTimeMs = VCMTickTime::MillisecondTimestamp()
|
||||||
|
+ maxWaitTimeMS;
|
||||||
WebRtc_Word64 waitTimeMs = maxWaitTimeMS;
|
WebRtc_Word64 waitTimeMs = maxWaitTimeMS;
|
||||||
while (waitTimeMs > 0)
|
while (waitTimeMs > 0)
|
||||||
{
|
{
|
||||||
@ -849,7 +850,7 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
|
|||||||
|
|
||||||
if (oldestFrame == NULL)
|
if (oldestFrame == NULL)
|
||||||
{
|
{
|
||||||
// Even after signalling we're still missing a complete _continuous_ frame
|
// Even after signaling we're still missing a complete _continuous_ frame
|
||||||
_critSect.Leave();
|
_critSect.Leave();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1269,7 +1270,8 @@ VCMJitterBuffer::GetNackList(WebRtc_UWord16& nackSize,bool& listExtended)
|
|||||||
|
|
||||||
// Assume called internally with critsect
|
// Assume called internally with critsect
|
||||||
WebRtc_Word32
|
WebRtc_Word32
|
||||||
VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum, WebRtc_Word32& highSeqNum) const
|
VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum,
|
||||||
|
WebRtc_Word32& highSeqNum) const
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int seqNum = -1;
|
int seqNum = -1;
|
||||||
@ -1277,7 +1279,7 @@ VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum, WebRtc_Word
|
|||||||
highSeqNum = -1;
|
highSeqNum = -1;
|
||||||
lowSeqNum = _lastDecodedSeqNum;
|
lowSeqNum = _lastDecodedSeqNum;
|
||||||
|
|
||||||
// find highest seqnumbers
|
// find highest seq numbers
|
||||||
for (i = 0; i < _maxNumberOfFrames; ++i)
|
for (i = 0; i < _maxNumberOfFrames; ++i)
|
||||||
{
|
{
|
||||||
seqNum = _frameBuffers[i]->GetHighSeqNum();
|
seqNum = _frameBuffers[i]->GetHighSeqNum();
|
||||||
@ -1342,11 +1344,13 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
|
|||||||
//This happens if we lose the first packet, nothing is popped
|
//This happens if we lose the first packet, nothing is popped
|
||||||
if (highSeqNum == -1)
|
if (highSeqNum == -1)
|
||||||
{
|
{
|
||||||
nackSize = 0;// we have not received any packets yet
|
// we have not received any packets yet
|
||||||
|
nackSize = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nackSize = 0xffff; // signal that we want a key frame request to be sent
|
// signal that we want a key frame request to be sent
|
||||||
|
nackSize = 0xffff;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1368,9 +1372,10 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
|
|||||||
if (numberOfSeqNum > kNackHistoryLength)
|
if (numberOfSeqNum > kNackHistoryLength)
|
||||||
{
|
{
|
||||||
// Nack list is too big, flush and try to restart.
|
// Nack list is too big, flush and try to restart.
|
||||||
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
|
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
|
||||||
"Nack list too large, try to find a key frame and restart from seq: %d."
|
VCMId(_vcmId, _receiverId),
|
||||||
" Lowest seq in jb %d", highSeqNum,lowSeqNum);
|
"Nack list too large, try to find a key frame and restart "
|
||||||
|
"from seq: %d. Lowest seq in jb %d", highSeqNum,lowSeqNum);
|
||||||
|
|
||||||
// This nack size will trigger a key request...
|
// This nack size will trigger a key request...
|
||||||
bool foundIFrame = false;
|
bool foundIFrame = false;
|
||||||
@ -1463,8 +1468,8 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
|
|||||||
(kStateDecoding != state))
|
(kStateDecoding != state))
|
||||||
{
|
{
|
||||||
// Reaching thus far means we are going to update the nack list
|
// Reaching thus far means we are going to update the nack list
|
||||||
// When in hybrid mode, we also need to check empty frames, so as not
|
// When in hybrid mode, we also need to check empty frames, so as
|
||||||
// to add empty packets to the nack list
|
// not to add empty packets to the nack list
|
||||||
if (_nackMode == kNackHybrid)
|
if (_nackMode == kNackHybrid)
|
||||||
{
|
{
|
||||||
// build external rttScore based on RTT value
|
// build external rttScore based on RTT value
|
||||||
@ -1534,7 +1539,7 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
|
|||||||
listExtended = true;
|
listExtended = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(WebRtc_UWord32 j = 0; j < nackSize; j++)
|
for (WebRtc_UWord32 j = 0; j < nackSize; j++)
|
||||||
{
|
{
|
||||||
// Check if the list has been extended since it was last created. I.e,
|
// Check if the list has been extended since it was last created. I.e,
|
||||||
// new items have been added
|
// new items have been added
|
||||||
@ -1543,7 +1548,7 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
|
|||||||
WebRtc_UWord32 k = 0;
|
WebRtc_UWord32 k = 0;
|
||||||
for (k = j; k < _NACKSeqNumLength; k++)
|
for (k = j; k < _NACKSeqNumLength; k++)
|
||||||
{
|
{
|
||||||
// Found the item in the last list. I.e, no new items found yet.
|
// Found the item in the last list, i.e, no new items found yet.
|
||||||
if (_NACKSeqNum[k] == (WebRtc_UWord16)_NACKSeqNumInternal[j])
|
if (_NACKSeqNum[k] == (WebRtc_UWord16)_NACKSeqNumInternal[j])
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -1727,7 +1732,8 @@ void
|
|||||||
VCMJitterBuffer::UpdateOldJitterSample(const VCMPacket& packet)
|
VCMJitterBuffer::UpdateOldJitterSample(const VCMPacket& packet)
|
||||||
{
|
{
|
||||||
if (_waitingForCompletion.timestamp != packet.timestamp &&
|
if (_waitingForCompletion.timestamp != packet.timestamp &&
|
||||||
LatestTimestamp(_waitingForCompletion.timestamp, packet.timestamp) == packet.timestamp)
|
LatestTimestamp(_waitingForCompletion.timestamp, packet.timestamp) ==
|
||||||
|
packet.timestamp)
|
||||||
{
|
{
|
||||||
// This is a newer frame than the one waiting for completion.
|
// This is a newer frame than the one waiting for completion.
|
||||||
_waitingForCompletion.frameSize = packet.sizeBytes;
|
_waitingForCompletion.frameSize = packet.sizeBytes;
|
||||||
@ -1798,7 +1804,10 @@ VCMJitterBuffer::RecycleFramesUntilKeyFrame()
|
|||||||
{
|
{
|
||||||
// Throw at least one frame.
|
// Throw at least one frame.
|
||||||
_dropCount++;
|
_dropCount++;
|
||||||
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), "Jitter buffer drop count:%d, lowSeq %d", _dropCount, oldestFrame->GetLowSeqNum());
|
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
|
||||||
|
VCMId(_vcmId, _receiverId),
|
||||||
|
"Jitter buffer drop count:%d, lowSeq %d", _dropCount,
|
||||||
|
oldestFrame->GetLowSeqNum());
|
||||||
_frameBuffersTSOrder.Erase(oldestFrameListItem);
|
_frameBuffersTSOrder.Erase(oldestFrameListItem);
|
||||||
RecycleFrame(oldestFrame);
|
RecycleFrame(oldestFrame);
|
||||||
|
|
||||||
@ -1810,12 +1819,15 @@ VCMJitterBuffer::RecycleFramesUntilKeyFrame()
|
|||||||
|
|
||||||
if(oldestFrame != NULL)
|
if(oldestFrame != NULL)
|
||||||
{
|
{
|
||||||
foundIFrame = foundIFrame || (oldestFrame->FrameType() != kVideoFrameDelta);
|
foundIFrame = foundIFrame ||
|
||||||
|
(oldestFrame->FrameType() != kVideoFrameDelta);
|
||||||
if (foundIFrame)
|
if (foundIFrame)
|
||||||
{
|
{
|
||||||
// fake the last played out to match the start of this key frame
|
// fake the last played out to match the start of this key frame
|
||||||
_lastDecodedSeqNum = (WebRtc_UWord16)((WebRtc_UWord16)(oldestFrame->GetLowSeqNum()) - 1);
|
_lastDecodedSeqNum = (WebRtc_UWord16)((WebRtc_UWord16)
|
||||||
_lastDecodedTimeStamp = (WebRtc_UWord32)(oldestFrame->TimeStamp() - 1);
|
(oldestFrame->GetLowSeqNum()) - 1);
|
||||||
|
_lastDecodedTimeStamp = (WebRtc_UWord32)
|
||||||
|
(oldestFrame->TimeStamp() - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1843,7 +1855,8 @@ VCMJitterBuffer::CleanUpOldFrames()
|
|||||||
|
|
||||||
// Release the frame if it's older than the last decoded frame.
|
// Release the frame if it's older than the last decoded frame.
|
||||||
if (_lastDecodedTimeStamp > -1 &&
|
if (_lastDecodedTimeStamp > -1 &&
|
||||||
LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp), frameTimeStamp)
|
LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
|
||||||
|
frameTimeStamp)
|
||||||
== static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp))
|
== static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp))
|
||||||
{
|
{
|
||||||
const WebRtc_Word32 frameLowSeqNum = oldestFrame->GetLowSeqNum();
|
const WebRtc_Word32 frameLowSeqNum = oldestFrame->GetLowSeqNum();
|
||||||
@ -1855,7 +1868,8 @@ VCMJitterBuffer::CleanUpOldFrames()
|
|||||||
{
|
{
|
||||||
// Could happen when sending filler data.
|
// Could happen when sending filler data.
|
||||||
// Filler packet (size = 0) belonging to last decoded frame.
|
// Filler packet (size = 0) belonging to last decoded frame.
|
||||||
// Frame: | packet | packet | packet M=1 | filler data (size = 0) | filler data (size = 0)| ...
|
// Frame: | packet | packet | packet M=1 |
|
||||||
|
// filler data (size = 0) | filler data (size = 0)| ...
|
||||||
|
|
||||||
// This frame follows the last decoded frame
|
// This frame follows the last decoded frame
|
||||||
_lastDecodedSeqNum = frameHighSeqNum;
|
_lastDecodedSeqNum = frameHighSeqNum;
|
||||||
@ -1966,7 +1980,8 @@ VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame)
|
|||||||
// First frame
|
// First frame
|
||||||
frame.SetPreviousFrameLoss();
|
frame.SetPreviousFrameLoss();
|
||||||
}
|
}
|
||||||
else if (frame.GetLowSeqNum() != ((WebRtc_UWord16)_lastDecodedSeqNum + (WebRtc_UWord16)1))
|
else if (frame.GetLowSeqNum() != ((WebRtc_UWord16)_lastDecodedSeqNum +
|
||||||
|
(WebRtc_UWord16)1))
|
||||||
{
|
{
|
||||||
// Frame loss
|
// Frame loss
|
||||||
frame.SetPreviousFrameLoss();
|
frame.SetPreviousFrameLoss();
|
||||||
@ -1992,12 +2007,7 @@ VCMJitterBuffer::WaitForNack()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// RTT low, we can afford the wait
|
// Either NACK only or hybrid
|
||||||
else if (_rttMs <= kLowRttNackMs)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// interim values - hybrid mode
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ enum { kH264StartCodeLengthBytes = 4};
|
|||||||
// Used to indicate if a received packet contain a complete NALU (or equivalent)
|
// Used to indicate if a received packet contain a complete NALU (or equivalent)
|
||||||
enum VCMNaluCompleteness
|
enum VCMNaluCompleteness
|
||||||
{
|
{
|
||||||
kNaluUnset=0, //Packet has not been filled.
|
kNaluUnset = 0, //Packet has not been filled.
|
||||||
kNaluComplete=1, //Packet can be decoded as is.
|
kNaluComplete = 1, //Packet can be decoded as is.
|
||||||
kNaluStart, // Packet contain beginning of NALU
|
kNaluStart, // Packet contain beginning of NALU
|
||||||
kNaluIncomplete, //Packet is not beginning or end of NALU
|
kNaluIncomplete, //Packet is not beginning or end of NALU
|
||||||
kNaluEnd // Packet is the end of a NALU
|
kNaluEnd, // Packet is the end of a NALU
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -113,7 +113,7 @@ VCMReceiver::InsertPacket(const VCMPacket& packet,
|
|||||||
|
|
||||||
WebRtc_Word64 renderTimeMs = _timing.RenderTimeMs(packet.timestamp, nowMs);
|
WebRtc_Word64 renderTimeMs = _timing.RenderTimeMs(packet.timestamp, nowMs);
|
||||||
|
|
||||||
if(renderTimeMs < 0)
|
if (renderTimeMs < 0)
|
||||||
{
|
{
|
||||||
// Render time error. Assume that this is due to some change in
|
// Render time error. Assume that this is due to some change in
|
||||||
// the incoming video stream and reset the JB and the timing.
|
// the incoming video stream and reset the JB and the timing.
|
||||||
@ -163,7 +163,7 @@ VCMReceiver::InsertPacket(const VCMPacket& packet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert packet into jitter buffer
|
// Insert packet into jitter buffer
|
||||||
// both data and empty packets
|
// both media and empty packets
|
||||||
const VCMFrameBufferEnum ret = _jitterBuffer.InsertPacket(buffer, packet);
|
const VCMFrameBufferEnum ret = _jitterBuffer.InsertPacket(buffer, packet);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -27,7 +27,8 @@ VCMSessionInfo::VCMSessionInfo():
|
|||||||
_highSeqNum(-1),
|
_highSeqNum(-1),
|
||||||
_highestPacketIndex(0),
|
_highestPacketIndex(0),
|
||||||
_emptySeqNumLow(-1),
|
_emptySeqNumLow(-1),
|
||||||
_emptySeqNumHigh(-1)
|
_emptySeqNumHigh(-1),
|
||||||
|
_markerSeqNum(-1)
|
||||||
{
|
{
|
||||||
memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
|
memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
|
||||||
memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
|
memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
|
||||||
@ -47,6 +48,10 @@ VCMSessionInfo::GetLowSeqNum() const
|
|||||||
WebRtc_Word32
|
WebRtc_Word32
|
||||||
VCMSessionInfo::GetHighSeqNum() const
|
VCMSessionInfo::GetHighSeqNum() const
|
||||||
{
|
{
|
||||||
|
if (_emptySeqNumHigh != -1)
|
||||||
|
{
|
||||||
|
return _emptySeqNumHigh;
|
||||||
|
}
|
||||||
return _highSeqNum;
|
return _highSeqNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +69,7 @@ VCMSessionInfo::Reset()
|
|||||||
_previousFrameLoss = false;
|
_previousFrameLoss = false;
|
||||||
_sessionNACK = false;
|
_sessionNACK = false;
|
||||||
_highestPacketIndex = 0;
|
_highestPacketIndex = 0;
|
||||||
|
_markerSeqNum = -1;
|
||||||
memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
|
memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
|
||||||
memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
|
memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
|
||||||
memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte));
|
memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte));
|
||||||
@ -89,7 +95,7 @@ VCMSessionInfo::SetStartSeqNumber(WebRtc_UWord16 seqNumber)
|
|||||||
bool
|
bool
|
||||||
VCMSessionInfo::HaveStartSeqNumber()
|
VCMSessionInfo::HaveStartSeqNumber()
|
||||||
{
|
{
|
||||||
if(_lowSeqNum == -1 || _highSeqNum == -1)
|
if (_lowSeqNum == -1 || _highSeqNum == -1)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -118,7 +124,7 @@ VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
packetSize = packet.sizeBytes +
|
packetSize = packet.sizeBytes +
|
||||||
(packet.insertStartCode?kH264StartCodeLengthBytes:0);
|
(packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_packetSizeBytes[packetIndex] += packetSize;
|
_packetSizeBytes[packetIndex] += packetSize;
|
||||||
@ -146,7 +152,8 @@ VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
_ORwithPrevByte[packetIndex] = true;
|
_ORwithPrevByte[packetIndex] = true;
|
||||||
if (packet.dataPtr != NULL)
|
if (packet.dataPtr != NULL)
|
||||||
{
|
{
|
||||||
memcpy((void*)(ptrStartOfLayer + offset), packet.dataPtr, packetSize);
|
memcpy((void*)(ptrStartOfLayer + offset), packet.dataPtr,
|
||||||
|
packetSize);
|
||||||
}
|
}
|
||||||
returnLength = packetSize;
|
returnLength = packetSize;
|
||||||
}
|
}
|
||||||
@ -155,14 +162,14 @@ VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
_ORwithPrevByte[packetIndex] = false;
|
_ORwithPrevByte[packetIndex] = false;
|
||||||
if (packet.dataPtr != NULL)
|
if (packet.dataPtr != NULL)
|
||||||
{
|
{
|
||||||
const unsigned char startCode[] = {0, 0, 0, 1};
|
const unsigned char startCode[] = {0, 0, 0, 1};
|
||||||
if(packet.insertStartCode)
|
if(packet.insertStartCode)
|
||||||
{
|
{
|
||||||
memcpy((void*)(ptrStartOfLayer + offset), startCode,
|
memcpy((void*)(ptrStartOfLayer + offset), startCode,
|
||||||
kH264StartCodeLengthBytes);
|
kH264StartCodeLengthBytes);
|
||||||
}
|
}
|
||||||
memcpy((void*)(ptrStartOfLayer + offset
|
memcpy((void*)(ptrStartOfLayer + offset
|
||||||
+ (packet.insertStartCode?kH264StartCodeLengthBytes:0)),
|
+ (packet.insertStartCode ? kH264StartCodeLengthBytes : 0)),
|
||||||
packet.dataPtr,
|
packet.dataPtr,
|
||||||
packet.sizeBytes);
|
packet.sizeBytes);
|
||||||
}
|
}
|
||||||
@ -172,16 +179,14 @@ VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
if (packet.isFirstPacket)
|
if (packet.isFirstPacket)
|
||||||
{
|
{
|
||||||
_haveFirstPacket = true;
|
_haveFirstPacket = true;
|
||||||
//initializing FEC sequence numbers
|
|
||||||
_emptySeqNumHigh = -1;
|
|
||||||
_emptySeqNumLow = -1;
|
|
||||||
}
|
}
|
||||||
if (packet.markerBit)
|
if (packet.markerBit)
|
||||||
{
|
{
|
||||||
_markerBit = true;
|
_markerBit = true;
|
||||||
|
_markerSeqNum = packet.seqNum;
|
||||||
}
|
}
|
||||||
// Store information about if the packet is decodable as is or not.
|
// Store information about if the packet is decodable as is or not.
|
||||||
_naluCompleteness[packetIndex]=packet.completeNALU;
|
_naluCompleteness[packetIndex] = packet.completeNALU;
|
||||||
|
|
||||||
UpdateCompleteSession();
|
UpdateCompleteSession();
|
||||||
|
|
||||||
@ -193,9 +198,10 @@ VCMSessionInfo::UpdateCompleteSession()
|
|||||||
{
|
{
|
||||||
if (_haveFirstPacket && _markerBit)
|
if (_haveFirstPacket && _markerBit)
|
||||||
{
|
{
|
||||||
// do we have all packets in this session?
|
// Do we have all the packets in this session?
|
||||||
bool completeSession = true;
|
bool completeSession = true;
|
||||||
for (int i = 0; i<= _highestPacketIndex; ++i)
|
|
||||||
|
for (int i = 0; i <= _highestPacketIndex; ++i)
|
||||||
{
|
{
|
||||||
if (_naluCompleteness[i] == kNaluUnset)
|
if (_naluCompleteness[i] == kNaluUnset)
|
||||||
{
|
{
|
||||||
@ -213,13 +219,12 @@ bool VCMSessionInfo::IsSessionComplete()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the start and end index of packetIndex packet.
|
// Find the start and end index of packetIndex packet.
|
||||||
// startIndex -1 if start not found endIndex=-1 if end index not found
|
// startIndex -1 if start not found endIndex = -1 if end index not found
|
||||||
void
|
void
|
||||||
VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
|
VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
|
||||||
WebRtc_Word32& startIndex,
|
WebRtc_Word32& startIndex,
|
||||||
WebRtc_Word32& endIndex)
|
WebRtc_Word32& endIndex)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_naluCompleteness[packetIndex] == kNaluStart ||
|
if (_naluCompleteness[packetIndex] == kNaluStart ||
|
||||||
_naluCompleteness[packetIndex] == kNaluComplete)
|
_naluCompleteness[packetIndex] == kNaluComplete)
|
||||||
{
|
{
|
||||||
@ -230,10 +235,11 @@ VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
|
|||||||
for (startIndex = packetIndex - 1; startIndex >= 0; --startIndex)
|
for (startIndex = packetIndex - 1; startIndex >= 0; --startIndex)
|
||||||
{
|
{
|
||||||
|
|
||||||
if( (_naluCompleteness[startIndex] == kNaluComplete &&
|
if ((_naluCompleteness[startIndex] == kNaluComplete &&
|
||||||
_packetSizeBytes[startIndex] > 0) ||
|
_packetSizeBytes[startIndex] > 0) ||
|
||||||
// Found previous NALU.
|
// Found previous NALU.
|
||||||
(_naluCompleteness[startIndex] == kNaluEnd && startIndex>0))
|
(_naluCompleteness[startIndex] == kNaluEnd &&
|
||||||
|
startIndex > 0))
|
||||||
{
|
{
|
||||||
startIndex++;
|
startIndex++;
|
||||||
break;
|
break;
|
||||||
@ -246,31 +252,35 @@ VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_naluCompleteness[packetIndex] == kNaluEnd ||
|
if (_naluCompleteness[packetIndex] == kNaluEnd ||
|
||||||
_naluCompleteness[packetIndex] == kNaluComplete)
|
_naluCompleteness[packetIndex] == kNaluComplete)
|
||||||
{
|
{
|
||||||
endIndex=packetIndex;
|
endIndex = packetIndex;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Find the next NALU
|
// Find the next NALU
|
||||||
for (endIndex=packetIndex+1;endIndex<=_highestPacketIndex;++endIndex)
|
for (endIndex = packetIndex + 1; endIndex <= _highestPacketIndex;
|
||||||
|
++endIndex)
|
||||||
{
|
{
|
||||||
if ((_naluCompleteness[endIndex]==kNaluComplete &&
|
if ((_naluCompleteness[endIndex] == kNaluComplete &&
|
||||||
_packetSizeBytes[endIndex]>0) ||
|
_packetSizeBytes[endIndex] > 0) ||
|
||||||
_naluCompleteness[endIndex]==kNaluStart) // Found next NALU.
|
// Found next NALU.
|
||||||
|
_naluCompleteness[endIndex] == kNaluStart)
|
||||||
{
|
{
|
||||||
endIndex--;
|
endIndex--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( _naluCompleteness[endIndex]==kNaluEnd)
|
if ( _naluCompleteness[endIndex] == kNaluEnd)
|
||||||
{
|
{
|
||||||
// This is where the NALU end.
|
// This is where the NALU end.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (endIndex > _highestPacketIndex)
|
if (endIndex > _highestPacketIndex)
|
||||||
|
{
|
||||||
endIndex = -1;
|
endIndex = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +303,7 @@ VCMSessionInfo::DeletePackets(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
{
|
{
|
||||||
// Get the offset we want to move to.
|
// Get the offset we want to move to.
|
||||||
int destOffset = 0;
|
int destOffset = 0;
|
||||||
for(int j = 0;j < startIndex;j++)
|
for (int j = 0;j < startIndex;j++)
|
||||||
{
|
{
|
||||||
destOffset += _packetSizeBytes[j];
|
destOffset += _packetSizeBytes[j];
|
||||||
}
|
}
|
||||||
@ -318,15 +328,10 @@ VCMSessionInfo::DeletePackets(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
WebRtc_UWord32
|
WebRtc_UWord32
|
||||||
VCMSessionInfo::MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer)
|
VCMSessionInfo::MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer)
|
||||||
{
|
{
|
||||||
if(_lowSeqNum < 0) // No packets in this session
|
if (_lowSeqNum < 0) // No packets in this session
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (_lowSeqNum == _emptySeqNumLow)
|
|
||||||
{
|
|
||||||
// no data packets in this session
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebRtc_Word32 startIndex = 0;
|
WebRtc_Word32 startIndex = 0;
|
||||||
WebRtc_Word32 endIndex = 0;
|
WebRtc_Word32 endIndex = 0;
|
||||||
@ -336,7 +341,7 @@ VCMSessionInfo::MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer)
|
|||||||
{
|
{
|
||||||
if (_naluCompleteness[packetIndex] == kNaluUnset) // Found a lost packet
|
if (_naluCompleteness[packetIndex] == kNaluUnset) // Found a lost packet
|
||||||
{
|
{
|
||||||
FindNaluBorder(packetIndex,startIndex,endIndex);
|
FindNaluBorder(packetIndex, startIndex, endIndex);
|
||||||
if (startIndex == -1)
|
if (startIndex == -1)
|
||||||
{
|
{
|
||||||
startIndex = 0;
|
startIndex = 0;
|
||||||
@ -346,34 +351,37 @@ VCMSessionInfo::MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer)
|
|||||||
endIndex = _highestPacketIndex;
|
endIndex = _highestPacketIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
returnLength += DeletePackets(ptrStartOfLayer,packetIndex,endIndex);
|
returnLength += DeletePackets(ptrStartOfLayer,
|
||||||
|
packetIndex, endIndex);
|
||||||
packetIndex = endIndex;
|
packetIndex = endIndex;
|
||||||
}// end lost packet
|
}// end lost packet
|
||||||
}
|
}
|
||||||
|
|
||||||
//Make sure the first packet is decodable (Either complete nalu or start of NALU)
|
// Make sure the first packet is decodable (Either complete nalu or start
|
||||||
|
// of NALU)
|
||||||
if (_packetSizeBytes[0] > 0)
|
if (_packetSizeBytes[0] > 0)
|
||||||
{
|
{
|
||||||
switch (_naluCompleteness[0])
|
switch (_naluCompleteness[0])
|
||||||
{
|
{
|
||||||
case kNaluComplete: //Packet can be decoded as is.
|
case kNaluComplete: // Packet can be decoded as is.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kNaluStart: // Packet contain beginning of NALU- No need to do anything.
|
case kNaluStart:
|
||||||
|
// Packet contain beginning of NALU- No need to do anything.
|
||||||
break;
|
break;
|
||||||
case kNaluIncomplete: //Packet is not beginning or end of NALU
|
case kNaluIncomplete: //Packet is not beginning or end of NALU
|
||||||
//Need to find the end of this fua NALU and delete all packets.
|
// Need to find the end of this NALU and delete all packets.
|
||||||
FindNaluBorder(0,startIndex,endIndex);
|
FindNaluBorder(0,startIndex,endIndex);
|
||||||
if(endIndex == -1) // No end found. Delete
|
if (endIndex == -1) // No end found. Delete
|
||||||
{
|
{
|
||||||
endIndex = _highestPacketIndex;
|
endIndex = _highestPacketIndex;
|
||||||
}
|
}
|
||||||
//Delete this NALU.
|
// Delete this NALU.
|
||||||
returnLength += DeletePackets(ptrStartOfLayer,0,endIndex);
|
returnLength += DeletePackets(ptrStartOfLayer, 0, endIndex);
|
||||||
break;
|
break;
|
||||||
case kNaluEnd: // Packet is the end of a NALU
|
case kNaluEnd: // Packet is the end of a NALU
|
||||||
//Delete this NALU
|
// Delete this NALU
|
||||||
returnLength += DeletePackets(ptrStartOfLayer,0,0);
|
returnLength += DeletePackets(ptrStartOfLayer, 0, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -441,7 +449,7 @@ VCMSessionInfo::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
|
|||||||
}
|
}
|
||||||
if (_lowSeqNum == -1)
|
if (_lowSeqNum == -1)
|
||||||
{
|
{
|
||||||
// no packets in this frame
|
// no media packets in this frame
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,8 +486,17 @@ VCMSessionInfo::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
// Score place holder - based on RTT and partition (when available).
|
// Score place holder - based on RTT and partition (when available).
|
||||||
const float nackScoreTh = 0.25f;
|
const float nackScoreTh = 0.25f;
|
||||||
WebRtc_Word32 highMediaPacket = _emptySeqNumLow > _lowSeqNum ?
|
|
||||||
_emptySeqNumLow - 1: _highSeqNum;
|
WebRtc_Word32 highMediaPacket;
|
||||||
|
if (_markerSeqNum != -1)
|
||||||
|
{
|
||||||
|
highMediaPacket = _markerSeqNum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
highMediaPacket = _emptySeqNumLow - 1 > _highSeqNum ?
|
||||||
|
_emptySeqNumLow - 1: _highSeqNum;
|
||||||
|
}
|
||||||
|
|
||||||
while (list[index] <= highMediaPacket && index < numberOfSeqNum)
|
while (list[index] <= highMediaPacket && index < numberOfSeqNum)
|
||||||
{
|
{
|
||||||
@ -569,66 +586,12 @@ VCMSessionInfo::UpdatePacketSize(WebRtc_Word32 packetIndex,
|
|||||||
_packetSizeBytes[packetIndex] = length;
|
_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
|
WebRtc_Word64
|
||||||
VCMSessionInfo::InsertPacket(const VCMPacket& packet,
|
VCMSessionInfo::InsertPacket(const VCMPacket& packet,
|
||||||
WebRtc_UWord8* ptrStartOfLayer)
|
WebRtc_UWord8* ptrStartOfLayer)
|
||||||
{
|
{
|
||||||
// not allowed
|
// not allowed
|
||||||
assert(!packet.insertStartCode || !packet.bits);
|
assert(!packet.insertStartCode || !packet.bits);
|
||||||
|
|
||||||
if (packet.frameType == kFrameEmpty)
|
|
||||||
{
|
|
||||||
// update seq number as an empty packet
|
|
||||||
// empty packets will be counted twice: both empty and standard packets.
|
|
||||||
InformOfEmptyPacket(packet.seqNum);
|
|
||||||
}
|
|
||||||
// Check if this is first packet (only valid for some codecs)
|
// Check if this is first packet (only valid for some codecs)
|
||||||
if (packet.isFirstPacket)
|
if (packet.isFirstPacket)
|
||||||
{
|
{
|
||||||
@ -637,12 +600,18 @@ VCMSessionInfo::InsertPacket(const VCMPacket& packet,
|
|||||||
}
|
}
|
||||||
else if (_frameType == kFrameEmpty && packet.frameType != kFrameEmpty)
|
else if (_frameType == kFrameEmpty && packet.frameType != kFrameEmpty)
|
||||||
{
|
{
|
||||||
// in case an empty packet came in first, update the frame type
|
// Update the frame type with the first media packet
|
||||||
_frameType = packet.frameType;
|
_frameType = packet.frameType;
|
||||||
}
|
}
|
||||||
|
if (packet.frameType == kFrameEmpty)
|
||||||
|
{
|
||||||
|
// update seq number as an empty packet
|
||||||
|
InformOfEmptyPacket(packet.seqNum);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check sequence number and update highest and lowest sequence numbers received.
|
// Check sequence number and update highest and lowest sequence numbers
|
||||||
// Move data if this seq num is lower than previously lowest.
|
// received. Move data if this seq num is lower than previously lowest.
|
||||||
|
|
||||||
if (packet.seqNum > _highSeqNum)
|
if (packet.seqNum > _highSeqNum)
|
||||||
{
|
{
|
||||||
@ -672,19 +641,22 @@ VCMSessionInfo::InsertPacket(const VCMPacket& packet,
|
|||||||
+ (WebRtc_UWord16)1;
|
+ (WebRtc_UWord16)1;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// This packet's seq num is lower than previously lowest seq num, but no wrap
|
// This packet's seq num is lower than previously lowest seq num,
|
||||||
// We need to move the data in all arrays indexed by packetIndex and insert the new
|
// but no wrap We need to move the data in all arrays indexed by
|
||||||
// packet's info
|
// packetIndex and insert the new packet's info
|
||||||
// How many packets should we leave room for (positions to shift)?
|
// How many packets should we leave room for (positions to shift)?
|
||||||
// Example - this seq num is 3 lower than previously lowest seq num
|
// Example - this seq num is 3 lower than previously lowest seq num
|
||||||
// Before: |--prev packet with lowest seq num--|--|...|
|
// Before: |--prev packet with lowest seq num--|--|...|
|
||||||
// After: |--new lowest seq num--|--|--|--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 positionsToShift = (WebRtc_UWord16)_lowSeqNum -
|
||||||
|
packet.seqNum;
|
||||||
WebRtc_UWord16 numOfPacketsToMove = _highestPacketIndex + 1;
|
WebRtc_UWord16 numOfPacketsToMove = _highestPacketIndex + 1;
|
||||||
|
|
||||||
// sanity, do we have room for the shift?
|
// sanity, do we have room for the shift?
|
||||||
if ((positionsToShift + numOfPacketsToMove) > kMaxPacketsInJitterBuffer)
|
if ((positionsToShift + numOfPacketsToMove) >
|
||||||
|
kMaxPacketsInJitterBuffer)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -696,13 +668,17 @@ VCMSessionInfo::InsertPacket(const VCMPacket& packet,
|
|||||||
|
|
||||||
// Shift _packetSizeBytes array
|
// Shift _packetSizeBytes array
|
||||||
memmove(&_packetSizeBytes[positionsToShift],
|
memmove(&_packetSizeBytes[positionsToShift],
|
||||||
&_packetSizeBytes[0], numOfPacketsToMove*sizeof(WebRtc_UWord32));
|
&_packetSizeBytes[0],
|
||||||
memset(&_packetSizeBytes[0], 0, positionsToShift*sizeof(WebRtc_UWord32));
|
numOfPacketsToMove * sizeof(WebRtc_UWord32));
|
||||||
|
memset(&_packetSizeBytes[0], 0,
|
||||||
|
positionsToShift * sizeof(WebRtc_UWord32));
|
||||||
|
|
||||||
//Shift _naluCompleteness
|
// Shift _naluCompleteness
|
||||||
memmove(&_naluCompleteness[positionsToShift],
|
memmove(&_naluCompleteness[positionsToShift],
|
||||||
&_naluCompleteness[0], numOfPacketsToMove*sizeof(WebRtc_UWord8));
|
&_naluCompleteness[0],
|
||||||
memset(&_naluCompleteness[0], kNaluUnset, positionsToShift*sizeof(WebRtc_UWord8));
|
numOfPacketsToMove * sizeof(WebRtc_UWord8));
|
||||||
|
memset(&_naluCompleteness[0], kNaluUnset,
|
||||||
|
positionsToShift * sizeof(WebRtc_UWord8));
|
||||||
|
|
||||||
_highestPacketIndex += positionsToShift;
|
_highestPacketIndex += positionsToShift;
|
||||||
_lowSeqNum = packet.seqNum;
|
_lowSeqNum = packet.seqNum;
|
||||||
@ -723,7 +699,7 @@ VCMSessionInfo::InsertPacket(const VCMPacket& packet,
|
|||||||
// Check for duplicate packets
|
// Check for duplicate packets
|
||||||
if (_packetSizeBytes[packetIndex] != 0)
|
if (_packetSizeBytes[packetIndex] != 0)
|
||||||
{
|
{
|
||||||
// We have already received a packet with this sequence number, ignore it.
|
// We have already received a packet with this seq number, ignore it.
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,7 +719,7 @@ VCMSessionInfo::InformOfEmptyPacket(const WebRtc_UWord16 seqNum)
|
|||||||
// and low sequence numbers and may assume that the packets in between are
|
// and low sequence numbers and may assume that the packets in between are
|
||||||
// empty packets belonging to the same frame (timestamp).
|
// empty packets belonging to the same frame (timestamp).
|
||||||
|
|
||||||
if (_emptySeqNumLow == -1 && _emptySeqNumHigh == -1)
|
if (_emptySeqNumLow == -1 && _emptySeqNumHigh == -1)
|
||||||
{
|
{
|
||||||
_emptySeqNumLow = seqNum;
|
_emptySeqNumLow = seqNum;
|
||||||
_emptySeqNumHigh = seqNum;
|
_emptySeqNumHigh = seqNum;
|
||||||
@ -795,23 +771,27 @@ VCMSessionInfo::PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
{
|
{
|
||||||
if (currentPacketOffset > 0)
|
if (currentPacketOffset > 0)
|
||||||
{
|
{
|
||||||
WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer + currentPacketOffset;
|
WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer +
|
||||||
|
currentPacketOffset;
|
||||||
|
|
||||||
if (_packetSizeBytes[i-1] == 0 || previousLost)
|
if (_packetSizeBytes[i-1] == 0 || previousLost)
|
||||||
{
|
{
|
||||||
// It is be better to throw away this packet if we are missing the
|
// It is be better to throw away this packet if we are
|
||||||
// previous packet.
|
// missing the previous packet.
|
||||||
memset(ptrFirstByte, 0, _packetSizeBytes[i]);
|
memset(ptrFirstByte, 0, _packetSizeBytes[i]);
|
||||||
previousLost = true;
|
previousLost = true;
|
||||||
}
|
}
|
||||||
else if (_packetSizeBytes[i] > 0) // Ignore if empty packet
|
else if (_packetSizeBytes[i] > 0) // Ignore if empty packet
|
||||||
{
|
{
|
||||||
// Glue with previous byte
|
// Glue with previous byte
|
||||||
// Move everything from [this packet start + 1, end of buffer] one byte to the left
|
// Move everything from [this packet start + 1,
|
||||||
|
// end of buffer] one byte to the left
|
||||||
WebRtc_UWord8* ptrPrevByte = ptrFirstByte - 1;
|
WebRtc_UWord8* ptrPrevByte = ptrFirstByte - 1;
|
||||||
*ptrPrevByte = (*ptrPrevByte) | (*ptrFirstByte);
|
*ptrPrevByte = (*ptrPrevByte) | (*ptrFirstByte);
|
||||||
WebRtc_UWord32 lengthToEnd = length - (currentPacketOffset + 1);
|
WebRtc_UWord32 lengthToEnd = length -
|
||||||
memmove((void*)ptrFirstByte, (void*)(ptrFirstByte + 1), lengthToEnd);
|
(currentPacketOffset + 1);
|
||||||
|
memmove((void*)ptrFirstByte, (void*)(ptrFirstByte + 1),
|
||||||
|
lengthToEnd);
|
||||||
_packetSizeBytes[i]--;
|
_packetSizeBytes[i]--;
|
||||||
length--;
|
length--;
|
||||||
previousLost = false;
|
previousLost = false;
|
||||||
@ -827,7 +807,8 @@ VCMSessionInfo::PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer,
|
|||||||
else if (_packetSizeBytes[i] == 0 && codec == kVideoCodecH263)
|
else if (_packetSizeBytes[i] == 0 && codec == kVideoCodecH263)
|
||||||
{
|
{
|
||||||
WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer + currentPacketOffset;
|
WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer + currentPacketOffset;
|
||||||
memmove(ptrFirstByte + 10, ptrFirstByte, length - currentPacketOffset);
|
memmove(ptrFirstByte + 10, ptrFirstByte,
|
||||||
|
length - currentPacketOffset);
|
||||||
memset(ptrFirstByte, 0, 10);
|
memset(ptrFirstByte, 0, 10);
|
||||||
_packetSizeBytes[i] = 10;
|
_packetSizeBytes[i] = 10;
|
||||||
length += _packetSizeBytes[i];
|
length += _packetSizeBytes[i];
|
||||||
|
@ -47,16 +47,14 @@ public:
|
|||||||
webrtc::FrameType FrameType() const { return _frameType; }
|
webrtc::FrameType FrameType() const { return _frameType; }
|
||||||
|
|
||||||
virtual WebRtc_Word32 GetHighestPacketIndex();
|
virtual WebRtc_Word32 GetHighestPacketIndex();
|
||||||
virtual WebRtc_UWord32 GetPacketSize(WebRtc_Word32 packetIndex);
|
|
||||||
virtual void ClearPacketSize(WebRtc_Word32 packetIndex);
|
|
||||||
virtual void UpdatePacketSize(WebRtc_Word32 packetIndex, WebRtc_UWord32 length);
|
virtual void UpdatePacketSize(WebRtc_Word32 packetIndex, WebRtc_UWord32 length);
|
||||||
virtual void PrependPacketIndices(WebRtc_Word32 numberOfPacketIndexes);
|
|
||||||
|
|
||||||
void SetStartSeqNumber(WebRtc_UWord16 seqNumber);
|
void SetStartSeqNumber(WebRtc_UWord16 seqNumber);
|
||||||
|
|
||||||
bool HaveStartSeqNumber();
|
bool HaveStartSeqNumber();
|
||||||
|
|
||||||
WebRtc_Word32 GetLowSeqNum() const;
|
WebRtc_Word32 GetLowSeqNum() const;
|
||||||
|
// returns highest seqNum, media or empty
|
||||||
WebRtc_Word32 GetHighSeqNum() const;
|
WebRtc_Word32 GetHighSeqNum() const;
|
||||||
|
|
||||||
WebRtc_UWord32 PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer, VideoCodecType codec);
|
WebRtc_UWord32 PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer, VideoCodecType codec);
|
||||||
@ -94,6 +92,8 @@ protected:
|
|||||||
WebRtc_UWord8 _naluCompleteness[kMaxPacketsInJitterBuffer];
|
WebRtc_UWord8 _naluCompleteness[kMaxPacketsInJitterBuffer];
|
||||||
WebRtc_Word32 _emptySeqNumLow;
|
WebRtc_Word32 _emptySeqNumLow;
|
||||||
WebRtc_Word32 _emptySeqNumHigh;
|
WebRtc_Word32 _emptySeqNumHigh;
|
||||||
|
// Store the sequence number that marks the last media packet
|
||||||
|
WebRtc_Word32 _markerSeqNum;
|
||||||
bool _ORwithPrevByte[kMaxPacketsInJitterBuffer];
|
bool _ORwithPrevByte[kMaxPacketsInJitterBuffer];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1786,7 +1786,8 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
//printf("DONE fill JB - number of delta frames > max number of frames\n");
|
//printf("DONE fill JB - number of delta frames > max number of frames\n");
|
||||||
|
|
||||||
//
|
//
|
||||||
// TEST fill JB with more than max number of frame (50 delta frames + 51 key frames) with wrap in seqNum
|
// TEST fill JB with more than max number of frame (50 delta frames +
|
||||||
|
// 51 key frames) with wrap in seqNum
|
||||||
//
|
//
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
// | 65485 | 65486 | 65487 | .... | 65535 | 0 | 1 | 2 | .....| 50 |
|
// | 65485 | 65486 | 65487 | .... | 65535 | 0 | 1 | 2 | .....| 50 |
|
||||||
@ -1829,7 +1830,8 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
|
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
|
||||||
|
|
||||||
// Get packet notification, should be first inserted frame
|
// Get packet notification, should be first inserted frame
|
||||||
TEST(timeStampStart == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
|
TEST(timeStampStart == jb.GetNextTimeStamp(10, incomingFrameType,
|
||||||
|
renderTimeMs));
|
||||||
|
|
||||||
// check incoming frame type
|
// check incoming frame type
|
||||||
TEST(incomingFrameType == kVideoFrameDelta);
|
TEST(incomingFrameType == kVideoFrameDelta);
|
||||||
@ -1849,13 +1851,15 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
|
|
||||||
// Now, no free frame - frames will be recycled until first key frame
|
// Now, no free frame - frames will be recycled until first key frame
|
||||||
frameIn = jb.GetFrame(packet);
|
frameIn = jb.GetFrame(packet);
|
||||||
TEST(frameIn != 0 && frameIn && ptrLastDeltaFrame); // ptr to last inserted delta frame should be returned
|
// ptr to last inserted delta frame should be returned
|
||||||
|
TEST(frameIn != 0 && frameIn && ptrLastDeltaFrame);
|
||||||
|
|
||||||
// Insert frame
|
// Insert frame
|
||||||
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
|
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
|
||||||
|
|
||||||
// First inserted key frame should be oldest in buffer
|
// First inserted key frame should be oldest in buffer
|
||||||
TEST(timeStampFirstKey == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
|
TEST(timeStampFirstKey == jb.GetNextTimeStamp(10, incomingFrameType,
|
||||||
|
renderTimeMs));
|
||||||
|
|
||||||
// check incoming frame type
|
// check incoming frame type
|
||||||
TEST(incomingFrameType == kVideoFrameKey);
|
TEST(incomingFrameType == kVideoFrameKey);
|
||||||
@ -1874,7 +1878,93 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
|
|
||||||
jb.Flush();
|
jb.Flush();
|
||||||
|
|
||||||
//printf("DONE fill JB - nr of delta + key frames (w/ wrap in seqNum) > max nr of frames\n");
|
// printf("DONE fill JB - nr of delta + key frames (w/ wrap in seqNum) >
|
||||||
|
// max nr of frames\n");
|
||||||
|
|
||||||
|
// Test handling empty packets
|
||||||
|
// first insert 2 empty packets
|
||||||
|
jb.ReleaseFrame(frameIn);
|
||||||
|
timeStamp = 33 * 90;
|
||||||
|
seqNum = 5;
|
||||||
|
packet.isFirstPacket = false;
|
||||||
|
packet.markerBit = false;
|
||||||
|
packet.seqNum = seqNum;
|
||||||
|
packet.timestamp = timeStamp;
|
||||||
|
packet.frameType = kFrameEmpty;
|
||||||
|
frameIn = jb.GetFrame(packet);
|
||||||
|
TEST(frameIn);
|
||||||
|
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
|
||||||
|
|
||||||
|
seqNum = 6;
|
||||||
|
packet.isFirstPacket = false;
|
||||||
|
packet.markerBit = false;
|
||||||
|
packet.seqNum = seqNum;
|
||||||
|
packet.timestamp = timeStamp;
|
||||||
|
packet.frameType = kFrameEmpty;
|
||||||
|
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
|
||||||
|
// now insert the first data packet
|
||||||
|
seqNum = 1;
|
||||||
|
packet.isFirstPacket = true;
|
||||||
|
packet.markerBit = false;
|
||||||
|
packet.seqNum = seqNum;
|
||||||
|
packet.timestamp = timeStamp;
|
||||||
|
packet.frameType = kVideoFrameDelta;
|
||||||
|
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
|
||||||
|
// insert an additional data packet
|
||||||
|
seqNum = 2;
|
||||||
|
packet.isFirstPacket = false;
|
||||||
|
packet.markerBit = false;
|
||||||
|
packet.seqNum = seqNum;
|
||||||
|
packet.timestamp = timeStamp;
|
||||||
|
packet.frameType = kVideoFrameDelta;
|
||||||
|
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
|
||||||
|
|
||||||
|
// insert the last packet and verify frame completness
|
||||||
|
// (even though packet 4 (empty) is missing)
|
||||||
|
seqNum = 3;
|
||||||
|
packet.isFirstPacket = false;
|
||||||
|
packet.markerBit = true;
|
||||||
|
packet.seqNum = seqNum;
|
||||||
|
packet.timestamp = timeStamp;
|
||||||
|
packet.frameType = kVideoFrameDelta;
|
||||||
|
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
|
||||||
|
jb.Flush();
|
||||||
|
|
||||||
|
// testing that empty packets do not clog the jitter buffer
|
||||||
|
// Set hybrid mode
|
||||||
|
jb.SetNackMode(kNackHybrid);
|
||||||
|
TEST(jb.GetNackMode() == kNackHybrid);
|
||||||
|
|
||||||
|
int maxSize = 100;
|
||||||
|
seqNum = 3;
|
||||||
|
VCMEncodedFrame* testFrame;
|
||||||
|
for (int i = 0; i < maxSize + 10; i++)
|
||||||
|
{
|
||||||
|
timeStamp += 33 * 90;
|
||||||
|
packet.isFirstPacket = false;
|
||||||
|
packet.markerBit = false;
|
||||||
|
packet.seqNum = seqNum;
|
||||||
|
packet.timestamp = timeStamp;
|
||||||
|
packet.frameType = kFrameEmpty;
|
||||||
|
testFrame = jb.GetFrame(packet);
|
||||||
|
TEST(frameIn != 0);
|
||||||
|
TEST(kFirstPacket == jb.InsertPacket(testFrame, packet));
|
||||||
|
}
|
||||||
|
// verify insertion of a data packet (old empty frames will be flushed)
|
||||||
|
timeStamp += 33 * 90;
|
||||||
|
packet.isFirstPacket = true;
|
||||||
|
packet.markerBit = false;
|
||||||
|
packet.seqNum = seqNum;
|
||||||
|
packet.timestamp = timeStamp;
|
||||||
|
packet.frameType = kFrameEmpty;
|
||||||
|
testFrame = jb.GetFrame(packet);
|
||||||
|
TEST(frameIn != 0);
|
||||||
|
|
||||||
|
jb.SetNackMode(kNoNack);
|
||||||
|
|
||||||
|
|
||||||
|
// printf(DONE testing inserting empty packets to the JB)
|
||||||
|
|
||||||
|
|
||||||
// H.264 tests
|
// H.264 tests
|
||||||
//Test incomplete NALU frames
|
//Test incomplete NALU frames
|
||||||
@ -1977,7 +2067,8 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
packet.completeNALU=kNaluStart;
|
packet.completeNALU=kNaluStart;
|
||||||
packet.markerBit=false;
|
packet.markerBit=false;
|
||||||
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
|
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
|
||||||
insertedLength+=packet.sizeBytes; // This packet should be decoded since it's the beginning of a NAL
|
// This packet should be decoded since it's the beginning of a NAL
|
||||||
|
insertedLength+=packet.sizeBytes;
|
||||||
|
|
||||||
seqNum+=2;
|
seqNum+=2;
|
||||||
packet.seqNum=seqNum;
|
packet.seqNum=seqNum;
|
||||||
@ -1987,10 +2078,13 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
packet.completeNALU=kNaluEnd;
|
packet.completeNALU=kNaluEnd;
|
||||||
packet.markerBit=true;
|
packet.markerBit=true;
|
||||||
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
|
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
|
||||||
insertedLength+=0; // This packet should not be decoded because it is an incomplete NAL if it is the last
|
// This packet should not be decoded because it is an incomplete NAL if it
|
||||||
|
// is the last
|
||||||
|
insertedLength+=0;
|
||||||
|
|
||||||
frameOut = jb.GetFrameForDecoding();
|
frameOut = jb.GetFrameForDecoding();
|
||||||
CheckOutFrame(frameOut, insertedLength, false); // Only last NALU is complete
|
// Only last NALU is complete
|
||||||
|
CheckOutFrame(frameOut, insertedLength, false);
|
||||||
jb.ReleaseFrame(frameOut);
|
jb.ReleaseFrame(frameOut);
|
||||||
|
|
||||||
|
|
||||||
@ -2006,7 +2100,9 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
emptypacket.markerBit=true;
|
emptypacket.markerBit=true;
|
||||||
TEST(frameIn=jb.GetFrame(emptypacket));
|
TEST(frameIn=jb.GetFrame(emptypacket));
|
||||||
TEST(kFirstPacket == jb.InsertPacket(frameIn, emptypacket));
|
TEST(kFirstPacket == jb.InsertPacket(frameIn, emptypacket));
|
||||||
insertedLength+=0; // This packet should not be decoded because it is an incomplete NAL if it is the last
|
// This packet should not be decoded because it is an incomplete NAL if it
|
||||||
|
// is the last
|
||||||
|
insertedLength+=0;
|
||||||
|
|
||||||
TEST(-1 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
|
TEST(-1 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
|
||||||
TEST(NULL==jb.GetFrameForDecoding());
|
TEST(NULL==jb.GetFrameForDecoding());
|
||||||
@ -2036,8 +2132,8 @@ int JitterBufferTest(CmdArgs& args)
|
|||||||
|
|
||||||
// get the frame
|
// get the frame
|
||||||
frameOut = jb.GetCompleteFrameForDecoding(10);
|
frameOut = jb.GetCompleteFrameForDecoding(10);
|
||||||
CheckOutFrame(frameOut, packet.sizeBytes, false); // Only last NALU is complete
|
// Only last NALU is complete
|
||||||
|
CheckOutFrame(frameOut, packet.sizeBytes, false);
|
||||||
jb.Flush();
|
jb.Flush();
|
||||||
|
|
||||||
// Three reordered H263 packets with bits.
|
// Three reordered H263 packets with bits.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user