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
23 // ----------------------------------- Called from outside, one offs or info funcs
25 Player::Player(MessageQueue* messageQueue, bool tIsRecording, bool tIsRadio)
26 : vfeed(this), afeed(this)
28 commandMessageQueue = messageQueue;
29 audio = Audio::getInstance();
30 video = Video::getInstance();
31 logger = Log::getInstance();
32 vdr = VDR::getInstance();
36 currentFrameNumber = 0;
41 isRecording = tIsRecording;
49 startupBlockSize = 60000;
50 video->turnVideoOff();
55 startupBlockSize = 250000;
62 if (initted) shutdown();
67 if (initted) return 0;
69 pthread_mutex_init(&mutex, NULL);
71 mutex=CreateMutex(NULL,FALSE,NULL);
74 demuxer = new DemuxerVDR();
75 if (!demuxer) return 0;
77 if (!demuxer->init(this, audio, video))
79 logger->log("Player", Log::ERR, "Demuxer failed to init");
95 int Player::shutdown()
97 if (!initted) return 0;
111 void Player::setStartFrame(ULONG startFrame)
113 currentFrameNumber = startFrame;
116 void Player::setLengthBytes(ULLONG length)
118 lengthBytes = length;
119 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
122 void Player::setLengthFrames(ULONG length)
124 lengthFrames = length;
125 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
128 ULONG Player::getLengthFrames()
133 ULONG Player::getCurrentFrameNum()
135 if (startup) return 0;
136 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
139 // ----------------------------------- Externally called events
143 if (!initted) return;
144 if (state == S_PLAY) return;
146 bool doUnlock = false;
147 if (state == S_PAUSE_P) doUnlock = true;
149 if (doUnlock) unLock();
154 if (!initted) return;
155 if (state == S_STOP) return;
157 logger->log("Player", Log::DEBUG, "Stop called lock");
162 void Player::togglePause()
164 if (!initted) return;
167 if ((state == S_FFWD) || (state == S_FBWD))
169 switchState(S_PAUSE_I);
171 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
177 switchState(S_PAUSE_P);
183 void Player::toggleFastForward()
185 if (!initted) return;
187 if (state == S_FFWD) switchState(S_PLAY);
188 else switchState(S_FFWD);
192 void Player::toggleFastBackward()
194 if (!initted) return;
196 if (state == S_FBWD) switchState(S_PLAY);
197 else switchState(S_FBWD);
201 void Player::jumpToPercent(int percent)
204 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
205 ULONG newFrame = percent * lengthFrames / 100;
206 switchState(S_JUMP, newFrame);
207 // unLock(); - let thread unlock this
210 void Player::skipForward(int seconds)
213 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
214 ULONG newFrame = getCurrentFrameNum() + (seconds * video->getFPS());
215 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
216 else switchState(S_JUMP, newFrame);
217 // unLock(); - let thread unlock this
220 void Player::skipBackward(int seconds)
223 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
224 long newFrameNum = getCurrentFrameNum() - (seconds * video->getFPS());
225 if (newFrameNum < 0) newFrameNum = 0;
226 switchState(S_JUMP, newFrameNum);
227 // unLock(); - let thread unlock this
230 // ----------------------------------- Implementations called events
232 void Player::switchState(UCHAR toState, ULONG jumpFrame)
234 if (!initted) return;
236 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
238 switch(state) // current state selector
240 case S_PLAY: // from S_PLAY -----------------------------------
244 case S_PLAY: // to S_PLAY
248 case S_PAUSE_P: // to S_PAUSE_P
255 case S_PAUSE_I: // to S_PAUSE_I
260 case S_FFWD: // to S_FFWD
262 currentFrameNumber = getCurrentFrameNum();
263 audio->systemMuteOn();
272 case S_FBWD: // to S_FBWD
274 currentFrameNumber = getCurrentFrameNum();
275 audio->systemMuteOn();
284 case S_STOP: // to S_STOP
298 case S_JUMP: // to S_JUMP
300 restartAtFrame(jumpFrame);
305 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
309 case S_PLAY: // to S_PLAY
316 case S_PAUSE_P: // to S_PAUSE_P
320 case S_PAUSE_I: // to S_PAUSE_I
324 case S_FFWD: // to S_FFWD
326 currentFrameNumber = getCurrentFrameNum();
327 audio->systemMuteOn();
337 case S_FBWD: // to S_FBWD
339 currentFrameNumber = getCurrentFrameNum();
340 audio->systemMuteOn();
350 case S_STOP: // to S_STOP
361 audio->systemMuteOff();
365 case S_JUMP: // to S_JUMP
369 restartAtFrame(jumpFrame);
374 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
378 case S_PLAY: // to S_PLAY
381 restartAtFrame(currentFrameNumber);
384 case S_PAUSE_P: // to S_PAUSE_P
388 case S_PAUSE_I: // to S_PAUSE_I
392 case S_FFWD: // to S_FFWD
398 case S_FBWD: // to S_FBWD
404 case S_STOP: // to S_STOP
411 audio->systemMuteOff();
415 case S_JUMP: // to S_JUMP
418 restartAtFrame(jumpFrame);
423 case S_FFWD: // from S_FFWD -----------------------------------
427 case S_PLAY: // to S_PLAY
430 restartAtFrame(currentFrameNumber);
433 case S_PAUSE_P: // to S_PAUSE_P
438 case S_PAUSE_I: // to S_PAUSE_I
444 case S_FFWD: // to S_FFWD
448 case S_FBWD: // to S_FBWD
455 case S_STOP: // to S_STOP
466 case S_JUMP: // to S_JUMP
469 restartAtFrame(jumpFrame);
474 case S_FBWD: // from S_FBWD -----------------------------------
478 case S_PLAY: // to S_PLAY
481 restartAtFrame(currentFrameNumber);
484 case S_PAUSE_P: // to S_PAUSE_P
489 case S_PAUSE_I: // to S_PAUSE_I
495 case S_FFWD: // to S_FFWD
502 case S_FBWD: // to S_FBWD
506 case S_STOP: // to S_STOP
517 case S_JUMP: // to S_JUMP
520 restartAtFrame(jumpFrame);
525 case S_STOP: // from S_STOP -----------------------------------
529 case S_PLAY: // to S_PLAY
534 audio->systemMuteOff();
539 // FIXME use restartAtFrame here?
540 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
541 demuxer->setFrameNum(currentFrameNumber);
543 if (!isRadio) demuxer->seek();
551 logger->log("Player", Log::DEBUG, "Immediate play");
559 else // do prebuffering
561 logger->log("Player", Log::DEBUG, "Prebuffering...");
566 case S_PAUSE_P: // to S_PAUSE_P
570 case S_PAUSE_I: // to S_PAUSE_I
574 case S_FFWD: // to S_FFWD
578 case S_FBWD: // to S_FBWD
582 case S_STOP: // to S_STOP
586 case S_JUMP: // to S_JUMP
592 // case S_JUMP cannot be selected as a start state because it auto flips to play
596 // ----------------------------------- Internal functions
601 pthread_mutex_lock(&mutex);
602 logger->log("Player", Log::DEBUG, "LOCKED");
605 WaitForSingleObject(mutex, INFINITE);
609 void Player::unLock()
612 logger->log("Player", Log::DEBUG, "UNLOCKING");
613 pthread_mutex_unlock(&mutex);
619 void Player::restartAtFrame(ULONG newFrame)
628 if (!isRadio) demuxer->seek();
629 currentFrameNumber = newFrame;
630 demuxer->setFrameNum(newFrame);
638 audio->systemMuteOff();
642 void Player::doConnectionLost()
644 Message* m = new Message();
645 m->message = Message::CONNECTION_LOST;
647 commandMessageQueue->postMessage(m);
650 // ----------------------------------- Callback
652 void Player::call(void* caller)
654 if (caller == demuxer)
656 logger->log("Player", Log::DEBUG, "Callback from demuxer");
658 if (video->getTVsize() == Video::ASPECT4X3)
660 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
664 int dxCurrentAspect = demuxer->getAspectRatio();
665 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
667 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
668 video->setAspectRatio(Video::ASPECT4X3);
670 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
672 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
673 video->setAspectRatio(Video::ASPECT16X9);
677 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
685 videoStartup = false;
691 logger->log("Player", Log::DEBUG, "BANG BANG BANG BANG BANG BANG BANG BANG BANG BANG BANG");
694 threadSignalNoLock();
698 // ----------------------------------- Feed thread
700 void Player::threadMethod()
702 // this method used to be simple, the only thing it does
703 // is farm out to threadFeed Live/Play/Scan
704 // All the guff is to support scan hitting one end
708 if ((state == S_FFWD) || (state == S_FBWD))
711 // if this returns then scan hit one end
712 if (state == S_FFWD) // scan hit the end. stop
715 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
716 m->message = Message::STOP_PLAYBACK;
717 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
718 commandMessageQueue->postMessage(m);
719 logger->log("Player", Log::DEBUG, "Message posted...");
722 // if execution gets to here, threadFeedScan hit the start, go to play mode
726 if (!isRadio) demuxer->seek();
727 demuxer->setFrameNum(currentFrameNumber);
733 audio->systemMuteOff();
737 if (state == S_PLAY) threadFeedPlay();
745 void Player::threadFeedLive()
750 UINT preBufferTotal = 0;
762 askFor = startupBlockSize; // find audio streams sized block
764 askFor = blockSize; // normal
766 threadBuffer = vdr->getBlock(0, askFor, &thisRead);
768 if (!vdr->isConnected())
774 if (!threadBuffer) break;
778 int a_stream = demuxer->scan(threadBuffer, thisRead);
779 demuxer->setAudioStream(a_stream);
780 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
786 preBufferTotal += thisRead;
787 if (preBufferTotal > 500000)
789 logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
791 preBuffering = false;
800 // unLock(); // thread will be locked by play until here
801 // FIXME - see if this can segfault because it is starting threads out of the master mutex
807 while(writeLength < thisRead)
809 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
810 writeLength += thisWrite;
814 // demuxer is full and can't take anymore
816 threadWaitForSignal();
828 logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
830 if (videoStartup) // oh woe. there never was a stream, I was conned!
832 videoStartup = false;
834 MILLISLEEP(500); // I think this will solve a race
839 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
840 m->message = Message::STREAM_END;
841 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
842 commandMessageQueue->postMessage(m);
843 logger->log("Player", Log::DEBUG, "Message posted...");
846 void Player::threadFeedPlay()
849 UINT thisRead, writeLength, thisWrite, askFor;
850 time_t lastRescan = time(NULL);
852 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
853 if (!vdr->isConnected()) { doConnectionLost(); return; }
854 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
865 // If we havn't rescanned for a while..
866 if ((lastRescan + 60) < time(NULL))
868 lengthBytes = vdr->rescanRecording(&lengthFrames);
869 if (!vdr->isConnected()) { doConnectionLost(); return; }
870 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
871 lastRescan = time(NULL);
874 if (feedPosition >= lengthBytes) break; // finished playback
878 if (startupBlockSize > lengthBytes)
879 askFor = lengthBytes; // is a very small recording!
881 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
885 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
886 askFor = lengthBytes - feedPosition;
891 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
892 feedPosition += thisRead;
894 if (!vdr->isConnected())
900 if (!threadBuffer) break;
904 int a_stream = demuxer->scan(threadBuffer, thisRead);
905 demuxer->setAudioStream(a_stream);
906 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
912 while(writeLength < thisRead)
914 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
915 writeLength += thisWrite;
919 // demuxer is full and can't take anymore
921 threadWaitForSignal();
934 logger->log("Player", Log::DEBUG, "Recording playback ends");
936 if (videoStartup) // oh woe. there never was a stream, I was conned!
938 videoStartup = false;
940 MILLISLEEP(500); // I think this will solve a race
945 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
946 m->message = Message::STOP_PLAYBACK; // recording
947 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
948 commandMessageQueue->postMessage(m);
949 logger->log("Player", Log::DEBUG, "Message posted...");
952 void Player::threadFeedScan()
955 ULONG iframeNumber = 0;
956 ULONG iframeLength = 0;
961 if (state == S_FFWD) direction = 1; // and 0 for backward
965 if (!vdr->getNextIFrame(currentFrameNumber, direction, &filePos, &iframeNumber, &iframeLength)) break;
966 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
967 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
968 video->displayIFrame(threadBuffer, videoLength);
969 currentFrameNumber = iframeNumber;
975 // scan has hit one end
978 void Player::threadPostStopCleanup()
987 // ----------------------------------- Dev
992 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
994 // video->setAspectRatio(Video::ASPECT4X3);
999 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1000 video->setAspectRatio(Video::ASPECT16X9);