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* messageQueue, bool tIsRecording, bool tIsRadio)
26 : vfeed(this), afeed(this)
28 commandMessageQueue = messageQueue;
29 audio = Audio::getInstance();
30 video = Video::getInstance();
31 logger = Log::getInstance();
40 feedMode = MODE_NORMAL;
47 isRecording = tIsRecording;
55 startupBlockSize = 60000;
56 video->turnVideoOff();
61 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;
83 if (!demuxer->init(this, audio, video))
85 logger->log("Player", Log::ERR, "Demuxer failed to init");
101 int Player::shutdown()
103 if (!initted) return 0;
131 void Player::setStartFrame(ULONG startFrame)
133 startFrameNum = startFrame;
136 feedPosition = VDR::getInstance()->positionFromFrameNumber(startFrameNum);
144 void Player::setLengthBytes(ULLONG length)
146 lastRescan = time(NULL);
147 lengthBytes = length;
148 logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
151 void Player::setLengthFrames(ULONG length)
153 lengthFrames = length;
154 logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
157 ULONG Player::getLengthFrames()
162 ULONG Player::getCurrentFrameNum()
164 if (startup) return 0;
165 return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
168 // ----------------------------------- Externally called events
173 bool doUnlock = false;
174 int result = playInt(&doUnlock);
175 if (doUnlock) unLock();
182 logger->log("Player", Log::DEBUG, "Stop called lock");
187 void Player::togglePause()
194 void Player::toggleFastForward()
197 toggleFastForwardInt();
201 void Player::toggleFastBackward()
204 toggleFastBackwardInt();
208 void Player::jumpToPercent(int percent)
211 jumpToPercentInt(percent);
212 // unLock(); - let thread unlock this
215 void Player::skipForward(int seconds)
218 skipForwardInt(seconds);
219 // unLock(); - let thread unlock this
222 void Player::skipBackward(int seconds)
225 skipBackwardInt(seconds);
226 // unLock(); - let thread unlock this
229 // ----------------------------------- Implementations called events
232 int Player::playInt(bool* doUnlock)
234 if (!initted) return 0;
236 // If we are just paused, unpause!
244 // If we are fast forwarding, set to normal
247 toggleFastForwardInt();
251 // If we are fast backwarding, set to normal
254 toggleFastBackwardInt();
258 // If we are already playing, ignore. no resyncing to do now!
265 // Standard play start
266 logger->log("Player", Log::DEBUG, "Standard play start");
275 if (startFrameNum > lengthFrames) startFrameNum = 0;
276 demuxer->setFrameNum(startFrameNum);
278 if (!isRadio) demuxer->seek();
285 logger->log("Player", Log::DEBUG, "Immediate play");
293 else // do prebuffering
295 logger->log("Player", Log::DEBUG, "Prebuffering...");
305 void Player::stopInt()
307 if (!initted) return;
308 if (!playing) return;
315 video->unFastForward();
316 audio->systemMuteOff();
317 feedMode = MODE_NORMAL;
325 if (threadIsActive()) threadStop();
336 void Player::togglePauseInt()
338 if (!initted) return;
339 if (!playing) return;
341 if (ffwd) toggleFastForwardInt();
342 if (fbwd) toggleFastBackwardInt();
358 void Player::toggleFastForwardInt()
360 if (!initted) return;
361 if (!playing) return;
363 if (paused) togglePauseInt();
364 if (fbwd) toggleFastBackwardInt();
377 if (!isRadio) demuxer->seek();
387 audio->systemMuteOff();
397 audio->systemMuteOn();
398 video->fastForward();
402 void Player::toggleFastBackwardInt()
404 if (!initted) return;
405 if (!playing) return;
407 if (paused) togglePauseInt();
408 if (ffwd) toggleFastForwardInt();
414 audio->systemMuteOff();
417 feedMode = MODE_NORMAL;
426 audio->systemMuteOn();
429 feedMode = MODE_BACKWARDS;
433 if (!isRadio) demuxer->seek();
439 void Player::skipForwardInt(int seconds)
441 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
442 restartAtFrame(getCurrentFrameNum() + (seconds * video->getFPS()));
445 void Player::skipBackwardInt(int seconds)
447 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
448 long newFrameNum = getCurrentFrameNum() - (seconds * video->getFPS());
449 if (newFrameNum < 0) newFrameNum = 0;
450 restartAtFrame(newFrameNum);
453 void Player::jumpToPercentInt(int percent)
455 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
456 ULONG newFrame = percent * lengthFrames / 100;
457 restartAtFrame(newFrame);
461 // ----------------------------------- Internal functions
466 pthread_mutex_lock(&mutex);
467 logger->log("Player", Log::DEBUG, "LOCKED");
470 WaitForSingleObject(mutex, INFINITE );
474 void Player::unLock()
477 logger->log("Player", Log::DEBUG, "UNLOCKING");
478 pthread_mutex_unlock(&mutex);
484 void Player::restartAtFrame(ULONG newFrame)
486 if (paused) togglePauseInt();
487 if (ffwd) toggleFastForwardInt();
489 ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(newFrame);
490 if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
491 logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", newFrame, feedPosition, newPosition);
500 if (!isRadio) demuxer->seek();
501 feedPosition = newPosition;
502 demuxer->setFrameNum(newFrame);
510 audio->systemMuteOff();
515 void Player::doConnectionLost()
517 Message* m = new Message();
518 m->message = Message::CONNECTION_LOST;
520 commandMessageQueue->postMessage(m);
523 // ----------------------------------- Callback
525 void Player::call(void* caller)
527 if (caller == demuxer)
529 logger->log("Player", Log::DEBUG, "Callback from demuxer");
531 if (video->getTVsize() == Video::ASPECT4X3)
533 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
537 int dxCurrentAspect = demuxer->getAspectRatio();
538 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
540 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
541 video->setAspectRatio(Video::ASPECT4X3);
543 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
545 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
546 video->setAspectRatio(Video::ASPECT16X9);
550 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
558 videoStartup = false;
566 threadSignalNoLock();
570 // ----------------------------------- Feed thread
572 void Player::threadMethod()
577 UINT preBufferTotal = 0;
579 VDR* vdr = VDR::getInstance();
590 // If we havn't rescanned for a while..
591 if (isRecording && ((lastRescan + 60) < time(NULL)))
593 lengthBytes = vdr->rescanRecording(&lengthFrames);
594 if (!vdr->isConnected()) { doConnectionLost(); return; }
595 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
596 lastRescan = time(NULL);
600 if (lengthBytes) // is playing a recording
602 if (feedPosition >= lengthBytes) break; // finished playback
606 if (startupBlockSize > lengthBytes)
607 askFor = lengthBytes; // is a very small recording!
609 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
613 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
614 askFor = lengthBytes - feedPosition;
619 else // is playing live
622 askFor = startupBlockSize; // find audio streams sized block
624 askFor = blockSize; // normal
627 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
629 if (!vdr->isConnected())
635 if (!threadBuffer) break;
639 int a_stream = demuxer->scan(threadBuffer, thisRead);
640 demuxer->setAudioStream(a_stream);
641 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
643 // setStartTS(thisRead);
645 // if (isRecording) setEndTS();
652 preBufferTotal += thisRead;
653 if (preBufferTotal > 500000)
655 logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
657 preBuffering = false;
666 // unLock(); // thread will be locked by play until here
667 // FIXME - see if this can segfault because it is starting threads out of the master mutex
671 if (feedMode == MODE_NORMAL)
673 feedPosition += thisRead;
675 else if (feedMode == MODE_BACKWARDS)
677 if (feedPosition >= blockSize)
679 feedPosition -= blockSize;
680 if (!isRadio) demuxer->seek();
684 // got to the start of the recording.. revert to play mode? how?
685 feedPosition += thisRead;
691 while(writeLength < thisRead)
693 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
694 writeLength += thisWrite;
695 // logger->log("Player", Log::DEBUG, "Put %i to demuxer", thisWrite);
699 // logger->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
700 // demuxer is full and can't take anymore
702 threadWaitForSignal();
704 // logger->log("Player", Log::DEBUG, "BACK FROM WAIT");
716 logger->log("Player", Log::DEBUG, "Recording playback ends");
718 if (videoStartup) // oh woe. there never was a stream, I was conned!
720 videoStartup = false;
722 MILLISLEEP(500); // I think this will solve a race
727 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
728 if (lengthBytes) m->message = Message::STOP_PLAYBACK; // recording
729 else m->message = Message::STREAM_END; // live
730 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
731 commandMessageQueue->postMessage(m);
732 logger->log("Player", Log::DEBUG, "Message posted...");
735 void Player::threadPostStopCleanup()
744 // ----------------------------------- Dev
749 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
751 // video->setAspectRatio(Video::ASPECT4X3);
756 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
757 video->setAspectRatio(Video::ASPECT16X9);