/* * 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 #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