2 Copyright 2004-2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "demuxervdr.h"
27 #include "demuxerts.h"
29 #include "messagequeue.h"
32 #include "dvbsubtitles.h"
33 #include "osdreceiver.h"
35 #define USER_RESPONSE_TIME 500 // Milliseconds
37 // ----------------------------------- Called from outside, one offs or info funcs
39 Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)
40 : vfeed(this), afeed(this)
42 messageQueue = tmessageQueue;
43 messageReceiver = tmessageReceiver;
44 osdReceiver = tosdReceiver;
45 audio = Audio::getInstance();
46 video = Video::getInstance();
47 logger = Log::getInstance();
48 vdr = VDR::getInstance();
52 currentFrameNumber = 0;
56 subtitlesShowing = false;
62 startupBlockSize = 250000;
68 if (initted) shutdown();
73 if (initted) return 0;
75 pthread_mutex_init(&mutex, NULL);
77 mutex=CreateMutex(NULL,FALSE,NULL);
80 demuxer = new DemuxerVDR();
81 if (!demuxer) return 0;
82 subtitles = new DVBSubtitles(osdReceiver);
83 if (!subtitles) return 0;
85 if (!demuxer->init(this, audio, video, 2097152, 524288, subtitles))
87 logger->log("Player", Log::ERR, "Demuxer failed to init");
103 int Player::shutdown()
105 if (!initted) return 0;
121 void Player::setStartFrame(ULONG startFrame)
123 currentFrameNumber = startFrame;
126 void Player::setLengthBytes(ULLONG length)
128 lengthBytes = length;
129 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
132 void Player::setLengthFrames(ULONG length)
134 lengthFrames = length;
135 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
138 ULONG Player::getLengthFrames()
143 ULONG Player::getCurrentFrameNum()
145 if (startup) return 0;
150 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
154 return currentFrameNumber;
156 return 0; // shouldn't happen
160 bool* Player::getDemuxerMpegAudioChannels()
162 return demuxer->getmpAudioChannels();
165 bool* Player::getDemuxerAc3AudioChannels()
167 return demuxer->getac3AudioChannels();
170 int Player::getCurrentAudioChannel()
172 return demuxer->getselAudioChannel();
175 void Player::setAudioChannel(int newChannel, int type)
177 demuxer->setAudioChannel(newChannel);
180 bool Player::toggleSubtitles()
182 if (!subtitlesShowing)
184 subtitlesShowing = true;
189 subtitlesShowing = false;
192 return subtitlesShowing;
195 // ----------------------------------- Externally called events
199 if (!initted) return;
200 if (state == S_PLAY) return;
203 bool doUnlock = false;
204 if (state == S_PAUSE_P) doUnlock = true;
206 if (doUnlock) unLock();
211 if (!initted) return;
212 if (state == S_STOP) return;
214 logger->log("Player", Log::DEBUG, "Stop called lock");
221 if (!initted) return;
224 if ((state == S_FFWD) || (state == S_FBWD))
226 switchState(S_PAUSE_I);
228 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
234 switchState(S_PAUSE_P);
240 void Player::fastForward()
242 if (!initted) return;
250 case 4: ifactor = 8; break;
251 case 8: ifactor = 16; break;
252 case 16: ifactor = 32; break;
253 case 32: ifactor = 4; break;
264 void Player::fastBackward()
266 if (!initted) return;
274 case 4: ifactor = 8; break;
275 case 8: ifactor = 16; break;
276 case 16: ifactor = 32; break;
277 case 32: ifactor = 4; break;
288 void Player::jumpToPercent(double percent)
291 logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
292 ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
293 switchState(S_JUMP, newFrame);
294 // unLock(); - let thread unlock this
297 void Player::jumpToMark(int mark)
300 logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
301 switchState(S_JUMP, mark);
302 // unLock(); - let thread unlock this
305 void Player::jumpToFrameP(int newFrame)
308 logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
309 switchState(S_JUMP_PI, newFrame);
313 void Player::skipForward(int seconds)
316 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
317 ULONG newFrame = getCurrentFrameNum();
318 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
319 newFrame += seconds * video->getFPS();
320 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
321 else switchState(S_JUMP, newFrame);
322 // unLock(); - let thread unlock this
325 void Player::skipBackward(int seconds)
328 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
329 long newFrame = getCurrentFrameNum();
330 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
331 newFrame -= seconds * video->getFPS();
332 if (newFrame < 0) newFrame = 0;
333 switchState(S_JUMP, newFrame);
334 // unLock(); - let thread unlock this
337 // ----------------------------------- Implementations called events
339 void Player::switchState(UCHAR toState, ULONG jumpFrame)
341 if (!initted) return;
343 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
345 switch(state) // current state selector
347 case S_PLAY: // from S_PLAY -----------------------------------
351 case S_PLAY: // to S_PLAY
355 case S_PAUSE_P: // to S_PAUSE_P
362 case S_PAUSE_I: // to S_PAUSE_I
367 case S_FFWD: // to S_FFWD
369 currentFrameNumber = getCurrentFrameNum();
370 audio->systemMuteOn();
380 case S_FBWD: // to S_FBWD
382 currentFrameNumber = getCurrentFrameNum();
383 audio->systemMuteOn();
393 case S_STOP: // to S_STOP
408 case S_JUMP: // to S_JUMP
410 restartAtFrame(jumpFrame);
413 case S_JUMP_PI: // to S_JUMP_PI
415 audio->systemMuteOn();
424 restartAtFramePI(jumpFrame);
429 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
433 case S_PLAY: // to S_PLAY
440 case S_PAUSE_P: // to S_PAUSE_P
444 case S_PAUSE_I: // to S_PAUSE_I
448 case S_FFWD: // to S_FFWD
450 currentFrameNumber = getCurrentFrameNum();
451 audio->systemMuteOn();
462 case S_FBWD: // to S_FBWD
464 currentFrameNumber = getCurrentFrameNum();
465 audio->systemMuteOn();
476 case S_STOP: // to S_STOP
488 audio->systemMuteOff();
492 case S_JUMP: // to S_JUMP
495 audio->systemMuteOn();
497 restartAtFrame(jumpFrame);
500 case S_JUMP_PI: // to S_JUMP_PI
502 audio->systemMuteOn();
512 restartAtFramePI(jumpFrame);
517 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
521 case S_PLAY: // to S_PLAY
524 restartAtFrame(currentFrameNumber);
527 case S_PAUSE_P: // to S_PAUSE_P
531 case S_PAUSE_I: // to S_PAUSE_I
535 case S_FFWD: // to S_FFWD
541 case S_FBWD: // to S_FBWD
547 case S_STOP: // to S_STOP
554 audio->systemMuteOff();
558 case S_JUMP: // to S_JUMP
561 restartAtFrame(jumpFrame);
564 case S_JUMP_PI: // to S_JUMP_PI
566 restartAtFramePI(jumpFrame);
571 case S_FFWD: // from S_FFWD -----------------------------------
575 case S_PLAY: // to S_PLAY
578 ULONG stepback = USER_RESPONSE_TIME * video->getFPS() * ifactor / 1000;
579 if (stepback < currentFrameNumber)
580 currentFrameNumber -= stepback;
582 currentFrameNumber = 0;
583 restartAtFrame(currentFrameNumber);
586 case S_PAUSE_P: // to S_PAUSE_P
591 case S_PAUSE_I: // to S_PAUSE_I
597 case S_FFWD: // to S_FFWD
601 case S_FBWD: // to S_FBWD
608 case S_STOP: // to S_STOP
619 case S_JUMP: // to S_JUMP
622 restartAtFrame(jumpFrame);
625 case S_JUMP_PI: // to S_JUMP_PI
629 restartAtFramePI(jumpFrame);
634 case S_FBWD: // from S_FBWD -----------------------------------
638 case S_PLAY: // to S_PLAY
641 restartAtFrame(currentFrameNumber);
644 case S_PAUSE_P: // to S_PAUSE_P
649 case S_PAUSE_I: // to S_PAUSE_I
655 case S_FFWD: // to S_FFWD
662 case S_FBWD: // to S_FBWD
666 case S_STOP: // to S_STOP
677 case S_JUMP: // to S_JUMP
680 restartAtFrame(jumpFrame);
683 case S_JUMP_PI: // to S_JUMP_PI
687 restartAtFramePI(jumpFrame);
692 case S_STOP: // from S_STOP -----------------------------------
696 case S_PLAY: // to S_PLAY
701 audio->setStreamType(Audio::MPEG2_PES);
702 audio->systemMuteOff();
705 // FIXME use restartAtFrame here?
706 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
707 demuxer->setFrameNum(currentFrameNumber);
712 logger->log("Player", Log::DEBUG, "Immediate play");
722 case S_PAUSE_P: // to S_PAUSE_P
726 case S_PAUSE_I: // to S_PAUSE_I
730 case S_FFWD: // to S_FFWD
734 case S_FBWD: // to S_FBWD
738 case S_STOP: // to S_STOP
742 case S_JUMP: // to S_JUMP
746 case S_JUMP_PI: // to S_JUMP_PI
752 // case S_JUMP cannot be a start state because it auto flips to play
753 // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
757 // ----------------------------------- Internal functions
762 pthread_mutex_lock(&mutex);
763 logger->log("Player", Log::DEBUG, "LOCKED");
766 WaitForSingleObject(mutex, INFINITE);
770 void Player::unLock()
773 logger->log("Player", Log::DEBUG, "UNLOCKING");
774 pthread_mutex_unlock(&mutex);
780 void Player::restartAtFrame(ULONG newFrame)
789 audio->setStreamType(Audio::MPEG2_PES);
792 currentFrameNumber = newFrame;
793 demuxer->setFrameNum(newFrame);
802 audio->systemMuteOff();
807 void Player::restartAtFramePI(ULONG newFrame)
810 ULONG nextiframeNumber;
818 // newFrame could be anywhere, go forwards to next I-Frame
819 if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
821 // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
822 vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
824 buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
825 if (!vdr->isConnected())
827 if (buffer) free(buffer);
832 videoLength = demuxer->stripAudio(buffer, amountReceived);
833 video->displayIFrame(buffer, videoLength);
834 video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
836 currentFrameNumber = iframeNumber;
840 void Player::doConnectionLost()
842 logger->log("Player", Log::DEBUG, "Connection lost, sending message");
843 Message* m = new Message();
844 m->to = messageReceiver;
846 m->message = Message::PLAYER_EVENT;
847 m->parameter = Player::CONNECTION_LOST;
848 messageQueue->postMessage(m);
851 // ----------------------------------- Callback
853 void Player::call(void* caller)
855 if (caller == demuxer)
857 logger->log("Player", Log::DEBUG, "Callback from demuxer");
859 if (video->getTVsize() == Video::ASPECT4X3)
861 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
865 int dxCurrentAspect = demuxer->getAspectRatio();
866 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
868 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
869 video->setAspectRatio(Video::ASPECT4X3);
871 Message* m = new Message();
873 m->to = messageReceiver;
874 m->message = Message::PLAYER_EVENT;
875 m->parameter = Player::ASPECT43;
876 messageQueue->postMessageFromOuterSpace(m);
878 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
880 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
881 video->setAspectRatio(Video::ASPECT16X9);
883 Message* m = new Message();
885 m->to = messageReceiver;
886 m->message = Message::PLAYER_EVENT;
887 m->parameter = Player::ASPECT169;
888 messageQueue->postMessageFromOuterSpace(m);
892 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
900 videoStartup = false;
908 threadSignalNoLock();
912 // ----------------------------------- Feed thread
914 void Player::threadMethod()
916 // this method used to be simple, the only thing it does
917 // is farm out to threadFeed Live/Play/Scan
918 // All the guff is to support scan hitting one end
920 if ((state == S_FFWD) || (state == S_FBWD))
923 // if this returns then scan hit one end
924 if (state == S_FFWD) // scan hit the end. stop
927 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
928 m->to = messageReceiver;
930 m->message = Message::PLAYER_EVENT;
931 m->parameter = STOP_PLAYBACK;
932 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
933 messageQueue->postMessage(m);
934 logger->log("Player", Log::DEBUG, "Message posted...");
937 // if execution gets to here, threadFeedScan hit the start, go to play mode
940 audio->setStreamType(Audio::MPEG2_PES);
943 demuxer->setFrameNum(currentFrameNumber);
950 audio->systemMuteOff();
954 if (state == S_PLAY) threadFeedPlay();
957 void Player::threadFeedPlay()
960 UINT thisRead, writeLength, thisWrite, askFor;
961 time_t lastRescan = time(NULL);
963 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
964 if (!vdr->isConnected()) { doConnectionLost(); return; }
965 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
976 // If we havn't rescanned for a while..
977 if ((lastRescan + 60) < time(NULL))
979 lengthBytes = vdr->rescanRecording(&lengthFrames);
980 if (!vdr->isConnected()) { doConnectionLost(); return; }
981 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
982 lastRescan = time(NULL);
985 if (feedPosition >= lengthBytes) break; // finished playback
989 if (startupBlockSize > lengthBytes)
990 askFor = lengthBytes; // is a very small recording!
992 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
996 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
997 askFor = lengthBytes - feedPosition;
1002 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1003 feedPosition += thisRead;
1005 if (!vdr->isConnected())
1011 if (!threadBuffer) break;
1015 int a_stream = demuxer->scan(threadBuffer, thisRead);
1016 demuxer->setAudioStream(a_stream);
1017 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1023 while(writeLength < thisRead)
1025 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1026 writeLength += thisWrite;
1030 // demuxer is full and can't take anymore
1032 threadWaitForSignal();
1040 threadBuffer = NULL;
1045 logger->log("Player", Log::DEBUG, "Recording playback ends");
1047 if (videoStartup) // oh woe. there never was a stream, I was conned!
1049 videoStartup = false;
1051 MILLISLEEP(500); // I think this will solve a race
1057 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1058 m->to = messageReceiver;
1060 m->message = Message::PLAYER_EVENT;
1061 m->parameter = Player::STOP_PLAYBACK;
1062 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1063 messageQueue->postMessage(m);
1066 void Player::threadFeedScan()
1068 // This method is actually really simple - get frame from vdr,
1069 // spit it at the video chip, wait for a time. Most of the code here
1070 // is to get the wait right so that the scan occurs at the correct rate.
1072 ULONG direction = 0;
1073 ULONG baseFrameNumber = 0;
1074 ULONG iframeNumber = 0;
1075 ULONG iframeLength = 0;
1077 UINT amountReceived;
1081 struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info
1082 struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data
1083 struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1085 DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1088 int frameTimeOffset = 0; // Time in msec between frames
1089 int disp_msec = 0; // Time taken to display data
1090 int total_msec = 0; // Time taken to fetch data and display it
1093 if (state == S_FFWD) direction = 1; // and 0 for backward
1097 // Fetch I-frames until we get one that can be displayed in good time
1098 // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1099 baseFrameNumber = currentFrameNumber;
1103 if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1106 if (iframeNumber >= lengthFrames) return;
1107 // scan has got to the end of what we knew to be there before we started scanning
1109 baseFrameNumber = iframeNumber;
1110 frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1112 gettimeofday(&clock0, NULL);
1114 clock0 = timeGetTime();
1118 while (clock2.tv_sec != 0 &&
1119 (clock0.tv_sec - clock2.tv_sec) * 1000 +
1120 (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1122 while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1124 // logger->log("Player", Log::DEBUG, "XXX Got frame");
1126 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1128 if (!vdr->isConnected())
1130 if (threadBuffer) free(threadBuffer);
1136 gettimeofday(&clock1, NULL);
1137 if (clock2.tv_sec != 0)
1138 sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1139 + (clock2.tv_usec - clock1.tv_usec) / 1000
1140 + frameTimeOffset - disp_msec;
1142 clock1 = timeGetTime();
1144 sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1146 if (sleepTime < 0) sleepTime = 0;
1148 MILLISLEEP(sleepTime);
1149 // logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1151 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1152 video->displayIFrame(threadBuffer, videoLength);
1153 currentFrameNumber = iframeNumber;
1155 threadBuffer = NULL;
1158 gettimeofday(&clock2, NULL);
1159 total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1160 + (clock2.tv_usec - clock0.tv_usec) / 1000
1162 disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1163 + (clock2.tv_usec - clock1.tv_usec) / 1000
1166 clock2 = timeGetTime();
1167 total_msec = clock2 - clock0 - sleepTime;
1168 disp_msec = clock2 - clock1 - sleepTime;
1170 // logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1174 void Player::threadPostStopCleanup()
1179 threadBuffer = NULL;
1183 // ----------------------------------- Dev
1186 void Player::test1()
1188 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1191 void Player::test2()
1193 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");