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:
mikhal@google.com 2011-07-01 18:15:11 +00:00
parent c13708271a
commit cdc943e2d5
7 changed files with 272 additions and 180 deletions

View File

@ -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;

View File

@ -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;
} }

View File

@ -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

View File

@ -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)

View File

@ -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];

View File

@ -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];
}; };

View File

@ -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.