Updates to VCM rx side: A. 2 bug fixes:

1. Updated code to set _lastdecodedSeqNum after clean up of old frames (2/3 instances were updated, 1 was ok). 
2. Updated _lastDecodedSeqNum based on empty packets that arrive after the frame which they belong to was already decoded (as was with existing code with regard to filler packets). 
B. Code clean up.  
Review URL: http://webrtc-codereview.appspot.com/78001

git-svn-id: http://webrtc.googlecode.com/svn/trunk@237 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mikhal@google.com 2011-07-20 20:58:09 +00:00
parent ade0c6ca28
commit 18a186eab2
4 changed files with 231 additions and 169 deletions

View File

@ -37,7 +37,8 @@ namespace webrtc {
// Criteria used when searching for frames in the frame buffer list // Criteria used when searching for frames in the frame buffer list
bool bool
VCMJitterBuffer::FrameEqualTimestamp(VCMFrameBuffer* frame, const void* timestamp) VCMJitterBuffer::FrameEqualTimestamp(VCMFrameBuffer* frame,
const void* timestamp)
{ {
if (timestamp == NULL) if (timestamp == NULL)
{ {
@ -142,8 +143,10 @@ VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
_missingMarkerBits = rhs._missingMarkerBits; _missingMarkerBits = rhs._missingMarkerBits;
_firstPacket = rhs._firstPacket; _firstPacket = rhs._firstPacket;
_lastDecodedSeqNum = rhs._lastDecodedSeqNum; _lastDecodedSeqNum = rhs._lastDecodedSeqNum;
memcpy(_receiveStatistics, rhs._receiveStatistics, sizeof(_receiveStatistics)); memcpy(_receiveStatistics, rhs._receiveStatistics,
memcpy(_NACKSeqNumInternal, rhs._NACKSeqNumInternal, sizeof(_NACKSeqNumInternal)); sizeof(_receiveStatistics));
memcpy(_NACKSeqNumInternal, rhs._NACKSeqNumInternal,
sizeof(_NACKSeqNumInternal));
memcpy(_NACKSeqNum, rhs._NACKSeqNum, sizeof(_NACKSeqNum)); memcpy(_NACKSeqNum, rhs._NACKSeqNum, sizeof(_NACKSeqNum));
for (int i = 0; i < kMaxNumberOfFrames; i++) for (int i = 0; i < kMaxNumberOfFrames; i++)
{ {
@ -153,7 +156,8 @@ VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
_frameBuffers[i] = NULL; _frameBuffers[i] = NULL;
} }
} }
while(_frameBuffersTSOrder.Erase(_frameBuffersTSOrder.First()) != -1) { } while(_frameBuffersTSOrder.Erase(_frameBuffersTSOrder.First()) != -1)
{ }
for (int i = 0; i < _maxNumberOfFrames; i++) for (int i = 0; i < _maxNumberOfFrames; i++)
{ {
_frameBuffers[i] = new VCMFrameBuffer(*(rhs._frameBuffers[i])); _frameBuffers[i] = new VCMFrameBuffer(*(rhs._frameBuffers[i]));
@ -267,7 +271,7 @@ VCMJitterBuffer::FlushInternal()
{ {
// Erase all frames from the sorted list and set their state to free. // Erase all frames from the sorted list and set their state to free.
_frameBuffersTSOrder.Flush(); _frameBuffersTSOrder.Flush();
for (int i = 0; i < _maxNumberOfFrames; i++) for (WebRtc_Word32 i = 0; i < _maxNumberOfFrames; i++)
{ {
ReleaseFrameInternal(_frameBuffers[i]); ReleaseFrameInternal(_frameBuffers[i]);
} }
@ -326,10 +330,13 @@ VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
int length = frame->Length(); int length = frame->Length();
if (_master) if (_master)
{ {
// Only trace the primary jitter buffer to make it possible to parse and plot the trace file. // Only trace the primary jitter buffer to make it possible to parse
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), // and plot the trace file.
"JB(0x%x) FB(0x%x): Complete frame added to jitter buffer, size:%d type %d", WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
this, frame,length,frame->FrameType()); VCMId(_vcmId, _receiverId),
"JB(0x%x) FB(0x%x): Complete frame added to jitter buffer,"
" size:%d type %d",
this, frame,length,frame->FrameType());
} }
if (length != 0 && !frame->GetCountedFrame()) if (length != 0 && !frame->GetCountedFrame())
@ -341,7 +348,7 @@ VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
// Check if we should drop frame // Check if we should drop frame
// an old complete frame can arrive too late // an old complete frame can arrive too late
if(_lastDecodedTimeStamp > 0 && if (_lastDecodedTimeStamp > 0 &&
LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp), LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
frame->TimeStamp()) == _lastDecodedTimeStamp) frame->TimeStamp()) == _lastDecodedTimeStamp)
{ {
@ -350,11 +357,15 @@ VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
frame->Reset(); frame->Reset();
frame->SetState(kStateEmpty); frame->SetState(kStateEmpty);
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
"JB(0x%x) FB(0x%x): Dropping old frame in Jitter buffer", this, frame); VCMId(_vcmId, _receiverId),
"JB(0x%x) FB(0x%x): Dropping old frame in Jitter buffer",
this, frame);
_dropCount++; _dropCount++;
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
"Jitter buffer drop count: %d, consecutive drops: %u", _dropCount, _numConsecutiveOldFrames); VCMId(_vcmId, _receiverId),
"Jitter buffer drop count: %d, consecutive drops: %u",
_dropCount, _numConsecutiveOldFrames);
// Flush() if this happens consistently. // Flush() if this happens consistently.
_numConsecutiveOldFrames++; _numConsecutiveOldFrames++;
if (_numConsecutiveOldFrames > kMaxConsecutiveOldFrames) if (_numConsecutiveOldFrames > kMaxConsecutiveOldFrames)
@ -437,9 +448,10 @@ VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame)
} }
_critSect.Enter(); _critSect.Enter();
if (LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp), packet.timestamp) if (LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
== _lastDecodedTimeStamp packet.timestamp) == _lastDecodedTimeStamp
&& packet.sizeBytes > 0) // Make sure that old filler packets are inserted. && packet.sizeBytes > 0)
// Make sure that old Empty packets are inserted.
{ {
// Trying to get an old frame. // Trying to get an old frame.
_numConsecutiveOldPackets++; _numConsecutiveOldPackets++;
@ -452,7 +464,9 @@ VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame)
} }
_numConsecutiveOldPackets = 0; _numConsecutiveOldPackets = 0;
frame = _frameBuffersTSOrder.FindFrame(FrameEqualTimestamp, &packet.timestamp); frame = _frameBuffersTSOrder.FindFrame(FrameEqualTimestamp,
&packet.timestamp);
_critSect.Leave(); _critSect.Leave();
if (frame != NULL) if (frame != NULL)
@ -626,18 +640,17 @@ VCMJitterBuffer::FindOldestCompleteContinuousFrame()
// Use seqNum not timestamp since a full frame might be lost // Use seqNum not timestamp since a full frame might be lost
if (_lastDecodedSeqNum != -1) if (_lastDecodedSeqNum != -1)
{ {
// it's not enough that we have complete frame we need the seq numbers // it's not enough that we have complete frame we need the layers to
// to be continuous too for layers it's not enough that we have complete // be continuous too
// frame we need the layers to be continuous too
currentLow = oldestFrame->GetLowSeqNum(); currentLow = oldestFrame->GetLowSeqNum();
WebRtc_UWord16 lastDecodedSeqNum = (WebRtc_UWord16)_lastDecodedSeqNum; WebRtc_UWord16 lastDecodedSeqNum = (WebRtc_UWord16)_lastDecodedSeqNum;
// we could have received the first packet of the last frame before a // We could have received the first packet of the last frame before a
// long period if drop, that case is handled by GetNackList // long period if drop, that case is handled by GetNackList
if (((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow) if (((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow)
{ {
// wait since we want a complete continuous frame // Wait since we want a complete continuous frame
return NULL; return NULL;
} }
} }
@ -651,7 +664,8 @@ VCMJitterBuffer::FindOldestCompleteContinuousFrame()
bool bool
VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem) VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
{ {
const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameItem); const VCMFrameListItem*
nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameItem);
VCMFrameBuffer* oldestFrame = NULL; VCMFrameBuffer* oldestFrame = NULL;
if (oldestFrameItem != NULL) if (oldestFrameItem != NULL)
{ {
@ -659,12 +673,12 @@ VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
} }
if (nextFrameItem != NULL) if (nextFrameItem != NULL)
{ {
// We have received at least one packet from a later frame. // We have received at least one packet from a later frame.
if(!oldestFrame->HaveLastPacket()) // If we don't have the markerbit if(!oldestFrame->HaveLastPacket()) // If we don't have the markerbit
{ {
VCMFrameBuffer* nextFrame = nextFrameItem->GetItem(); VCMFrameBuffer* nextFrame = nextFrameItem->GetItem();
// 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. // so we're not missing the last packet.
if (nextFrame != NULL && nextFrame->GetLowSeqNum() == if (nextFrame != NULL && nextFrame->GetLowSeqNum() ==
static_cast<WebRtc_UWord16>(oldestFrame->GetHighSeqNum() + 1)) static_cast<WebRtc_UWord16>(oldestFrame->GetHighSeqNum() + 1))
{ {
@ -677,7 +691,7 @@ VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
const VCMFrameBufferStateEnum state = oldestFrame->GetState(); const VCMFrameBufferStateEnum state = oldestFrame->GetState();
if (state == kStateComplete) if (state == kStateComplete)
{ {
if(oldestFrame->Length() > 0) if (oldestFrame->Length() > 0)
{ {
UpdateJitterAndDelayEstimates(*oldestFrame, false); UpdateJitterAndDelayEstimates(*oldestFrame, false);
} }
@ -698,9 +712,10 @@ VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
return; return;
} }
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
"JB(0x%x) FB(0x%x): RecycleFrame, size:%d", VCMId(_vcmId, _receiverId),
this, frame, frame->Length()); "JB(0x%x) FB(0x%x): RecycleFrame, size:%d",
this, frame, frame->Length());
ReleaseFrameInternal(frame); ReleaseFrameInternal(frame);
} }
@ -738,8 +753,10 @@ VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
// Calculate frame rate // Calculate frame rate
// Let r be rate. // Let r be rate.
// r(0) = 1000*framecount/delta_time. (I.e. frames per second since last calculation.) // r(0) = 1000*framecount/delta_time.
// frameRate = r(0)/2 + r(-1)/2 (I.e. fr/s average this and the previous calculation.) // (I.e. frames per second since last calculation.)
// frameRate = r(0)/2 + r(-1)/2
// (I.e. fr/s average this and the previous calculation.)
frameRate = (_incomingFrameRate + (WebRtc_Word32)rate) >> 1; frameRate = (_incomingFrameRate + (WebRtc_Word32)rate) >> 1;
_incomingFrameRate = (WebRtc_UWord8)rate; _incomingFrameRate = (WebRtc_UWord8)rate;
@ -750,7 +767,8 @@ VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
} }
else else
{ {
bitRate = 10 * ((100 * _incomingBitCount) / static_cast<WebRtc_UWord32>(diff)); bitRate = 10 * ((100 * _incomingBitCount) /
static_cast<WebRtc_UWord32>(diff));
} }
_incomingBitRate = bitRate; _incomingBitRate = bitRate;
@ -772,7 +790,8 @@ VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
return 0; return 0;
} }
// Returns immediately or a X ms event hang waiting for a decodable frame, X decided by caller // Returns immediately or a X ms event hang waiting for a decodable frame,
// X decided by caller
VCMEncodedFrame* VCMEncodedFrame*
VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS) VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
{ {
@ -806,7 +825,8 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
while (waitTimeMs > 0) while (waitTimeMs > 0)
{ {
_critSect.Leave(); _critSect.Leave();
const EventTypeWrapper ret = _frameEvent.Wait(static_cast<WebRtc_UWord32>(waitTimeMs)); const EventTypeWrapper ret =
_frameEvent.Wait(static_cast<WebRtc_UWord32>(waitTimeMs));
_critSect.Enter(); _critSect.Enter();
if (ret == kEventSignaled) if (ret == kEventSignaled)
{ {
@ -817,7 +837,8 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
return NULL; return NULL;
} }
// Finding oldest frame ready for decoder, but check sequence number and size // Finding oldest frame ready for decoder, but check
// sequence number and size
CleanUpOldFrames(); CleanUpOldFrames();
CleanUpSizeZeroFrames(); CleanUpSizeZeroFrames();
oldestFrameListItem = FindOldestCompleteContinuousFrame(); oldestFrameListItem = FindOldestCompleteContinuousFrame();
@ -827,7 +848,8 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
} }
if (oldestFrame == NULL) if (oldestFrame == NULL)
{ {
waitTimeMs = endWaitTimeMs - VCMTickTime::MillisecondTimestamp(); waitTimeMs = endWaitTimeMs -
VCMTickTime::MillisecondTimestamp();
} }
else else
{ {
@ -850,17 +872,11 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
if (oldestFrame == NULL) if (oldestFrame == NULL)
{ {
// Even after signaling 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;
} }
// we have a frame
// store seqnum
_lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
// store current timestamp
_lastDecodedTimeStamp = oldestFrame->TimeStamp();
// Update jitter estimate // Update jitter estimate
const bool retransmitted = (oldestFrame->GetNackCount() > 0); const bool retransmitted = (oldestFrame->GetNackCount() > 0);
if (retransmitted) if (retransmitted)
@ -884,6 +900,10 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
_critSect.Leave(); _critSect.Leave();
// We have a frame - store seqnum & timestamp
_lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
_lastDecodedTimeStamp = oldestFrame->TimeStamp();
return oldestFrame; return oldestFrame;
} }
@ -899,7 +919,7 @@ VCMJitterBuffer::GetEstimatedJitterMsInternal()
{ {
WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER; WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER;
// compute RTT multiplier for estimation // Compute RTT multiplier for estimation
double rttMult = 1.0f; double rttMult = 1.0f;
if (_nackMode == kNackHybrid && _rttMs > kLowRttNackMs) if (_nackMode == kNackHybrid && _rttMs > kLowRttNackMs)
{ {
@ -912,8 +932,8 @@ VCMJitterBuffer::GetEstimatedJitterMsInternal()
{ {
// Since the incoming packets are all missing marker bits we have to // Since the incoming packets are all missing marker bits we have to
// wait until the first packet of the next frame arrives, before we can // wait until the first packet of the next frame arrives, before we can
// safely say that the frame is complete. Therefore we have to compensate // safely say that the frame is complete. Therefore we have to
// the jitter buffer level with one frame period. // compensate the jitter buffer level with one frame period.
// TODO(holmer): The timestamp diff should probably be filtered // TODO(holmer): The timestamp diff should probably be filtered
// (max filter) since the diff can alternate between e.g. 3000 and 6000 // (max filter) since the diff can alternate between e.g. 3000 and 6000
// if we have a frame rate between 15 and 30 frames per seconds. // if we have a frame rate between 15 and 30 frames per seconds.
@ -943,7 +963,7 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
_critSect.Enter(); _critSect.Enter();
// Finding oldest frame ready for decoder, but check sequence number and size // Finding oldest frame ready for decoder, check sequence number and size
CleanUpOldFrames(); CleanUpOldFrames();
CleanUpSizeZeroFrames(); CleanUpSizeZeroFrames();
@ -952,7 +972,7 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
if (oldestFrame == NULL) if (oldestFrame == NULL)
{ {
_critSect.Leave(); _critSect.Leave();
if(_packetEvent.Wait(maxWaitTimeMS) == kEventSignaled) if (_packetEvent.Wait(maxWaitTimeMS) == kEventSignaled)
{ {
// are we closing down the Jitter buffer // are we closing down the Jitter buffer
if (!_running) if (!_running)
@ -964,7 +984,8 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
CleanUpOldFrames(); CleanUpOldFrames();
CleanUpSizeZeroFrames(); CleanUpSizeZeroFrames();
oldestFrame = _frameBuffersTSOrder.FirstFrame(); oldestFrame = _frameBuffersTSOrder.FirstFrame();
}else }
else
{ {
_critSect.Enter(); _critSect.Enter();
} }
@ -979,7 +1000,8 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
// we have a frame // we have a frame
// return frame type // return frame type
incomingFrameType = oldestFrame->FrameType(); // All layers are assumed to have the same type // All layers are assumed to have the same type
incomingFrameType = oldestFrame->FrameType();
renderTimeMs = oldestFrame->RenderTimeMs(); renderTimeMs = oldestFrame->RenderTimeMs();
@ -992,14 +1014,15 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
} }
// Answers the question: // Answers the question:
// Will the packet sequence be complete if the next frame is grabbed for decoding right now? // Will the packet sequence be complete if the next frame is grabbed for
// That is, have we lost a frame between the last decoded frame and the next, or is the next // decoding right now? That is, have we lost a frame between the last decoded
// frame and the next, or is the next
// frame missing one or more packets? // frame missing one or more packets?
bool bool
VCMJitterBuffer::CompleteSequenceWithNextFrame() VCMJitterBuffer::CompleteSequenceWithNextFrame()
{ {
CriticalSectionScoped cs(_critSect); CriticalSectionScoped cs(_critSect);
// Finding oldest frame ready for decoder, but check sequence number and size // Finding oldest frame ready for decoder, check sequence number and size
CleanUpOldFrames(); CleanUpOldFrames();
CleanUpSizeZeroFrames(); CleanUpSizeZeroFrames();
@ -1011,7 +1034,8 @@ VCMJitterBuffer::CompleteSequenceWithNextFrame()
} }
VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem(); VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();
const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameListItem); const VCMFrameListItem* nextFrameItem =
_frameBuffersTSOrder.Next(oldestFrameListItem);
if (nextFrameItem == NULL && !oldestFrame->HaveLastPacket()) if (nextFrameItem == NULL && !oldestFrame->HaveLastPacket())
{ {
// Frame not ready to be decoded. // Frame not ready to be decoded.
@ -1031,7 +1055,8 @@ VCMJitterBuffer::CompleteSequenceWithNextFrame()
{ {
return false; return false;
} }
else if (oldestFrame->GetLowSeqNum() != (_lastDecodedSeqNum + 1) % 0x00010000) else if (oldestFrame->GetLowSeqNum() != (_lastDecodedSeqNum + 1)
% 0x00010000)
{ {
return false; return false;
} }
@ -1063,7 +1088,8 @@ VCMJitterBuffer::GetFrameForDecoding()
} }
VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem(); VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();
const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameListItem); const VCMFrameListItem* nextFrameItem =
_frameBuffersTSOrder.Next(oldestFrameListItem);
if (nextFrameItem == NULL && !oldestFrame->HaveLastPacket()) if (nextFrameItem == NULL && !oldestFrame->HaveLastPacket())
{ {
return NULL; return NULL;
@ -1088,7 +1114,8 @@ VCMJitterBuffer::GetFrameForDecoding()
} }
// Then wait for this one to get complete // Then wait for this one to get complete
_waitingForCompletion.frameSize = oldestFrame->Length(); _waitingForCompletion.frameSize = oldestFrame->Length();
_waitingForCompletion.latestPacketTime = oldestFrame->LatestPacketTimeMs(); _waitingForCompletion.latestPacketTime =
oldestFrame->LatestPacketTimeMs();
_waitingForCompletion.timestamp = oldestFrame->TimeStamp(); _waitingForCompletion.timestamp = oldestFrame->TimeStamp();
oldestFrame->SetState(kStateDecoding); oldestFrame->SetState(kStateDecoding);
} }
@ -1100,11 +1127,9 @@ VCMJitterBuffer::GetFrameForDecoding()
VerifyAndSetPreviousFrameLost(*oldestFrame); VerifyAndSetPreviousFrameLost(*oldestFrame);
// store current time // Store current seqnum & time
_lastDecodedTimeStamp = oldestFrame->TimeStamp();
// store seqnum
_lastDecodedSeqNum = oldestFrame->GetHighSeqNum(); _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
_lastDecodedTimeStamp = oldestFrame->TimeStamp();
return oldestFrame; return oldestFrame;
} }
@ -1143,13 +1168,6 @@ VCMJitterBuffer::GetFrameForDecodingNACK()
return NULL; return NULL;
} }
} }
// We have a complete/decodable continuous frame, decode it.
// store seqnum
_lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
// store current time
_lastDecodedTimeStamp = oldestFrame->TimeStamp();
// Update jitter estimate // Update jitter estimate
const bool retransmitted = (oldestFrame->GetNackCount() > 0); const bool retransmitted = (oldestFrame->GetNackCount() > 0);
if (retransmitted) if (retransmitted)
@ -1171,13 +1189,19 @@ VCMJitterBuffer::GetFrameForDecodingNACK()
CleanUpOldFrames(); CleanUpOldFrames();
CleanUpSizeZeroFrames(); CleanUpSizeZeroFrames();
// We have a complete/decodable continuous frame, decode it.
// Store seqnum & timestamp
_lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
_lastDecodedTimeStamp = oldestFrame->TimeStamp();
return oldestFrame; return oldestFrame;
} }
// Must be called under the critical section _critSect. Should never be called with // Must be called under the critical section _critSect. Should never be called with
// retransmitted frames, they must be filtered out before this function is called. // retransmitted frames, they must be filtered out before this function is called.
void void
VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMJitterSample& sample, bool incompleteFrame) VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMJitterSample& sample,
bool incompleteFrame)
{ {
if (sample.latestPacketTime == -1) if (sample.latestPacketTime == -1)
{ {
@ -1185,17 +1209,19 @@ VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMJitterSample& sample, bool inc
} }
if (incompleteFrame) if (incompleteFrame)
{ {
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
"Received incomplete frame timestamp %u frame size %u at time %u", VCMId(_vcmId, _receiverId), "Received incomplete frame "
sample.timestamp, sample.frameSize, "timestamp %u frame size %u at time %u",
MaskWord64ToUWord32(sample.latestPacketTime)); sample.timestamp, sample.frameSize,
MaskWord64ToUWord32(sample.latestPacketTime));
} }
else else
{ {
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
"Received complete frame timestamp %u frame size %u at time %u", VCMId(_vcmId, _receiverId), "Received complete frame "
sample.timestamp, sample.frameSize, "timestamp %u frame size %u at time %u",
MaskWord64ToUWord32(sample.latestPacketTime)); sample.timestamp, sample.frameSize,
MaskWord64ToUWord32(sample.latestPacketTime));
} }
UpdateJitterAndDelayEstimates(sample.latestPacketTime, UpdateJitterAndDelayEstimates(sample.latestPacketTime,
sample.timestamp, sample.timestamp,
@ -1203,10 +1229,12 @@ VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMJitterSample& sample, bool inc
incompleteFrame); incompleteFrame);
} }
// Must be called under the critical section _critSect. Should never be called with // Must be called under the critical section _critSect. Should never be
// retransmitted frames, they must be filtered out before this function is called. // called with retransmitted frames, they must be filtered out before this
// function is called.
void void
VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame, bool incompleteFrame) VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame,
bool incompleteFrame)
{ {
if (frame.LatestPacketTimeMs() == -1) if (frame.LatestPacketTimeMs() == -1)
{ {
@ -1216,28 +1244,31 @@ VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame, bool incom
// estimate. // estimate.
if (incompleteFrame) if (incompleteFrame)
{ {
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
"Received incomplete frame timestamp %u frame type %d frame size %u" VCMId(_vcmId, _receiverId),
" at time %u, jitter estimate was %u", "Received incomplete frame timestamp %u frame type %d "
"frame size %u at time %u, jitter estimate was %u",
frame.TimeStamp(), frame.FrameType(), frame.Length(), frame.TimeStamp(), frame.FrameType(), frame.Length(),
MaskWord64ToUWord32(frame.LatestPacketTimeMs()), MaskWord64ToUWord32(frame.LatestPacketTimeMs()),
GetEstimatedJitterMsInternal()); GetEstimatedJitterMsInternal());
} }
else else
{ {
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
"Received complete frame timestamp %u frame type %d frame size %u " VCMId(_vcmId, _receiverId),"Received complete frame "
"at time %u, jitter estimate was %u", "timestamp %u frame type %d frame size %u at time %u, "
frame.TimeStamp(), frame.FrameType(), frame.Length(), "jitter estimate was %u",
MaskWord64ToUWord32(frame.LatestPacketTimeMs()), frame.TimeStamp(), frame.FrameType(), frame.Length(),
GetEstimatedJitterMsInternal()); MaskWord64ToUWord32(frame.LatestPacketTimeMs()),
GetEstimatedJitterMsInternal());
} }
UpdateJitterAndDelayEstimates(frame.LatestPacketTimeMs(), frame.TimeStamp(), UpdateJitterAndDelayEstimates(frame.LatestPacketTimeMs(), frame.TimeStamp(),
frame.Length(), incompleteFrame); frame.Length(), incompleteFrame);
} }
// Must be called under the critical section _critSect. Should never be called with // Must be called under the critical section _critSect. Should never be called
// retransmitted frames, they must be filtered out before this function is called. // with retransmitted frames, they must be filtered out before this function
// is called.
void void
VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs, VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs,
WebRtc_UWord32 timestamp, WebRtc_UWord32 timestamp,
@ -1250,10 +1281,14 @@ VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs,
} }
WebRtc_Word64 frameDelay; WebRtc_Word64 frameDelay;
// Calculate the delay estimate // Calculate the delay estimate
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
"Packet received and sent to jitter estimate with: timestamp=%u wallClock=%u", VCMId(_vcmId, _receiverId),
timestamp, MaskWord64ToUWord32(latestPacketTimeMs)); "Packet received and sent to jitter estimate with: "
bool notReordered = _delayEstimate.CalculateDelay(timestamp, &frameDelay, latestPacketTimeMs); "timestamp=%u wallClock=%u", timestamp,
MaskWord64ToUWord32(latestPacketTimeMs));
bool notReordered = _delayEstimate.CalculateDelay(timestamp,
&frameDelay,
latestPacketTimeMs);
// Filter out frames which have been reordered in time by the network // Filter out frames which have been reordered in time by the network
if (notReordered) if (notReordered)
{ {
@ -1273,8 +1308,8 @@ WebRtc_Word32
VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum, VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum,
WebRtc_Word32& highSeqNum) const WebRtc_Word32& highSeqNum) const
{ {
int i = 0; WebRtc_Word32 i = 0;
int seqNum = -1; WebRtc_Word32 seqNum = -1;
highSeqNum = -1; highSeqNum = -1;
lowSeqNum = _lastDecodedSeqNum; lowSeqNum = _lastDecodedSeqNum;
@ -1325,7 +1360,7 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
WebRtc_Word32 highSeqNum = -1; WebRtc_Word32 highSeqNum = -1;
listExtended = false; listExtended = false;
// don't create list, if we won't wait for it // Don't create list, if we won't wait for it
if (!WaitForNack()) if (!WaitForNack())
{ {
nackSize = 0; nackSize = 0;
@ -1341,7 +1376,7 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
// write a list of all seq num we have // write a list of all seq num we have
if (lowSeqNum == -1 || highSeqNum == -1) if (lowSeqNum == -1 || highSeqNum == -1)
{ {
//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)
{ {
// we have not received any packets yet // we have not received any packets yet
@ -1429,8 +1464,8 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
nackSize = 0xffff; nackSize = 0xffff;
listExtended = true; listExtended = true;
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1, WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1,
"\tNo key frame found, request one. _lastDecodedSeqNum[0] %d", "\tNo key frame found, request one. _lastDecodedSeqNum[0] "
_lastDecodedSeqNum); "%d", _lastDecodedSeqNum);
} }
else else
{ {
@ -1479,15 +1514,15 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
rttScore); rttScore);
if (_frameBuffers[i]->IsRetransmitted() == false) if (_frameBuffers[i]->IsRetransmitted() == false)
{ {
// if no retransmission required,set the state to decodable // If no retransmission required,set the state to decodable
// meaning that we will not wait for NACK // meaning that we will not wait for NACK.
_frameBuffers[i]->SetState(kStateDecodable); _frameBuffers[i]->SetState(kStateDecodable);
} }
} }
else else
{ {
// used when the frame is being processed by the decoding thread // Used when the frame is being processed by the decoding thread
// don't need to use that info in this loop // don't need to use that info in this loop.
_frameBuffers[i]->ZeroOutSeqNum(_NACKSeqNumInternal, _frameBuffers[i]->ZeroOutSeqNum(_NACKSeqNumInternal,
numberOfSeqNum); numberOfSeqNum);
} }
@ -1532,10 +1567,10 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
{ {
nackSize = emptyIndex; nackSize = emptyIndex;
} }
// convert to unsigned short 16 bit and store in a list to be used externally.
if (nackSize > _NACKSeqNumLength) if (nackSize > _NACKSeqNumLength)
{ {
// Larger list means that the nack list was extended since the last call. // Larger list: nack list was extended since the last call.
listExtended = true; listExtended = true;
} }
@ -1580,7 +1615,8 @@ VCMJitterBuffer::ReleaseFrame(VCMEncodedFrame* frame)
} }
WebRtc_Word64 WebRtc_Word64
VCMJitterBuffer::LastPacketTime(VCMEncodedFrame* frame, bool& retransmitted) const VCMJitterBuffer::LastPacketTime(VCMEncodedFrame* frame,
bool& retransmitted) const
{ {
CriticalSectionScoped cs(_critSect); CriticalSectionScoped cs(_critSect);
retransmitted = (static_cast<VCMFrameBuffer*>(frame)->GetNackCount() > 0); retransmitted = (static_cast<VCMFrameBuffer*>(frame)->GetNackCount() > 0);
@ -1638,14 +1674,18 @@ VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet)
if (frame != NULL) if (frame != NULL)
{ {
VCMFrameBufferStateEnum state = frame->GetState(); VCMFrameBufferStateEnum state = frame->GetState();
if (state == kStateDecoding && packet.sizeBytes == 0) if ((packet.sizeBytes == 0) &&
{ ((state == kStateDecoding) ||
// Filler packet, make sure we update the last decoded seq num (state == kStateEmpty &&
// since this packet should've been a part of the frame being decoded. _lastDecodedTimeStamp == packet.timestamp)))
// If the filler packet belongs to a very old frame (already decoded {
// and freed) a new frame will be created for the filler packet. // Empty packet (sizeBytes = 0), make sure we update the last
// That frame will be empty and later on cleaned up. // decoded seq num since this packet belongs either to a frame
UpdateLastDecodedWithFiller(packet); // being decoded (condition 1) or to a frame which was already
// decoded and freed (condition 2). A new frame will be created
// for the empty packet. That frame will be empty and later on
// cleaned up.
UpdateLastDecodedWithEmpty(packet);
} }
// Insert packet // Insert packet
@ -1715,9 +1755,9 @@ VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet)
} }
void void
VCMJitterBuffer::UpdateLastDecodedWithFiller(const VCMPacket& packet) VCMJitterBuffer::UpdateLastDecodedWithEmpty(const VCMPacket& packet)
{ {
// Empty packet (filler) inserted to a frame which // Empty packet inserted to a frame which
// is already decoding. Update the last decoded seq no. // is already decoding. Update the last decoded seq no.
if (_lastDecodedTimeStamp == packet.timestamp && if (_lastDecodedTimeStamp == packet.timestamp &&
(packet.seqNum > _lastDecodedSeqNum || (packet.seqNum > _lastDecodedSeqNum ||
@ -1866,10 +1906,10 @@ VCMJitterBuffer::CleanUpOldFrames()
((frameLowSeqNum == 0) && ((frameLowSeqNum == 0) &&
(_lastDecodedSeqNum == 0xffff)))) (_lastDecodedSeqNum == 0xffff))))
{ {
// Could happen when sending filler data. // Could happen when sending empty packets
// Filler packet (size = 0) belonging to last decoded frame. // Empty packet (size = 0) belonging to last decoded frame.
// Frame: | packet | packet | packet M=1 | // Frame: | packet | packet | packet M=1 |
// filler data (size = 0) | filler data (size = 0)| ... // empty data (size = 0) | empty data (size = 0)| ...
// This frame follows the last decoded frame // This frame follows the last decoded frame
_lastDecodedSeqNum = frameHighSeqNum; _lastDecodedSeqNum = frameHighSeqNum;
@ -1914,18 +1954,22 @@ VCMJitterBuffer::CleanUpSizeZeroFrames()
else else
{ {
bool releaseFrame = false; bool releaseFrame = false;
const WebRtc_Word32 frameHighSeqNum = ptrTempBuffer->GetHighSeqNum(); const WebRtc_Word32 frameHighSeqNum =
const WebRtc_Word32 frameLowSeqNum = ptrTempBuffer->GetLowSeqNum(); ptrTempBuffer->GetHighSeqNum();
const WebRtc_Word32 frameLowSeqNum =
ptrTempBuffer->GetLowSeqNum();
if ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) || // Frame is next in line if ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) ||
// Frame is next in line
((frameLowSeqNum == 0) && (_lastDecodedSeqNum== 0xffff))) ((frameLowSeqNum == 0) && (_lastDecodedSeqNum== 0xffff)))
{ {
// This frame follows the last decoded frame, release it. // This frame follows the last decoded frame, release it.
_lastDecodedSeqNum = frameHighSeqNum; _lastDecodedSeqNum = frameHighSeqNum;
releaseFrame = true; releaseFrame = true;
} }
// If frameHighSeqNum < _lastDecodedSeqNum but need to take wrap into account. // If frameHighSeqNum < _lastDecodedSeqNum
else if(frameHighSeqNum < _lastDecodedSeqNum) // but need to take wrap into account.
else if (frameHighSeqNum < _lastDecodedSeqNum)
{ {
if (frameHighSeqNum < 0x0fff && if (frameHighSeqNum < 0x0fff &&
_lastDecodedSeqNum> 0xf000) _lastDecodedSeqNum> 0xf000)
@ -1939,7 +1983,7 @@ VCMJitterBuffer::CleanUpSizeZeroFrames()
releaseFrame = true; releaseFrame = true;
} }
} }
else if(frameHighSeqNum > _lastDecodedSeqNum && else if (frameHighSeqNum > _lastDecodedSeqNum &&
_lastDecodedSeqNum < 0x0fff && _lastDecodedSeqNum < 0x0fff &&
frameHighSeqNum > 0xf000) frameHighSeqNum > 0xf000)
{ {
@ -1970,7 +2014,7 @@ VCMJitterBuffer::CleanUpSizeZeroFrames()
} }
} }
// used in GetFrameForDecoding // Used in GetFrameForDecoding
void void
VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame) VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame)
{ {
@ -1980,8 +2024,8 @@ VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame)
// First frame // First frame
frame.SetPreviousFrameLoss(); frame.SetPreviousFrameLoss();
} }
else if (frame.GetLowSeqNum() != ((WebRtc_UWord16)_lastDecodedSeqNum + else if ((WebRtc_UWord16)frame.GetLowSeqNum() !=
(WebRtc_UWord16)1)) ((WebRtc_UWord16)_lastDecodedSeqNum + (WebRtc_UWord16)1))
{ {
// Frame loss // Frame loss
frame.SetPreviousFrameLoss(); frame.SetPreviousFrameLoss();

View File

@ -71,7 +71,8 @@ public:
// Statistics, Calculate frame and bit rates // Statistics, Calculate frame and bit rates
WebRtc_Word32 GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate); WebRtc_Word32 GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate);
// Wait for the first packet in the next frame to arrive, blocks for <= maxWaitTimeMS ms // Wait for the first packet in the next frame to arrive, blocks
// for <= maxWaitTimeMS ms
WebRtc_Word64 GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS, WebRtc_Word64 GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
FrameType& incomingFrameType, FrameType& incomingFrameType,
WebRtc_Word64& renderTimeMs); WebRtc_Word64& renderTimeMs);
@ -82,7 +83,8 @@ public:
// or more packets? // or more packets?
bool CompleteSequenceWithNextFrame(); bool CompleteSequenceWithNextFrame();
// Wait maxWaitTimeMS for a complete frame to arrive. After timeout NULL is returned. // Wait maxWaitTimeMS for a complete frame to arrive. After timeout NULL
// is returned.
VCMEncodedFrame* GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS); VCMEncodedFrame* GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS);
// Get a frame for decoding (even an incomplete) without delay. // Get a frame for decoding (even an incomplete) without delay.
@ -100,10 +102,12 @@ public:
// Returns the time in ms when the latest packet was inserted into the frame. // Returns the time in ms when the latest packet was inserted into the frame.
// Retransmitted is set to true if any of the packets belonging to the frame // Retransmitted is set to true if any of the packets belonging to the frame
// has been retransmitted. // has been retransmitted.
WebRtc_Word64 LastPacketTime(VCMEncodedFrame* frame, bool& retransmitted) const; WebRtc_Word64 LastPacketTime(VCMEncodedFrame* frame,
bool& retransmitted) const;
// Insert a packet into a frame // Insert a packet into a frame
VCMFrameBufferEnum InsertPacket(VCMEncodedFrame* frame, const VCMPacket& packet); VCMFrameBufferEnum InsertPacket(VCMEncodedFrame* frame,
const VCMPacket& packet);
// Sync // Sync
WebRtc_UWord32 GetEstimatedJitterMS(); WebRtc_UWord32 GetEstimatedJitterMS();
@ -113,7 +117,8 @@ public:
void SetNackMode(VCMNackMode mode); // Enable/disable nack void SetNackMode(VCMNackMode mode); // Enable/disable nack
VCMNackMode GetNackMode() const; // Get nack mode VCMNackMode GetNackMode() const; // Get nack mode
// Get list of missing sequence numbers (size in number of elements) // Get list of missing sequence numbers (size in number of elements)
WebRtc_UWord16* GetNackList(WebRtc_UWord16& nackSize, bool& listExtended); WebRtc_UWord16* GetNackList(WebRtc_UWord16& nackSize,
bool& listExtended);
WebRtc_Word64 LastDecodedTimestamp() const; WebRtc_Word64 LastDecodedTimestamp() const;
static WebRtc_UWord32 LatestTimestamp(const WebRtc_UWord32 existingTimestamp, static WebRtc_UWord32 LatestTimestamp(const WebRtc_UWord32 existingTimestamp,
@ -134,7 +139,8 @@ protected:
VCMFrameBuffer* GetEmptyFrame(); VCMFrameBuffer* GetEmptyFrame();
// Recycle oldest frames up to a key frame, used if JB is completely full // Recycle oldest frames up to a key frame, used if JB is completely full
bool RecycleFramesUntilKeyFrame(); bool RecycleFramesUntilKeyFrame();
// Update frame state (set as complete or reconstructable if conditions are met) // Update frame state
// (set as complete or reconstructable if conditions are met)
void UpdateFrameState(VCMFrameBuffer* frameListItem); void UpdateFrameState(VCMFrameBuffer* frameListItem);
// Help functions for getting a frame // Help functions for getting a frame
@ -150,8 +156,10 @@ protected:
void VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame); void VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame);
bool IsPacketRetransmitted(const VCMPacket& packet) const; bool IsPacketRetransmitted(const VCMPacket& packet) const;
void UpdateJitterAndDelayEstimates(VCMJitterSample& sample, bool incompleteFrame); void UpdateJitterAndDelayEstimates(VCMJitterSample& sample,
void UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame, bool incompleteFrame); bool incompleteFrame);
void UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame,
bool incompleteFrame);
void UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs, void UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs,
WebRtc_UWord32 timestamp, WebRtc_UWord32 timestamp,
WebRtc_UWord32 frameSize, WebRtc_UWord32 frameSize,
@ -160,15 +168,17 @@ protected:
WebRtc_UWord32 GetEstimatedJitterMsInternal(); WebRtc_UWord32 GetEstimatedJitterMsInternal();
// NACK help // NACK help
WebRtc_UWord16* CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended); WebRtc_UWord16* CreateNackList(WebRtc_UWord16& nackSize,
bool& listExtended);
WebRtc_Word32 GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum, WebRtc_Word32 GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum,
WebRtc_Word32& highSeqNum) const; WebRtc_Word32& highSeqNum) const;
void UpdateLastDecodedWithFiller(const VCMPacket& packet); void UpdateLastDecodedWithEmpty(const VCMPacket& packet);
private: private:
static bool FrameEqualTimestamp(VCMFrameBuffer* frame, const void* timestamp); static bool FrameEqualTimestamp(VCMFrameBuffer* frame,
const void* timestamp);
static bool CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame, static bool CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
const void* notUsed); const void* notUsed);
// Decide whether should wait for NACK (mainly relevant for hybrid mode) // Decide whether should wait for NACK (mainly relevant for hybrid mode)
@ -222,7 +232,7 @@ private:
// NACK // NACK
VCMNackMode _nackMode; VCMNackMode _nackMode;
// Holds the internal nack list (the missing seqence numbers) // Holds the internal nack list (the missing sequence numbers)
WebRtc_Word32 _NACKSeqNumInternal[kNackHistoryLength]; WebRtc_Word32 _NACKSeqNumInternal[kNackHistoryLength];
WebRtc_UWord16 _NACKSeqNum[kNackHistoryLength]; WebRtc_UWord16 _NACKSeqNum[kNackHistoryLength];
WebRtc_UWord32 _NACKSeqNumLength; WebRtc_UWord32 _NACKSeqNumLength;

