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;
140 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
144 return currentFrameNumber;
146 return 0; // shouldn't happen
150 // ----------------------------------- Externally called events
154 if (!initted) return;
155 if (state == S_PLAY) return;
157 bool doUnlock = false;
158 if (state == S_PAUSE_P) doUnlock = true;
160 if (doUnlock) unLock();
165 if (!initted) return;
166 if (state == S_STOP) return;
168 logger->log("Player", Log::DEBUG, "Stop called lock");
173 void Player::togglePause()
175 if (!initted) return;
178 if ((state == S_FFWD) || (state == S_FBWD))
180 switchState(S_PAUSE_I);
182 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
188 switchState(S_PAUSE_P);
194 void Player::toggleFastForward()
196 if (!initted) return;
198 if (state == S_FFWD) switchState(S_PLAY);
199 else switchState(S_FFWD);
203 void Player::toggleFastBackward()
205 if (!initted) return;
207 if (state == S_FBWD) switchState(S_PLAY);
208 else switchState(S_FBWD);
212 void Player::jumpToPercent(int percent)
215 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
216 ULONG newFrame = percent * lengthFrames / 100;
217 switchState(S_JUMP, newFrame);
218 // unLock(); - let thread unlock this
221 void Player::skipForward(int seconds)
224 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
225 ULONG newFrame = getCurrentFrameNum() + (seconds * video->getFPS());
226 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
227 else switchState(S_JUMP, newFrame);
228 // unLock(); - let thread unlock this
231 void Player::skipBackward(int seconds)
234 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
235 long newFrameNum = getCurrentFrameNum() - (seconds * video->getFPS());
236 if (newFrameNum < 0) newFrameNum = 0;
237 switchState(S_JUMP, newFrameNum);
238 // unLock(); - let thread unlock this
241 // ----------------------------------- Implementations called events
243 void Player::switchState(UCHAR toState, ULONG jumpFrame)
245 if (!initted) return;
247 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
249 switch(state) // current state selector
251 case S_PLAY: // from S_PLAY -----------------------------------
255 case S_PLAY: // to S_PLAY
259 case S_PAUSE_P: // to S_PAUSE_P
266 case S_PAUSE_I: // to S_PAUSE_I
271 case S_FFWD: // to S_FFWD
273 currentFrameNumber = getCurrentFrameNum();
274 audio->systemMuteOn();
283 case S_FBWD: // to S_FBWD
285 currentFrameNumber = getCurrentFrameNum();
286 audio->systemMuteOn();
295 case S_STOP: // to S_STOP
309 case S_JUMP: // to S_JUMP
311 restartAtFrame(jumpFrame);
316 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
320 case S_PLAY: // to S_PLAY
327 case S_PAUSE_P: // to S_PAUSE_P
331 case S_PAUSE_I: // to S_PAUSE_I
335 case S_FFWD: // to S_FFWD
337 currentFrameNumber = getCurrentFrameNum();
338 audio->systemMuteOn();
348 case S_FBWD: // to S_FBWD
350 currentFrameNumber = getCurrentFrameNum();
351 audio->systemMuteOn();
361 case S_STOP: // to S_STOP
372 audio->systemMuteOff();
376 case S_JUMP: // to S_JUMP
380 restartAtFrame(jumpFrame);
385 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
389 case S_PLAY: // to S_PLAY
392 restartAtFrame(currentFrameNumber);
395 case S_PAUSE_P: // to S_PAUSE_P
399 case S_PAUSE_I: // to S_PAUSE_I
403 case S_FFWD: // to S_FFWD
409 case S_FBWD: // to S_FBWD
415 case S_STOP: // to S_STOP
422 audio->systemMuteOff();
426 case S_JUMP: // to S_JUMP
429 restartAtFrame(jumpFrame);
434 case S_FFWD: // from S_FFWD -----------------------------------
438 case S_PLAY: // to S_PLAY
441 restartAtFrame(currentFrameNumber);
444 case S_PAUSE_P: // to S_PAUSE_P
449 case S_PAUSE_I: // to S_PAUSE_I
455 case S_FFWD: // to S_FFWD
459 case S_FBWD: // to S_FBWD
466 case S_STOP: // to S_STOP
477 case S_JUMP: // to S_JUMP
480 restartAtFrame(jumpFrame);
485 case S_FBWD: // from S_FBWD -----------------------------------
489 case S_PLAY: // to S_PLAY
492 restartAtFrame(currentFrameNumber);
495 case S_PAUSE_P: // to S_PAUSE_P
500 case S_PAUSE_I: // to S_PAUSE_I
506 case S_FFWD: // to S_FFWD
513 case S_FBWD: // to S_FBWD
517 case S_STOP: // to S_STOP
528 case S_JUMP: // to S_JUMP
531 restartAtFrame(jumpFrame);
536 case S_STOP: // from S_STOP -----------------------------------
540 case S_PLAY: // to S_PLAY
545 audio->systemMuteOff();
550 // FIXME use restartAtFrame here?
551 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
552 demuxer->setFrameNum(currentFrameNumber);
554 if (!isRadio) demuxer->seek();
562 logger->log("Player", Log::DEBUG, "Immediate play");
570 else // do prebuffering
572 logger->log("Player", Log::DEBUG, "Prebuffering...");
577 case S_PAUSE_P: // to S_PAUSE_P
581 case S_PAUSE_I: // to S_PAUSE_I
585 case S_FFWD: // to S_FFWD
589 case S_FBWD: // to S_FBWD
593 case S_STOP: // to S_STOP
597 case S_JUMP: // to S_JUMP
603 // case S_JUMP cannot be selected as a start state because it auto flips to play
607 // ----------------------------------- Internal functions
612 pthread_mutex_lock(&mutex);
613 logger->log("Player", Log::DEBUG, "LOCKED");
616 WaitForSingleObject(mutex, INFINITE);
620 void Player::unLock()
623 logger->log("Player", Log::DEBUG, "UNLOCKING");
624 pthread_mutex_unlock(&mutex);
630 void Player::restartAtFrame(ULONG newFrame)
639 if (!isRadio) demuxer->seek();
640 currentFrameNumber = newFrame;
641 demuxer->setFrameNum(newFrame);
649 audio->systemMuteOff();
653 void Player::doConnectionLost()
655 Message* m = new Message();
656 m->message = Message::CONNECTION_LOST;
658 commandMessageQueue->postMessage(m);
661 // ----------------------------------- Callback
663 void Player::call(void* caller)
665 if (caller == demuxer)
667 logger->log("Player", Log::DEBUG, "Callback from demuxer");
669 if (video->getTVsize() == Video::ASPECT4X3)
671 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
675 int dxCurrentAspect = demuxer->getAspectRatio();
676 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
678 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
679 video->setAspectRatio(Video::ASPECT4X3);
681 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
683 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
684 video->setAspectRatio(Video::ASPECT16X9);
688 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
696 videoStartup = false;
702 logger->log("Player", Log::DEBUG, "BANG BANG BANG BANG BANG BANG BANG BANG BANG BANG BANG");
705 threadSignalNoLock();
709 // ----------------------------------- Feed thread
711 void Player::threadMethod()
713 // this method used to be simple, the only thing it does
714 // is farm out to threadFeed Live/Play/Scan
715 // All the guff is to support scan hitting one end
719 if ((state == S_FFWD) || (state == S_FBWD))
722 // if this returns then scan hit one end
723 if (state == S_FFWD) // scan hit the end. stop
726 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
727 m->message = Message::STOP_PLAYBACK;
728 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
729 commandMessageQueue->postMessage(m);
730 logger->log("Player", Log::DEBUG, "Message posted...");
733 // if execution gets to here, threadFeedScan hit the start, go to play mode
737 if (!isRadio) demuxer->seek();
738 demuxer->setFrameNum(currentFrameNumber);
744 audio->systemMuteOff();
748 if (state == S_PLAY) threadFeedPlay();
756 void Player::threadFeedLive()
761 UINT preBufferTotal = 0;
773 askFor = startupBlockSize; // find audio streams sized block
775 askFor = blockSize; // normal
777 threadBuffer = vdr->getBlock(0, askFor, &thisRead);
779 if (!vdr->isConnected())
785 if (!threadBuffer) break;
789 int a_stream = demuxer->scan(threadBuffer, thisRead);
790 demuxer->setAudioStream(a_stream);
791 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
797 preBufferTotal += thisRead;
798 if (preBufferTotal > 500000)
800 logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
802 preBuffering = false;
811 // unLock(); // thread will be locked by play until here
812 // FIXME - see if this can segfault because it is starting threads out of the master mutex
818 while(writeLength < thisRead)
820 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
821 writeLength += thisWrite;
825 // demuxer is full and can't take anymore
827 threadWaitForSignal();
839 logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
841 if (videoStartup) // oh woe. there never was a stream, I was conned!
843 videoStartup = false;
845 MILLISLEEP(500); // I think this will solve a race
850 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
851 m->message = Message::STREAM_END;
852 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
853 commandMessageQueue->postMessage(m);
854 logger->log("Player", Log::DEBUG, "Message posted...");
857 void Player::threadFeedPlay()
860 UINT thisRead, writeLength, thisWrite, askFor;
861 time_t lastRescan = time(NULL);
863 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
864 if (!vdr->isConnected()) { doConnectionLost(); return; }
865 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
876 // If we havn't rescanned for a while..
877 if ((lastRescan + 60) < time(NULL))
879 lengthBytes = vdr->rescanRecording(&lengthFrames);
880 if (!vdr->isConnected()) { doConnectionLost(); return; }
881 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
882 lastRescan = time(NULL);
885 if (feedPosition >= lengthBytes) break; // finished playback
889 if (startupBlockSize > lengthBytes)
890 askFor = lengthBytes; // is a very small recording!
892 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
896 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
897 askFor = lengthBytes - feedPosition;
902 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
903 feedPosition += thisRead;
905 if (!vdr->isConnected())
911 if (!threadBuffer) break;
915 int a_stream = demuxer->scan(threadBuffer, thisRead);
916 demuxer->setAudioStream(a_stream);
917 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
923 while(writeLength < thisRead)
925 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
926 writeLength += thisWrite;
930 // demuxer is full and can't take anymore
932 threadWaitForSignal();
945 logger->log("Player", Log::DEBUG, "Recording playback ends");
947 if (videoStartup) // oh woe. there never was a stream, I was conned!
949 videoStartup = false;
951 MILLISLEEP(500); // I think this will solve a race
956 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
957 m->message = Message::STOP_PLAYBACK; // recording
958 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
959 commandMessageQueue->postMessage(m);
960 logger->log("Player", Log::DEBUG, "Message posted...");
963 void Player::threadFeedScan()
966 ULONG iframeNumber = 0;
967 ULONG iframeLength = 0;
972 if (state == S_FFWD) direction = 1; // and 0 for backward
976 if (!vdr->getNextIFrame(currentFrameNumber, direction, &filePos, &iframeNumber, &iframeLength)) break;
977 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
978 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
979 video->displayIFrame(threadBuffer, videoLength);
980 currentFrameNumber = iframeNumber;
986 // scan has hit one end
989 void Player::threadPostStopCleanup()
998 // ----------------------------------- Dev
1001 void Player::test1()
1003 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1005 // video->setAspectRatio(Video::ASPECT4X3);
1008 void Player::test2()
1010 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1011 video->setAspectRatio(Video::ASPECT16X9);