2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "playervideo.h"
23 PlayerVideo::PlayerVideo(MessageQueue* messageQueue, UCHAR tIsRecording)
24 : vfeed(this), afeed(this)
26 commandMessageQueue = messageQueue;
33 feedMode = MODE_NORMAL;
34 isRecording = tIsRecording;
39 PlayerVideo::~PlayerVideo()
41 if (initted) shutdown();
44 int PlayerVideo::init()
46 if (initted) return 0;
48 video = Video::getInstance();
50 if (!demuxer.init(this))
52 Log::getInstance()->log("Player", Log::ERR, "Demuxer failed to init");
57 vfeed.init(video->getFD());
58 afeed.init(audio->getFD());
69 int PlayerVideo::shutdown()
71 if (!initted) return 0;
74 Log::getInstance()->log("Player", Log::DEBUG, "Player shutdown...");
90 Log::getInstance()->log("Player", Log::DEBUG, "Player shutdown done");
95 int PlayerVideo::play()
97 if (!initted) return 0;
99 // If we are just paused, unpause!
106 // If we are fast forwarding, set to normal
113 // If we are fast backwarding, set to normal
116 toggleFastBackward();
120 // If we are already playing, bail // FIXME - resync?
123 Log::getInstance()->log("Player", Log::DEBUG, "DOING RESYNC");
154 // Standard play start
161 // ------------------------ This one works, but doesn't allow any pre-buffering.
171 usleep(500000); // SYNC
176 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
183 // struct timespec delay;
185 // delay.tv_nsec = 500000000;
186 // nanosleep(&delay, NULL);
195 // ------------------------------------------------------------------------------------------------
201 void PlayerVideo::stop()
203 if (!initted) return;
204 if (!playing) return;
211 video->unFastForward();
212 audio->systemMuteOff();
213 feedMode = MODE_NORMAL;
219 Log* templog = Log::getInstance();
220 templog->log("PlayerVideo", Log::DEBUG, "Temp 1");
222 templog->log("PlayerVideo", Log::DEBUG, "Temp 2");
224 templog->log("PlayerVideo", Log::DEBUG, "Temp 3");
226 templog->log("PlayerVideo", Log::DEBUG, "Temp 4");
228 templog->log("PlayerVideo", Log::DEBUG, "Temp 5");
230 templog->log("PlayerVideo", Log::DEBUG, "Temp 6");
232 templog->log("PlayerVideo", Log::DEBUG, "Temp 7");
234 templog->log("PlayerVideo", Log::DEBUG, "Temp 8");
236 templog->log("PlayerVideo", Log::DEBUG, "Temp 9");
238 templog->log("PlayerVideo", Log::DEBUG, "Temp 10");
243 void PlayerVideo::togglePause()
245 if (!initted) return;
246 if (!playing) return;
248 if (ffwd) toggleFastForward();
249 if (fbwd) toggleFastBackward();
266 void PlayerVideo::test()
275 static int flipflop = 0;
278 if (flipflop) a = video->setAspectRatio(Video::ASPECT16X9);
279 else a = video->setAspectRatio(Video::ASPECT4X3);
281 flipflop = !flipflop;
283 printf("A = %i\n", a);
286 Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 1 4X3");
287 video->setAspectRatio(Video::ASPECT4X3);
290 void PlayerVideo::test2()
292 Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 2 16X9");
293 video->setAspectRatio(Video::ASPECT16X9);
296 void PlayerVideo::test3()
298 Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 3 NORMAL");
299 video->setMode(Video::NORMAL);
302 void PlayerVideo::test4()
304 Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 4 LETTERBOX");
305 video->setMode(Video::LETTERBOX);
308 void PlayerVideo::test5()
310 Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 5 REINIT");
323 void PlayerVideo::setPosition(ULLONG position)
325 feedPosition = position;
328 void PlayerVideo::setLength(ULLONG length)
330 lastRescan = time(NULL);
331 streamLength = length;
332 Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Player has received length of %llu", streamLength);
335 void PlayerVideo::skipForward(int seconds)
337 // skip forward 1 minute
338 Log::getInstance()->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
340 if (paused) togglePause();
342 ULLONG moveBy = seconds * 500000;
350 audio->doMuting(); // ???
352 feedPosition += moveBy;
354 // printf("Audio test %i\n", audio->test());
365 usleep(500000); // SYNC
372 void PlayerVideo::skipBackward(int seconds)
374 // skip forward 1 minute
375 Log::getInstance()->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
377 if (paused) togglePause();
379 ULLONG moveBy = seconds * 500000;
388 audio->doMuting(); // ???
390 if (feedPosition > moveBy) feedPosition -= moveBy;
400 usleep(500000); // SYNC
407 void PlayerVideo::toggleFastForward()
409 if (!initted) return;
410 if (!playing) return;
412 if (paused) togglePause();
413 if (fbwd) toggleFastBackward();
418 // video->unFastForward();
439 audio->systemMuteOff();
442 usleep(500000); // SYNC
448 demuxer.flushAudio();
456 audio->systemMuteOff();
463 audio->systemMuteOn();
464 video->fastForward();
468 void PlayerVideo::toggleFastBackward()
470 if (!initted) return;
471 if (!playing) return;
473 if (paused) togglePause();
474 if (ffwd) toggleFastForward();
480 audio->systemMuteOff();
483 feedMode = MODE_NORMAL;
490 audio->systemMuteOn();
493 feedMode = MODE_BACKWARDS;
501 void PlayerVideo::jumpToPercent(int percent)
512 feedPosition = streamLength * percent / 100;
522 usleep(500000); // SYNC
529 void PlayerVideo::call(void* caller)
531 if (caller == &demuxer)
533 Log* temp = Log::getInstance();
534 temp->log("Player", Log::DEBUG, "Callback from demuxer");
536 int dxCurrentAspect = demuxer.getAspectRatio();
537 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
539 temp->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
540 video->setAspectRatio(Video::ASPECT4X3);
542 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
544 temp->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
545 video->setAspectRatio(Video::ASPECT16X9);
549 temp->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
555 threadSignalNoLock();
561 void PlayerVideo::threadMethod()
567 VDR* vdr = VDR::getInstance();
578 // If we havn't rescanned for a while..
579 if (isRecording && ((lastRescan + 60) < time(NULL)))
581 streamLength = vdr->rescanRecording();
582 Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
583 lastRescan = time(NULL);
586 if (streamLength) // is playing a recording
588 if (feedPosition >= streamLength) break; // finished playback
592 if (startupBlockSize > streamLength)
593 askFor = streamLength; // is a very small recording!
595 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
599 if ((feedPosition + blockSize) > streamLength) // last block of recording
600 askFor = streamLength - feedPosition;
605 else // is playing live
608 askFor = startupBlockSize; // find audio streams sized block
610 askFor = blockSize; // normal
613 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
614 if (!threadBuffer) break;
618 int a_stream = demuxer.scan(threadBuffer, thisRead);
619 demuxer.setAudioStream(a_stream);
620 Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
624 if (feedMode == MODE_NORMAL)
626 feedPosition += thisRead;
628 else if (feedMode == MODE_BACKWARDS)
630 if (feedPosition >= blockSize)
632 feedPosition -= blockSize;
637 // got to the start of the recording.. revert to play mode? how?
638 feedPosition += thisRead;
644 while(writeLength < thisRead)
646 thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
647 writeLength += thisWrite;
651 // Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
652 // demuxer is full and cant take anymore
653 threadWaitForSignal();
654 // Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
666 Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
667 Message* m = new Message();
668 if (streamLength) m->message = Message::STOP_PLAYBACK; // recording
669 else m->message = Message::STREAM_END; // live
670 Log::getInstance()->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
671 commandMessageQueue->postMessage(m);
672 Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
675 void PlayerVideo::threadPostStopCleanup()
677 Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 1");
680 Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 2");