[mmap] partial revert of 8cef8db4 to disable using mmap file reader
[videoplayer.git] / frameQueue.cpp
blobd962dfe64a975ed3c927566dd8b21ed5be8fdd65
1 /* ***** BEGIN LICENSE BLOCK *****
3 * The MIT License
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
23 * THE SOFTWARE.
25 * ***** END LICENSE BLOCK ***** */
27 #include <QtGui>
28 #include <sstream>
30 #include "frameQueue.h"
31 #include "videoTransport.h"
32 #include "readerInterface.h"
33 #include "stats.h"
35 #define DEBUG 0
36 #define LISTLEN 50
37 #define MAXREADS 10
39 FrameQueue::FrameQueue() :
40 QThread()
42 m_doReading = true;
43 displayFrame = NULL;
44 displayFrameNum = 0;
45 speed=0;
46 direction=0;
49 FrameQueue::~FrameQueue()
51 m_doReading = false;
52 wake();
53 wait();
55 if (displayFrame)
56 delete displayFrame;
57 displayFrame = NULL;
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;
74 int wantedFrame;
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)
79 return 0;
81 //if we can seek then get the number of the last frame in the queue
82 if (future == true) {
83 if (futureFrames.size())
84 lastFrame = futureFrames.last()->frameNum;
86 else {
87 if (pastFrames.size())
88 lastFrame = pastFrames.last()->frameNum;
91 //frame offset from the last one
92 int offset = speed;
93 if (direction == -1)
94 offset = offset * -1;
95 wantedFrame = lastFrame + offset;
97 return wantedFrame;
100 void FrameQueue::addFrames(bool future)
102 QLinkedList<VideoData *> *list = (future == true) ? &futureFrames : &pastFrames;
103 int stop= MAXREADS;
105 QMutexLocker listLocker(&listMutex);
106 int numFrames = list->size();
107 listLocker.unlock();
109 //add extra frames to the past frames list
110 while (stop-- && numFrames < LISTLEN) {
112 int wantedFrame = wantedFrameNum(future);
114 VideoData *v;
115 reader->pullFrame(wantedFrame, v);
117 listLocker.relock();
118 list->append(v);
119 numFrames = list->size();
120 listLocker.unlock();
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");
136 else {
137 QMutexLocker listLocker(&listMutex);
139 //playing forward
140 if (displayFrame)
141 pastFrames.prepend(displayFrame);
143 displayFrame = futureFrames.takeFirst();
144 displayFrameNum = displayFrame->frameNum;
145 listLocker.unlock();
149 //backwards
150 if (direction == -1) {
152 if (pastFrames.isEmpty()) {
153 //printf("Dropped frame - no past frame available\n");
155 else {
156 QMutexLocker listLocker(&listMutex);
158 //playing backward
159 if (displayFrame)
160 futureFrames.prepend(displayFrame);
162 displayFrame = pastFrames.takeFirst();
163 displayFrameNum = displayFrame->frameNum;
164 listLocker.unlock();
168 //stats
170 QMutexLocker listLocker(&listMutex);
172 Stats &stat = Stats::getInstance();
173 std::stringstream ss;
175 ss << futureFrames.size();
176 stat.addStat("FrameQueue", "QueueFuture", ss.str());
178 ss.str("");
179 ss << pastFrames.size();
180 stat.addStat("FrameQueue", "QueuePast", ss.str());
183 return displayFrame;
186 void FrameQueue::wake()
188 frameConsumed.wakeOne();
191 VideoData *FrameQueue::allocateFrame(void)
193 if (usedFrames.empty()) {
194 return new VideoData;
196 else {
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()
210 if (DEBUG)
211 printf("Starting FrameQueue\n");
213 //set to play forward to avoid deleting the frame lists first time round
214 int lastSpeed = speed;
216 //performance timer
217 QTime timer;
218 timer.restart();
219 int addtime=0;
220 int prunetime=0;
221 int sleeptime=0;
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) {
230 if (DEBUG)
231 printf("Trashing frame lists - speed=%d, last=%d\n", speed,
232 lastSpeed);
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);
247 lastSpeed = speed;
249 //------------------------------------------------------------------------------------------------
250 //make sure the lists are long enough
251 switch (direction) {
252 case 1:
253 if (DEBUG)
254 printf("Adding future frames\n");
255 addFrames(true);
256 break;
258 case -1:
259 if (DEBUG)
260 printf("Adding past frames\n");
261 if (reader->randomAccess == true)
262 addFrames(false);
263 break;
265 case 0:
266 //when pasued or stopped fill both lists for nice jog-wheel response
267 addFrames(true);
268 if (reader->randomAccess == true)
269 addFrames(false);
270 break;
272 default:
273 break;
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();
286 listLocker.unlock();
288 //remove excess future frames
289 while (numFutureFrames > LISTLEN) {
290 listLocker.relock();
291 VideoData *oldFrame = futureFrames.takeLast();
292 if (DEBUG)
293 printf("Retiring future frame %ld\n", oldFrame->frameNum);
294 usedFrames.prepend(oldFrame);
295 numFutureFrames = futureFrames.size();
296 listLocker.unlock();
299 //remove excess past frames
300 while (numPastFrames > LISTLEN) {
301 listLocker.relock();
302 VideoData *oldFrame = pastFrames.takeLast();
303 if (DEBUG)
304 printf("Retiring past frame %ld\n", oldFrame->frameNum);
305 usedFrames.prepend(oldFrame);
306 numPastFrames = pastFrames.size();
307 listLocker.unlock();
311 prunetime = timer.restart();
313 //stats
315 int busytime = addtime + prunetime;
316 timer.restart();
318 int totaltime = busytime + sleeptime;
320 if(totaltime) {
321 int load = (busytime * 100) / totaltime;
323 Stats &stat = Stats::getInstance();
324 std::stringstream ss;
325 ss << load << "%";
326 stat.addStat("FrameQueue", "Load", ss.str());
328 ss.str("");
329 ss << addtime << " ms";
330 stat.addStat("FrameQueue", "AddTime", ss.str());
332 ss.str("");
333 ss << prunetime << "ms";
334 stat.addStat("FrameQueue", "RemTime", ss.str());
338 //wait for display thread to display a new frame
339 frameMutex.lock();
340 if(m_doReading)
341 frameConsumed.wait(&frameMutex);
342 frameMutex.unlock();
344 sleeptime = timer.elapsed();
345 timer.restart();