View File

@ -75,7 +75,8 @@ VCMSessionInfo::Reset()
memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte)); memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte));
} }
WebRtc_UWord32 VCMSessionInfo::GetSessionLength() WebRtc_UWord32
VCMSessionInfo::GetSessionLength()
{ {
WebRtc_UWord32 length = 0; WebRtc_UWord32 length = 0;
for (WebRtc_Word32 i = 0; i <= _highestPacketIndex; ++i) for (WebRtc_Word32 i = 0; i <= _highestPacketIndex; ++i)
@ -163,7 +164,7 @@ VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
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);
@ -185,8 +186,8 @@ VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
_markerBit = true; _markerBit = true;
_markerSeqNum = packet.seqNum; _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();
@ -253,7 +254,7 @@ VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
} }
if (_naluCompleteness[packetIndex] == kNaluEnd || if (_naluCompleteness[packetIndex] == kNaluEnd ||
_naluCompleteness[packetIndex] == kNaluComplete) _naluCompleteness[packetIndex] == kNaluComplete)
{ {
endIndex = packetIndex; endIndex = packetIndex;
} }
@ -271,7 +272,7 @@ VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
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;
@ -472,7 +473,7 @@ VCMSessionInfo::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
// found first packet, for now let's go only one back // found first packet, for now let's go only one back
if ((list[index - 1] == -1) || (list[index - 1] == -2)) if ((list[index - 1] == -1) || (list[index - 1] == -2))
{ {
// this is indeed the first packet, as previous packet was populated // This is indeed the first packet, as previous packet was populated
isBaseAvailable = true; isBaseAvailable = true;
} }
} }
@ -483,7 +484,7 @@ VCMSessionInfo::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
} }
// Zero out between first entry and end point // Zero out between first entry and end point
int i = 0; WebRtc_Word32 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;
@ -494,6 +495,7 @@ VCMSessionInfo::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
} }
else else
{ {
// Estimation
highMediaPacket = _emptySeqNumLow - 1 > _highSeqNum ? highMediaPacket = _emptySeqNumLow - 1 > _highSeqNum ?
_emptySeqNumLow - 1: _highSeqNum; _emptySeqNumLow - 1: _highSeqNum;
} }
@ -605,9 +607,8 @@ VCMSessionInfo::InsertPacket(const VCMPacket& packet,
} }
if (packet.frameType == kFrameEmpty) if (packet.frameType == kFrameEmpty)
{ {
// update seq number as an empty packet // Update seq number as an empty packet
InformOfEmptyPacket(packet.seqNum); return InformOfEmptyPacket(packet.seqNum);
return 0;
} }
// Check sequence number and update highest and lowest sequence numbers // Check sequence number and update highest and lowest sequence numbers
@ -621,7 +622,8 @@ VCMSessionInfo::InsertPacket(const VCMPacket& packet,
{ {
_highSeqNum = packet.seqNum; _highSeqNum = packet.seqNum;
} }
} else if (_highSeqNum > 0xff00 && packet.seqNum < 0x00ff) }
else if (_highSeqNum > 0xff00 && packet.seqNum < 0x00ff)
{ {
// wrap // wrap
_highSeqNum = packet.seqNum; _highSeqNum = packet.seqNum;
@ -719,7 +721,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;

View File

@ -26,7 +26,8 @@ public:
VCMSessionInfo(const VCMSessionInfo& rhs); VCMSessionInfo(const VCMSessionInfo& rhs);
WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 numberOfSeqNum); WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list,
WebRtc_Word32 numberOfSeqNum);
// Hybrid version: Zero out seq num for NACK list // Hybrid version: Zero out seq num for NACK list
// apply a score based on the packet location and the external rttScore // apply a score based on the packet location and the external rttScore
WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list, WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list,
@ -34,7 +35,8 @@ public:
float rttScore); float rttScore);
virtual void Reset(); virtual void Reset();
WebRtc_Word64 InsertPacket(const VCMPacket& packet, WebRtc_UWord8* ptrStartOfLayer); WebRtc_Word64 InsertPacket(const VCMPacket& packet,
WebRtc_UWord8* ptrStartOfLayer);
WebRtc_Word32 InformOfEmptyPacket(const WebRtc_UWord16 seqNum); WebRtc_Word32 InformOfEmptyPacket(const WebRtc_UWord16 seqNum);
virtual bool IsSessionComplete(); virtual bool IsSessionComplete();
@ -47,7 +49,8 @@ public:
webrtc::FrameType FrameType() const { return _frameType; } webrtc::FrameType FrameType() const { return _frameType; }
virtual WebRtc_Word32 GetHighestPacketIndex(); virtual WebRtc_Word32 GetHighestPacketIndex();
virtual void UpdatePacketSize(WebRtc_Word32 packetIndex, WebRtc_UWord32 length); virtual void UpdatePacketSize(WebRtc_Word32 packetIndex,
WebRtc_UWord32 length);
void SetStartSeqNumber(WebRtc_UWord16 seqNumber); void SetStartSeqNumber(WebRtc_UWord16 seqNumber);
@ -57,7 +60,8 @@ public:
// returns highest seqNum, media or empty // 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);
void SetPreviousFrameLoss() { _previousFrameLoss = true; } void SetPreviousFrameLoss() { _previousFrameLoss = true; }
bool PreviousFrameLoss() const { return _previousFrameLoss; } bool PreviousFrameLoss() const { return _previousFrameLoss; }
@ -73,16 +77,18 @@ protected:
WebRtc_Word32 startIndex, WebRtc_Word32 startIndex,
WebRtc_Word32 endIndex); WebRtc_Word32 endIndex);
void UpdateCompleteSession(); void UpdateCompleteSession();
// If we have inserted the first packet into this frame
bool _haveFirstPacket; // If we have inserted the first packet into this frame bool _haveFirstPacket;
bool _markerBit; // If we have inserted a packet with markerbit into this frame // If we have inserted a packet with markerbit into this frame
bool _sessionNACK; // If this session has been NACKed by JB bool _markerBit;
// If this session has been NACKed by JB
bool _sessionNACK;
bool _completeSession; bool _completeSession;
webrtc::FrameType _frameType; webrtc::FrameType _frameType;
bool _previousFrameLoss; bool _previousFrameLoss;
// Lowest/Highest packet sequence number in a session
WebRtc_Word32 _lowSeqNum; // Lowest packet sequence number in a session WebRtc_Word32 _lowSeqNum;
WebRtc_Word32 _highSeqNum; // Highest packet sequence number in a session WebRtc_Word32 _highSeqNum;
// Highest packet index in this frame // Highest packet index in this frame
WebRtc_UWord16 _highestPacketIndex; WebRtc_UWord16 _highestPacketIndex;