Refactored the jitter buffer to use std::list.

BUG=
TEST=

Review URL: https://webrtc-codereview.appspot.com/352016

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1635 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2012-02-08 08:58:55 +00:00
parent 7dfa883954
commit 2979461595
7 changed files with 158 additions and 415 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
@ -11,13 +11,11 @@
#ifndef WEBRTC_MODULES_VIDEO_CODING_FRAME_BUFFER_H_
#define WEBRTC_MODULES_VIDEO_CODING_FRAME_BUFFER_H_
#include "modules/interface/module_common_types.h"
#include "modules/video_coding/main/source/encoded_frame.h"
#include "modules/video_coding/main/source/jitter_buffer_common.h"
#include "modules/video_coding/main/source/session_info.h"
#include "typedefs.h"
#include "module_common_types.h"
#include "encoded_frame.h"
#include "frame_list.h"
#include "jitter_buffer_common.h"
#include "session_info.h"
namespace webrtc
{

View File

@ -1,117 +0,0 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "frame_list.h"
#include "frame_buffer.h"
#include "jitter_buffer.h"
#include <cstdlib>
namespace webrtc {
VCMFrameListTimestampOrderAsc::~VCMFrameListTimestampOrderAsc()
{
Flush();
}
void
VCMFrameListTimestampOrderAsc::Flush()
{
while(Erase(First()) != -1) { }
}
// Inserts frame in timestamp order, with the oldest timestamp first. Takes wrap
// arounds into account
WebRtc_Word32
VCMFrameListTimestampOrderAsc::Insert(VCMFrameBuffer* frame)
{
VCMFrameListItem* item = static_cast<VCMFrameListItem*>(First());
VCMFrameListItem* newItem = new VCMFrameListItem(frame);
bool inserted = false;
if (newItem == NULL)
{
return -1;
}
while (item != NULL)
{
const WebRtc_UWord32 itemTimestamp = item->GetItem()->TimeStamp();
if (LatestTimestamp(itemTimestamp, frame->TimeStamp(), NULL) ==
itemTimestamp)
{
if (InsertBefore(item, newItem) < 0)
{
delete newItem;
return -1;
}
inserted = true;
break;
}
item = Next(item);
}
if (!inserted && ListWrapper::Insert(ListWrapper::Last(), newItem) < 0)
{
delete newItem;
return -1;
}
return 0;
}
VCMFrameBuffer*
VCMFrameListTimestampOrderAsc::FirstFrame() const
{
VCMFrameListItem* item = First();
if (item != NULL)
{
return item->GetItem();
}
return NULL;
}
VCMFrameListItem*
VCMFrameListTimestampOrderAsc::FindFrameListItem(FindFrameCriteria criteria,
const void* compareWith,
VCMFrameListItem* startItem) const
{
if (startItem == NULL)
{
startItem = First();
}
if (criteria == NULL)
{
return NULL;
}
while (startItem != NULL)
{
if (criteria(startItem->GetItem(), compareWith))
{
return startItem;
}
startItem = Next(startItem);
}
// No frame found
return NULL;
}
VCMFrameBuffer*
VCMFrameListTimestampOrderAsc::FindFrame(FindFrameCriteria criteria,
const void* compareWith,
VCMFrameListItem* startItem) const
{
const VCMFrameListItem* frameListItem = FindFrameListItem(criteria,
compareWith,
startItem);
if (frameListItem == NULL)
{
return NULL;
}
return frameListItem->GetItem();
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_VIDEO_CODING_FRAME_LIST_H_
#define WEBRTC_MODULES_VIDEO_CODING_FRAME_LIST_H_
#include "list_wrapper.h"
#include "typedefs.h"
#include <stdlib.h>
namespace webrtc
{
class VCMFrameBuffer;
typedef bool (*FindFrameCriteria)(VCMFrameBuffer*, const void*);
class VCMFrameListItem : public ListItem
{
friend class VCMFrameListTimestampOrderAsc;
public:
VCMFrameListItem(const VCMFrameBuffer* ptr) : ListItem(ptr) {}
~VCMFrameListItem() {};
VCMFrameBuffer* GetItem() const
{ return static_cast<VCMFrameBuffer*>(ListItem::GetItem()); }
};
class VCMFrameListTimestampOrderAsc : public ListWrapper
{
public:
VCMFrameListTimestampOrderAsc() : ListWrapper() {};
~VCMFrameListTimestampOrderAsc();
void Flush();
// Inserts frame in timestamp order, with the oldest timestamp first.
// Takes wrap arounds into account.
WebRtc_Word32 Insert(VCMFrameBuffer* frame);
VCMFrameBuffer* FirstFrame() const;
VCMFrameListItem* Next(VCMFrameListItem* item) const
{ return static_cast<VCMFrameListItem*>(ListWrapper::Next(item)); }
VCMFrameListItem* Previous(VCMFrameListItem* item) const
{ return static_cast<VCMFrameListItem*>(ListWrapper::Previous(item)); }
VCMFrameListItem* First() const
{ return static_cast<VCMFrameListItem*>(ListWrapper::First()); }
VCMFrameListItem* Last() const
{ return static_cast<VCMFrameListItem*>(ListWrapper::Last()); }
VCMFrameListItem* FindFrameListItem(FindFrameCriteria criteria,
const void* compareWith = NULL,
VCMFrameListItem* startItem = NULL) const;
VCMFrameBuffer* FindFrame(FindFrameCriteria criteria,
const void* compareWith = NULL,
VCMFrameListItem* startItem = NULL) const;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_CODING_FRAME_LIST_H_

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
@ -7,25 +7,21 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/video_coding/main/source/jitter_buffer.h"
#include "critical_section_wrapper.h"
#include "frame_buffer.h"
#include "inter_frame_delay.h"
#include "internal_defines.h"
#include "jitter_buffer.h"
#include "jitter_buffer_common.h"
#include "jitter_estimator.h"
#include "packet.h"
#include "event.h"
#include "trace.h"
#include "modules/video_coding/main/source/tick_time_base.h"
#include "list_wrapper.h"
#include <algorithm>
#include <cassert>
#include <string.h>
#include <cmath>
#include "modules/video_coding/main/source/event.h"
#include "modules/video_coding/main/source/frame_buffer.h"
#include "modules/video_coding/main/source/inter_frame_delay.h"
#include "modules/video_coding/main/source/internal_defines.h"
#include "modules/video_coding/main/source/jitter_buffer_common.h"
#include "modules/video_coding/main/source/jitter_estimator.h"
#include "modules/video_coding/main/source/packet.h"
#include "modules/video_coding/main/source/tick_time_base.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/trace.h"
#if defined(_WIN32)
// VS 2005: Don't warn for default initialized arrays. See help for more info.
@ -34,27 +30,38 @@
namespace webrtc {
// Criteria used when searching for frames in the frame buffer list
bool
VCMJitterBuffer::FrameEqualTimestamp(VCMFrameBuffer* frame,
const void* timestamp)
{
if (timestamp == NULL)
{
return false;
}
return (*static_cast<const WebRtc_UWord32*>(timestamp)) == frame->TimeStamp();
}
// Predicates used when searching for frames in the frame buffer list
class FrameSmallerTimestamp {
public:
FrameSmallerTimestamp(uint32_t timestamp) : timestamp_(timestamp) {}
bool operator()(VCMFrameBuffer* frame) {
return (LatestTimestamp(timestamp_, frame->TimeStamp(), NULL) ==
timestamp_);
}
bool
VCMJitterBuffer::CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
const void* /*notUsed*/)
{
const VCMFrameBufferStateEnum state = frame->GetState();
// We can decode key frame or decodable/complete frames.
private:
uint32_t timestamp_;
};
class FrameEqualTimestamp {
public:
FrameEqualTimestamp(uint32_t timestamp) : timestamp_(timestamp) {}
bool operator()(VCMFrameBuffer* frame) {
return (timestamp_ == frame->TimeStamp());
}
private:
uint32_t timestamp_;
};
class CompleteDecodableKeyFrameCriteria {
public:
bool operator()(VCMFrameBuffer* frame) {
return (frame->FrameType() == kVideoFrameKey) &&
(state == kStateComplete || state == kStateDecodable);
}
(frame->GetState() == kStateComplete ||
frame->GetState() == kStateDecodable);
}
};
// Constructor
VCMJitterBuffer::VCMJitterBuffer(TickTimeBase* clock,
@ -71,7 +78,7 @@ VCMJitterBuffer::VCMJitterBuffer(TickTimeBase* clock,
_packetEvent(),
_maxNumberOfFrames(kStartNumberOfFrames),
_frameBuffers(),
_frameBuffersTSOrder(),
_frameList(),
_lastDecodedState(),
_packetsNotDecodable(0),
_receiveStatistics(),
@ -162,14 +169,16 @@ VCMJitterBuffer::CopyFrom(const VCMJitterBuffer& rhs)
_frameBuffers[i] = NULL;
}
}
while(_frameBuffersTSOrder.Erase(_frameBuffersTSOrder.First()) != -1)
{ }
_frameList.clear();
for (int i = 0; i < _maxNumberOfFrames; i++)
{
_frameBuffers[i] = new VCMFrameBuffer(*(rhs._frameBuffers[i]));
if (_frameBuffers[i]->Length() > 0)
{
_frameBuffersTSOrder.Insert(_frameBuffers[i]);
FrameList::reverse_iterator rit = std::find_if(
_frameList.rbegin(), _frameList.rend(),
FrameSmallerTimestamp(_frameBuffers[i]->TimeStamp()));
_frameList.insert(rit.base(), _frameBuffers[i]);
}
}
rhs._critSect->Leave();
@ -217,7 +226,7 @@ VCMJitterBuffer::Stop()
_critSect->Enter();
_running = false;
_lastDecodedState.Reset();
_frameBuffersTSOrder.Flush();
_frameList.clear();
for (int i = 0; i < kMaxNumberOfFrames; i++)
{
if (_frameBuffers[i] != NULL)
@ -253,7 +262,7 @@ void
VCMJitterBuffer::FlushInternal()
{
// Erase all frames from the sorted list and set their state to free.
_frameBuffersTSOrder.Flush();
_frameList.clear();
for (WebRtc_Word32 i = 0; i < _maxNumberOfFrames; i++)
{
ReleaseFrameInternal(_frameBuffers[i]);
@ -389,12 +398,11 @@ VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
}
}
const VCMFrameListItem*
oldFrameListItem = FindOldestCompleteContinuousFrame(false);
const FrameList::iterator it = FindOldestCompleteContinuousFrame(false);
VCMFrameBuffer* oldFrame = NULL;
if (oldFrameListItem != NULL)
if (it != _frameList.end())
{
oldFrame = oldFrameListItem->GetItem();
oldFrame = *it;
}
// Only signal if this is the oldest frame.
@ -464,16 +472,18 @@ VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame)
}
_numConsecutiveOldPackets = 0;
frame = _frameBuffersTSOrder.FindFrame(FrameEqualTimestamp,
&packet.timestamp);
FrameList::iterator it = std::find_if(
_frameList.begin(),
_frameList.end(),
FrameEqualTimestamp(packet.timestamp));
if (it != _frameList.end()) {
frame = *it;
return VCM_OK;
}
_critSect->Leave();
if (frame != NULL)
{
return VCM_OK;
}
// No match, return empty frame
frame = GetEmptyFrame();
if (frame != NULL)
@ -550,51 +560,46 @@ VCMJitterBuffer::GetEmptyFrame()
// Find oldest complete frame used for getting next frame to decode
// Must be called under critical section
VCMFrameListItem*
FrameList::iterator
VCMJitterBuffer::FindOldestCompleteContinuousFrame(bool enable_decodable) {
// If we have more than one frame done since last time, pick oldest.
VCMFrameListItem* oldest_frame_item = _frameBuffersTSOrder.First();
VCMFrameBuffer* oldest_frame = NULL;
FrameList::iterator it = _frameList.begin();
// When temporal layers are available, we search for a complete or decodable
// frame until we hit one of the following:
// 1. Continuous base or sync layer.
// 2. The end of the list was reached.
while (oldest_frame_item != NULL) {
oldest_frame = oldest_frame_item->GetItem();
if (oldest_frame) {
VCMFrameBufferStateEnum state = oldest_frame->GetState();
// Is this frame complete or decodable and continuous?
if ((state == kStateComplete ||
(enable_decodable && state == kStateDecodable)) &&
_lastDecodedState.ContinuousFrame(oldest_frame)) {
for (; it != _frameList.end(); ++it) {
oldest_frame = *it;
VCMFrameBufferStateEnum state = oldest_frame->GetState();
// Is this frame complete or decodable and continuous?
if ((state == kStateComplete ||
(enable_decodable && state == kStateDecodable)) &&
_lastDecodedState.ContinuousFrame(oldest_frame)) {
break;
} else {
int temporal_id = oldest_frame->TemporalId();
oldest_frame = NULL;
if (temporal_id <= 0) {
// When temporal layers are disabled or we have hit a base layer
// we break (regardless of continuity and completeness).
break;
} else {
int temporal_id = oldest_frame->TemporalId();
oldest_frame = NULL;
if (temporal_id <= 0) {
// When temporal layers are disabled or we have hit a base layer
// we break (regardless of continuity and completeness).
break;
}
}
}
// Temporal layers are available, and we have yet to reach a base layer
// frame (complete/decodable or not) => Read next frame.
oldest_frame_item = _frameBuffersTSOrder.Next(oldest_frame_item);
}
if (oldest_frame == NULL) {
// No complete frame no point to continue.
return NULL;
return _frameList.end();
} else if (_waitingForKeyFrame &&
oldest_frame->FrameType() != kVideoFrameKey) {
// We are waiting for a key frame.
return NULL;
return _frameList.end();
}
// We have a complete continuous frame.
return oldest_frame_item;
return it;
}
// Call from inside the critical section _critSect
@ -700,15 +705,9 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
if (_lastDecodedState.init() && WaitForNack()) {
_waitingForKeyFrame = true;
}
VCMFrameListItem*
oldestFrameListItem = FindOldestCompleteContinuousFrame(false);
VCMFrameBuffer* oldestFrame = NULL;
if (oldestFrameListItem != NULL)
{
oldestFrame = oldestFrameListItem->GetItem();
}
if (oldestFrame == NULL)
FrameList::iterator it = FindOldestCompleteContinuousFrame(false);
if (it == _frameList.end())
{
if (maxWaitTimeMS == 0)
{
@ -736,12 +735,8 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
// Finding oldest frame ready for decoder, but check
// sequence number and size
CleanUpOldFrames();
oldestFrameListItem = FindOldestCompleteContinuousFrame(false);
if (oldestFrameListItem != NULL)
{
oldestFrame = oldestFrameListItem->GetItem();
}
if (oldestFrame == NULL)
it = FindOldestCompleteContinuousFrame(false);
if (it == _frameList.end())
{
waitTimeMs = endWaitTimeMs -
_clock->MillisecondTimestamp();
@ -765,13 +760,16 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
_frameEvent.Reset();
}
if (oldestFrame == NULL)
if (it == _frameList.end())
{
// Even after signaling we're still missing a complete continuous frame
_critSect->Leave();
return NULL;
}
VCMFrameBuffer* oldestFrame = *it;
it = _frameList.erase(it);
// Update jitter estimate
const bool retransmitted = (oldestFrame->GetNackCount() > 0);
if (retransmitted)
@ -783,8 +781,6 @@ VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
// Ignore retransmitted and empty frames.
UpdateJitterAndDelayEstimates(*oldestFrame, false);
}
_frameBuffersTSOrder.Erase(oldestFrameListItem);
oldestFrameListItem = NULL;
oldestFrame->SetState(kStateDecoding);
@ -853,9 +849,9 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
// Finding oldest frame ready for decoder, check sequence number and size
CleanUpOldFrames();
VCMFrameBuffer* oldestFrame = _frameBuffersTSOrder.FirstFrame();
FrameList::iterator it = _frameList.begin();
if (oldestFrame == NULL)
if (it == _frameList.end())
{
_packetEvent.Reset();
_critSect->Leave();
@ -870,7 +866,7 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
_critSect->Enter();
CleanUpOldFrames();
oldestFrame = _frameBuffersTSOrder.FirstFrame();
it = _frameList.begin();
}
else
{
@ -878,7 +874,7 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
}
}
if (oldestFrame == NULL)
if (it == _frameList.end())
{
_critSect->Leave();
return -1;
@ -887,11 +883,11 @@ VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
// return frame type
// All layers are assumed to have the same type
incomingFrameType = oldestFrame->FrameType();
incomingFrameType = (*it)->FrameType();
renderTimeMs = oldestFrame->RenderTimeMs();
renderTimeMs = (*it)->RenderTimeMs();
const WebRtc_UWord32 timestamp = oldestFrame->TimeStamp();
const WebRtc_UWord32 timestamp = (*it)->TimeStamp();
_critSect->Leave();
@ -911,17 +907,12 @@ VCMJitterBuffer::CompleteSequenceWithNextFrame()
// Finding oldest frame ready for decoder, check sequence number and size
CleanUpOldFrames();
VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
if (oldestFrameListItem == NULL)
{
// No frame found
return true;
}
if (_frameList.empty())
return true;
VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();
const VCMFrameListItem* nextFrameItem =
_frameBuffersTSOrder.Next(oldestFrameListItem);
if (nextFrameItem == NULL && oldestFrame->GetState() != kStateComplete)
VCMFrameBuffer* oldestFrame = _frameList.front();
if (_frameList.size() <= 1 &&
oldestFrame->GetState() != kStateComplete)
{
// Frame not ready to be decoded.
return true;
@ -968,19 +959,14 @@ VCMJitterBuffer::GetFrameForDecoding()
CleanUpOldFrames();
VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
if (oldestFrameListItem == NULL)
{
return NULL;
if (_frameList.empty()) {
return NULL;
}
VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();
const VCMFrameListItem* nextFrameItem =
_frameBuffersTSOrder.Next(oldestFrameListItem);
// Don't output incomplete frames if subsequent frames haven't arrived yet.
if (nextFrameItem == NULL && oldestFrame->GetState() != kStateComplete)
{
return NULL;
VCMFrameBuffer* oldestFrame = _frameList.front();
if (_frameList.size() <= 1 &&
oldestFrame->GetState() != kStateComplete) {
return NULL;
}
// Incomplete frame pulled out from jitter buffer,
@ -1006,8 +992,7 @@ VCMJitterBuffer::GetFrameForDecoding()
oldestFrame->LatestPacketTimeMs();
_waitingForCompletion.timestamp = oldestFrame->TimeStamp();
}
_frameBuffersTSOrder.Erase(oldestFrameListItem);
oldestFrameListItem = NULL;
_frameList.erase(_frameList.begin());
// Look for previous frame loss
VerifyAndSetPreviousFrameLost(*oldestFrame);
@ -1052,27 +1037,18 @@ VCMJitterBuffer::GetFrameForDecodingNACK()
// Allow for a decodable frame when in Hybrid mode.
bool enableDecodable = _nackMode == kNackHybrid ? true : false;
VCMFrameListItem*
oldestFrameListItem = FindOldestCompleteContinuousFrame(enableDecodable);
VCMFrameBuffer* oldestFrame = NULL;
if (oldestFrameListItem != NULL)
{
oldestFrame = oldestFrameListItem->GetItem();
}
if (oldestFrame == NULL)
FrameList::iterator it = FindOldestCompleteContinuousFrame(enableDecodable);
if (it == _frameList.end())
{
// If we didn't find one we're good with a complete key/decodable frame.
oldestFrameListItem = _frameBuffersTSOrder.FindFrameListItem(
CompleteDecodableKeyFrameCriteria);
if (oldestFrameListItem != NULL)
{
oldestFrame = oldestFrameListItem->GetItem();
}
if (oldestFrame == NULL)
it = find_if(_frameList.begin(), _frameList.end(),
CompleteDecodableKeyFrameCriteria());
if (it == _frameList.end())
{
return NULL;
}
}
VCMFrameBuffer* oldestFrame = *it;
// Update jitter estimate
const bool retransmitted = (oldestFrame->GetNackCount() > 0);
if (retransmitted)
@ -1084,8 +1060,7 @@ VCMJitterBuffer::GetFrameForDecodingNACK()
// Ignore retransmitted and empty frames.
UpdateJitterAndDelayEstimates(*oldestFrame, false);
}
_frameBuffersTSOrder.Erase(oldestFrameListItem);
oldestFrameListItem = NULL;
it = _frameList.erase(it);
// Look for previous frame loss
VerifyAndSetPreviousFrameLost(*oldestFrame);
@ -1601,7 +1576,10 @@ VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet)
if (state == kStateEmpty && first)
{
ret = kFirstPacket;
_frameBuffersTSOrder.Insert(frame);
FrameList::reverse_iterator rit = std::find_if(
_frameList.rbegin(), _frameList.rend(),
FrameSmallerTimestamp(frame->TimeStamp()));
_frameList.insert(rit.base(), frame);
}
}
}
@ -1719,35 +1697,22 @@ VCMJitterBuffer::SetNackMode(VCMNackMode mode,
bool
VCMJitterBuffer::RecycleFramesUntilKeyFrame()
{
// Throw at least one frame.
VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
VCMFrameBuffer* oldestFrame = NULL;
if (oldestFrameListItem != NULL)
{
oldestFrame = oldestFrameListItem->GetItem();
}
// Remove up to oldest key frame
while (oldestFrameListItem != NULL)
while (_frameList.size() > 0)
{
// Throw at least one frame.
_dropCount++;
FrameList::iterator it = _frameList.begin();
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
VCMId(_vcmId, _receiverId),
"Jitter buffer drop count:%d, lowSeq %d", _dropCount,
oldestFrame->GetLowSeqNum());
_frameBuffersTSOrder.Erase(oldestFrameListItem);
RecycleFrame(oldestFrame);
oldestFrameListItem = _frameBuffersTSOrder.First();
if (oldestFrameListItem != NULL)
{
oldestFrame = oldestFrameListItem->GetItem();
}
if (oldestFrame != NULL && oldestFrame->FrameType() == kVideoFrameKey)
(*it)->GetLowSeqNum());
RecycleFrame(*it);
it = _frameList.erase(it);
if (it != _frameList.end() && (*it)->FrameType() == kVideoFrameKey)
{
// Fake the lastDecodedState to match this key frame.
_lastDecodedState.SetStateOneBack(oldestFrame);
_lastDecodedState.SetStateOneBack(*it);
return true;
}
}
@ -1758,18 +1723,14 @@ VCMJitterBuffer::RecycleFramesUntilKeyFrame()
// Must be called under the critical section _critSect.
void VCMJitterBuffer::CleanUpOldFrames() {
VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
VCMFrameBuffer* oldestFrame = NULL;
while (oldestFrameListItem != NULL) {
oldestFrame = oldestFrameListItem->GetItem();
while (_frameList.size() > 0) {
VCMFrameBuffer* oldestFrame = _frameList.front();
bool nextFrameEmpty = (_lastDecodedState.ContinuousFrame(oldestFrame) &&
oldestFrame->GetState() == kStateEmpty);
if (_lastDecodedState.IsOldFrame(oldestFrame) || (nextFrameEmpty &&
_frameBuffersTSOrder.Next(oldestFrameListItem) != NULL)) {
_frameBuffersTSOrder.Erase(oldestFrameListItem);
ReleaseFrameInternal(oldestFrame);
oldestFrameListItem = _frameBuffersTSOrder.First();
if (_lastDecodedState.IsOldFrame(oldestFrame) ||
(nextFrameEmpty && _frameList.size() > 1)) {
ReleaseFrameInternal(_frameList.front());
_frameList.erase(_frameList.begin());
} else {
break;
}
@ -1786,7 +1747,6 @@ void VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame) {
frame.SetPreviousFrameLoss();
}
bool
VCMJitterBuffer::WaitForNack()
{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
@ -11,16 +11,18 @@
#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_H_
#define WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_H_
#include <list>
#include "modules/interface/module_common_types.h"
#include "modules/video_coding/main/interface/video_coding_defines.h"
#include "modules/video_coding/main/source/decoding_state.h"
#include "modules/video_coding/main/source/event.h"
#include "modules/video_coding/main/source/inter_frame_delay.h"
#include "modules/video_coding/main/source/jitter_buffer_common.h"
#include "modules/video_coding/main/source/jitter_estimator.h"
#include "system_wrappers/interface/constructor_magic.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "typedefs.h"
#include "critical_section_wrapper.h"
#include "decoding_state.h"
#include "module_common_types.h"
#include "video_coding_defines.h"
#include "inter_frame_delay.h"
#include "event.h"
#include "frame_list.h"
#include "jitter_buffer_common.h"
#include "jitter_estimator.h"
namespace webrtc
{
@ -32,6 +34,8 @@ enum VCMNackMode
kNoNack
};
typedef std::list<VCMFrameBuffer*> FrameList;
// forward declarations
class TickTimeBase;
class VCMFrameBuffer;
@ -160,7 +164,7 @@ private:
// Help functions for getting a frame
// Find oldest complete frame, used for getting next frame to decode
// When enabled, will return a decodable frame
VCMFrameListItem* FindOldestCompleteContinuousFrame(bool enableDecodable);
FrameList::iterator FindOldestCompleteContinuousFrame(bool enableDecodable);
void CleanUpOldFrames();
@ -184,10 +188,6 @@ private:
WebRtc_Word32 GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum,
WebRtc_Word32& highSeqNum) const;
static bool FrameEqualTimestamp(VCMFrameBuffer* frame,
const void* timestamp);
static bool CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
const void* notUsed);
// Decide whether should wait for NACK (mainly relevant for hybrid mode)
bool WaitForNack();
@ -206,7 +206,7 @@ private:
WebRtc_Word32 _maxNumberOfFrames;
// Array of pointers to the frames in JB
VCMFrameBuffer* _frameBuffers[kMaxNumberOfFrames];
VCMFrameListTimestampOrderAsc _frameBuffersTSOrder;
FrameList _frameList;
// timing
VCMDecodingState _lastDecodedState;

View File

@ -46,7 +46,6 @@
'fec_tables_xor.h',
'frame_buffer.h',
'frame_dropper.h',
'frame_list.h',
'generic_decoder.h',
'generic_encoder.h',
'inter_frame_delay.h',
@ -78,7 +77,6 @@
'exp_filter.cc',
'frame_buffer.cc',
'frame_dropper.cc',
'frame_list.cc',
'generic_decoder.cc',
'generic_encoder.cc',
'inter_frame_delay.cc',

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <math.h>
#include <stdio.h>
#include "common_types.h"
#include "../source/event.h"
@ -24,6 +24,7 @@
#include "test_util.h"
#include "test_macros.h"
// TODO(holmer): Get rid of this to conform with style guide.
using namespace webrtc;
// TODO (Mikhal/Stefan): Update as gtest and separate to specific tests.
@ -105,37 +106,6 @@ int JitterBufferTest(CmdArgs& args)
WebRtc_UWord8 data[1500];
VCMPacket packet(data, size, seqNum, timeStamp, true);
VCMFrameListTimestampOrderAsc frameList;
VCMFrameBuffer* fb = NULL;
for (int i=0; i < 100; i++)
{
fb = new VCMFrameBuffer();
fb->SetState(kStateEmpty);
packet.timestamp = 0xfffffff0 + i;
packet.seqNum = seqNum;
packet.payloadType = 126;
seqNum++;
fb->InsertPacket(packet, clock.MillisecondTimestamp(), false, 0);
TEST(frameList.Insert(fb) == 0);
}
VCMFrameListItem* item = NULL;
WebRtc_UWord32 prevTimestamp = 0;
int i = 0;
for (i=0; !frameList.Empty(); i++)
{
item = frameList.First();
fb = static_cast<VCMFrameBuffer*>(item->GetItem());
TEST(i > 0 || fb->TimeStamp() == 0xfffffff0); // Frame 0 has no prev
TEST(prevTimestamp - fb->TimeStamp() == static_cast<WebRtc_UWord32>(-1)
|| i == 0);
prevTimestamp = fb->TimeStamp();
frameList.Erase(item);
delete fb;
}
TEST(i == 100);
//printf("DONE timestamp ordered frame list\n");
VCMJitterBuffer jb(&clock);
seqNum = 1234;