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
23 // ----------------------------------- Called from outside, one offs or info funcs
25 Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, bool tIsRecording)
26 : vfeed(this), afeed(this)
28 messageQueue = tmessageQueue;
29 messageReceiver = tmessageReceiver;
30 audio = Audio::getInstance();
31 video = Video::getInstance();
32 logger = Log::getInstance();
33 vdr = VDR::getInstance();
37 currentFrameNumber = 0;
43 isRecording = tIsRecording;
48 startupBlockSize = 250000;
49 preBufferSize = 500000;
55 if (initted) shutdown();
60 if (initted) return 0;
62 pthread_mutex_init(&mutex, NULL);
64 mutex=CreateMutex(NULL,FALSE,NULL);
68 demuxer = new DemuxerVDR();
70 demuxer = new DemuxerTS();
71 if (!demuxer) return 0;
73 if (!demuxer->init(this, audio, video, 2097152, 524288))
75 logger->log("Player", Log::ERR, "Demuxer failed to init");
91 int Player::shutdown()
93 if (!initted) return 0;
107 void Player::setStartFrame(ULONG startFrame)
109 currentFrameNumber = startFrame;
112 void Player::setLengthBytes(ULLONG length)
114 lengthBytes = length;
115 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
118 void Player::setLengthFrames(ULONG length)
120 lengthFrames = length;
121 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
124 ULONG Player::getLengthFrames()
129 ULONG Player::getCurrentFrameNum()
131 if (startup) return 0;
136 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
140 return currentFrameNumber;
142 return 0; // shouldn't happen
146 bool* Player::getDemuxerMpegAudioChannels()
148 return demuxer->getmpAudioChannels();
151 bool* Player::getDemuxerAc3AudioChannels()
153 return demuxer->getac3AudioChannels();
156 int Player::getCurrentAudioChannel()
158 return demuxer->getselAudioChannel();
161 void Player::setAudioChannel(int newChannel)
163 demuxer->setAudioChannel(newChannel);
166 // ----------------------------------- Externally called events
168 void Player::play(ULONG Vpid, ULONG Apid)
171 DemuxerTS* dts = (DemuxerTS*)demuxer;
179 if (!initted) return;
180 if (state == S_PLAY) return;
183 bool doUnlock = false;
184 if (state == S_PAUSE_P) doUnlock = true;
186 if (doUnlock) unLock();
191 if (!initted) return;
192 if (state == S_STOP) return;
194 logger->log("Player", Log::DEBUG, "Stop called lock");
201 if (!initted) return;
204 if ((state == S_FFWD) || (state == S_FBWD))
206 switchState(S_PAUSE_I);
208 else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
214 switchState(S_PAUSE_P);
220 void Player::fastForward()
222 if (!initted) return;
230 case 4: ifactor = 8; break;
231 case 8: ifactor = 16; break;
232 case 16: ifactor = 32; break;
233 case 32: ifactor = 4; break;
244 void Player::fastBackward()
246 if (!initted) return;
254 case 4: ifactor = 8; break;
255 case 8: ifactor = 16; break;
256 case 16: ifactor = 32; break;
257 case 32: ifactor = 4; break;
268 void Player::jumpToPercent(double percent)
271 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
272 ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
273 switchState(S_JUMP, newFrame);
274 // unLock(); - let thread unlock this
277 void Player::jumpToMark(int mark)
280 logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
281 switchState(S_JUMP, mark);
282 // unLock(); - let thread unlock this
285 void Player::jumpToFrameP(int newFrame)
288 logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
289 switchState(S_JUMP_PI, newFrame);
293 void Player::skipForward(int seconds)
296 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
297 ULONG newFrame = getCurrentFrameNum();
298 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
299 newFrame += seconds * video->getFPS();
300 if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
301 else switchState(S_JUMP, newFrame);
302 // unLock(); - let thread unlock this
305 void Player::skipBackward(int seconds)
308 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
309 long newFrame = getCurrentFrameNum();
310 if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
311 newFrame -= seconds * video->getFPS();
312 if (newFrame < 0) newFrame = 0;
313 switchState(S_JUMP, newFrame);
314 // unLock(); - let thread unlock this
317 // ----------------------------------- Implementations called events
319 void Player::switchState(UCHAR toState, ULONG jumpFrame)
321 if (!initted) return;
323 logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
325 switch(state) // current state selector
327 case S_PLAY: // from S_PLAY -----------------------------------
331 case S_PLAY: // to S_PLAY
335 case S_PAUSE_P: // to S_PAUSE_P
342 case S_PAUSE_I: // to S_PAUSE_I
347 case S_FFWD: // to S_FFWD
349 currentFrameNumber = getCurrentFrameNum();
350 audio->systemMuteOn();
359 case S_FBWD: // to S_FBWD
361 currentFrameNumber = getCurrentFrameNum();
362 audio->systemMuteOn();
371 case S_STOP: // to S_STOP
385 case S_JUMP: // to S_JUMP
387 restartAtFrame(jumpFrame);
390 case S_JUMP_PI: // to S_JUMP_PI
392 audio->systemMuteOn();
400 restartAtFramePI(jumpFrame);
405 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
409 case S_PLAY: // to S_PLAY
416 case S_PAUSE_P: // to S_PAUSE_P
420 case S_PAUSE_I: // to S_PAUSE_I
424 case S_FFWD: // to S_FFWD
426 currentFrameNumber = getCurrentFrameNum();
427 audio->systemMuteOn();
437 case S_FBWD: // to S_FBWD
439 currentFrameNumber = getCurrentFrameNum();
440 audio->systemMuteOn();
450 case S_STOP: // to S_STOP
461 audio->systemMuteOff();
465 case S_JUMP: // to S_JUMP
469 restartAtFrame(jumpFrame);
472 case S_JUMP_PI: // to S_JUMP_PI
474 audio->systemMuteOn();
483 restartAtFramePI(jumpFrame);
488 case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
492 case S_PLAY: // to S_PLAY
495 restartAtFrame(currentFrameNumber);
498 case S_PAUSE_P: // to S_PAUSE_P
502 case S_PAUSE_I: // to S_PAUSE_I
506 case S_FFWD: // to S_FFWD
512 case S_FBWD: // to S_FBWD
518 case S_STOP: // to S_STOP
525 audio->systemMuteOff();
529 case S_JUMP: // to S_JUMP
532 restartAtFrame(jumpFrame);
535 case S_JUMP_PI: // to S_JUMP_PI
537 restartAtFramePI(jumpFrame);
542 case S_FFWD: // from S_FFWD -----------------------------------
546 case S_PLAY: // to S_PLAY
549 restartAtFrame(currentFrameNumber);
552 case S_PAUSE_P: // to S_PAUSE_P
557 case S_PAUSE_I: // to S_PAUSE_I
563 case S_FFWD: // to S_FFWD
567 case S_FBWD: // to S_FBWD
574 case S_STOP: // to S_STOP
585 case S_JUMP: // to S_JUMP
588 restartAtFrame(jumpFrame);
591 case S_JUMP_PI: // to S_JUMP_PI
595 restartAtFramePI(jumpFrame);
600 case S_FBWD: // from S_FBWD -----------------------------------
604 case S_PLAY: // to S_PLAY
607 restartAtFrame(currentFrameNumber);
610 case S_PAUSE_P: // to S_PAUSE_P
615 case S_PAUSE_I: // to S_PAUSE_I
621 case S_FFWD: // to S_FFWD
628 case S_FBWD: // to S_FBWD
632 case S_STOP: // to S_STOP
643 case S_JUMP: // to S_JUMP
646 restartAtFrame(jumpFrame);
649 case S_JUMP_PI: // to S_JUMP_PI
653 restartAtFramePI(jumpFrame);
658 case S_STOP: // from S_STOP -----------------------------------
662 case S_PLAY: // to S_PLAY
667 audio->systemMuteOff();
672 // FIXME use restartAtFrame here?
673 if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
674 demuxer->setFrameNum(currentFrameNumber);
684 logger->log("Player", Log::DEBUG, "Immediate play");
692 else // do prebuffering
694 logger->log("Player", Log::DEBUG, "Prebuffering...");
699 case S_PAUSE_P: // to S_PAUSE_P
703 case S_PAUSE_I: // to S_PAUSE_I
707 case S_FFWD: // to S_FFWD
711 case S_FBWD: // to S_FBWD
715 case S_STOP: // to S_STOP
719 case S_JUMP: // to S_JUMP
723 case S_JUMP_PI: // to S_JUMP_PI
729 // case S_JUMP cannot be a start state because it auto flips to play
730 // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
734 // ----------------------------------- Internal functions
739 pthread_mutex_lock(&mutex);
740 logger->log("Player", Log::DEBUG, "LOCKED");
743 WaitForSingleObject(mutex, INFINITE);
747 void Player::unLock()
750 logger->log("Player", Log::DEBUG, "UNLOCKING");
751 pthread_mutex_unlock(&mutex);
757 void Player::restartAtFrame(ULONG newFrame)
767 currentFrameNumber = newFrame;
768 demuxer->setFrameNum(newFrame);
776 audio->systemMuteOff();
781 void Player::restartAtFramePI(ULONG newFrame)
784 ULONG nextiframeNumber;
792 // newFrame could be anywhere, go forwards to next I-Frame
793 if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
795 // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
796 vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
798 buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
799 videoLength = demuxer->stripAudio(buffer, amountReceived);
800 video->displayIFrame(buffer, videoLength);
801 video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
804 currentFrameNumber = iframeNumber;
807 void Player::doConnectionLost()
809 logger->log("Player", Log::DEBUG, "Connection lost, sending message");
810 Message* m = new Message();
811 m->to = messageReceiver;
813 m->message = Message::PLAYER_EVENT;
814 m->parameter = Player::CONNECTION_LOST;
815 messageQueue->postMessage(m);
818 // ----------------------------------- Callback
820 void Player::call(void* caller)
822 if (caller == demuxer)
824 logger->log("Player", Log::DEBUG, "Callback from demuxer");
826 if (video->getTVsize() == Video::ASPECT4X3)
828 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
832 int dxCurrentAspect = demuxer->getAspectRatio();
833 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
835 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
836 video->setAspectRatio(Video::ASPECT4X3);
838 Message* m = new Message();
840 m->to = messageReceiver;
841 m->message = Message::PLAYER_EVENT;
842 m->parameter = Player::ASPECT43;
843 messageQueue->postMessageFromOuterSpace(m);
845 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
847 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
848 video->setAspectRatio(Video::ASPECT16X9);
850 Message* m = new Message();
852 m->to = messageReceiver;
853 m->message = Message::PLAYER_EVENT;
854 m->parameter = Player::ASPECT169;
855 messageQueue->postMessageFromOuterSpace(m);
859 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
867 videoStartup = false;
875 threadSignalNoLock();
879 // ----------------------------------- Feed thread
881 void Player::threadMethod()
883 // this method used to be simple, the only thing it does
884 // is farm out to threadFeed Live/Play/Scan
885 // All the guff is to support scan hitting one end
889 if ((state == S_FFWD) || (state == S_FBWD))
892 // if this returns then scan hit one end
893 if (state == S_FFWD) // scan hit the end. stop
896 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
897 m->to = messageReceiver;
899 m->message = Message::PLAYER_EVENT;
900 m->parameter = STOP_PLAYBACK;
901 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
902 messageQueue->postMessage(m);
903 logger->log("Player", Log::DEBUG, "Message posted...");
906 // if execution gets to here, threadFeedScan hit the start, go to play mode
911 demuxer->setFrameNum(currentFrameNumber);
917 audio->systemMuteOff();
921 if (state == S_PLAY) threadFeedPlay();
929 void Player::threadFeedLive()
934 UINT preBufferTotal = 0;
946 askFor = startupBlockSize; // find audio streams sized block
948 askFor = blockSize; // normal
950 threadBuffer = vdr->getBlock(0, askFor, &thisRead);
952 if (!vdr->isConnected())
958 if (!threadBuffer) break;
962 int a_stream = demuxer->scan(threadBuffer, thisRead);
963 demuxer->setAudioStream(a_stream);
964 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
970 preBufferTotal += thisRead;
971 if (preBufferTotal >= preBufferSize)
973 logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
975 preBuffering = false;
979 // FIXME check the win32 code on the mvp
996 // unLock(); // thread will be locked by play until here
997 // FIXME - see if this can segfault because it is starting threads out of the master mutex
1003 while(writeLength < thisRead)
1005 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1006 writeLength += thisWrite;
1008 // logger->log("Player", Log::DEBUG, "Player put %u to demuxer", thisWrite);
1012 // logger->log("Player", Log::DEBUG, "Demuxer full");
1013 // demuxer is full and can't take anymore
1015 threadWaitForSignal();
1023 threadBuffer = NULL;
1027 logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
1029 if (videoStartup) // oh woe. there never was a stream, I was conned!
1031 videoStartup = false;
1033 MILLISLEEP(500); // I think this will solve a race
1038 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1039 m->to = messageReceiver;
1041 m->message = Message::PLAYER_EVENT;
1042 m->parameter = Player::STREAM_END;
1043 logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1044 messageQueue->postMessage(m);
1045 logger->log("Player", Log::DEBUG, "Message posted...");
1048 void Player::threadFeedPlay()
1050 ULLONG feedPosition;
1051 UINT thisRead, writeLength, thisWrite, askFor;
1052 time_t lastRescan = time(NULL);
1054 feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1055 if (!vdr->isConnected()) { doConnectionLost(); return; }
1056 logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1067 // If we havn't rescanned for a while..
1068 if ((lastRescan + 60) < time(NULL))
1070 lengthBytes = vdr->rescanRecording(&lengthFrames);
1071 if (!vdr->isConnected()) { doConnectionLost(); return; }
1072 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1073 lastRescan = time(NULL);
1076 if (feedPosition >= lengthBytes) break; // finished playback
1080 if (startupBlockSize > lengthBytes)
1081 askFor = lengthBytes; // is a very small recording!
1083 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1087 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1088 askFor = lengthBytes - feedPosition;
1093 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1094 feedPosition += thisRead;
1096 if (!vdr->isConnected())
1102 if (!threadBuffer) break;
1106 int a_stream = demuxer->scan(threadBuffer, thisRead);
1107 demuxer->setAudioStream(a_stream);
1108 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1114 while(writeLength < thisRead)
1116 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
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
1190 baseFrameNumber = currentFrameNumber;
1193 if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1196 if (iframeNumber >= lengthFrames) return;
1197 // scan has got to the end of what we knew to be there before we started scanning
1199 baseFrameNumber = iframeNumber;
1200 frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1202 gettimeofday(&clock0, NULL);
1204 clock0 = timeGetTime();
1208 while (clock2.tv_sec != 0 &&
1209 (clock0.tv_sec - clock2.tv_sec) * 1000 +
1210 (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1212 while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1214 // logger->log("Player", Log::DEBUG, "XXX Got frame");
1216 threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1218 gettimeofday(&clock1, NULL);
1219 if (clock2.tv_sec != 0)
1220 sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1221 + (clock2.tv_usec - clock1.tv_usec) / 1000
1222 + frameTimeOffset - disp_msec;
1224 clock1 = timeGetTime();
1226 sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1228 if (sleepTime < 0) sleepTime = 0;
1230 MILLISLEEP(sleepTime);
1231 // logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1233 videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1234 video->displayIFrame(threadBuffer, videoLength);
1235 currentFrameNumber = iframeNumber;
1237 threadBuffer = NULL;
1240 gettimeofday(&clock2, NULL);
1241 total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1242 + (clock2.tv_usec - clock0.tv_usec) / 1000
1244 disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1245 + (clock2.tv_usec - clock1.tv_usec) / 1000
1248 clock2 = timeGetTime();
1249 total_msec = clock2 - clock0 - sleepTime;
1250 disp_msec = clock2 - clock1 - sleepTime;
1252 // logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1256 void Player::threadPostStopCleanup()
1261 threadBuffer = NULL;
1265 // ----------------------------------- Dev
1268 void Player::test1()
1270 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1272 // video->setAspectRatio(Video::ASPECT4X3);
1273 jumpToFrameP(37507);
1276 void Player::test2()
1278 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1279 video->setAspectRatio(Video::ASPECT16X9);