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 Player::Player(MessageQueue* messageQueue, bool tIsRecording, bool tIsRadio)
24 : vfeed(this), afeed(this)
26 commandMessageQueue = messageQueue;
27 audio = Audio::getInstance();
28 video = Video::getInstance();
29 logger = Log::getInstance();
37 feedMode = MODE_NORMAL;
44 isRecording = tIsRecording;
52 startupBlockSize = 60000;
53 video->turnVideoOff();
58 startupBlockSize = 250000;
65 if (initted) shutdown();
66 if (demuxer != NULL) delete demuxer;
71 if (initted) return 0;
73 demuxer = new DemuxerVDR;
75 if (demuxer == NULL) return 0;
77 if (!demuxer->init(this))
79 logger->log("Player", Log::ERR, "Demuxer failed to init");
84 vfeed.init(video->getFD());
85 afeed.init(audio->getFD());
99 int Player::shutdown()
101 if (!initted) return 0;
124 if (!initted) return 0;
126 // If we are just paused, unpause!
133 // If we are still seeking in from the last jump, ignore
134 if (videoStartup) return 1;
136 // If we are fast forwarding, set to normal
143 // If we are fast backwarding, set to normal
146 toggleFastBackward();
150 // Standard play start
151 logger->log("Player", Log::DEBUG, "Standard play start");
158 if (!isRadio) demuxer->seek();
165 logger->log("Player", Log::DEBUG, "Immediate play");
173 else // do prebuffering
175 logger->log("Player", Log::DEBUG, "Prebuffering...");
179 // ------------------------------------------------------------------------------------------------
187 if (!initted) return;
188 if (!playing) return;
190 // If we are still seeking in from the last jump, ignore
191 if (videoStartup) return;
198 video->unFastForward();
199 audio->systemMuteOff();
200 feedMode = MODE_NORMAL;
219 void Player::togglePause()
221 if (!initted) return;
222 if (!playing) return;
224 if (ffwd) toggleFastForward();
225 if (fbwd) toggleFastBackward();
241 void Player::setPosition(ULLONG position)
243 feedPosition = position;
246 void Player::setLength(ULLONG length)
248 lastRescan = time(NULL);
249 streamLength = length;
250 logger->log("Player", Log::DEBUG, "Player has received length of %llu", streamLength);
253 void Player::restartAt(ULLONG timecode)
255 // If we are still seeking in from the last jump, ignore
256 if (videoStartup) return;
258 if (paused) togglePause();
259 if (ffwd) toggleFastForward();
261 ULONG wantedFrameNumber = video->timecodeToFrameNumber(timecode);
262 ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(wantedFrameNumber);
263 if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
264 logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", wantedFrameNumber, feedPosition, newPosition);
273 if (!isRadio) demuxer->seek();
274 feedPosition = newPosition;
282 audio->systemMuteOff();
287 void Player::skipForward(int seconds)
289 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
290 restartAt(getPositionTS() + (seconds * 90000));
293 void Player::skipBackward(int seconds)
295 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
296 long long newTimeCode = getPositionTS() - (seconds * 90000);
297 if (newTimeCode < 0) newTimeCode = 0;
298 restartAt(newTimeCode);
301 void Player::jumpToPercent(int percent)
303 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
304 ULLONG newTimeCode = (ULLONG)(getEndTS() * ((float)percent / 100));
305 restartAt(newTimeCode);
308 void Player::toggleFastForward()
310 if (!initted) return;
311 if (!playing) return;
313 // If we are still seeking in from the last jump, ignore
314 if (videoStartup) return;
316 if (paused) togglePause();
317 if (fbwd) toggleFastBackward();
330 if (!isRadio) demuxer->seek();
340 audio->systemMuteOff();
348 audio->systemMuteOn();
349 video->fastForward();
353 void Player::toggleFastBackward()
355 if (!initted) return;
356 if (!playing) return;
358 // If we are still seeking in from the last jump, ignore
359 if (videoStartup) return;
361 if (paused) togglePause();
362 if (ffwd) toggleFastForward();
368 audio->systemMuteOff();
371 feedMode = MODE_NORMAL;
378 audio->systemMuteOn();
381 feedMode = MODE_BACKWARDS;
385 if (!isRadio) demuxer->seek();
391 ULLONG Player::getPositionTS()
393 if (startup) return 0ULL;
394 long long currentTS = video->getCurrentTimestamp() - startTS;
395 if (currentTS < 0) currentTS += 8589934592ULL;
396 return (ULLONG)currentTS;
399 ULLONG Player::getEndTS()
401 long long rendTS = endTS - startTS;
402 if (rendTS < 0) rendTS += 8589934592ULL;
403 return (ULLONG)rendTS;
406 void Player::call(void* caller)
408 if (caller == demuxer)
410 logger->log("Player", Log::DEBUG, "Callback from demuxer");
412 if (video->getTVsize() == Video::ASPECT4X3)
414 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
418 int dxCurrentAspect = demuxer->getAspectRatio();
419 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
421 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
422 video->setAspectRatio(Video::ASPECT4X3);
424 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
426 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
427 video->setAspectRatio(Video::ASPECT16X9);
431 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
439 videoStartup = false;
446 threadSignalNoLock();
449 void Player::doConnectionLost()
451 Message* m = new Message();
452 m->message = Message::CONNECTION_LOST;
454 commandMessageQueue->postMessage(m);
459 void Player::threadMethod()
466 VDR* vdr = VDR::getInstance();
477 // If we havn't rescanned for a while..
478 if (isRecording && ((lastRescan + 60) < time(NULL)))
480 streamLength = vdr->rescanRecording();
481 if (!vdr->isConnected()) { doConnectionLost(); return; }
482 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
483 lastRescan = time(NULL);
487 if (streamLength) // is playing a recording
489 if (feedPosition >= streamLength) break; // finished playback
493 if (startupBlockSize > streamLength)
494 askFor = streamLength; // is a very small recording!
496 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
500 if ((feedPosition + blockSize) > streamLength) // last block of recording
501 askFor = streamLength - feedPosition;
506 else // is playing live
509 askFor = startupBlockSize; // find audio streams sized block
511 askFor = blockSize; // normal
514 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
515 if (!vdr->isConnected())
521 if (!threadBuffer) break;
525 int a_stream = demuxer->scan(threadBuffer, thisRead);
526 demuxer->setAudioStream(a_stream);
527 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
529 setStartTS(thisRead);
531 if (isRecording) setEndTS();
538 preBufferTotal += thisRead;
539 if (preBufferTotal > 500000)
541 logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
543 preBuffering = false;
552 // FIXME - see if this can segfault because it is starting threads out of the master mutex
556 if (feedMode == MODE_NORMAL)
558 feedPosition += thisRead;
560 else if (feedMode == MODE_BACKWARDS)
562 if (feedPosition >= blockSize)
564 feedPosition -= blockSize;
565 if (!isRadio) demuxer->seek();
569 // got to the start of the recording.. revert to play mode? how?
570 feedPosition += thisRead;
576 while(writeLength < thisRead)
578 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
579 writeLength += thisWrite;
580 // logger->log("Player", Log::DEBUG, "Put %i to demuxer", thisWrite);
584 // logger->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
585 // demuxer is full and can't take any more
587 threadWaitForSignal();
589 // logger->log("Player", Log::DEBUG, "BACK FROM WAIT");
601 logger->log("Player", Log::DEBUG, "Recording playback ends");
605 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
606 if (streamLength) m->message = Message::STOP_PLAYBACK; // recording
607 else m->message = Message::STREAM_END; // live
608 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
609 commandMessageQueue->postMessage(m);
610 logger->log("Player", Log::DEBUG, "Message posted...");
613 void Player::threadPostStopCleanup()
622 void Player::setStartTS(UINT dataInBuffer)
624 if (isRecording && feedPosition) // (feedPosition != 0)
626 // FIXME find out how much data need to get to find a TS
627 // Need to get the actual start of the recording
630 UCHAR* tempBuffer = VDR::getInstance()->getBlock(0, 100000, &thisRead);
631 if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
632 if (!tempBuffer) return;
633 if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &startTS);
638 demuxer->findVideoPTS(threadBuffer, dataInBuffer, &startTS);
642 void Player::setEndTS()
644 logger->log("Player", Log::DEBUG, "Setting end TS");
647 UCHAR* tempBuffer = VDR::getInstance()->getBlock((streamLength - 100000), 100000, &thisRead);
648 if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
649 if (!tempBuffer) return;
650 if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &endTS);
652 logger->log("Player", Log::DEBUG, "Set end TS");
658 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
660 // video->setAspectRatio(Video::ASPECT4X3);
665 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
666 video->setAspectRatio(Video::ASPECT16X9);