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
26 #include "demuxervdr.h"
27 #include "demuxerts.h"
29 #include "messagequeue.h"
33 #define USER_RESPONSE_TIME 500 // Milliseconds
35 // ----------------------------------- Called from outside, one offs or info funcs
37 Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, bool tIsRecording)
38 : vfeed(this), afeed(this)
40 messageQueue = tmessageQueue;
41 messageReceiver = tmessageReceiver;
42 audio = Audio::getInstance();
43 video = Video::getInstance();
44 logger = Log::getInstance();
45 vdr = VDR::getInstance();
49 currentFrameNumber = 0;
55 isRecording = tIsRecording;
60 startupBlockSize = 250000;
61 preBufferSize = 500000;
67 if (initted) shutdown();
72 if (initted) return 0;
74 pthread_mutex_init(&mutex, NULL);
76 mutex=CreateMutex(NULL,FALSE,NULL);
80 demuxer = new DemuxerVDR();
82 demuxer = new DemuxerTS();
83 if (!demuxer) return 0;
85 if (!demuxer->init(this, audio, video, 2097152, 524288))
87 logger->log("Player", Log::ERR, "Demuxer failed to init");
103 int Player::shutdown()
105 if (!initted) return 0;
119 void Player::setStartFrame(ULONG startFrame)
121 currentFrameNumber = startFrame;
124 void Player::setLengthBytes(ULLONG length)
126 lengthBytes = length;
127 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
130 void Player::setLengthFrames(ULONG length)
132 lengthFrames = length;
133 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
136 ULONG Player::getLengthFrames()
141 ULONG Player::getCurrentFrameNum()
143 if (startup) return 0;
148 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
152 return currentFrameNumber;
154 return 0; // shouldn't happen
158 bool* Player::getDemuxerMpegAudioChannels()
160 return demuxer->getmpAudioChannels();
163 bool* Player::getDemuxerAc3AudioChannels()
165 return demuxer->getac3AudioChannels();
168 int Player::getCurrentAudioChannel()
170 return demuxer->getselAudioChannel();
173 void Player::setAudioChannel(int newChannel)
176 demuxer->setAudioChannel(newChannel);
178 ((DemuxerTS*)demuxer)->setAID(newChannel);
181 // ----------------------------------- Externally called events
183 void Player::play(ULONG Vpid, ULONG Apid)
186 DemuxerTS* dts = (DemuxerTS*)demuxer;
194 if (!initted) return;
195 if (state == S_PLAY) return;
198 bool doUnlock = false;
199 if (state == S_PAUSE_P) doUnlock = true;
201 if (doUnlock) unLock();
206 if (!initted) return;
207 if (state == S_STOP) return;
209 logger->log("Player", Log::DEBUG, "Stop called lock");
216 if (!initted) return;
219 if ((state == S_FFWD) || (state == S_FBWD))
221 switchState(S_PAUSE_I);
223 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
229 switchState(S_PAUSE_P);
235 void Player::fastForward()
237 if (!initted) return;
245 case 4: ifactor = 8; break;
246 case 8: ifactor = 16; break;
247 case 16: ifactor = 32; break;
248 case 32: ifactor = 4; break;
259 void Player::fastBackward()
261 if (!initted) return;
269 case 4: ifactor = 8; break;
270 case 8: ifactor = 16; break;
271 case 16: ifactor = 32; break;
272 case 32: ifactor = 4; break;
283 void Player::jumpToPercent(double percent)
286 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
287 ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
288 switchState(S_JUMP, newFrame);
289 // unLock(); - let thread unlock this
292 void Player::jumpToMark(int mark)
295 logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
296 switchState(S_JUMP, mark);
297 // unLock(); - let thread unlock this
300 void Player::jumpToFrameP(int newFrame)
303 logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
304 switchState(S_JUMP_PI, newFrame);
308 void Player::skipForward(int seconds)
311 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
312 ULONG newFrame = getCurrentFrameNum();
313 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
314 newFrame += seconds * video->getFPS();
315 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
316 else switchState(S_JUMP, newFrame);
317 // unLock(); - let thread unlock this
320 void Player::skipBackward(int seconds)
323 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
324 long newFrame = getCurrentFrameNum();
325 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
326 newFrame -= seconds * video->getFPS();
327 if (newFrame < 0) newFrame = 0;
328 switchState(S_JUMP, newFrame);
329 // unLock(); - let thread unlock this
332 // ----------------------------------- Implementations called events
334 void Player::switchState(UCHAR toState, ULONG jumpFrame)
336 if (!initted) return;
338 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
340 switch(state) // current state selector
342 case S_PLAY: // from S_PLAY -----------------------------------
346 case S_PLAY: // to S_PLAY
350 case S_PAUSE_P: // to S_PAUSE_P
357 case S_PAUSE_I: // to S_PAUSE_I
362 case S_FFWD: // to S_FFWD
364 currentFrameNumber = getCurrentFrameNum();
365 audio->systemMuteOn();
374 case S_FBWD: // to S_FBWD
376 currentFrameNumber = getCurrentFrameNum();
377 audio->systemMuteOn();
386 case S_STOP: // to S_STOP
400 case S_JUMP: // to S_JUMP
402 restartAtFrame(jumpFrame);
405 case S_JUMP_PI: // to S_JUMP_PI
407 audio->systemMuteOn();
415 restartAtFramePI(jumpFrame);
420 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
424 case S_PLAY: // to S_PLAY
431 case S_PAUSE_P: // to S_PAUSE_P
435 case S_PAUSE_I: // to S_PAUSE_I
439 case S_FFWD: // to S_FFWD
441 currentFrameNumber = getCurrentFrameNum();
442 audio->systemMuteOn();
452 case S_FBWD: // to S_FBWD
454 currentFrameNumber = getCurrentFrameNum();
455 audio->systemMuteOn();
465 case S_STOP: // to S_STOP
476 audio->systemMuteOff();
480 case S_JUMP: // to S_JUMP
483 audio->systemMuteOn();
485 restartAtFrame(jumpFrame);
488 case S_JUMP_PI: // to S_JUMP_PI
490 audio->systemMuteOn();
499 restartAtFramePI(jumpFrame);
504 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
508 case S_PLAY: // to S_PLAY
511 restartAtFrame(currentFrameNumber);
514 case S_PAUSE_P: // to S_PAUSE_P
518 case S_PAUSE_I: // to S_PAUSE_I
522 case S_FFWD: // to S_FFWD
528 case S_FBWD: // to S_FBWD
534 case S_STOP: // to S_STOP
541 audio->systemMuteOff();
545 case S_JUMP: // to S_JUMP
548 restartAtFrame(jumpFrame);
551 case S_JUMP_PI: // to S_JUMP_PI
553 restartAtFramePI(jumpFrame);
558 case S_FFWD: // from S_FFWD -----------------------------------
562 case S_PLAY: // to S_PLAY
565 ULONG stepback = USER_RESPONSE_TIME * video->getFPS() * ifactor / 1000;
566 if (stepback < currentFrameNumber)
567 currentFrameNumber -= stepback;
569 currentFrameNumber = 0;
570 restartAtFrame(currentFrameNumber);
573 case S_PAUSE_P: // to S_PAUSE_P
578 case S_PAUSE_I: // to S_PAUSE_I
584 case S_FFWD: // to S_FFWD
588 case S_FBWD: // to S_FBWD
595 case S_STOP: // to S_STOP
606 case S_JUMP: // to S_JUMP
609 restartAtFrame(jumpFrame);
612 case S_JUMP_PI: // to S_JUMP_PI
616 restartAtFramePI(jumpFrame);
621 case S_FBWD: // from S_FBWD -----------------------------------
625 case S_PLAY: // to S_PLAY
628 restartAtFrame(currentFrameNumber);
631 case S_PAUSE_P: // to S_PAUSE_P
636 case S_PAUSE_I: // to S_PAUSE_I
642 case S_FFWD: // to S_FFWD
649 case S_FBWD: // to S_FBWD
653 case S_STOP: // to S_STOP
664 case S_JUMP: // to S_JUMP
667 restartAtFrame(jumpFrame);
670 case S_JUMP_PI: // to S_JUMP_PI
674 restartAtFramePI(jumpFrame);
679 case S_STOP: // from S_STOP -----------------------------------
683 case S_PLAY: // to S_PLAY
688 audio->setStreamType(Audio::MPEG2_PES);
689 audio->systemMuteOff();
694 // FIXME use restartAtFrame here?
695 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
696 demuxer->setFrameNum(currentFrameNumber);
706 logger->log("Player", Log::DEBUG, "Immediate play");
714 else // do prebuffering
716 logger->log("Player", Log::DEBUG, "Prebuffering...");
721 case S_PAUSE_P: // to S_PAUSE_P
725 case S_PAUSE_I: // to S_PAUSE_I
729 case S_FFWD: // to S_FFWD
733 case S_FBWD: // to S_FBWD
737 case S_STOP: // to S_STOP
741 case S_JUMP: // to S_JUMP
745 case S_JUMP_PI: // to S_JUMP_PI
751 // case S_JUMP cannot be a start state because it auto flips to play
752 // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
756 // ----------------------------------- Internal functions
761 pthread_mutex_lock(&mutex);
762 logger->log("Player", Log::DEBUG, "LOCKED");
765 WaitForSingleObject(mutex, INFINITE);
769 void Player::unLock()
772 logger->log("Player", Log::DEBUG, "UNLOCKING");
773 pthread_mutex_unlock(&mutex);
779 void Player::restartAtFrame(ULONG newFrame)
787 audio->setStreamType(Audio::MPEG2_PES);
790 currentFrameNumber = newFrame;
791 demuxer->setFrameNum(newFrame);
799 audio->systemMuteOff();
804 void Player::restartAtFramePI(ULONG newFrame)
807 ULONG nextiframeNumber;
815 // newFrame could be anywhere, go forwards to next I-Frame
816 if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
818 // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
819 vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
821 buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
822 videoLength = demuxer->stripAudio(buffer, amountReceived);
823 video->displayIFrame(buffer, videoLength);
824 video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
827 currentFrameNumber = iframeNumber;
830 void Player::doConnectionLost()
832 logger->log("Player", Log::DEBUG, "Connection lost, sending message");
833 Message* m = new Message();
834 m->to = messageReceiver;
836 m->message = Message::PLAYER_EVENT;
837 m->parameter = Player::CONNECTION_LOST;
838 messageQueue->postMessage(m);
841 // ----------------------------------- Callback
843 void Player::call(void* caller)
845 if (caller == demuxer)
847 logger->log("Player", Log::DEBUG, "Callback from demuxer");
849 if (video->getTVsize() == Video::ASPECT4X3)
851 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
855 int dxCurrentAspect = demuxer->getAspectRatio();
856 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
858 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
859 video->setAspectRatio(Video::ASPECT4X3);
861 Message* m = new Message();
863 m->to = messageReceiver;
864 m->message = Message::PLAYER_EVENT;
865 m->parameter = Player::ASPECT43;
866 messageQueue->postMessageFromOuterSpace(m);
868 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
870 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
871 video->setAspectRatio(Video::ASPECT16X9);
873 Message* m = new Message();
875 m->to = messageReceiver;
876 m->message = Message::PLAYER_EVENT;
877 m->parameter = Player::ASPECT169;
878 messageQueue->postMessageFromOuterSpace(m);
882 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
890 videoStartup = false;
898 threadSignalNoLock();
902 // ----------------------------------- Feed thread
904 void Player::threadMethod()
906 // this method used to be simple, the only thing it does
907 // is farm out to threadFeed Live/Play/Scan
908 // All the guff is to support scan hitting one end
912 if ((state == S_FFWD) || (state == S_FBWD))
915 // if this returns then scan hit one end
916 if (state == S_FFWD) // scan hit the end. stop
919 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
920 m->to = messageReceiver;
922 m->message = Message::PLAYER_EVENT;
923 m->parameter = STOP_PLAYBACK;
924 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
925 messageQueue->postMessage(m);
926 logger->log("Player", Log::DEBUG, "Message posted...");
929 // if execution gets to here, threadFeedScan hit the start, go to play mode
932 audio->setStreamType(Audio::MPEG2_PES);
935 demuxer->setFrameNum(currentFrameNumber);
941 audio->systemMuteOff();
945 if (state == S_PLAY) threadFeedPlay();
953 void Player::threadFeedLive()
958 UINT preBufferTotal = 0;
970 askFor = startupBlockSize; // find audio streams sized block
972 askFor = blockSize; // normal
974 threadBuffer = vdr->getBlock(0, askFor, &thisRead);
976 if (!vdr->isConnected())
982 if (!threadBuffer) break;
986 int a_stream = demuxer->scan(threadBuffer, thisRead);
987 demuxer->setAudioStream(a_stream);
988 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
994 preBufferTotal += thisRead;
995 if (preBufferTotal >= preBufferSize)
997 logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
999 preBuffering = false;
1003 // FIXME check the win32 code on the mvp
1020 // unLock(); // thread will be locked by play until here
1021 // FIXME - see if this can segfault because it is starting threads out of the master mutex
1027 while(writeLength < thisRead)
1029 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1030 writeLength += thisWrite;
1032 // logger->log("Player", Log::DEBUG, "Player put %u to demuxer", thisWrite);
1036 // logger->log("Player", Log::DEBUG, "Demuxer full");
1037 // demuxer is full and can't take anymore
1039 threadWaitForSignal();
1047 threadBuffer = NULL;
1051 logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
1053 if (videoStartup) // oh woe. there never was a stream, I was conned!
1055 videoStartup = false;
1057 MILLISLEEP(500); // I think this will solve a race
1062 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1063 m->to = messageReceiver;
1065 m->message = Message::PLAYER_EVENT;
1066 m->parameter = Player::STREAM_END;
1067 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1068 messageQueue->postMessage(m);
1069 logger->log("Player", Log::DEBUG, "Message posted...");
1072 void Player::threadFeedPlay()
1074 ULLONG feedPosition;
1075 UINT thisRead, writeLength, thisWrite, askFor;
1076 time_t lastRescan = time(NULL);
1078 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1079 if (!vdr->isConnected()) { doConnectionLost(); return; }
1080 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1091 // If we havn't rescanned for a while..
1092 if ((lastRescan + 60) < time(NULL))
1094 lengthBytes = vdr->rescanRecording(&lengthFrames);
1095 if (!vdr->isConnected()) { doConnectionLost(); return; }
1096 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1097 lastRescan = time(NULL);
1100 if (feedPosition >= lengthBytes) break; // finished playback
1104 if (startupBlockSize > lengthBytes)
1105 askFor = lengthBytes; // is a very small recording!
1107 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1111 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1112 askFor = lengthBytes - feedPosition;
1117 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1118 feedPosition += thisRead;
1120 if (!vdr->isConnected())
1126 if (!threadBuffer) break;
1130 int a_stream = demuxer->scan(threadBuffer, thisRead);
1131 demuxer->setAudioStream(a_stream);
1132 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1138 while(writeLength < thisRead)
1140 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1141 writeLength += thisWrite;
1145 // demuxer is full and can't take anymore
1147 threadWaitForSignal();
1155 threadBuffer = NULL;
1160 logger->log("Player", Log::DEBUG, "Recording playback ends");
1162 if (videoStartup) // oh woe. there never was a stream, I was conned!
1164 videoStartup = false;
1166 MILLISLEEP(500); // I think this will solve a race
1172 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1173 m->to = messageReceiver;
1175 m->message = Message::PLAYER_EVENT;
1176 m->parameter = Player::STOP_PLAYBACK;
1177 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1178 messageQueue->postMessage(m);
1181 void Player::threadFeedScan()
1183 // This method is actually really simple - get frame from vdr,
1184 // spit it at the video chip, wait for a time. Most of the code here
1185 // is to get the wait right so that the scan occurs at the correct rate.
1187 ULONG direction = 0;
1188 ULONG baseFrameNumber = 0;
1189 ULONG iframeNumber = 0;
1190 ULONG iframeLength = 0;
1192 UINT amountReceived;
1196 struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info
1197 struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data
1198 struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1200 DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1203 int frameTimeOffset = 0; // Time in msec between frames
1204 int disp_msec = 0; // Time taken to display data
1205 int total_msec = 0; // Time taken to fetch data and display it
1208 if (state == S_FFWD) direction = 1; // and 0 for backward
1212 // Fetch I-frames until we get one that can be displayed in good time
1213 // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1214 baseFrameNumber = currentFrameNumber;
1218 if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1221 if (iframeNumber >= lengthFrames) return;
1222 // scan has got to the end of what we knew to be there before we started scanning
1224 baseFrameNumber = iframeNumber;
1225 frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1227 gettimeofday(&clock0, NULL);
1229 clock0 = timeGetTime();
1233 while (clock2.tv_sec != 0 &&
1234 (clock0.tv_sec - clock2.tv_sec) * 1000 +
1235 (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1237 while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1239 // logger->log("Player", Log::DEBUG, "XXX Got frame");
1241 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1243 gettimeofday(&clock1, NULL);
1244 if (clock2.tv_sec != 0)
1245 sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1246 + (clock2.tv_usec - clock1.tv_usec) / 1000
1247 + frameTimeOffset - disp_msec;
1249 clock1 = timeGetTime();
1251 sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1253 if (sleepTime < 0) sleepTime = 0;
1255 MILLISLEEP(sleepTime);
1256 // logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1258 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1259 video->displayIFrame(threadBuffer, videoLength);
1260 currentFrameNumber = iframeNumber;
1262 threadBuffer = NULL;
1265 gettimeofday(&clock2, NULL);
1266 total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1267 + (clock2.tv_usec - clock0.tv_usec) / 1000
1269 disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1270 + (clock2.tv_usec - clock1.tv_usec) / 1000
1273 clock2 = timeGetTime();
1274 total_msec = clock2 - clock0 - sleepTime;
1275 disp_msec = clock2 - clock1 - sleepTime;
1277 // logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1281 void Player::threadPostStopCleanup()
1286 threadBuffer = NULL;
1290 // ----------------------------------- Dev
1293 void Player::test1()
1295 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1297 // video->setAspectRatio(Video::ASPECT4X3);
1298 jumpToFrameP(37507);
1301 void Player::test2()
1303 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1304 video->setAspectRatio(Video::ASPECT16X9);