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) 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;
166 if (state == S_PAUSE) switchState(S_PLAY);
167 else switchState(S_PAUSE);
171 void Player::toggleFastForward()
173 if (!initted) return;
175 if (state == S_FFWD) switchState(S_PLAY);
176 else switchState(S_FFWD);
180 void Player::toggleFastBackward()
182 if (!initted) return;
184 if (state == S_FBWD) switchState(S_PLAY);
185 else switchState(S_FBWD);
189 void Player::jumpToPercent(int percent)
192 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
193 ULONG newFrame = percent * lengthFrames / 100;
194 switchState(S_JUMP, newFrame);
195 // unLock(); - let thread unlock this
198 void Player::skipForward(int seconds)
201 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
202 ULONG newFrame = getCurrentFrameNum() + (seconds * video->getFPS());
203 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
204 else switchState(S_JUMP, newFrame);
205 // unLock(); - let thread unlock this
208 void Player::skipBackward(int seconds)
211 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
212 long newFrameNum = getCurrentFrameNum() - (seconds * video->getFPS());
213 if (newFrameNum < 0) newFrameNum = 0;
214 switchState(S_JUMP, newFrameNum);
215 // unLock(); - let thread unlock this
218 // ----------------------------------- Implementations called events
220 void Player::switchState(UCHAR toState, ULONG jumpFrame)
222 if (!initted) return;
224 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
226 switch(state) // current state selector
228 case S_PLAY: // from S_PLAY -----------------------------------
232 case S_PLAY: // to S_PLAY
236 case S_PAUSE: // to S_PAUSE
243 case S_FFWD: // to S_FFWD
245 currentFrameNumber = getCurrentFrameNum();
246 audio->systemMuteOn();
255 case S_FBWD: // to S_FBWD
257 currentFrameNumber = getCurrentFrameNum();
258 audio->systemMuteOn();
267 case S_STOP: // to S_STOP
281 case S_JUMP: // to S_JUMP
283 restartAtFrame(jumpFrame);
288 case S_PAUSE: // from S_PAUSE -----------------------------------
292 case S_PLAY: // to S_PLAY
294 if (threadIsActive())
303 restartAtFrame(currentFrameNumber);
308 case S_PAUSE: // to S_PAUSE
312 case S_FFWD: // to S_FFWD
314 currentFrameNumber = getCurrentFrameNum();
315 audio->systemMuteOn();
318 if (threadIsActive()) threadStop();
325 case S_FBWD: // to S_FBWD
327 currentFrameNumber = getCurrentFrameNum();
328 audio->systemMuteOn();
331 if (threadIsActive()) threadStop();
338 case S_STOP: // to S_STOP
342 if (threadIsActive()) threadStop();
349 audio->systemMuteOff();
353 case S_JUMP: // to S_JUMP
357 restartAtFrame(jumpFrame);
362 case S_FFWD: // from S_FFWD -----------------------------------
366 case S_PLAY: // to S_PLAY
369 restartAtFrame(currentFrameNumber);
372 case S_PAUSE: // to S_PAUSE
378 case S_FFWD: // to S_FFWD
382 case S_FBWD: // to S_FBWD
389 case S_STOP: // to S_STOP
400 case S_JUMP: // to S_JUMP
403 restartAtFrame(jumpFrame);
408 case S_FBWD: // from S_FBWD -----------------------------------
412 case S_PLAY: // to S_PLAY
415 restartAtFrame(currentFrameNumber);
418 case S_PAUSE: // to S_PAUSE
424 case S_FFWD: // to S_FFWD
431 case S_FBWD: // to S_FBWD
435 case S_STOP: // to S_STOP
446 case S_JUMP: // to S_JUMP
449 restartAtFrame(jumpFrame);
454 case S_STOP: // from S_STOP -----------------------------------
458 case S_PLAY: // to S_PLAY
463 audio->systemMuteOff();
468 // FIXME use restartAtFrame here?
469 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
470 demuxer->setFrameNum(currentFrameNumber);
472 if (!isRadio) demuxer->seek();
480 logger->log("Player", Log::DEBUG, "Immediate play");
488 else // do prebuffering
490 logger->log("Player", Log::DEBUG, "Prebuffering...");
495 case S_PAUSE: // to S_PAUSE
499 case S_FFWD: // to S_FFWD
503 case S_FBWD: // to S_FBWD
507 case S_STOP: // to S_STOP
511 case S_JUMP: // to S_JUMP
517 // case S_JUMP cannot be selected as a start state because it auto flips to play
521 // ----------------------------------- Internal functions
526 pthread_mutex_lock(&mutex);
527 logger->log("Player", Log::DEBUG, "LOCKED");
530 WaitForSingleObject(mutex, INFINITE );
534 void Player::unLock()
537 logger->log("Player", Log::DEBUG, "UNLOCKING");
538 pthread_mutex_unlock(&mutex);
544 void Player::restartAtFrame(ULONG newFrame)
553 if (!isRadio) demuxer->seek();
554 currentFrameNumber = newFrame;
555 demuxer->setFrameNum(newFrame);
563 audio->systemMuteOff();
567 void Player::doConnectionLost()
569 Message* m = new Message();
570 m->message = Message::CONNECTION_LOST;
572 commandMessageQueue->postMessage(m);
575 // ----------------------------------- Callback
577 void Player::call(void* caller)
579 if (caller == demuxer)
581 logger->log("Player", Log::DEBUG, "Callback from demuxer");
583 if (video->getTVsize() == Video::ASPECT4X3)
585 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
589 int dxCurrentAspect = demuxer->getAspectRatio();
590 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
592 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
593 video->setAspectRatio(Video::ASPECT4X3);
595 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
597 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
598 video->setAspectRatio(Video::ASPECT16X9);
602 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
610 videoStartup = false;
616 logger->log("Player", Log::DEBUG, "BANG BANG BANG BANG BANG BANG BANG BANG BANG BANG BANG");
619 threadSignalNoLock();
623 // ----------------------------------- Feed thread
625 void Player::threadMethod()
627 // this method used to be simple, the only thing it does
628 // is farm out to threadFeed Live/Play/Scan
629 // All the guff is to support scan hitting one end
633 if ((state == S_FFWD) || (state == S_FBWD))
636 // if this returns then scan hit one end
637 if (state == S_FFWD) // scan hit the end. stop
640 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
641 m->message = Message::STOP_PLAYBACK;
642 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
643 commandMessageQueue->postMessage(m);
644 logger->log("Player", Log::DEBUG, "Message posted...");
647 // if execution gets to here, threadFeedScan hit the start, go to play mode
651 if (!isRadio) demuxer->seek();
652 demuxer->setFrameNum(currentFrameNumber);
658 audio->systemMuteOff();
662 if (state == S_PLAY) threadFeedPlay();
670 void Player::threadFeedLive()
675 UINT preBufferTotal = 0;
687 askFor = startupBlockSize; // find audio streams sized block
689 askFor = blockSize; // normal
691 threadBuffer = vdr->getBlock(0, askFor, &thisRead);
693 if (!vdr->isConnected())
699 if (!threadBuffer) break;
703 int a_stream = demuxer->scan(threadBuffer, thisRead);
704 demuxer->setAudioStream(a_stream);
705 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
711 preBufferTotal += thisRead;
712 if (preBufferTotal > 500000)
714 logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
716 preBuffering = false;
725 // unLock(); // thread will be locked by play until here
726 // FIXME - see if this can segfault because it is starting threads out of the master mutex
732 while(writeLength < thisRead)
734 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
735 writeLength += thisWrite;
739 // demuxer is full and can't take anymore
741 threadWaitForSignal();
753 logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
755 if (videoStartup) // oh woe. there never was a stream, I was conned!
757 videoStartup = false;
759 MILLISLEEP(500); // I think this will solve a race
764 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
765 m->message = Message::STREAM_END;
766 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
767 commandMessageQueue->postMessage(m);
768 logger->log("Player", Log::DEBUG, "Message posted...");
771 void Player::threadFeedPlay()
774 UINT thisRead, writeLength, thisWrite, askFor;
775 time_t lastRescan = time(NULL);
777 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
778 if (!vdr->isConnected()) { doConnectionLost(); return; }
779 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
790 // If we havn't rescanned for a while..
791 if ((lastRescan + 60) < time(NULL))
793 lengthBytes = vdr->rescanRecording(&lengthFrames);
794 if (!vdr->isConnected()) { doConnectionLost(); return; }
795 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
796 lastRescan = time(NULL);
799 if (feedPosition >= lengthBytes) break; // finished playback
803 if (startupBlockSize > lengthBytes)
804 askFor = lengthBytes; // is a very small recording!
806 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
810 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
811 askFor = lengthBytes - feedPosition;
816 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
817 feedPosition += thisRead;
819 if (!vdr->isConnected())
825 if (!threadBuffer) break;
829 int a_stream = demuxer->scan(threadBuffer, thisRead);
830 demuxer->setAudioStream(a_stream);
831 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
837 while(writeLength < thisRead)
839 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
840 writeLength += thisWrite;
844 // demuxer is full and can't take anymore
846 threadWaitForSignal();
859 logger->log("Player", Log::DEBUG, "Recording playback ends");
861 if (videoStartup) // oh woe. there never was a stream, I was conned!
863 videoStartup = false;
865 MILLISLEEP(500); // I think this will solve a race
870 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
871 m->message = Message::STOP_PLAYBACK; // recording
872 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
873 commandMessageQueue->postMessage(m);
874 logger->log("Player", Log::DEBUG, "Message posted...");
877 void Player::threadFeedScan()
880 ULONG iframeNumber = 0;
881 ULONG iframeLength = 0;
886 if (state == S_FFWD) direction = 1; // and 0 for backward
890 if (!vdr->getNextIFrame(currentFrameNumber, direction, &filePos, &iframeNumber, &iframeLength)) break;
891 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
892 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
893 video->displayIFrame(threadBuffer, videoLength);
894 currentFrameNumber = iframeNumber;
900 // scan has hit one end
903 void Player::threadPostStopCleanup()
912 // ----------------------------------- Dev
917 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
919 // video->setAspectRatio(Video::ASPECT4X3);
924 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
925 video->setAspectRatio(Video::ASPECT16X9);