blob: 9ade8b51a498c0402dffb767f60d8cdcf80a3c1d [file] [log] [blame]
/*
* 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 "webrtc/modules/utility/source/video_frames_queue.h"
#ifdef WEBRTC_MODULE_UTILITY_VIDEO
#include <assert.h>
#include "webrtc/common_video/interface/texture_video_frame.h"
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
namespace webrtc {
VideoFramesQueue::VideoFramesQueue()
: _renderDelayMs(10)
{
}
VideoFramesQueue::~VideoFramesQueue() {
for (FrameList::iterator iter = _incomingFrames.begin();
iter != _incomingFrames.end(); ++iter) {
delete *iter;
}
for (FrameList::iterator iter = _emptyFrames.begin();
iter != _emptyFrames.end(); ++iter) {
delete *iter;
}
}
int32_t VideoFramesQueue::AddFrame(const I420VideoFrame& newFrame) {
if (newFrame.native_handle() != NULL) {
_incomingFrames.push_back(newFrame.CloneFrame());
return 0;
}
I420VideoFrame* ptrFrameToAdd = NULL;
// Try to re-use a VideoFrame. Only allocate new memory if it is necessary.
if (!_emptyFrames.empty()) {
ptrFrameToAdd = _emptyFrames.front();
_emptyFrames.pop_front();
}
if (!ptrFrameToAdd) {
if (_emptyFrames.size() + _incomingFrames.size() >
KMaxNumberOfFrames) {
LOG(LS_WARNING) << "Too many frames, limit: " << KMaxNumberOfFrames;
return -1;
}
ptrFrameToAdd = new I420VideoFrame();
}
ptrFrameToAdd->CopyFrame(newFrame);
_incomingFrames.push_back(ptrFrameToAdd);
return 0;
}
// Find the most recent frame that has a VideoFrame::RenderTimeMs() that is
// lower than current time in ms (TickTime::MillisecondTimestamp()).
// Note _incomingFrames is sorted so that the oldest frame is first.
// Recycle all frames that are older than the most recent frame.
I420VideoFrame* VideoFramesQueue::FrameToRecord() {
I420VideoFrame* ptrRenderFrame = NULL;
for (FrameList::iterator iter = _incomingFrames.begin();
iter != _incomingFrames.end(); ++iter) {
I420VideoFrame* ptrOldestFrameInList = *iter;
if (ptrOldestFrameInList->render_time_ms() <=
TickTime::MillisecondTimestamp() + _renderDelayMs) {
// List is traversed beginning to end. If ptrRenderFrame is not
// NULL it must be the first, and thus oldest, VideoFrame in the
// queue. It can be recycled.
if (ptrRenderFrame) {
ReturnFrame(ptrRenderFrame);
_incomingFrames.pop_front();
}
ptrRenderFrame = ptrOldestFrameInList;
} else {
// All VideoFrames following this one will be even newer. No match
// will be found.
break;
}
}
return ptrRenderFrame;
}
int32_t VideoFramesQueue::ReturnFrame(I420VideoFrame* ptrOldFrame) {
// No need to reuse texture frames because they do not allocate memory.
if (ptrOldFrame->native_handle() == NULL) {
ptrOldFrame->set_timestamp(0);
ptrOldFrame->set_width(0);
ptrOldFrame->set_height(0);
ptrOldFrame->set_render_time_ms(0);
ptrOldFrame->ResetSize();
_emptyFrames.push_back(ptrOldFrame);
} else {
delete ptrOldFrame;
}
return 0;
}
int32_t VideoFramesQueue::SetRenderDelay(uint32_t renderDelay) {
_renderDelayMs = renderDelay;
return 0;
}
} // namespace webrtc
#endif // WEBRTC_MODULE_UTILITY_VIDEO