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, UCHAR tIsRecording, UCHAR isRadio)
24 : vfeed(this), afeed(this)
26 commandMessageQueue = messageQueue;
27 audio = Audio::getInstance();
28 video = Video::getInstance();
29 logger = Log::getInstance();
37 feedMode = MODE_NORMAL;
39 isRecording = tIsRecording;
49 startupBlockSize = 60000;
50 video->turnVideoOff();
55 startupBlockSize = 250000;
62 if (initted) shutdown();
67 if (initted) return 0;
69 if (!demuxer.init(this))
71 logger->log("Player", Log::ERR, "Demuxer failed to init");
76 vfeed.init(video->getFD());
77 afeed.init(audio->getFD());
91 int Player::shutdown()
93 if (!initted) return 0;
96 logger->log("Player", Log::DEBUG, "Player shutdown...");
112 logger->log("Player", Log::DEBUG, "Player shutdown done");
117 void Player::resyncAudio()
120 if (!initted) return;
126 void Player::resyncVideo()
129 if (!initted) return;
137 if (!initted) return 0;
139 // If we are just paused, unpause!
146 // If we are fast forwarding, set to normal
153 // If we are fast backwarding, set to normal
156 toggleFastBackward();
160 // If we are already playing, bail // FIXME - resync?
163 logger->log("Player", Log::DEBUG, "DOING RESYNC");
168 // Standard play start
169 logger->log("Player", Log::DEBUG, "Standard play start");
175 // ------------------------ This one works, but doesn't allow any pre-buffering.
185 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
188 // ------------------------------------------------------------------------------------------------
196 if (!initted) return;
197 if (!playing) return;
199 logger->log("Player", Log::DEBUG, "Stop called", streamLength);
206 video->unFastForward();
207 audio->systemMuteOff();
208 feedMode = MODE_NORMAL;
227 void Player::togglePause()
229 if (!initted) return;
230 if (!playing) return;
232 if (ffwd) toggleFastForward();
233 if (fbwd) toggleFastBackward();
249 void Player::setPosition(ULLONG position)
251 feedPosition = position;
254 void Player::setLength(ULLONG length)
256 lastRescan = time(NULL);
257 streamLength = length;
258 logger->log("Player", Log::DEBUG, "Player has received length of %llu", streamLength);
261 void Player::restartAt(ULLONG timecode)
263 if (paused) togglePause();
264 if (ffwd) toggleFastForward();
266 ULONG wantedFrameNumber = video->timecodeToFrameNumber(timecode);
267 ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(wantedFrameNumber);
268 if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
269 logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", wantedFrameNumber, feedPosition, newPosition);
278 feedPosition = newPosition;
285 audio->systemMuteOff();
290 void Player::skipForward(int seconds)
292 logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
293 restartAt(getPositionTS() + (seconds * 90000));
296 void Player::skipBackward(int seconds)
298 logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
299 long long newTimeCode = getPositionTS() - (seconds * 90000);
300 if (newTimeCode < 0) newTimeCode = 0;
301 restartAt(newTimeCode);
304 void Player::jumpToPercent(int percent)
306 logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent);
307 ULLONG newTimeCode = (ULLONG)(getEndTS() * ((float)percent / 100));
308 restartAt(newTimeCode);
311 void Player::toggleFastForward()
313 if (!initted) return;
314 if (!playing) return;
316 if (paused) togglePause();
317 if (fbwd) toggleFastBackward();
338 audio->systemMuteOff();
346 audio->systemMuteOn();
347 video->fastForward();
351 void Player::toggleFastBackward()
353 if (!initted) return;
354 if (!playing) return;
356 if (paused) togglePause();
357 if (ffwd) toggleFastForward();
363 audio->systemMuteOff();
366 feedMode = MODE_NORMAL;
373 audio->systemMuteOn();
376 feedMode = MODE_BACKWARDS;
384 ULLONG Player::getPositionTS()
386 if (startup) return 0ULL;
387 long long currentTS = video->getCurrentTimestamp() - startTS;
388 if (currentTS < 0) currentTS += 8589934592ULL;
389 return (ULLONG)currentTS;
392 ULLONG Player::getEndTS()
394 long long rendTS = endTS - startTS;
395 if (rendTS < 0) rendTS += 8589934592ULL;
396 return (ULLONG)rendTS;
399 void Player::call(void* caller)
401 if (caller == &demuxer)
403 logger->log("Player", Log::DEBUG, "Callback from demuxer");
405 if (video->getTVsize() == Video::ASPECT4X3)
407 logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
411 int dxCurrentAspect = demuxer.getAspectRatio();
412 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
414 logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
415 video->setAspectRatio(Video::ASPECT4X3);
417 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
419 logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
420 video->setAspectRatio(Video::ASPECT16X9);
424 logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
432 videoStartup = false;
433 logger->log("Player", Log::DEBUG, "Starting VFeed");
440 threadSignalNoLock();
443 void Player::doConnectionLost()
445 Message* m = new Message();
446 m->message = Message::CONNECTION_LOST;
448 commandMessageQueue->postMessage(m);
453 void Player::threadMethod()
459 VDR* vdr = VDR::getInstance();
470 // If we havn't rescanned for a while..
471 if (isRecording && ((lastRescan + 60) < time(NULL)))
473 streamLength = vdr->rescanRecording();
474 if (!vdr->isConnected()) { doConnectionLost(); return; }
475 logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
476 lastRescan = time(NULL);
480 if (streamLength) // is playing a recording
482 if (feedPosition >= streamLength) break; // finished playback
486 if (startupBlockSize > streamLength)
487 askFor = streamLength; // is a very small recording!
489 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
493 if ((feedPosition + blockSize) > streamLength) // last block of recording
494 askFor = streamLength - feedPosition;
499 else // is playing live
502 askFor = startupBlockSize; // find audio streams sized block
504 askFor = blockSize; // normal
507 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
508 if (!vdr->isConnected())
514 if (!threadBuffer) break;
518 int a_stream = demuxer.scan(threadBuffer, thisRead);
519 demuxer.setAudioStream(a_stream);
520 logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
522 setStartTS(thisRead);
524 if (isRecording) setEndTS();
529 if (feedMode == MODE_NORMAL)
531 feedPosition += thisRead;
533 else if (feedMode == MODE_BACKWARDS)
535 if (feedPosition >= blockSize)
537 feedPosition -= blockSize;
542 // got to the start of the recording.. revert to play mode? how?
543 feedPosition += thisRead;
549 while(writeLength < thisRead)
551 thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
552 writeLength += thisWrite;
556 // logger->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
557 // demuxer is full and cant take anymore
559 threadWaitForSignal();
561 // logger->log("Player", Log::DEBUG, "BACK FROM WAIT");
573 logger->log("Player", Log::DEBUG, "Recording playback ends");
577 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
578 if (streamLength) m->message = Message::STOP_PLAYBACK; // recording
579 else m->message = Message::STREAM_END; // live
580 logger->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
581 commandMessageQueue->postMessage(m);
582 logger->log("Player", Log::DEBUG, "Message posted...");
585 void Player::threadPostStopCleanup()
587 logger->log("Player", Log::DEBUG, "Post stop cleanup 1");
590 logger->log("Player", Log::DEBUG, "Post stop cleanup 2");
594 logger->log("Player", Log::DEBUG, "Post stop cleanup 3");
597 void Player::setStartTS(UINT dataInBuffer)
599 if (isRecording && feedPosition) // (feedPosition != 0)
601 // FIXME find out how much data need to get to find a TS
602 // Need to get the actual start of the recording
605 UCHAR* tempBuffer = VDR::getInstance()->getBlock(0, 100000, &thisRead);
606 if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
607 if (!tempBuffer) return;
608 if (thisRead) demuxer.findVideoPTS(tempBuffer, thisRead, &startTS);
613 demuxer.findVideoPTS(threadBuffer, dataInBuffer, &startTS);
617 void Player::setEndTS()
619 logger->log("Player", Log::DEBUG, "Setting end TS");
622 UCHAR* tempBuffer = VDR::getInstance()->getBlock((streamLength - 100000), 100000, &thisRead);
623 if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
624 if (!tempBuffer) return;
625 if (thisRead) demuxer.findVideoPTS(tempBuffer, thisRead, &endTS);
627 logger->log("Player", Log::DEBUG, "Set end TS");
633 logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
634 video->setAspectRatio(Video::ASPECT4X3);
639 logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
640 video->setAspectRatio(Video::ASPECT16X9);