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;
57 subtitlesShowing = false;
63 startupBlockSize = 250000;
69 if (initted) shutdown();
72 int Player::init(bool p_isPesRecording)
74 if (initted) return 0;
76 pthread_mutex_init(&mutex, NULL);
78 mutex=CreateMutex(NULL,FALSE,NULL);
80 is_pesrecording = p_isPesRecording;
82 demuxer = new DemuxerVDR();
84 demuxer = new DemuxerTS();
85 if (!demuxer) return 0;
86 subtitles = new DVBSubtitles(osdReceiver);
87 if (!subtitles) return 0;
89 teletext = new TeletextDecoderVBIEBU();
90 if (!teletext) return 0;
91 teletext->setRecordigMode(true);
93 if (!demuxer->init(this, audio, video,teletext, 2097152, 524288,65536, subtitles))
95 logger->log("Player", Log::ERR, "Demuxer failed to init");
112 int Player::shutdown()
114 if (!initted) return 0;
132 void Player::setStartFrame(ULONG startFrame)
134 currentFrameNumber = startFrame;
137 void Player::setLengthBytes(ULLONG length)
139 lengthBytes = length;
140 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
143 void Player::setLengthFrames(ULONG length)
145 lengthFrames = length;
146 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
149 ULONG Player::getLengthFrames()
154 ULONG Player::getCurrentFrameNum()
156 if (startup) return 0;
161 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
165 return currentFrameNumber;
167 return 0; // shouldn't happen
171 bool* Player::getDemuxerMpegAudioChannels()
173 return demuxer->getmpAudioChannels();
176 bool* Player::getDemuxerAc3AudioChannels()
178 return demuxer->getac3AudioChannels();
181 bool* Player::getDemuxerSubtitleChannels()
183 return demuxer->getSubtitleChannels();
186 int Player::getCurrentAudioChannel()
188 if (is_pesrecording) {
189 return demuxer->getselAudioChannel();
191 return ((DemuxerTS*)demuxer)->getAID();
195 int Player::getCurrentSubtitleChannel()
197 if (is_pesrecording) {
198 return demuxer->getselSubtitleChannel();
200 return ((DemuxerTS*)demuxer)->getSubID();
204 void Player::setSubtitleChannel(int newChannel)
206 if (is_pesrecording) {
207 return demuxer->setDVBSubtitleStream(newChannel);
209 return ((DemuxerTS*)demuxer)->setSubID(newChannel);
213 int *Player::getTeletxtSubtitlePages()
215 return teletext->getSubtitlePages();
218 void Player::setAudioChannel(int newChannel, int type)
220 if (is_pesrecording) {
221 demuxer->setAudioStream(newChannel);
224 ((DemuxerTS*)demuxer)->setAID(newChannel,type);
229 bool Player::toggleSubtitles()
231 if (!subtitlesShowing)
233 subtitlesShowing = true;
238 subtitlesShowing = false;
241 return subtitlesShowing;
244 void Player::turnSubtitlesOn(bool ison) {
247 subtitlesShowing = true;
252 subtitlesShowing = false;
258 Channel Player::getDemuxerChannel() {
259 if (!is_pesrecording) {
260 return ((DemuxerTS*) demuxer)->getChannelInfo();
262 return Channel(); //Should not happen!
266 // ----------------------------------- Externally called events
270 if (!initted) return;
271 if (state == S_PLAY) return;
274 bool doUnlock = false;
275 if (state == S_PAUSE_P) doUnlock = true;
277 if (doUnlock) unLock();
282 if (!initted) return;
283 if (state == S_STOP) return;
285 logger->log("Player", Log::DEBUG, "Stop called lock");
292 if (!initted) return;
295 if ((state == S_FFWD) || (state == S_FBWD))
297 switchState(S_PAUSE_I);
299 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
305 switchState(S_PAUSE_P);
311 void Player::fastForward()
313 if (!initted) return;
321 case 4: ifactor = 8; break;
322 case 8: ifactor = 16; break;
323 case 16: ifactor = 32; break;
324 case 32: ifactor = 4; break;
335 void Player::fastBackward()
337 if (!initted) return;
345 case 4: ifactor = 8; break;
346 case 8: ifactor = 16; break;
347 case 16: ifactor = 32; break;
348 case 32: ifactor = 4; break;
359 void Player::jumpToPercent(double percent)
362 logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
363 ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
364 switchState(S_JUMP, newFrame);
365 // unLock(); - let thread unlock this
368 void Player::jumpToMark(int mark)
371 logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
372 switchState(S_JUMP, mark);
373 // unLock(); - let thread unlock this
376 void Player::jumpToFrameP(int newFrame)
379 logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
380 switchState(S_JUMP_PI, newFrame);
384 void Player::skipForward(int seconds)
387 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
388 ULONG newFrame = getCurrentFrameNum();
389 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
390 newFrame += seconds * video->getFPS();
391 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
392 else switchState(S_JUMP, newFrame);
393 // unLock(); - let thread unlock this
396 void Player::skipBackward(int seconds)
399 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
400 long newFrame = getCurrentFrameNum();
401 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
402 newFrame -= seconds * video->getFPS();
403 if (newFrame < 0) newFrame = 0;
404 switchState(S_JUMP, newFrame);
405 // unLock(); - let thread unlock this
408 // ----------------------------------- Implementations called events
410 void Player::switchState(UCHAR toState, ULONG jumpFrame)
412 if (!initted) return;
414 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
416 switch(state) // current state selector
418 case S_PLAY: // from S_PLAY -----------------------------------
422 case S_PLAY: // to S_PLAY
426 case S_PAUSE_P: // to S_PAUSE_P
433 case S_PAUSE_I: // to S_PAUSE_I
438 case S_FFWD: // to S_FFWD
440 currentFrameNumber = getCurrentFrameNum();
441 audio->systemMuteOn();
452 case S_FBWD: // to S_FBWD
454 currentFrameNumber = getCurrentFrameNum();
455 audio->systemMuteOn();
466 case S_STOP: // to S_STOP
482 case S_JUMP: // to S_JUMP
484 restartAtFrame(jumpFrame);
487 case S_JUMP_PI: // to S_JUMP_PI
489 audio->systemMuteOn();
499 restartAtFramePI(jumpFrame);
504 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
508 case S_PLAY: // to S_PLAY
515 case S_PAUSE_P: // to S_PAUSE_P
519 case S_PAUSE_I: // to S_PAUSE_I
523 case S_FFWD: // to S_FFWD
525 currentFrameNumber = getCurrentFrameNum();
526 audio->systemMuteOn();
538 case S_FBWD: // to S_FBWD
540 currentFrameNumber = getCurrentFrameNum();
541 audio->systemMuteOn();
553 case S_STOP: // to S_STOP
566 audio->systemMuteOff();
570 case S_JUMP: // to S_JUMP
573 audio->systemMuteOn();
575 restartAtFrame(jumpFrame);
578 case S_JUMP_PI: // to S_JUMP_PI
580 audio->systemMuteOn();
591 restartAtFramePI(jumpFrame);
596 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
600 case S_PLAY: // to S_PLAY
603 restartAtFrame(currentFrameNumber);
606 case S_PAUSE_P: // to S_PAUSE_P
610 case S_PAUSE_I: // to S_PAUSE_I
614 case S_FFWD: // to S_FFWD
620 case S_FBWD: // to S_FBWD
626 case S_STOP: // to S_STOP
633 audio->systemMuteOff();
637 case S_JUMP: // to S_JUMP
640 restartAtFrame(jumpFrame);
643 case S_JUMP_PI: // to S_JUMP_PI
645 restartAtFramePI(jumpFrame);
650 case S_FFWD: // from S_FFWD -----------------------------------
654 case S_PLAY: // to S_PLAY
657 ULONG stepback = USER_RESPONSE_TIME * video->getFPS() * ifactor / 1000;
658 if (stepback < currentFrameNumber)
659 currentFrameNumber -= stepback;
661 currentFrameNumber = 0;
662 restartAtFrame(currentFrameNumber);
665 case S_PAUSE_P: // to S_PAUSE_P
670 case S_PAUSE_I: // to S_PAUSE_I
676 case S_FFWD: // to S_FFWD
680 case S_FBWD: // to S_FBWD
687 case S_STOP: // to S_STOP
698 case S_JUMP: // to S_JUMP
701 restartAtFrame(jumpFrame);
704 case S_JUMP_PI: // to S_JUMP_PI
708 restartAtFramePI(jumpFrame);
713 case S_FBWD: // from S_FBWD -----------------------------------
717 case S_PLAY: // to S_PLAY
720 restartAtFrame(currentFrameNumber);
723 case S_PAUSE_P: // to S_PAUSE_P
728 case S_PAUSE_I: // to S_PAUSE_I
734 case S_FFWD: // to S_FFWD
741 case S_FBWD: // to S_FBWD
745 case S_STOP: // to S_STOP
756 case S_JUMP: // to S_JUMP
759 restartAtFrame(jumpFrame);
762 case S_JUMP_PI: // to S_JUMP_PI
766 restartAtFramePI(jumpFrame);
771 case S_STOP: // from S_STOP -----------------------------------
775 case S_PLAY: // to S_PLAY
780 audio->setStreamType(Audio::MPEG2_PES);
781 audio->systemMuteOff();
784 // FIXME use restartAtFrame here?
785 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
786 demuxer->setFrameNum(currentFrameNumber);
791 logger->log("Player", Log::DEBUG, "Immediate play");
802 case S_PAUSE_P: // to S_PAUSE_P
806 case S_PAUSE_I: // to S_PAUSE_I
810 case S_FFWD: // to S_FFWD
814 case S_FBWD: // to S_FBWD
818 case S_STOP: // to S_STOP
822 case S_JUMP: // to S_JUMP
826 case S_JUMP_PI: // to S_JUMP_PI
832 // case S_JUMP cannot be a start state because it auto flips to play
833 // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
837 // ----------------------------------- Internal functions
842 pthread_mutex_lock(&mutex);
843 logger->log("Player", Log::DEBUG, "LOCKED");
846 WaitForSingleObject(mutex, INFINITE);
850 void Player::unLock()
853 logger->log("Player", Log::DEBUG, "UNLOCKING");
854 pthread_mutex_unlock(&mutex);
860 void Player::restartAtFrame(ULONG newFrame)
870 audio->setStreamType(Audio::MPEG2_PES);
873 currentFrameNumber = newFrame;
874 demuxer->setFrameNum(newFrame);
884 audio->systemMuteOff();
889 void Player::restartAtFramePI(ULONG newFrame)
892 ULONG nextiframeNumber;
900 // newFrame could be anywhere, go forwards to next I-Frame
901 if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
903 // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
904 vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
906 buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
907 if (!vdr->isConnected())
909 if (buffer) free(buffer);
914 videoLength = demuxer->stripAudio(buffer, amountReceived);
915 video->displayIFrame(buffer, videoLength);
916 video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
918 currentFrameNumber = iframeNumber;
922 void Player::doConnectionLost()
924 logger->log("Player", Log::DEBUG, "Connection lost, sending message");
925 Message* m = new Message();
926 m->to = messageReceiver;
928 m->message = Message::PLAYER_EVENT;
929 m->parameter = Player::CONNECTION_LOST;
930 messageQueue->postMessage(m);
933 // ----------------------------------- Callback
935 void Player::call(void* caller)
937 if (caller == demuxer)
939 logger->log("Player", Log::DEBUG, "Callback from demuxer");
941 if (video->getTVsize() == Video::ASPECT4X3)
943 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
947 int dxCurrentAspect = demuxer->getAspectRatio();
948 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
950 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
951 video->setAspectRatio(Video::ASPECT4X3);
953 Message* m = new Message();
955 m->to = messageReceiver;
956 m->message = Message::PLAYER_EVENT;
957 m->parameter = Player::ASPECT43;
958 messageQueue->postMessageFromOuterSpace(m);
960 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
962 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
963 video->setAspectRatio(Video::ASPECT16X9);
965 Message* m = new Message();
967 m->to = messageReceiver;
968 m->message = Message::PLAYER_EVENT;
969 m->parameter = Player::ASPECT169;
970 messageQueue->postMessageFromOuterSpace(m);
974 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
982 videoStartup = false;
990 threadSignalNoLock();
994 // ----------------------------------- Feed thread
996 void Player::threadMethod()
998 // this method used to be simple, the only thing it does
999 // is farm out to threadFeed Live/Play/Scan
1000 // All the guff is to support scan hitting one end
1002 if ((state == S_FFWD) || (state == S_FBWD))
1005 // if this returns then scan hit one end
1006 if (state == S_FFWD) // scan hit the end. stop
1009 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1010 m->to = messageReceiver;
1012 m->message = Message::PLAYER_EVENT;
1013 m->parameter = STOP_PLAYBACK;
1014 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1015 messageQueue->postMessage(m);
1016 logger->log("Player", Log::DEBUG, "Message posted...");
1019 // if execution gets to here, threadFeedScan hit the start, go to play mode
1022 audio->setStreamType(Audio::MPEG2_PES);
1025 demuxer->setFrameNum(currentFrameNumber);
1026 videoStartup = true;
1033 audio->systemMuteOff();
1037 if (state == S_PLAY) threadFeedPlay();
1040 void Player::threadFeedPlay()
1042 ULLONG feedPosition;
1043 UINT thisRead, writeLength, thisWrite, askFor;
1044 time_t lastRescan = time(NULL);
1046 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1047 if (!vdr->isConnected()) { doConnectionLost(); return; }
1048 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1059 // If we havn't rescanned for a while..
1060 if ((lastRescan + 60) < time(NULL))
1062 lengthBytes = vdr->rescanRecording(&lengthFrames);
1063 if (!vdr->isConnected()) { doConnectionLost(); return; }
1064 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1065 lastRescan = time(NULL);
1068 if (feedPosition >= lengthBytes) break; // finished playback
1072 if (startupBlockSize > lengthBytes)
1073 askFor = lengthBytes; // is a very small recording!
1075 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1079 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1080 askFor = lengthBytes - feedPosition;
1085 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1086 feedPosition += thisRead;
1088 if (!vdr->isConnected())
1094 if (!threadBuffer) break;
1098 int a_stream = demuxer->scan(threadBuffer, thisRead);
1099 demuxer->setAudioStream(a_stream);
1100 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1106 while(writeLength < thisRead)
1108 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1109 writeLength += thisWrite;
1113 // demuxer is full and can't take anymore
1115 threadWaitForSignal();
1123 threadBuffer = NULL;
1128 logger->log("Player", Log::DEBUG, "Recording playback ends");
1130 if (videoStartup) // oh woe. there never was a stream, I was conned!
1132 videoStartup = false;
1134 MILLISLEEP(500); // I think this will solve a race
1140 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1141 m->to = messageReceiver;
1143 m->message = Message::PLAYER_EVENT;
1144 m->parameter = Player::STOP_PLAYBACK;
1145 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1146 messageQueue->postMessage(m);
1149 void Player::threadFeedScan()
1151 // This method is actually really simple - get frame from vdr,
1152 // spit it at the video chip, wait for a time. Most of the code here
1153 // is to get the wait right so that the scan occurs at the correct rate.
1155 ULONG direction = 0;
1156 ULONG baseFrameNumber = 0;
1157 ULONG iframeNumber = 0;
1158 ULONG iframeLength = 0;
1160 UINT amountReceived;
1164 struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info
1165 struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data
1166 struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1168 DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1171 int frameTimeOffset = 0; // Time in msec between frames
1172 int disp_msec = 0; // Time taken to display data
1173 int total_msec = 0; // Time taken to fetch data and display it
1176 if (state == S_FFWD) direction = 1; // and 0 for backward
1180 // Fetch I-frames until we get one that can be displayed in good time
1181 // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1183 baseFrameNumber = currentFrameNumber;
1187 if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1190 if (iframeNumber >= lengthFrames) return;
1191 // scan has got to the end of what we knew to be there before we started scanning
1193 baseFrameNumber = iframeNumber;
1194 frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1196 gettimeofday(&clock0, NULL);
1198 clock0 = timeGetTime();
1202 while (clock2.tv_sec != 0 &&
1203 (clock0.tv_sec - clock2.tv_sec) * 1000 +
1204 (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1206 while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1208 // logger->log("Player", Log::DEBUG, "XXX Got frame");
1210 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1212 if (!vdr->isConnected())
1214 if (threadBuffer) free(threadBuffer);
1220 gettimeofday(&clock1, NULL);
1221 if (clock2.tv_sec != 0)
1222 sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1223 + (clock2.tv_usec - clock1.tv_usec) / 1000
1224 + frameTimeOffset - disp_msec;
1226 clock1 = timeGetTime();
1228 sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1230 if (sleepTime < 0) sleepTime = 0;
1232 MILLISLEEP(sleepTime);
1233 // logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1235 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1236 video->displayIFrame(threadBuffer, videoLength);
1237 currentFrameNumber = iframeNumber;
1239 threadBuffer = NULL;
1242 gettimeofday(&clock2, NULL);
1243 total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1244 + (clock2.tv_usec - clock0.tv_usec) / 1000
1246 disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1247 + (clock2.tv_usec - clock1.tv_usec) / 1000
1250 clock2 = timeGetTime();
1251 total_msec = clock2 - clock0 - sleepTime;
1252 disp_msec = clock2 - clock1 - sleepTime;
1254 // logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1258 void Player::threadPostStopCleanup()
1263 threadBuffer = NULL;
1267 // ----------------------------------- Dev
1270 void Player::test1()
1272 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1275 void Player::test2()
1277 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");