1 /* ***** BEGIN LICENSE BLOCK *****
5 * Copyright (c) 2008 BBC Research
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * ***** END LICENSE BLOCK ***** */
30 #include "frameQueue.h"
31 #include "videoTransport.h"
32 #include "readerInterface.h"
39 FrameQueue::FrameQueue() :
49 FrameQueue::~FrameQueue()
59 while (!pastFrames
.isEmpty())
60 delete pastFrames
.takeFirst();
62 while (!futureFrames
.isEmpty())
63 delete futureFrames
.takeFirst();
65 while (!usedFrames
.isEmpty())
66 delete usedFrames
.takeFirst();
69 int FrameQueue::wantedFrameNum(bool future
)
71 //if there are no frames in the list, then the last displayed frame number is the
72 //starting point for working out what the next needed frame is
73 int lastFrame
=displayFrameNum
;
76 //if the reader cannot do random access then it will always return the next frame
77 //we cannot seek so frame numbers are a bit meaningless here
78 if (reader
->randomAccess
== false)
81 //if we can seek then get the number of the last frame in the queue
83 if (futureFrames
.size())
84 lastFrame
= futureFrames
.last()->frameNum
;
87 if (pastFrames
.size())
88 lastFrame
= pastFrames
.last()->frameNum
;
91 //frame offset from the last one
95 wantedFrame
= lastFrame
+ offset
;
100 void FrameQueue::addFrames(bool future
)
102 QLinkedList
<VideoData
*> *list
= (future
== true) ? &futureFrames
: &pastFrames
;
105 QMutexLocker
listLocker(&listMutex
);
106 int numFrames
= list
->size();
109 //add extra frames to the past frames list
110 while (stop
-- && numFrames
< LISTLEN
) {
112 int wantedFrame
= wantedFrameNum(future
);
115 reader
->pullFrame(wantedFrame
, v
);
119 numFrames
= list
->size();
124 //called from the transport controller to get frame data for display
125 VideoData
* FrameQueue::getNextFrame(int transportSpeed
, int transportDirection
)
127 speed
= transportSpeed
;
128 direction
= transportDirection
;
130 //stopped or paused with no frame displayed, or forwards
131 if ((direction
== 0 && displayFrame
== NULL
) || direction
== 1) {
133 if (futureFrames
.isEmpty()) {
134 //printf("Dropped frame - no future frame available\n");
137 QMutexLocker
listLocker(&listMutex
);
141 pastFrames
.prepend(displayFrame
);
143 displayFrame
= futureFrames
.takeFirst();
144 displayFrameNum
= displayFrame
->frameNum
;
150 if (direction
== -1) {
152 if (pastFrames
.isEmpty()) {
153 //printf("Dropped frame - no past frame available\n");
156 QMutexLocker
listLocker(&listMutex
);
160 futureFrames
.prepend(displayFrame
);
162 displayFrame
= pastFrames
.takeFirst();
163 displayFrameNum
= displayFrame
->frameNum
;
170 QMutexLocker
listLocker(&listMutex
);
172 Stats
&stat
= Stats::getInstance();
173 std::stringstream ss
;
175 ss
<< futureFrames
.size();
176 stat
.addStat("FrameQueue", "QueueFuture", ss
.str());
179 ss
<< pastFrames
.size();
180 stat
.addStat("FrameQueue", "QueuePast", ss
.str());
186 void FrameQueue::wake()
188 frameConsumed
.wakeOne();
191 VideoData
*FrameQueue::allocateFrame(void)
193 if (usedFrames
.empty()) {
194 return new VideoData
;
197 QMutexLocker
listlocker(&listMutex
);
198 return usedFrames
.takeLast();
202 void FrameQueue::releaseFrame(VideoData
*v
)
204 QMutexLocker
listlocker(&listMutex
);
205 usedFrames
.append(v
);
208 void FrameQueue::run()
211 printf("Starting FrameQueue\n");
213 //set to play forward to avoid deleting the frame lists first time round
214 int lastSpeed
= speed
;
223 while (m_doReading
) {
225 //------------------------------------------------------------------------------------------------
226 //trash the contents of the frame lists when we change speed
227 //this could be made MUCH cleverer - to keep past and future frames that we need when changing speed
228 if (speed
!= lastSpeed
) {
231 printf("Trashing frame lists - speed=%d, last=%d\n", speed
,
234 QMutexLocker
listLocker(&listMutex
);
236 while (futureFrames
.size()) {
237 VideoData
*frame
= futureFrames
.takeLast();
238 usedFrames
.prepend(frame
);
241 while (pastFrames
.size()) {
242 VideoData
*frame
= pastFrames
.takeLast();
243 usedFrames
.prepend(frame
);
249 //------------------------------------------------------------------------------------------------
250 //make sure the lists are long enough
254 printf("Adding future frames\n");
260 printf("Adding past frames\n");
261 if (reader
->randomAccess
== true)
266 //when pasued or stopped fill both lists for nice jog-wheel response
268 if (reader
->randomAccess
== true)
277 addtime
= timer
.restart();
279 //------------------------------------------------------------------------------------------------
280 //make sure the lists are not too long
281 //remove excess frames from the future list, which accumulate when playing backwards
283 QMutexLocker
listLocker(&listMutex
);
284 int numFutureFrames
= futureFrames
.size();
285 int numPastFrames
= pastFrames
.size();
288 //remove excess future frames
289 while (numFutureFrames
> LISTLEN
) {
291 VideoData
*oldFrame
= futureFrames
.takeLast();
293 printf("Retiring future frame %ld\n", oldFrame
->frameNum
);
294 usedFrames
.prepend(oldFrame
);
295 numFutureFrames
= futureFrames
.size();
299 //remove excess past frames
300 while (numPastFrames
> LISTLEN
) {
302 VideoData
*oldFrame
= pastFrames
.takeLast();
304 printf("Retiring past frame %ld\n", oldFrame
->frameNum
);
305 usedFrames
.prepend(oldFrame
);
306 numPastFrames
= pastFrames
.size();
311 prunetime
= timer
.restart();
315 int busytime
= addtime
+ prunetime
;
318 int totaltime
= busytime
+ sleeptime
;
321 int load
= (busytime
* 100) / totaltime
;
323 Stats
&stat
= Stats::getInstance();
324 std::stringstream ss
;
326 stat
.addStat("FrameQueue", "Load", ss
.str());
329 ss
<< addtime
<< " ms";
330 stat
.addStat("FrameQueue", "AddTime", ss
.str());
333 ss
<< prunetime
<< "ms";
334 stat
.addStat("FrameQueue", "RemTime", ss
.str());
338 //wait for display thread to display a new frame
341 frameConsumed
.wait(&frameMutex
);
344 sleeptime
= timer
.elapsed();