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,double framespersecond)
74 if (initted) return 0;
76 pthread_mutex_init(&mutex, NULL);
78 mutex=CreateMutex(NULL,FALSE,NULL);
80 is_pesrecording = p_isPesRecording;
83 demuxer = new DemuxerVDR();
85 demuxer = new DemuxerTS();
86 if (!demuxer) return 0;
87 subtitles = new DVBSubtitles(osdReceiver);
88 if (!subtitles) return 0;
90 teletext = new TeletextDecoderVBIEBU();
91 if (!teletext) return 0;
92 teletext->setRecordigMode(true);
93 unsigned int demux_video_size=2097152;
94 if (video->supportsh264()) demux_video_size*=5;
96 if (!demuxer->init(this, audio, video,teletext, demux_video_size,524288,65536, framespersecond, subtitles))
98 logger->log("Player", Log::ERR, "Demuxer failed to init");
115 int Player::shutdown()
117 if (!initted) return 0;
135 void Player::setStartFrame(ULONG startFrame)
137 currentFrameNumber = startFrame;
140 void Player::setLengthBytes(ULLONG length)
142 lengthBytes = length;
143 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
146 void Player::setLengthFrames(ULONG length)
148 lengthFrames = length;
149 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
152 ULONG Player::getLengthFrames()
157 ULONG Player::getCurrentFrameNum()
159 if (startup) return 0;
164 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
168 return currentFrameNumber;
170 return 0; // shouldn't happen
174 bool* Player::getDemuxerMpegAudioChannels()
176 return demuxer->getmpAudioChannels();
179 bool* Player::getDemuxerAc3AudioChannels()
181 return demuxer->getac3AudioChannels();
184 bool* Player::getDemuxerSubtitleChannels()
186 return demuxer->getSubtitleChannels();
189 int Player::getCurrentAudioChannel()
191 if (is_pesrecording) {
192 return demuxer->getselAudioChannel();
194 return ((DemuxerTS*)demuxer)->getAID();
198 int Player::getCurrentSubtitleChannel()
200 if (is_pesrecording) {
201 return demuxer->getselSubtitleChannel();
203 return ((DemuxerTS*)demuxer)->getSubID();
207 void Player::setSubtitleChannel(int newChannel)
209 if (is_pesrecording) {
210 return demuxer->setDVBSubtitleStream(newChannel);
212 return ((DemuxerTS*)demuxer)->setSubID(newChannel);
216 int *Player::getTeletxtSubtitlePages()
218 return teletext->getSubtitlePages();
221 void Player::setAudioChannel(int newChannel, int type)
223 if (is_pesrecording) {
224 demuxer->setAudioStream(newChannel);
227 ((DemuxerTS*)demuxer)->setAID(newChannel,type);
232 bool Player::toggleSubtitles()
234 if (!subtitlesShowing)
236 subtitlesShowing = true;
241 subtitlesShowing = false;
244 return subtitlesShowing;
247 void Player::turnSubtitlesOn(bool ison) {
250 subtitlesShowing = true;
255 subtitlesShowing = false;
261 Channel Player::getDemuxerChannel() {
262 if (!is_pesrecording) {
263 return ((DemuxerTS*) demuxer)->getChannelInfo();
265 return Channel(); //Should not happen!
269 // ----------------------------------- Externally called events
273 if (!initted) return;
274 if (state == S_PLAY) return;
277 bool doUnlock = false;
278 if (state == S_PAUSE_P) doUnlock = true;
280 if (doUnlock) unLock();
285 if (!initted) return;
286 if (state == S_STOP) return;
288 logger->log("Player", Log::DEBUG, "Stop called lock");
295 if (!initted) return;
298 if ((state == S_FFWD) || (state == S_FBWD))
300 switchState(S_PAUSE_I);
302 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
308 switchState(S_PAUSE_P);
314 void Player::fastForward()
316 if (!initted) return;
324 case 4: ifactor = 8; break;
325 case 8: ifactor = 16; break;
326 case 16: ifactor = 32; break;
327 case 32: ifactor = 4; break;
338 void Player::fastBackward()
340 if (!initted) return;
348 case 4: ifactor = 8; break;
349 case 8: ifactor = 16; break;
350 case 16: ifactor = 32; break;
351 case 32: ifactor = 4; break;
362 void Player::jumpToPercent(double percent)
365 logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
366 ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
367 switchState(S_JUMP, newFrame);
368 // unLock(); - let thread unlock this
371 void Player::jumpToMark(int mark)
374 logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
375 switchState(S_JUMP, mark);
376 // unLock(); - let thread unlock this
379 void Player::jumpToFrameP(int newFrame)
382 logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
383 switchState(S_JUMP_PI, newFrame);
387 void Player::skipForward(int seconds)
390 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
391 ULONG newFrame = getCurrentFrameNum();
392 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
393 newFrame +=(ULONG) (((double)seconds) * fps);
394 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
395 else switchState(S_JUMP, newFrame);
396 // unLock(); - let thread unlock this
399 void Player::skipBackward(int seconds)
402 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
403 long newFrame = getCurrentFrameNum();
404 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
405 newFrame -= (ULONG) (((double)seconds) * fps);
406 if (newFrame < 0) newFrame = 0;
407 switchState(S_JUMP, newFrame);
408 // unLock(); - let thread unlock this
411 // ----------------------------------- Implementations called events
413 void Player::switchState(UCHAR toState, ULONG jumpFrame)
415 if (!initted) return;
417 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
419 switch(state) // current state selector
421 case S_PLAY: // from S_PLAY -----------------------------------
425 case S_PLAY: // to S_PLAY
429 case S_PAUSE_P: // to S_PAUSE_P
436 case S_PAUSE_I: // to S_PAUSE_I
441 case S_FFWD: // to S_FFWD
443 currentFrameNumber = getCurrentFrameNum();
444 audio->systemMuteOn();
455 case S_FBWD: // to S_FBWD
457 currentFrameNumber = getCurrentFrameNum();
458 audio->systemMuteOn();
469 case S_STOP: // to S_STOP
485 case S_JUMP: // to S_JUMP
487 restartAtFrame(jumpFrame);
490 case S_JUMP_PI: // to S_JUMP_PI
492 audio->systemMuteOn();
502 restartAtFramePI(jumpFrame);
507 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
511 case S_PLAY: // to S_PLAY
518 case S_PAUSE_P: // to S_PAUSE_P
522 case S_PAUSE_I: // to S_PAUSE_I
526 case S_FFWD: // to S_FFWD
528 currentFrameNumber = getCurrentFrameNum();
529 audio->systemMuteOn();
541 case S_FBWD: // to S_FBWD
543 currentFrameNumber = getCurrentFrameNum();
544 audio->systemMuteOn();
556 case S_STOP: // to S_STOP
569 audio->systemMuteOff();
573 case S_JUMP: // to S_JUMP
576 audio->systemMuteOn();
578 restartAtFrame(jumpFrame);
581 case S_JUMP_PI: // to S_JUMP_PI
583 audio->systemMuteOn();
594 restartAtFramePI(jumpFrame);
599 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
603 case S_PLAY: // to S_PLAY
606 restartAtFrame(currentFrameNumber);
609 case S_PAUSE_P: // to S_PAUSE_P
613 case S_PAUSE_I: // to S_PAUSE_I
617 case S_FFWD: // to S_FFWD
623 case S_FBWD: // to S_FBWD
629 case S_STOP: // to S_STOP
636 audio->systemMuteOff();
640 case S_JUMP: // to S_JUMP
643 restartAtFrame(jumpFrame);
646 case S_JUMP_PI: // to S_JUMP_PI
648 restartAtFramePI(jumpFrame);
653 case S_FFWD: // from S_FFWD -----------------------------------
657 case S_PLAY: // to S_PLAY
660 ULONG stepback = (ULONG)(((double)USER_RESPONSE_TIME * ifactor) * fps / 1000.);
661 if (stepback < currentFrameNumber)
662 currentFrameNumber -= stepback;
664 currentFrameNumber = 0;
665 restartAtFrame(currentFrameNumber);
668 case S_PAUSE_P: // to S_PAUSE_P
673 case S_PAUSE_I: // to S_PAUSE_I
679 case S_FFWD: // to S_FFWD
683 case S_FBWD: // to S_FBWD
690 case S_STOP: // to S_STOP
701 case S_JUMP: // to S_JUMP
704 restartAtFrame(jumpFrame);
707 case S_JUMP_PI: // to S_JUMP_PI
711 restartAtFramePI(jumpFrame);
716 case S_FBWD: // from S_FBWD -----------------------------------
720 case S_PLAY: // to S_PLAY
723 restartAtFrame(currentFrameNumber);
726 case S_PAUSE_P: // to S_PAUSE_P
731 case S_PAUSE_I: // to S_PAUSE_I
737 case S_FFWD: // to S_FFWD
744 case S_FBWD: // to S_FBWD
748 case S_STOP: // to S_STOP
759 case S_JUMP: // to S_JUMP
762 restartAtFrame(jumpFrame);
765 case S_JUMP_PI: // to S_JUMP_PI
769 restartAtFramePI(jumpFrame);
774 case S_STOP: // from S_STOP -----------------------------------
778 case S_PLAY: // to S_PLAY
783 audio->setStreamType(Audio::MPEG2_PES);
784 audio->systemMuteOff();
787 // FIXME use restartAtFrame here?
788 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
789 demuxer->setFrameNum(currentFrameNumber);
794 logger->log("Player", Log::DEBUG, "Immediate play");
805 case S_PAUSE_P: // to S_PAUSE_P
809 case S_PAUSE_I: // to S_PAUSE_I
813 case S_FFWD: // to S_FFWD
817 case S_FBWD: // to S_FBWD
821 case S_STOP: // to S_STOP
825 case S_JUMP: // to S_JUMP
829 case S_JUMP_PI: // to S_JUMP_PI
835 // case S_JUMP cannot be a start state because it auto flips to play
836 // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
840 // ----------------------------------- Internal functions
845 pthread_mutex_lock(&mutex);
846 logger->log("Player", Log::DEBUG, "LOCKED");
849 WaitForSingleObject(mutex, INFINITE);
853 void Player::unLock()
856 logger->log("Player", Log::DEBUG, "UNLOCKING");
857 pthread_mutex_unlock(&mutex);
863 void Player::restartAtFrame(ULONG newFrame)
873 audio->setStreamType(Audio::MPEG2_PES);
876 currentFrameNumber = newFrame;
877 demuxer->setFrameNum(newFrame);
887 audio->systemMuteOff();
892 void Player::restartAtFramePI(ULONG newFrame)
895 ULONG nextiframeNumber;
903 // newFrame could be anywhere, go forwards to next I-Frame
904 if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
906 // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
907 vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
909 buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
910 if (!vdr->isConnected())
912 if (buffer) free(buffer);
917 videoLength = demuxer->stripAudio(buffer, amountReceived);
918 video->displayIFrame(buffer, videoLength);
919 video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
921 currentFrameNumber = iframeNumber;
925 void Player::doConnectionLost()
927 logger->log("Player", Log::DEBUG, "Connection lost, sending message");
928 Message* m = new Message();
929 m->to = messageReceiver;
931 m->message = Message::PLAYER_EVENT;
932 m->parameter = Player::CONNECTION_LOST;
933 messageQueue->postMessage(m);
936 // ----------------------------------- Callback
938 void Player::call(void* caller)
940 if (caller == demuxer)
942 logger->log("Player", Log::DEBUG, "Callback from demuxer");
944 if (video->getTVsize() == Video::ASPECT4X3)
946 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
950 int dxCurrentAspect = demuxer->getAspectRatio();
951 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
953 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
954 video->setAspectRatio(Video::ASPECT4X3);
956 Message* m = new Message();
958 m->to = messageReceiver;
959 m->message = Message::PLAYER_EVENT;
960 m->parameter = Player::ASPECT43;
961 messageQueue->postMessageFromOuterSpace(m);
963 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
965 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
966 video->setAspectRatio(Video::ASPECT16X9);
968 Message* m = new Message();
970 m->to = messageReceiver;
971 m->message = Message::PLAYER_EVENT;
972 m->parameter = Player::ASPECT169;
973 messageQueue->postMessageFromOuterSpace(m);
977 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
985 videoStartup = false;
993 threadSignalNoLock();
997 // ----------------------------------- Feed thread
999 void Player::threadMethod()
1001 // this method used to be simple, the only thing it does
1002 // is farm out to threadFeed Live/Play/Scan
1003 // All the guff is to support scan hitting one end
1005 if ((state == S_FFWD) || (state == S_FBWD))
1008 // if this returns then scan hit one end
1009 if (state == S_FFWD) // scan hit the end. stop
1012 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1013 m->to = messageReceiver;
1015 m->message = Message::PLAYER_EVENT;
1016 m->parameter = STOP_PLAYBACK;
1017 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1018 messageQueue->postMessage(m);
1019 logger->log("Player", Log::DEBUG, "Message posted...");
1022 // if execution gets to here, threadFeedScan hit the start, go to play mode
1025 audio->setStreamType(Audio::MPEG2_PES);
1028 demuxer->setFrameNum(currentFrameNumber);
1029 videoStartup = true;
1036 audio->systemMuteOff();
1040 if (state == S_PLAY) threadFeedPlay();
1043 void Player::threadFeedPlay()
1045 ULLONG feedPosition;
1046 UINT thisRead, writeLength, thisWrite, askFor;
1047 time_t lastRescan = time(NULL);
1049 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1050 if (!vdr->isConnected()) { doConnectionLost(); return; }
1051 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1062 // If we havn't rescanned for a while..
1063 if ((lastRescan + 60) < time(NULL))
1065 lengthBytes = vdr->rescanRecording(&lengthFrames);
1066 if (!vdr->isConnected()) { doConnectionLost(); return; }
1067 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1068 lastRescan = time(NULL);
1071 if (feedPosition >= lengthBytes) break; // finished playback
1075 if (startupBlockSize > lengthBytes)
1076 askFor = lengthBytes; // is a very small recording!
1078 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1082 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1083 askFor = lengthBytes - feedPosition;
1087 //logger->log("Player", Log::DEBUG, "Get Block in");
1089 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1090 //logger->log("Player", Log::DEBUG, "Get Block out");
1092 feedPosition += thisRead;
1094 if (!vdr->isConnected())
1100 if (!threadBuffer) break;
1104 int a_stream = demuxer->scan(threadBuffer, thisRead);
1105 demuxer->setAudioStream(a_stream);
1106 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1112 while(writeLength < thisRead)
1114 //logger->log("Player", Log::DEBUG, "Put in");
1115 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1116 //logger->log("Player", Log::DEBUG, "Put out");
1117 writeLength += thisWrite;
1121 // demuxer is full and can't take anymore
1123 threadWaitForSignal();
1131 threadBuffer = NULL;
1136 logger->log("Player", Log::DEBUG, "Recording playback ends");
1138 if (videoStartup) // oh woe. there never was a stream, I was conned!
1140 videoStartup = false;
1142 MILLISLEEP(500); // I think this will solve a race
1148 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1149 m->to = messageReceiver;
1151 m->message = Message::PLAYER_EVENT;
1152 m->parameter = Player::STOP_PLAYBACK;
1153 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1154 messageQueue->postMessage(m);
1157 void Player::threadFeedScan()
1159 // This method is actually really simple - get frame from vdr,
1160 // spit it at the video chip, wait for a time. Most of the code here
1161 // is to get the wait right so that the scan occurs at the correct rate.
1163 ULONG direction = 0;
1164 ULONG baseFrameNumber = 0;
1165 ULONG iframeNumber = 0;
1166 ULONG iframeLength = 0;
1168 UINT amountReceived;
1172 struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info
1173 struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data
1174 struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1176 DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1179 int frameTimeOffset = 0; // Time in msec between frames
1180 int disp_msec = 0; // Time taken to display data
1181 int total_msec = 0; // Time taken to fetch data and display it
1184 if (state == S_FFWD) direction = 1; // and 0 for backward
1188 // Fetch I-frames until we get one that can be displayed in good time
1189 // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1191 baseFrameNumber = currentFrameNumber;
1195 if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1198 if (iframeNumber >= lengthFrames) return;
1199 // scan has got to the end of what we knew to be there before we started scanning
1201 baseFrameNumber = iframeNumber;
1202 frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));
1204 gettimeofday(&clock0, NULL);
1206 clock0 = timeGetTime();
1210 while (clock2.tv_sec != 0 &&
1211 (clock0.tv_sec - clock2.tv_sec) * 1000 +
1212 (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1214 while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1216 logger->log("Player", Log::DEBUG, "XXX Got frame");
1218 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1220 if (!vdr->isConnected())
1222 if (threadBuffer) free(threadBuffer);
1228 gettimeofday(&clock1, NULL);
1229 if (clock2.tv_sec != 0)
1230 sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1231 + (clock2.tv_usec - clock1.tv_usec) / 1000
1232 + frameTimeOffset - disp_msec;
1234 clock1 = timeGetTime();
1236 sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1238 if (sleepTime < 0) sleepTime = 0;
1240 MILLISLEEP(sleepTime);
1241 logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1243 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1244 video->displayIFrame(threadBuffer, videoLength);
1245 currentFrameNumber = iframeNumber;
1247 threadBuffer = NULL;
1250 gettimeofday(&clock2, NULL);
1251 total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1252 + (clock2.tv_usec - clock0.tv_usec) / 1000
1254 disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1255 + (clock2.tv_usec - clock1.tv_usec) / 1000
1258 clock2 = timeGetTime();
1259 total_msec = clock2 - clock0 - sleepTime;
1260 disp_msec = clock2 - clock1 - sleepTime;
1262 logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1266 void Player::threadPostStopCleanup()
1271 threadBuffer = NULL;
1275 // ----------------------------------- Dev
1278 void Player::test1()
1280 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1283 void Player::test2()
1285 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");