From 2979461595219b66341b4d3171809ee25750edf0 Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Wed, 8 Feb 2012 08:58:55 +0000 Subject: [PATCH] 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 --- .../video_coding/main/source/frame_buffer.h | 12 +- .../video_coding/main/source/frame_list.cc | 117 ------- .../video_coding/main/source/frame_list.h | 66 ---- .../video_coding/main/source/jitter_buffer.cc | 308 ++++++++---------- .../video_coding/main/source/jitter_buffer.h | 32 +- .../main/source/video_coding.gypi | 2 - .../main/test/jitter_buffer_test.cc | 36 +- 7 files changed, 158 insertions(+), 415 deletions(-) delete mode 100644 src/modules/video_coding/main/source/frame_list.cc delete mode 100644 src/modules/video_coding/main/source/frame_list.h diff --git a/src/modules/video_coding/main/source/frame_buffer.h b/src/modules/video_coding/main/source/frame_buffer.h index ce2d4c3fa..ea0575412 100644 --- a/src/modules/video_coding/main/source/frame_buffer.h +++ b/src/modules/video_coding/main/source/frame_buffer.h @@ -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 { diff --git a/src/modules/video_coding/main/source/frame_list.cc b/src/modules/video_coding/main/source/frame_list.cc deleted file mode 100644 index 3908892e2..000000000 --- a/src/modules/video_coding/main/source/frame_list.cc +++ /dev/null @@ -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 - -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(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(); -} - -} - diff --git a/src/modules/video_coding/main/source/frame_list.h b/src/modules/video_coding/main/source/frame_list.h deleted file mode 100644 index cc5d053e1..000000000 --- a/src/modules/video_coding/main/source/frame_list.h +++ /dev/null @@ -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 - -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(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(ListWrapper::Next(item)); } - VCMFrameListItem* Previous(VCMFrameListItem* item) const - { return static_cast(ListWrapper::Previous(item)); } - VCMFrameListItem* First() const - { return static_cast(ListWrapper::First()); } - VCMFrameListItem* Last() const - { return static_cast(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_ diff --git a/src/modules/video_coding/main/source/jitter_buffer.cc b/src/modules/video_coding/main/source/jitter_buffer.cc index c285730bf..3c2de4790 100644 --- a/src/modules/video_coding/main/source/jitter_buffer.cc +++ b/src/modules/video_coding/main/source/jitter_buffer.cc @@ -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 #include -#include -#include + +#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(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() { diff --git a/src/modules/video_coding/main/source/jitter_buffer.h b/src/modules/video_coding/main/source/jitter_buffer.h index 3961ed197..d9511870d 100644 --- a/src/modules/video_coding/main/source/jitter_buffer.h +++ b/src/modules/video_coding/main/source/jitter_buffer.h @@ -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 + +#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 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; diff --git a/src/modules/video_coding/main/source/video_coding.gypi b/src/modules/video_coding/main/source/video_coding.gypi index 2aed964d8..3a9928341 100644 --- a/src/modules/video_coding/main/source/video_coding.gypi +++ b/src/modules/video_coding/main/source/video_coding.gypi @@ -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', diff --git a/src/modules/video_coding/main/test/jitter_buffer_test.cc b/src/modules/video_coding/main/test/jitter_buffer_test.cc index 75e6aec7c..206698363 100644 --- a/src/modules/video_coding/main/test/jitter_buffer_test.cc +++ b/src/modules/video_coding/main/test/jitter_buffer_test.cc @@ -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 #include +#include #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(item->GetItem()); - TEST(i > 0 || fb->TimeStamp() == 0xfffffff0); // Frame 0 has no prev - TEST(prevTimestamp - fb->TimeStamp() == static_cast(-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;