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), tfeed(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 teletext = new TeletextDecoderVBIEBU();
86 if (!teletext) return 0;
87 teletext->setRecordigMode(true);
89 if (!demuxer->init(this, audio, video,teletext, 2097152, 524288,65536, subtitles))
91 logger->log("Player", Log::ERR, "Demuxer failed to init");
108 int Player::shutdown()
110 if (!initted) return 0;
128 void Player::setStartFrame(ULONG startFrame)
130 currentFrameNumber = startFrame;
133 void Player::setLengthBytes(ULLONG length)
135 lengthBytes = length;
136 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
139 void Player::setLengthFrames(ULONG length)
141 lengthFrames = length;
142 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
145 ULONG Player::getLengthFrames()
150 ULONG Player::getCurrentFrameNum()
152 if (startup) return 0;
157 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
161 return currentFrameNumber;
163 return 0; // shouldn't happen
167 bool* Player::getDemuxerMpegAudioChannels()
169 return demuxer->getmpAudioChannels();
172 bool* Player::getDemuxerAc3AudioChannels()
174 return demuxer->getac3AudioChannels();
177 bool* Player::getDemuxerSubtitleChannels()
179 return demuxer->getSubtitleChannels();
182 int Player::getCurrentAudioChannel()
184 return demuxer->getselAudioChannel();
187 int Player::getCurrentSubtitleChannel()
189 return demuxer->getselSubtitleChannel();
192 void Player::setSubtitleChannel(int newChannel)
194 return demuxer->setDVBSubtitleStream(newChannel);
197 int *Player::getTeletxtSubtitlePages()
199 return teletext->getSubtitlePages();
202 void Player::setAudioChannel(int newChannel, int type)
204 demuxer->setAudioStream(newChannel);
207 bool Player::toggleSubtitles()
209 if (!subtitlesShowing)
211 subtitlesShowing = true;
216 subtitlesShowing = false;
219 return subtitlesShowing;
222 void Player::turnSubtitlesOn(bool ison) {
225 subtitlesShowing = true;
230 subtitlesShowing = false;
236 // ----------------------------------- Externally called events
240 if (!initted) return;
241 if (state == S_PLAY) return;
244 bool doUnlock = false;
245 if (state == S_PAUSE_P) doUnlock = true;
247 if (doUnlock) unLock();
252 if (!initted) return;
253 if (state == S_STOP) return;
255 logger->log("Player", Log::DEBUG, "Stop called lock");
262 if (!initted) return;
265 if ((state == S_FFWD) || (state == S_FBWD))
267 switchState(S_PAUSE_I);
269 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
275 switchState(S_PAUSE_P);
281 void Player::fastForward()
283 if (!initted) return;
291 case 4: ifactor = 8; break;
292 case 8: ifactor = 16; break;
293 case 16: ifactor = 32; break;
294 case 32: ifactor = 4; break;
305 void Player::fastBackward()
307 if (!initted) return;
315 case 4: ifactor = 8; break;
316 case 8: ifactor = 16; break;
317 case 16: ifactor = 32; break;
318 case 32: ifactor = 4; break;
329 void Player::jumpToPercent(double percent)
332 logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
333 ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
334 switchState(S_JUMP, newFrame);
335 // unLock(); - let thread unlock this
338 void Player::jumpToMark(int mark)
341 logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
342 switchState(S_JUMP, mark);
343 // unLock(); - let thread unlock this
346 void Player::jumpToFrameP(int newFrame)
349 logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
350 switchState(S_JUMP_PI, newFrame);
354 void Player::skipForward(int seconds)
357 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
358 ULONG newFrame = getCurrentFrameNum();
359 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
360 newFrame += seconds * video->getFPS();
361 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
362 else switchState(S_JUMP, newFrame);
363 // unLock(); - let thread unlock this
366 void Player::skipBackward(int seconds)
369 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
370 long newFrame = getCurrentFrameNum();
371 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
372 newFrame -= seconds * video->getFPS();
373 if (newFrame < 0) newFrame = 0;
374 switchState(S_JUMP, newFrame);
375 // unLock(); - let thread unlock this
378 // ----------------------------------- Implementations called events
380 void Player::switchState(UCHAR toState, ULONG jumpFrame)
382 if (!initted) return;
384 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
386 switch(state) // current state selector
388 case S_PLAY: // from S_PLAY -----------------------------------
392 case S_PLAY: // to S_PLAY
396 case S_PAUSE_P: // to S_PAUSE_P
403 case S_PAUSE_I: // to S_PAUSE_I
408 case S_FFWD: // to S_FFWD
410 currentFrameNumber = getCurrentFrameNum();
411 audio->systemMuteOn();
422 case S_FBWD: // to S_FBWD
424 currentFrameNumber = getCurrentFrameNum();
425 audio->systemMuteOn();
436 case S_STOP: // to S_STOP
452 case S_JUMP: // to S_JUMP
454 restartAtFrame(jumpFrame);
457 case S_JUMP_PI: // to S_JUMP_PI
459 audio->systemMuteOn();
469 restartAtFramePI(jumpFrame);
474 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
478 case S_PLAY: // to S_PLAY
485 case S_PAUSE_P: // to S_PAUSE_P
489 case S_PAUSE_I: // to S_PAUSE_I
493 case S_FFWD: // to S_FFWD
495 currentFrameNumber = getCurrentFrameNum();
496 audio->systemMuteOn();
508 case S_FBWD: // to S_FBWD
510 currentFrameNumber = getCurrentFrameNum();
511 audio->systemMuteOn();
523 case S_STOP: // to S_STOP
536 audio->systemMuteOff();
540 case S_JUMP: // to S_JUMP
543 audio->systemMuteOn();
545 restartAtFrame(jumpFrame);
548 case S_JUMP_PI: // to S_JUMP_PI
550 audio->systemMuteOn();
561 restartAtFramePI(jumpFrame);
566 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
570 case S_PLAY: // to S_PLAY
573 restartAtFrame(currentFrameNumber);
576 case S_PAUSE_P: // to S_PAUSE_P
580 case S_PAUSE_I: // to S_PAUSE_I
584 case S_FFWD: // to S_FFWD
590 case S_FBWD: // to S_FBWD
596 case S_STOP: // to S_STOP
603 audio->systemMuteOff();
607 case S_JUMP: // to S_JUMP
610 restartAtFrame(jumpFrame);
613 case S_JUMP_PI: // to S_JUMP_PI
615 restartAtFramePI(jumpFrame);
620 case S_FFWD: // from S_FFWD -----------------------------------
624 case S_PLAY: // to S_PLAY
627 ULONG stepback = USER_RESPONSE_TIME * video->getFPS() * ifactor / 1000;
628 if (stepback < currentFrameNumber)
629 currentFrameNumber -= stepback;
631 currentFrameNumber = 0;
632 restartAtFrame(currentFrameNumber);
635 case S_PAUSE_P: // to S_PAUSE_P
640 case S_PAUSE_I: // to S_PAUSE_I
646 case S_FFWD: // to S_FFWD
650 case S_FBWD: // to S_FBWD
657 case S_STOP: // to S_STOP
668 case S_JUMP: // to S_JUMP
671 restartAtFrame(jumpFrame);
674 case S_JUMP_PI: // to S_JUMP_PI
678 restartAtFramePI(jumpFrame);
683 case S_FBWD: // from S_FBWD -----------------------------------
687 case S_PLAY: // to S_PLAY
690 restartAtFrame(currentFrameNumber);
693 case S_PAUSE_P: // to S_PAUSE_P
698 case S_PAUSE_I: // to S_PAUSE_I
704 case S_FFWD: // to S_FFWD
711 case S_FBWD: // to S_FBWD
715 case S_STOP: // to S_STOP
726 case S_JUMP: // to S_JUMP
729 restartAtFrame(jumpFrame);
732 case S_JUMP_PI: // to S_JUMP_PI
736 restartAtFramePI(jumpFrame);
741 case S_STOP: // from S_STOP -----------------------------------
745 case S_PLAY: // to S_PLAY
750 audio->setStreamType(Audio::MPEG2_PES);
751 audio->systemMuteOff();
754 // FIXME use restartAtFrame here?
755 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
756 demuxer->setFrameNum(currentFrameNumber);
761 logger->log("Player", Log::DEBUG, "Immediate play");
772 case S_PAUSE_P: // to S_PAUSE_P
776 case S_PAUSE_I: // to S_PAUSE_I
780 case S_FFWD: // to S_FFWD
784 case S_FBWD: // to S_FBWD
788 case S_STOP: // to S_STOP
792 case S_JUMP: // to S_JUMP
796 case S_JUMP_PI: // to S_JUMP_PI
802 // case S_JUMP cannot be a start state because it auto flips to play
803 // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
807 // ----------------------------------- Internal functions
812 pthread_mutex_lock(&mutex);
813 logger->log("Player", Log::DEBUG, "LOCKED");
816 WaitForSingleObject(mutex, INFINITE);
820 void Player::unLock()
823 logger->log("Player", Log::DEBUG, "UNLOCKING");
824 pthread_mutex_unlock(&mutex);
830 void Player::restartAtFrame(ULONG newFrame)
840 audio->setStreamType(Audio::MPEG2_PES);
843 currentFrameNumber = newFrame;
844 demuxer->setFrameNum(newFrame);
854 audio->systemMuteOff();
859 void Player::restartAtFramePI(ULONG newFrame)
862 ULONG nextiframeNumber;
870 // newFrame could be anywhere, go forwards to next I-Frame
871 if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
873 // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
874 vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
876 buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
877 if (!vdr->isConnected())
879 if (buffer) free(buffer);
884 videoLength = demuxer->stripAudio(buffer, amountReceived);
885 video->displayIFrame(buffer, videoLength);
886 video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
888 currentFrameNumber = iframeNumber;
892 void Player::doConnectionLost()
894 logger->log("Player", Log::DEBUG, "Connection lost, sending message");
895 Message* m = new Message();
896 m->to = messageReceiver;
898 m->message = Message::PLAYER_EVENT;
899 m->parameter = Player::CONNECTION_LOST;
900 messageQueue->postMessage(m);
903 // ----------------------------------- Callback
905 void Player::call(void* caller)
907 if (caller == demuxer)
909 logger->log("Player", Log::DEBUG, "Callback from demuxer");
911 if (video->getTVsize() == Video::ASPECT4X3)
913 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
917 int dxCurrentAspect = demuxer->getAspectRatio();
918 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
920 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
921 video->setAspectRatio(Video::ASPECT4X3);
923 Message* m = new Message();
925 m->to = messageReceiver;
926 m->message = Message::PLAYER_EVENT;
927 m->parameter = Player::ASPECT43;
928 messageQueue->postMessageFromOuterSpace(m);
930 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
932 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
933 video->setAspectRatio(Video::ASPECT16X9);
935 Message* m = new Message();
937 m->to = messageReceiver;
938 m->message = Message::PLAYER_EVENT;
939 m->parameter = Player::ASPECT169;
940 messageQueue->postMessageFromOuterSpace(m);
944 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
952 videoStartup = false;
960 threadSignalNoLock();
964 // ----------------------------------- Feed thread
966 void Player::threadMethod()
968 // this method used to be simple, the only thing it does
969 // is farm out to threadFeed Live/Play/Scan
970 // All the guff is to support scan hitting one end
972 if ((state == S_FFWD) || (state == S_FBWD))
975 // if this returns then scan hit one end
976 if (state == S_FFWD) // scan hit the end. stop
979 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
980 m->to = messageReceiver;
982 m->message = Message::PLAYER_EVENT;
983 m->parameter = STOP_PLAYBACK;
984 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
985 messageQueue->postMessage(m);
986 logger->log("Player", Log::DEBUG, "Message posted...");
989 // if execution gets to here, threadFeedScan hit the start, go to play mode
992 audio->setStreamType(Audio::MPEG2_PES);
995 demuxer->setFrameNum(currentFrameNumber);
1003 audio->systemMuteOff();
1007 if (state == S_PLAY) threadFeedPlay();
1010 void Player::threadFeedPlay()
1012 ULLONG feedPosition;
1013 UINT thisRead, writeLength, thisWrite, askFor;
1014 time_t lastRescan = time(NULL);
1016 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1017 if (!vdr->isConnected()) { doConnectionLost(); return; }
1018 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1029 // If we havn't rescanned for a while..
1030 if ((lastRescan + 60) < time(NULL))
1032 lengthBytes = vdr->rescanRecording(&lengthFrames);
1033 if (!vdr->isConnected()) { doConnectionLost(); return; }
1034 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1035 lastRescan = time(NULL);
1038 if (feedPosition >= lengthBytes) break; // finished playback
1042 if (startupBlockSize > lengthBytes)
1043 askFor = lengthBytes; // is a very small recording!
1045 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1049 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1050 askFor = lengthBytes - feedPosition;
1055 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1056 feedPosition += thisRead;
1058 if (!vdr->isConnected())
1064 if (!threadBuffer) break;
1068 int a_stream = demuxer->scan(threadBuffer, thisRead);
1069 demuxer->setAudioStream(a_stream);
1070 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1076 while(writeLength < thisRead)
1078 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1079 writeLength += thisWrite;
1083 // demuxer is full and can't take anymore
1085 threadWaitForSignal();
1093 threadBuffer = NULL;
1098 logger->log("Player", Log::DEBUG, "Recording playback ends");
1100 if (videoStartup) // oh woe. there never was a stream, I was conned!
1102 videoStartup = false;
1104 MILLISLEEP(500); // I think this will solve a race
1110 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1111 m->to = messageReceiver;
1113 m->message = Message::PLAYER_EVENT;
1114 m->parameter = Player::STOP_PLAYBACK;
1115 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1116 messageQueue->postMessage(m);
1119 void Player::threadFeedScan()
1121 // This method is actually really simple - get frame from vdr,
1122 // spit it at the video chip, wait for a time. Most of the code here
1123 // is to get the wait right so that the scan occurs at the correct rate.
1125 ULONG direction = 0;
1126 ULONG baseFrameNumber = 0;
1127 ULONG iframeNumber = 0;
1128 ULONG iframeLength = 0;
1130 UINT amountReceived;
1134 struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info
1135 struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data
1136 struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1138 DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1141 int frameTimeOffset = 0; // Time in msec between frames
1142 int disp_msec = 0; // Time taken to display data
1143 int total_msec = 0; // Time taken to fetch data and display it
1146 if (state == S_FFWD) direction = 1; // and 0 for backward
1150 // Fetch I-frames until we get one that can be displayed in good time
1151 // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1152 baseFrameNumber = currentFrameNumber;
1156 if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1159 if (iframeNumber >= lengthFrames) return;
1160 // scan has got to the end of what we knew to be there before we started scanning
1162 baseFrameNumber = iframeNumber;
1163 frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1165 gettimeofday(&clock0, NULL);
1167 clock0 = timeGetTime();
1171 while (clock2.tv_sec != 0 &&
1172 (clock0.tv_sec - clock2.tv_sec) * 1000 +
1173 (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1175 while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1177 // logger->log("Player", Log::DEBUG, "XXX Got frame");
1179 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1181 if (!vdr->isConnected())
1183 if (threadBuffer) free(threadBuffer);
1189 gettimeofday(&clock1, NULL);
1190 if (clock2.tv_sec != 0)
1191 sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1192 + (clock2.tv_usec - clock1.tv_usec) / 1000
1193 + frameTimeOffset - disp_msec;
1195 clock1 = timeGetTime();
1197 sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1199 if (sleepTime < 0) sleepTime = 0;
1201 MILLISLEEP(sleepTime);
1202 // logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1204 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1205 video->displayIFrame(threadBuffer, videoLength);
1206 currentFrameNumber = iframeNumber;
1208 threadBuffer = NULL;
1211 gettimeofday(&clock2, NULL);
1212 total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1213 + (clock2.tv_usec - clock0.tv_usec) / 1000
1215 disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1216 + (clock2.tv_usec - clock1.tv_usec) / 1000
1219 clock2 = timeGetTime();
1220 total_msec = clock2 - clock0 - sleepTime;
1221 disp_msec = clock2 - clock1 - sleepTime;
1223 // logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1227 void Player::threadPostStopCleanup()
1232 threadBuffer = NULL;
1236 // ----------------------------------- Dev
1239 void Player::test1()
1241 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1244 void Player::test2()
1246 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");