blob: 5a1ea596fbee7bc1cee327bcea616240cc4d41d4 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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 "video_frames_queue.h"
12
13#ifdef WEBRTC_MODULE_UTILITY_VIDEO
14
15#include <cassert>
16
17#include "module_common_types.h"
18#include "tick_util.h"
19#include "trace.h"
20
21namespace webrtc {
22VideoFramesQueue::VideoFramesQueue()
23 : _incomingFrames(),
24 _renderDelayMs(10)
25{
26}
27
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +000028VideoFramesQueue::~VideoFramesQueue() {
29 while (!_incomingFrames.Empty()) {
30 ListItem* item = _incomingFrames.First();
31 if (item) {
32 I420VideoFrame* ptrFrame = static_cast<I420VideoFrame*>(item->GetItem());
33 assert(ptrFrame != NULL);
34 delete ptrFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +000035 }
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +000036 _incomingFrames.Erase(item);
37 }
38 while (!_emptyFrames.Empty()) {
39 ListItem* item = _emptyFrames.First();
40 if (item) {
41 I420VideoFrame* ptrFrame =
42 static_cast<I420VideoFrame*>(item->GetItem());
43 assert(ptrFrame != NULL);
44 delete ptrFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +000045 }
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +000046 _emptyFrames.Erase(item);
47 }
niklase@google.com470e71d2011-07-07 08:21:25 +000048}
49
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +000050WebRtc_Word32 VideoFramesQueue::AddFrame(const I420VideoFrame& newFrame) {
51 I420VideoFrame* ptrFrameToAdd = NULL;
52 // Try to re-use a VideoFrame. Only allocate new memory if it is necessary.
53 if (!_emptyFrames.Empty()) {
54 ListItem* item = _emptyFrames.First();
55 if (item) {
56 ptrFrameToAdd = static_cast<I420VideoFrame*>(item->GetItem());
57 _emptyFrames.Erase(item);
niklase@google.com470e71d2011-07-07 08:21:25 +000058 }
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +000059 }
60 if (!ptrFrameToAdd) {
61 if (_emptyFrames.GetSize() + _incomingFrames.GetSize() >
62 KMaxNumberOfFrames) {
63 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
64 "%s: too many frames, limit: %d", __FUNCTION__,
65 KMaxNumberOfFrames);
66 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000067 }
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +000068
69 WEBRTC_TRACE(kTraceMemory, kTraceVideoRenderer, -1,
70 "%s: allocating buffer %d", __FUNCTION__,
71 _emptyFrames.GetSize() + _incomingFrames.GetSize());
72
73 ptrFrameToAdd = new I420VideoFrame();
74 if (!ptrFrameToAdd) {
75 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
76 "%s: could not create new frame for", __FUNCTION__);
77 return -1;
78 }
79 }
80 ptrFrameToAdd->CopyFrame(newFrame);
81 _incomingFrames.PushBack(ptrFrameToAdd);
82 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000083}
84
85// Find the most recent frame that has a VideoFrame::RenderTimeMs() that is
86// lower than current time in ms (TickTime::MillisecondTimestamp()).
87// Note _incomingFrames is sorted so that the oldest frame is first.
88// Recycle all frames that are older than the most recent frame.
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +000089I420VideoFrame* VideoFramesQueue::FrameToRecord() {
90 I420VideoFrame* ptrRenderFrame = NULL;
91 ListItem* item = _incomingFrames.First();
92 while(item) {
93 I420VideoFrame* ptrOldestFrameInList =
94 static_cast<I420VideoFrame*>(item->GetItem());
95 if (ptrOldestFrameInList->render_time_ms() <=
96 TickTime::MillisecondTimestamp() + _renderDelayMs) {
97 if (ptrRenderFrame) {
98 // List is traversed beginning to end. If ptrRenderFrame is not
99 // NULL it must be the first, and thus oldest, VideoFrame in the
100 // queue. It can be recycled.
101 ReturnFrame(ptrRenderFrame);
102 _incomingFrames.PopFront();
103 }
104 item = _incomingFrames.Next(item);
105 ptrRenderFrame = ptrOldestFrameInList;
106 } else {
107 // All VideoFrames following this one will be even newer. No match
108 // will be found.
109 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 }
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +0000111 }
112 return ptrRenderFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113}
114
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +0000115WebRtc_Word32 VideoFramesQueue::ReturnFrame(I420VideoFrame* ptrOldFrame) {
116 ptrOldFrame->set_timestamp(0);
117 ptrOldFrame->set_width(0);
118 ptrOldFrame->set_height(0);
119 ptrOldFrame->set_render_time_ms(0);
120 ptrOldFrame->ResetSize();
121 _emptyFrames.PushBack(ptrOldFrame);
122 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000123}
124
mikhal@webrtc.orgc381a842012-10-30 18:22:02 +0000125WebRtc_Word32 VideoFramesQueue::SetRenderDelay(WebRtc_UWord32 renderDelay) {
126 _renderDelayMs = renderDelay;
127 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000128}
129} // namespace webrtc
130#endif // WEBRTC_MODULE_UTILITY_VIDEO