1/* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/modules/utility/source/video_frames_queue.h" 12 13#ifdef WEBRTC_MODULE_UTILITY_VIDEO 14 15#include <assert.h> 16 17#include "webrtc/common_video/interface/texture_video_frame.h" 18#include "webrtc/modules/interface/module_common_types.h" 19#include "webrtc/system_wrappers/interface/logging.h" 20#include "webrtc/system_wrappers/interface/tick_util.h" 21 22namespace webrtc { 23VideoFramesQueue::VideoFramesQueue() 24 : _renderDelayMs(10) 25{ 26} 27 28VideoFramesQueue::~VideoFramesQueue() { 29 for (FrameList::iterator iter = _incomingFrames.begin(); 30 iter != _incomingFrames.end(); ++iter) { 31 delete *iter; 32 } 33 for (FrameList::iterator iter = _emptyFrames.begin(); 34 iter != _emptyFrames.end(); ++iter) { 35 delete *iter; 36 } 37} 38 39int32_t VideoFramesQueue::AddFrame(const I420VideoFrame& newFrame) { 40 if (newFrame.native_handle() != NULL) { 41 _incomingFrames.push_back(newFrame.CloneFrame()); 42 return 0; 43 } 44 45 I420VideoFrame* ptrFrameToAdd = NULL; 46 // Try to re-use a VideoFrame. Only allocate new memory if it is necessary. 47 if (!_emptyFrames.empty()) { 48 ptrFrameToAdd = _emptyFrames.front(); 49 _emptyFrames.pop_front(); 50 } 51 if (!ptrFrameToAdd) { 52 if (_emptyFrames.size() + _incomingFrames.size() > 53 KMaxNumberOfFrames) { 54 LOG(LS_WARNING) << "Too many frames, limit: " << KMaxNumberOfFrames; 55 return -1; 56 } 57 ptrFrameToAdd = new I420VideoFrame(); 58 } 59 ptrFrameToAdd->CopyFrame(newFrame); 60 _incomingFrames.push_back(ptrFrameToAdd); 61 return 0; 62} 63 64// Find the most recent frame that has a VideoFrame::RenderTimeMs() that is 65// lower than current time in ms (TickTime::MillisecondTimestamp()). 66// Note _incomingFrames is sorted so that the oldest frame is first. 67// Recycle all frames that are older than the most recent frame. 68I420VideoFrame* VideoFramesQueue::FrameToRecord() { 69 I420VideoFrame* ptrRenderFrame = NULL; 70 for (FrameList::iterator iter = _incomingFrames.begin(); 71 iter != _incomingFrames.end(); ++iter) { 72 I420VideoFrame* ptrOldestFrameInList = *iter; 73 if (ptrOldestFrameInList->render_time_ms() <= 74 TickTime::MillisecondTimestamp() + _renderDelayMs) { 75 // List is traversed beginning to end. If ptrRenderFrame is not 76 // NULL it must be the first, and thus oldest, VideoFrame in the 77 // queue. It can be recycled. 78 if (ptrRenderFrame) { 79 ReturnFrame(ptrRenderFrame); 80 _incomingFrames.pop_front(); 81 } 82 ptrRenderFrame = ptrOldestFrameInList; 83 } else { 84 // All VideoFrames following this one will be even newer. No match 85 // will be found. 86 break; 87 } 88 } 89 return ptrRenderFrame; 90} 91 92int32_t VideoFramesQueue::ReturnFrame(I420VideoFrame* ptrOldFrame) { 93 // No need to reuse texture frames because they do not allocate memory. 94 if (ptrOldFrame->native_handle() == NULL) { 95 ptrOldFrame->set_timestamp(0); 96 ptrOldFrame->set_width(0); 97 ptrOldFrame->set_height(0); 98 ptrOldFrame->set_render_time_ms(0); 99 ptrOldFrame->ResetSize(); 100 _emptyFrames.push_back(ptrOldFrame); 101 } else { 102 delete ptrOldFrame; 103 } 104 return 0; 105} 106 107int32_t VideoFramesQueue::SetRenderDelay(uint32_t renderDelay) { 108 _renderDelayMs = renderDelay; 109 return 0; 110} 111} // namespace webrtc 112#endif // WEBRTC_MODULE_UTILITY_VIDEO 113