From: Chris Tallon Date: Mon, 24 Feb 2020 18:27:43 +0000 (+0000) Subject: Rename Player class to PlayerVideoRec. Switch to std::mutex X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=2f5c4ccdaae88f054143514448db33d53f84d63c;p=vompclient.git Rename Player class to PlayerVideoRec. Switch to std::mutex --- diff --git a/objects.mk b/objects.mk index d87d0ef..62d9089 100644 --- a/objects.mk +++ b/objects.mk @@ -1,7 +1,7 @@ OBJ_COMMON = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.o \ message.o messagequeue.o wol.o audio.o video.o log.o \ vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \ - directory.o mark.o option.o player.o playerradio.o vfeed.o afeed.o \ + directory.o mark.o option.o playervideorec.o playerradio.o vfeed.o afeed.o \ demuxer.o demuxervdr.o demuxerts.o stream.o osd.o surface.o \ region.o colour.o boxstack.o boxx.o tbboxx.o vrecording.o \ vinfo.o vquestion.o vrecordinglist.o vrecordinglistclassic.o \ @@ -22,7 +22,7 @@ OBJ_COMMON = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.o OBJ_RASPBERRY = main.o threadp.o osdopenvg.o \ ledraspberry.o videoomx.o audioomx.o imageomx.o \ - wjpegsimple.o inputlinux.o inputcec.o signal.o + wjpegsimple.o inputlinux.o inputcec.o OBJ_WINDOWS = winmain.o threadwin.o inputwin.o ledwin.o videowin.o \ audiowin.o windowsosd.o dsallocator.o dssourcefilter.o dssourcepin.o \ diff --git a/osd.cc b/osd.cc index ab8bf23..e497911 100644 --- a/osd.cc +++ b/osd.cc @@ -28,7 +28,6 @@ Osd::Osd() { if (instance) return; instance = this; - initted = 0; fdOsd = 0; screen = NULL; diff --git a/osd.h b/osd.h index aef86fa..89db75e 100644 --- a/osd.h +++ b/osd.h @@ -50,7 +50,7 @@ class Osd protected: static Osd* instance; - int initted; + bool initted{}; Surface* screen; int fdOsd; }; diff --git a/osddirectfb.cc b/osddirectfb.cc index 844288c..d7980c8 100644 --- a/osddirectfb.cc +++ b/osddirectfb.cc @@ -78,7 +78,7 @@ int OsdDirectFB::init() osd_layer->GetConfiguration(osd_layer,&layer_config); - initted = 1; // must set this here or create surface won't work + initted = true; // must set this here or create surface won't work /* TODO clean up sizes */ Video* video = Video::getInstance(); @@ -92,7 +92,7 @@ int OsdDirectFB::init() int OsdDirectFB::shutdown() { if (!initted) return 0; - initted = 0; + initted = false; delete screen; if (osd_layer) osd_layer->Release(osd_layer); if (dfb) dfb->Release(dfb); diff --git a/osdopengl.cc b/osdopengl.cc index e1986cb..2b18a35 100644 --- a/osdopengl.cc +++ b/osdopengl.cc @@ -192,7 +192,7 @@ int OsdOpenGL::init() screen->create(video->getScreenWidth(), video->getScreenHeight()); screen->display(); - initted = 1; // must set this here or create surface won't work + initted = true; // must set this here or create surface won't work //glGenBuffers(1, &vB); //glGenBuffers(1, &iB); @@ -270,7 +270,7 @@ int OsdOpenGL::shutdown() { if (!initted) return 0; glmutex.lock(); - initted = 0; + initted = false; threadStop(); delete screen; screen=NULL; diff --git a/osdopenvg.cc b/osdopenvg.cc index 4a2f15f..8101a3d 100644 --- a/osdopenvg.cc +++ b/osdopenvg.cc @@ -303,7 +303,7 @@ int OsdOpenVG::init() Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out 1%d",syscall(SYS_gettid)); eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); //Now we will create the Screen - initted = 1; // must set this here or create surface won't work + initted = true; // must set this here or create surface won't work /*if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init stuff @@ -488,7 +488,7 @@ int OsdOpenVG::shutdown() if (!initted) return 0; - initted = 0; + initted = false; Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1"); threadStop(); Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1a"); diff --git a/osdwinpixel.cc b/osdwinpixel.cc index a64d34d..1698332 100644 --- a/osdwinpixel.cc +++ b/osdwinpixel.cc @@ -70,7 +70,7 @@ int OsdWinPixel::init() screen = new SurfaceWin(Surface::SCREEN); screen->create(video->getScreenWidth(), video->getScreenHeight()); screen->display(); - initted = 1; // must set this here or create surface won't work + initted = true; // must set this here or create surface won't work startRenderLoop(); @@ -81,7 +81,7 @@ int OsdWinPixel::init() int OsdWinPixel::shutdown() { if (!initted) return 0; - initted = 0; + initted = false; stopRenderLoop(); shutdownDirect3D9Objects(); diff --git a/osdwinpixel.h b/osdwinpixel.h index a9e4143..8ad2cc6 100644 --- a/osdwinpixel.h +++ b/osdwinpixel.h @@ -39,7 +39,7 @@ class OsdWinPixel : public Osd, public WindowsOsd int init(); int shutdown(); - int isInitialized() { return initted; } + bool isInitialized() { return initted; } int getFD(); diff --git a/osdwinvector.cc b/osdwinvector.cc index f9ef386..d6c7b34 100644 --- a/osdwinvector.cc +++ b/osdwinvector.cc @@ -398,7 +398,7 @@ int OsdWinVector::init() loadFont(false); - initted = 1; // must set this here or create surface won't work + initted = true; // must set this here or create surface won't work startRenderLoop(); diff --git a/osdwinvector.h b/osdwinvector.h index 058e205..923882a 100644 --- a/osdwinvector.h +++ b/osdwinvector.h @@ -45,7 +45,7 @@ class OsdWinVector : public OsdVector, public WindowsOsd int init(); int shutdown(); - int isInitialized() { return initted; } + bool isInitialized() { return initted; } void getScreenSize(int &width, int &height); void getRealScreenSize(int &width, int &height); diff --git a/player.cc b/player.cc deleted file mode 100644 index 6dba51f..0000000 --- a/player.cc +++ /dev/null @@ -1,1434 +0,0 @@ -/* - Copyright 2004-2008 Chris Tallon - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP. If not, see . -*/ - -#include "player.h" - -#include "log.h" -#include "audio.h" -#include "video.h" -#include "demuxervdr.h" -#include "demuxerts.h" -#include "vdr.h" -#include "messagequeue.h" -#include "input.h" -#include "message.h" -#include "dvbsubtitles.h" -#include "osdreceiver.h" - -#define USER_RESPONSE_TIME 500 // Milliseconds - -// ----------------------------------- Called from outside, one offs or info funcs - -Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver) -: vfeed(this), afeed(this), tfeed(this) -{ - messageQueue = tmessageQueue; - messageReceiver = tmessageReceiver; - osdReceiver = tosdReceiver; - audio = Audio::getInstance(); - video = Video::getInstance(); - logger = Log::getInstance(); - vdr = VDR::getInstance(); - - video->turnVideoOn(); -} - -Player::~Player() -{ - if (initted) shutdown(); -} - -int Player::init(bool p_isPesRecording, double framespersecond) -{ - if (initted) return 0; -#ifndef WIN32 - pthread_mutex_init(&mutex, NULL); -#else - mutex=CreateMutex(NULL,FALSE,NULL); -#endif - is_pesrecording = p_isPesRecording; - fps = framespersecond; - if (is_pesrecording) - demuxer = new DemuxerVDR(); - else - demuxer = new DemuxerTS(); - if (!demuxer) return 0; - subtitles = new DVBSubtitles(osdReceiver); - if (!subtitles) return 0; - - teletext = new TeletextDecoderVBIEBU(); - if (!teletext) return 0; - teletext->setRecordigMode(true); - unsigned int demux_video_size = 2097152; - unsigned int demux_audio_size = 524288; - if (video->supportsh264()) - { - demux_video_size *= 5 * 2; - } - if (audio->maysupportAc3()) - { - //demux_audio_size*=2; - } - - if (!demuxer->init(this, audio, video,teletext, demux_video_size,demux_audio_size,65536, framespersecond, subtitles)) - { - logger->log("Player", Log::ERR, "Demuxer failed to init"); - shutdown(); - return 0; - } - - vfeed.init(); - afeed.init(); - tfeed.init(); - - video->stop(); - video->blank(); - audio->stop(); - - if (Command::getInstance()->getSubDefault()) - turnSubtitlesOn(true); - else - turnSubtitlesOn(false); - - initted = true; - return 1; -} - -int Player::shutdown() -{ - if (!initted) return 0; - switchState(S_STOP); - initted = false; - - delete demuxer; - demuxer = NULL; - delete subtitles; - subtitles = NULL; - delete teletext; - teletext = NULL; - -#ifdef WIN32 - CloseHandle(mutex); -#endif - - return 1; -} - -void Player::setStartFrame(ULONG startFrame) -{ - ULONG nextiframeNumber; - ULONG iframeLength; - ULONG iframeNumber; - ULLONG filePos; - - // newFrame could be anywhere, go forwards to next I-Frame - if (!vdr->getNextIFrame(startFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return; - - // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame - vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength); - - logger->log("Player", Log::DEBUG, "setStartFrame %lu %lu %lu", startFrame, nextiframeNumber,iframeNumber); - currentFrameNumber = iframeNumber; -} - -void Player::setLengthBytes(ULLONG length) -{ - lengthBytes = length; - logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes); -} - -void Player::setLengthFrames(ULONG length) -{ - lengthFrames = length; - logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames); -} - -ULONG Player::getLengthFrames() -{ - return lengthFrames; -} - -ULONG Player::getCurrentFrameNum() -{ - if (startup) return 0; - switch(state) - { - case S_PLAY: - case S_PAUSE_P: - return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp()); - case S_PAUSE_I: - case S_FFWD: - case S_FBWD: - return currentFrameNumber; - default: - return 0; // shouldn't happen - } -} - -bool* Player::getDemuxerMpegAudioChannels() -{ - return demuxer->getmpAudioChannels(); -} - -bool* Player::getDemuxerAc3AudioChannels() -{ - return demuxer->getac3AudioChannels(); -} - -bool* Player::getDemuxerSubtitleChannels() -{ - return demuxer->getSubtitleChannels(); -} - -int Player::getCurrentAudioChannel() -{ - if (is_pesrecording) - return demuxer->getselAudioChannel(); - else - return dynamic_cast(demuxer)->getAID(); -} - -int Player::getCurrentSubtitleChannel() -{ - if (is_pesrecording) - return demuxer->getselSubtitleChannel(); - else - return dynamic_cast(demuxer)->getSubID(); -} - -void Player::setSubtitleChannel(int newChannel) -{ - if (is_pesrecording) - demuxer->setDVBSubtitleStream(newChannel); - else - dynamic_cast(demuxer)->setSubID(newChannel); -} - -int *Player::getTeletxtSubtitlePages() -{ - return teletext->getSubtitlePages(); -} - -void Player::setAudioChannel(int newChannel, int type, int streamtype) -{ - if (is_pesrecording) - { - demuxer->setAudioStream(newChannel); - return; - } - else - { - dynamic_cast(demuxer)->setAID(newChannel,type,streamtype,false); - return; - } -} - -bool Player::toggleSubtitles() -{ - if (!subtitlesShowing) - { - subtitlesShowing = true; - subtitles->show(); - } - else - { - subtitlesShowing = false; - subtitles->hide(); - } - return subtitlesShowing; -} - -void Player::turnSubtitlesOn(bool ison) -{ - if (ison) - { - subtitlesShowing = true; - subtitles->show(); - } - else - { - subtitlesShowing = false; - subtitles->hide(); - } -} - -void Player::tellSubtitlesOSDVisible(bool visible) -{ - subtitles->setOSDMenuVisibility(visible); -} - -Channel * Player::getDemuxerChannel() -{ - if (!is_pesrecording) - { - return dynamic_cast(demuxer)->getChannelInfo(); - } - return NULL; //Should not happen! -} - - -// ----------------------------------- Externally called events - -void Player::play() -{ - if (!initted) return; - if (state == S_PLAY) return; - lock(); - - bool doUnlock = false; - if (state == S_PAUSE_P) doUnlock = true; - switchState(S_PLAY); - if (doUnlock) unLock(); -} - -void Player::playpause() -{ - if (!initted) return; - lock(); - - bool doUnlock = false; - if (state==S_PLAY) - { - doUnlock=true; - switchState(S_PAUSE_P); - } - else - { - if (state == S_PAUSE_P) doUnlock = true; - switchState(S_PLAY); - } - if (doUnlock) unLock(); -} - -void Player::stop() -{ - if (!initted) return; - if (state == S_STOP) return; - lock(); - logger->log("Player", Log::DEBUG, "Stop called lock"); - switchState(S_STOP); - unLock(); -} - -void Player::pause() -{ - if (!initted) return; - lock(); - - if ((state == S_FFWD) || (state == S_FBWD)) - { - switchState(S_PAUSE_I); - } - else if ((state == S_PAUSE_I) || (state == S_PAUSE_P)) - { - switchState(S_PLAY); - } - else - { - switchState(S_PAUSE_P); - } - - unLock(); -} - -void Player::fastForward() -{ - if (!initted) return; - lock(); - - if (state == S_FFWD) - { - // change the rate - switch(ifactor) - { - case 4: ifactor = 8; break; - case 8: ifactor = 16; break; - case 16: ifactor = 32; break; - case 32: ifactor = 4; break; - } - } - else - { - ifactor = 4; - switchState(S_FFWD); - } - unLock(); -} - -void Player::fastBackward() -{ - if (!initted) return; - lock(); - - if (state == S_FBWD) - { - // change the rate - switch(ifactor) - { - case 4: ifactor = 8; break; - case 8: ifactor = 16; break; - case 16: ifactor = 32; break; - case 32: ifactor = 4; break; - } - } - else - { - ifactor = 4; - switchState(S_FBWD); - } - unLock(); -} - -void Player::jumpToPercent(double percent) -{ - lock(); - logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent); - ULONG newFrame = static_cast(percent * lengthFrames / 100); - switchState(S_JUMP, newFrame); -// unLock(); - let thread unlock this -} - -void Player::jumpToMark(int mark) -{ - lock(); - logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark); - switchState(S_JUMP, mark); -// unLock(); - let thread unlock this -} - -void Player::jumpToFrameP(int newFrame) -{ - lock(); - logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame); - switchState(S_JUMP_PI, newFrame); - unLock(); -} - -void Player::skipForward(int seconds) -{ - lock(); - logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); - ULONG newFrame = getCurrentFrameNum(); - if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid - newFrame += static_cast(static_cast(seconds) * fps); - if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); } - else switchState(S_JUMP, newFrame); -// unLock(); - let thread unlock this -} - -void Player::skipBackward(int seconds) -{ - lock(); - logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); - long newFrame = getCurrentFrameNum(); - if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid - newFrame -= static_cast(static_cast(seconds) * fps); - if (newFrame < 0) newFrame = 0; - switchState(S_JUMP, newFrame); -// unLock(); - let thread unlock this -} - -// ----------------------------------- Implementations called events - -void Player::switchState(UCHAR toState, ULONG jumpFrame) -{ - if (!initted) return; - - logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState); - - switch(state) // current state selector - { - case S_PLAY: // from S_PLAY ----------------------------------- - { - switch(toState) - { - case S_PLAY: // to S_PLAY - { - return; - } - case S_PAUSE_P: // to S_PAUSE_P - { - #ifdef VOMP_PLATFORM_RASPBERRY - vfeed.stop(); // can't vfeed during pause - #endif - - video->pause(); - audio->pause(); - state = S_PAUSE_P; - return; - } - case S_PAUSE_I: // to S_PAUSE_I - { - // can't occur - return; - } - case S_FFWD: // to S_FFWD - { - currentFrameNumber = getCurrentFrameNum(); - audio->systemMuteOn(); - threadStop(); - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - demuxer->flush(); - state = S_FFWD; - threadStart(); - return; - } - case S_FBWD: // to S_FBWD - { - currentFrameNumber = getCurrentFrameNum(); - audio->systemMuteOn(); - threadStop(); - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - demuxer->flush(); - state = S_FBWD; - threadStart(); - return; - } - case S_STOP: // to S_STOP - { - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - threadStop(); - video->stop(); - video->blank(); - audio->stop(); - audio->unPause(); - video->reset(); - demuxer->reset(); - state = S_STOP; - return; - } - case S_JUMP: // to S_JUMP - { - restartAtFrame(jumpFrame); - return; - } - case S_JUMP_PI: // to S_JUMP_PI - { - audio->systemMuteOn(); - threadStop(); - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - demuxer->flush(); - state = S_PAUSE_I; - video->reset(); - video->play(); - restartAtFramePI(jumpFrame); - return; - } - } - } - FALLTHROUGH // keep compiler happy (all posibilities return) - case S_PAUSE_P: // from S_PAUSE_P ----------------------------------- - { - switch(toState) - { - case S_PLAY: // to S_PLAY - { - video->unPause(); - audio->unPause(); - - #ifdef VOMP_PLATFORM_RASPBERRY - vfeed.start(false); - #endif - - state = S_PLAY; - return; - } - case S_PAUSE_P: // to S_PAUSE_P - { - return; - } - case S_PAUSE_I: // to S_PAUSE_I - { - return; - } - case S_FFWD: // to S_FFWD - { - currentFrameNumber = getCurrentFrameNum(); - audio->systemMuteOn(); - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - threadStop(); - video->unPause(); - audio->unPause(); - state = S_FFWD; - threadStart(); - return; - } - case S_FBWD: // to S_FBWD - { - currentFrameNumber = getCurrentFrameNum(); - audio->systemMuteOn(); - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - threadStop(); - video->unPause(); - audio->unPause(); - state = S_FBWD; - threadStart(); - return; - } - case S_STOP: // to S_STOP - { - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - threadStop(); - video->stop(); - video->blank(); - audio->stop(); - video->reset(); - audio->unPause(); - demuxer->reset(); - audio->systemMuteOff(); - state = S_STOP; - return; - } - case S_JUMP: // to S_JUMP - { - state = S_PLAY; - audio->systemMuteOn(); - audio->unPause(); - restartAtFrame(jumpFrame); - return; - } - case S_JUMP_PI: // to S_JUMP_PI - { - audio->systemMuteOn(); - audio->unPause(); - threadStop(); - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - demuxer->flush(); - state = S_PAUSE_I; - video->reset(); - video->play(); - restartAtFramePI(jumpFrame); - return; - } - } - } - FALLTHROUGH // keep compiler happy (all posibilities return) - case S_PAUSE_I: // from S_PAUSE_I ----------------------------------- - { - switch(toState) - { - case S_PLAY: // to S_PLAY - { - state = S_PLAY; - restartAtFrame(currentFrameNumber); - return; - } - case S_PAUSE_P: // to S_PAUSE_P - { - return; - } - case S_PAUSE_I: // to S_PAUSE_I - { - return; - } - case S_FFWD: // to S_FFWD - { - state = S_FFWD; - threadStart(); - return; - } - case S_FBWD: // to S_FBWD - { - state = S_FBWD; - threadStart(); - return; - } - case S_STOP: // to S_STOP - { - video->stop(); - video->blank(); - audio->stop(); - video->reset(); - demuxer->reset(); - audio->systemMuteOff(); - state = S_STOP; - return; - } - case S_JUMP: // to S_JUMP - { - state = S_PLAY; - restartAtFrame(jumpFrame); - return; - } - case S_JUMP_PI: // to S_JUMP_PI - { - restartAtFramePI(jumpFrame); - return; - } - } - } - FALLTHROUGH // keep compiler happy (all posibilities return) - case S_FFWD: // from S_FFWD ----------------------------------- - { - switch(toState) - { - case S_PLAY: // to S_PLAY - { - state = S_PLAY; - ULONG stepback = static_cast(USER_RESPONSE_TIME * ifactor * fps / 1000); - if (stepback < currentFrameNumber) - currentFrameNumber -= stepback; - else - currentFrameNumber = 0; - restartAtFrame(currentFrameNumber); - return; - } - case S_PAUSE_P: // to S_PAUSE_P - { - // can't occur - return; - } - case S_PAUSE_I: // to S_PAUSE_I - { - threadStop(); - state = S_PAUSE_I; - return; - } - case S_FFWD: // to S_FFWD - { - return; - } - case S_FBWD: // to S_FBWD - { - threadStop(); - state = S_FBWD; - threadStart(); - return; - } - case S_STOP: // to S_STOP - { - threadStop(); - video->stop(); - video->blank(); - audio->stop(); - video->reset(); - demuxer->reset(); - state = S_STOP; - return; - } - case S_JUMP: // to S_JUMP - { - state = S_PLAY; - restartAtFrame(jumpFrame); - return; - } - case S_JUMP_PI: // to S_JUMP_PI - { - threadStop(); - state = S_PAUSE_I; - restartAtFramePI(jumpFrame); - return; - } - } - } - FALLTHROUGH // keep compiler happy (all posibilities return) - case S_FBWD: // from S_FBWD ----------------------------------- - { - switch(toState) - { - case S_PLAY: // to S_PLAY - { - state = S_PLAY; - restartAtFrame(currentFrameNumber); - return; - } - case S_PAUSE_P: // to S_PAUSE_P - { - // can't occur - return; - } - case S_PAUSE_I: // to S_PAUSE_I - { - threadStop(); - state = S_PAUSE_I; - return; - } - case S_FFWD: // to S_FFWD - { - threadStop(); - state = S_FFWD; - threadStart(); - return; - } - case S_FBWD: // to S_FBWD - { - return; - } - case S_STOP: // to S_STOP - { - threadStop(); - video->stop(); - video->blank(); - audio->stop(); - video->reset(); - demuxer->reset(); - state = S_STOP; - return; - } - case S_JUMP: // to S_JUMP - { - state = S_PLAY; - restartAtFrame(jumpFrame); - return; - } - case S_JUMP_PI: // to S_JUMP_PI - { - threadStop(); - state = S_PAUSE_I; - restartAtFramePI(jumpFrame); - return; - } - } - } - FALLTHROUGH // keep compiler happy (all posibilities return) - case S_STOP: // from S_STOP ----------------------------------- - { - switch(toState) - { - case S_PLAY: // to S_PLAY - { - startup = true; - - audio->reset(); - audio->setStreamType(Audio::MPEG2_PES); - audio->systemMuteOff(); - video->reset(); - demuxer->reset(); - // FIXME use restartAtFrame here? - if (currentFrameNumber > lengthFrames) currentFrameNumber = 0; - demuxer->setFrameNum(currentFrameNumber); - demuxer->seek(); - videoStartup = true; - state = S_PLAY; - threadStart(); - logger->log("Player", Log::DEBUG, "Immediate play"); - afeed.start(); - vfeed.start(); - tfeed.start(); - subtitles->start(); - video->sync(); - audio->sync(); - audio->play(); - video->pause(); - return; - } - case S_PAUSE_P: // to S_PAUSE_P - { - return; - } - case S_PAUSE_I: // to S_PAUSE_I - { - return; - } - case S_FFWD: // to S_FFWD - { - return; - } - case S_FBWD: // to S_FBWD - { - return; - } - case S_STOP: // to S_STOP - { - return; - } - case S_JUMP: // to S_JUMP - { - return; - } - case S_JUMP_PI: // to S_JUMP_PI - { - return; - } - } - } - // case S_JUMP cannot be a start state because it auto flips to play - // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I - } -} - -// ----------------------------------- Internal functions - -void Player::lock() -{ -#ifndef WIN32 - pthread_mutex_lock(&mutex); - logger->log("Player", Log::DEBUG, "LOCKED"); - -#else - WaitForSingleObject(mutex, INFINITE); -#endif -} - -void Player::unLock() -{ -#ifndef WIN32 - logger->log("Player", Log::DEBUG, "UNLOCKING"); - pthread_mutex_unlock(&mutex); -#else - ReleaseMutex(mutex); -#endif -} - -void Player::restartAtFrame(ULONG newFrame) -{ - vfeed.stop(); - afeed.stop(); - tfeed.stop(); - subtitles->stop(); - threadStop(); - video->stop(); - video->reset(); - audio->reset(); - audio->setStreamType(Audio::MPEG2_PES); - demuxer->flush(); - demuxer->seek(); - currentFrameNumber = newFrame; - demuxer->setFrameNum(newFrame); - videoStartup = true; - afeed.start(); - tfeed.start(); - vfeed.start(); - subtitles->start(); - threadStart(); - audio->play(); - video->sync(); - audio->sync(); - audio->systemMuteOff(); - audio->doMuting(); -} - - -void Player::restartAtFramePI(ULONG newFrame) -{ - ULLONG filePos; - ULONG nextiframeNumber; - ULONG iframeLength; - ULONG iframeNumber; - - UCHAR* buffer; - UINT amountReceived; - UINT videoLength; - - // newFrame could be anywhere, go forwards to next I-Frame - if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return; - - // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame - vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength); - - buffer = vdr->getBlock(filePos, iframeLength, &amountReceived); - if (!vdr->isConnected()) - { - if (buffer) free(buffer); - doConnectionLost(); - } - else - { - videoLength = demuxer->stripAudio(buffer, amountReceived); - video->displayIFrame(buffer, videoLength); - video->displayIFrame(buffer, videoLength); // If you do it twice, it works :) - free(buffer); - currentFrameNumber = iframeNumber; - } -} - -void Player::doConnectionLost() -{ - logger->log("Player", Log::DEBUG, "Connection lost, sending message"); - Message* m = new Message(); - m->to = messageReceiver; - m->from = this; - m->message = Message::PLAYER_EVENT; - m->parameter = Player::CONNECTION_LOST; - messageQueue->postMessage(m); -} - -// ----------------------------------- Callback - -void Player::call(void* caller) -{ - if (caller == demuxer) - { - logger->log("Player", Log::DEBUG, "Callback from demuxer"); - - if (video->getTVsize() == Video::ASPECT4X3) - { - logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching"); - return; - } - - int parx,pary; - int dxCurrentAspect = demuxer->getAspectRatio(&parx,&pary); - if (dxCurrentAspect == Demuxer::ASPECT_4_3) - { - logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV"); - video->setAspectRatio(Video::ASPECT4X3,parx,pary); - - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = Player::ASPECT43; - messageQueue->postMessage(m); - } - else if (dxCurrentAspect == Demuxer::ASPECT_16_9) - { - logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV"); - video->setAspectRatio(Video::ASPECT16X9,parx,pary); - - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = Player::ASPECT169; - messageQueue->postMessage(m); - } - else - { - logger->log("Player", Log::DEBUG, "Demuxer said video is something else... setting it anyway"); - video->setAspectRatio(static_cast(dxCurrentAspect), parx, pary); - } - - } - else - { - if (videoStartup) - { - videoStartup = false; - video->reset(); - video->play(); - video->sync(); - vfeed.release(); - unLock(); - } - - threadSignalNoLock(); - } -} - -// ----------------------------------- Feed thread - -void Player::threadMethod() -{ - // this method used to be simple, the only thing it does - // is farm out to threadFeed Live/Play/Scan - // All the guff is to support scan hitting one end - - if ((state == S_FFWD) || (state == S_FBWD)) - { - if (video->PTSIFramePlayback()) threadPTSFeedScan(); - else threadFeedScan(); - // if this returns then scan hit one end - if (state == S_FFWD) // scan hit the end. stop - { - threadCheckExit(); - Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex - m->to = messageReceiver; - m->from = this; - m->message = Message::PLAYER_EVENT; - m->parameter = STOP_PLAYBACK; - logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue); - messageQueue->postMessage(m); - logger->log("Player", Log::DEBUG, "Message posted..."); - return; - } - // if execution gets to here, threadFeedScan hit the start, go to play mode - state = S_PLAY; - audio->reset(); - audio->setStreamType(Audio::MPEG2_PES); - demuxer->flush(); - demuxer->seek(); - demuxer->setFrameNum(currentFrameNumber); - videoStartup = true; - afeed.start(); - tfeed.start(); - vfeed.start(); - subtitles->start(); - audio->play(); - audio->sync(); - audio->systemMuteOff(); - audio->doMuting(); - } - - if (state == S_PLAY) threadFeedPlay(); -} - -void Player::threadFeedPlay() -{ - ULLONG feedPosition; - UINT thisRead, writeLength, thisWrite, askFor; - time_t lastRescan = time(NULL); - - feedPosition = vdr->positionFromFrameNumber(currentFrameNumber); - if (!vdr->isConnected()) { doConnectionLost(); return; } - logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition); - - - while(1) - { - thisRead = 0; - writeLength = 0; - thisWrite = 0; - - threadCheckExit(); - - // If we havn't rescanned for a while.. - if ((lastRescan + 60) < time(NULL)) - { - lengthBytes = vdr->rescanRecording(&lengthFrames); - if (!vdr->isConnected()) { doConnectionLost(); return; } - logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes); - lastRescan = time(NULL); - } - - if (feedPosition >= lengthBytes) break; // finished playback - - if (startup) - { - if (startupBlockSize > lengthBytes) - askFor = static_cast(lengthBytes); // is a very small recording! - else - askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams - } - else - { - if ((feedPosition + blockSize) > lengthBytes) // last block of recording - askFor = static_cast(lengthBytes - feedPosition); - else // normal - askFor = blockSize; - } - //logger->log("Player", Log::DEBUG, "Get Block in"); - - threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead); - //logger->log("Player", Log::DEBUG, "Get Block out"); - - feedPosition += thisRead; - - if (!vdr->isConnected()) - { - doConnectionLost(); - return; - } - - if (!threadBuffer) break; - - if (startup) - { - int a_stream = demuxer->scan(threadBuffer, thisRead); - demuxer->setAudioStream(a_stream); - logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream); - startup = false; - } - - threadCheckExit(); - - while(writeLength < thisRead) - { - //logger->log("Player", Log::DEBUG, "Put in"); - thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength); - //logger->log("Player", Log::DEBUG, "Put out"); - writeLength += thisWrite; - - if (!thisWrite) - { - // demuxer is full and can't take anymore - threadLock(); - if (!threadActive) { threadUnlock(); threadCheckExit(); } - threadWaitForSignal(); - threadUnlock(); - } - - threadCheckExit(); - } - - free(threadBuffer); - threadBuffer = NULL; - - } - - // end of recording - logger->log("Player", Log::DEBUG, "Recording playback ends"); - - if (videoStartup) // oh woe. there never was a stream, I was conned! - { - videoStartup = false; - unLock(); - MILLISLEEP(500); // I think this will solve a race - } - - threadCheckExit(); - - - Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex - m->to = messageReceiver; - m->from = this; - m->message = Message::PLAYER_EVENT; - m->parameter = Player::STOP_PLAYBACK; - logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue); - messageQueue->postMessage(m); -} - - -void Player::threadPTSFeedScan() -{ - // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows? - - ULONG direction = 0; - int dir_fac=-1; - ULONG baseFrameNumber = 0; - ULONG iframeNumber = 0; - ULONG iframeLength = 0; - ULONG currentfeedFrameNumber=currentFrameNumber; - ULONG firstFrameNumber=currentFrameNumber; - ULLONG filePos; - UINT amountReceived; - UINT videoLength; - - UINT playtime=0; - - int frameTimeOffset = 0; // Time in msec between frames - - if (state == S_FFWD) - { - direction = 1; // and 0 for backward - dir_fac = 1; - } - video->EnterIframePlayback(); - - while(1) - { - baseFrameNumber = currentfeedFrameNumber; - - threadCheckExit(); - if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength)) - return; - - if (iframeNumber >= lengthFrames) return; - // scan has got to the end of what we knew to be there before we started scanning - - baseFrameNumber = iframeNumber; - - frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor)); - - logger->log("Player", Log::DEBUG, "XXX Got frame"); - - threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived); - - if (!vdr->isConnected()) - { - if (threadBuffer) free(threadBuffer); - doConnectionLost(); - break; - } - - - threadCheckExit(); - - - videoLength = demuxer->stripAudio(threadBuffer, amountReceived); - demuxer->changeTimes(threadBuffer,videoLength,playtime); - int count=0; - while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block - { - MILLISLEEP(20); - threadCheckExit(); - count++; - if (count%300==0) { - ULLONG cur_time=video->getCurrentTimestamp(); - // logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g", - // firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps); - if (cur_time!=0) { - currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.)); - } - } - - } - playtime +=frameTimeOffset; - currentfeedFrameNumber = iframeNumber; - { - ULLONG cur_time=video->getCurrentTimestamp(); - // logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g", - // firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps); - if (cur_time!=0) { - currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.)); - } - } - - free(threadBuffer); - threadBuffer = NULL; - } -} - - - -void Player::threadFeedScan() -{ - // This method is actually really simple - get frame from vdr, - // spit it at the video chip, wait for a time. Most of the code here - // is to get the wait right so that the scan occurs at the correct rate. - - ULONG direction = 0; - ULONG baseFrameNumber = 0; - ULONG iframeNumber = 0; - ULONG iframeLength = 0; - ULLONG filePos; - UINT amountReceived; - UINT videoLength; - -#ifndef WIN32 - struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info - struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data - struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame -#else - DWORD clock0 = 0, clock1 = 0, clock2 = 0; -#endif - - int frameTimeOffset = 0; // Time in msec between frames - int disp_msec = 0; // Time taken to display data - int total_msec = 0; // Time taken to fetch data and display it - int sleepTime = 0; - - if (state == S_FFWD) direction = 1; // and 0 for backward - - while(1) - { - // Fetch I-frames until we get one that can be displayed in good time - // Repeat while clock0 + total_msec > clock2 + frameTimeOffset - - baseFrameNumber = currentFrameNumber; - do - { - threadCheckExit(); - if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength)) - return; - - if (iframeNumber >= lengthFrames) return; - // scan has got to the end of what we knew to be there before we started scanning - - baseFrameNumber = iframeNumber; - frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor)); -#ifndef WIN32 - gettimeofday(&clock0, NULL); -#else - clock0 = timeGetTime(); -#endif - } -#ifndef WIN32 - while (clock2.tv_sec != 0 && - (clock0.tv_sec - clock2.tv_sec) * 1000 + - (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec); -#else - while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset); -#endif - logger->log("Player", Log::DEBUG, "XXX Got frame"); - - threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived); - - if (!vdr->isConnected() || !amountReceived) - { - if (threadBuffer) free(threadBuffer); - doConnectionLost(); - break; - } - -#ifndef WIN32 - gettimeofday(&clock1, NULL); - if (clock2.tv_sec != 0) - sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000 - + (clock2.tv_usec - clock1.tv_usec) / 1000 - + frameTimeOffset - disp_msec; -#else - clock1 = timeGetTime(); - if (clock2 != 0) - sleepTime = clock2 + frameTimeOffset - disp_msec - clock1; -#endif - if (sleepTime < 0) sleepTime = 0; - threadCheckExit(); - MILLISLEEP(sleepTime); - logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime); - - videoLength = demuxer->stripAudio(threadBuffer, amountReceived); - video->displayIFrame(threadBuffer, videoLength); - currentFrameNumber = iframeNumber; - free(threadBuffer); - threadBuffer = NULL; - -#ifndef WIN32 - gettimeofday(&clock2, NULL); - total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000 - + (clock2.tv_usec - clock0.tv_usec) / 1000 - - sleepTime; - disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000 - + (clock2.tv_usec - clock1.tv_usec) / 1000 - - sleepTime; -#else - clock2 = timeGetTime(); - total_msec = clock2 - clock0 - sleepTime; - disp_msec = clock2 - clock1 - sleepTime; -#endif - logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec); - } -} - -void Player::threadPostStopCleanup() -{ - if (threadBuffer) - { - free(threadBuffer); - threadBuffer = NULL; - } -} - -// ----------------------------------- Dev - -#ifdef DEV -void Player::test1() -{ - logger->log("Player", Log::DEBUG, "PLAYER TEST 1"); -} - -void Player::test2() -{ - logger->log("Player", Log::DEBUG, "PLAYER TEST 2"); -} -#endif diff --git a/player.h b/player.h deleted file mode 100644 index 45d221c..0000000 --- a/player.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - Copyright 2004-2008 Chris Tallon - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef PLAYER_H -#define PLAYER_H - -#include -#include -#ifndef WIN32 -#include -#endif -#include - -#include "threadsystem.h" - -#include "callback.h" -#include "defines.h" -#include "vfeed.h" -#include "afeed.h" -#include "tfeed.h" - -#include "teletextdecodervbiebu.h" - -class MessageQueue; -class Audio; -class Video; -class VDR; -class Log; -class Demuxer; -class OSDReceiver; -class DVBSubtitles; -class Channel; - -class Player : public Thread_TYPE, public Callback -{ - public: - Player(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver); - virtual ~Player(); - - int init(bool p_isPesRecording,double framespersec); - int shutdown(); - void setStartFrame(ULONG frameNum); - void setLengthBytes(ULLONG length); - void setLengthFrames(ULONG length); - void setAudioChannel(int newChannel, int type, int streamtype); - void setSubtitleChannel(int newChannel); - bool toggleSubtitles(); - void turnSubtitlesOn(bool ison); - bool isSubtitlesOn() { return subtitlesShowing; } - void tellSubtitlesOSDVisible(bool visible); - - void play(); - void stop(); - void pause(); - void playpause(); - void fastForward(); - void fastBackward(); - void jumpToPercent(double percent); - void skipForward(int seconds); - void skipBackward(int seconds); - void jumpToMark(int mark); - void jumpToFrameP(int newFrame); - - UCHAR getState() { return state; } - ULONG getCurrentFrameNum(); - ULONG getLengthFrames(); - UCHAR getIScanRate() { return ifactor; } - bool* getDemuxerMpegAudioChannels(); - bool* getDemuxerAc3AudioChannels(); - bool* getDemuxerSubtitleChannels(); - int *getTeletxtSubtitlePages(); - int getCurrentAudioChannel(); - int getCurrentSubtitleChannel(); - bool isPesRecording() { return is_pesrecording; } - Channel *getDemuxerChannel(); - - TeletextDecoderVBIEBU * getTeletextDecoder() { return teletext; } - - void call(void*); // for callback interface - - const static UCHAR S_PLAY = 1; - const static UCHAR S_PAUSE_P = 2; - const static UCHAR S_PAUSE_I = 3; - const static UCHAR S_FFWD = 4; - const static UCHAR S_FBWD = 5; - const static UCHAR S_STOP = 6; - const static UCHAR S_JUMP = 7; - const static UCHAR S_JUMP_PI = 8; // Jump to Pause_I mode - - // Player events - - // FIXME so far this just duplicates the old system + the wss - - const static UCHAR CONNECTION_LOST = 1; - const static UCHAR STOP_PLAYBACK = 2; - const static UCHAR STREAM_END = 3; - const static UCHAR ASPECT43 = 4; - const static UCHAR ASPECT169 = 5; - -#ifdef DEV - void test1(); - void test2(); -#endif - - protected: - void threadMethod(); - void threadPostStopCleanup(); - - private: - void switchState(UCHAR newState, ULONG jumpFrame=0); - - void threadFeedPlay(); - void threadFeedScan(); - void threadPTSFeedScan(); - - void doConnectionLost(); - void restartAtFrame(ULONG newFrame); - void restartAtFramePI(ULONG newFrame); - - bool subtitlesShowing{}; - MessageQueue* messageQueue; - void* messageReceiver; - OSDReceiver* osdReceiver; - Log* logger; - Audio* audio; - Video* video; - Demuxer* demuxer; - DVBSubtitles* subtitles; - VDR* vdr; - VFeed vfeed; - AFeed afeed; - TFeed tfeed; - TeletextDecoderVBIEBU *teletext; - - - - bool initted{}; - bool startup; - bool videoStartup{}; - - bool is_pesrecording{true}; - double fps; - -#ifndef WIN32 - pthread_mutex_t mutex; -#else - HANDLE mutex; -#endif - void lock(); - void unLock(); - - ULLONG lengthBytes{}; - ULONG lengthFrames{}; - ULONG currentFrameNumber{}; - UINT blockSize{100000}; - UINT startupBlockSize{250000}; - UCHAR* threadBuffer{}; - UCHAR state{S_STOP}; - UCHAR ifactor{4}; // 4, 8, 16, 32 -}; - -#endif - - -/* - -Possible states: - -Play, Pause, FFwd, FBwd, (Stop), [Jump] - - Possible Working - -Play -> PauseP * * - -> PauseI - -> FFwd * * - -> FBwd * * - -> Stop * * - -> Jump * * - -> Jump_PI * * - -PauseP -> Play * * - -> PauseI - -> FFwd * * - -> FBwd * * - -> Stop * * - -> Jump * * - -> Jump_PI * * - -PauseI -> Play * * - -> PauseP - -> FFwd * * - -> FBwd * * - -> Stop * * - -> Jump * * - -> Jump_PI * * - -FFwd -> Play * * - -> PauseP - -> PauseI * * - -> FBwd * * - -> Stop * * - -> Jump * * - -> Jump_PI * * - -FBwd -> Play * * - -> PauseP - -> PauseI * * - -> FFwd * * - -> Stop * * - -> Jump * * - -> Jump_PI * * - -Stop -> Play * * - -> PauseP - -> PauseI - -> FFwd - -> FBwd - -> Jump - -> Jump_PI - -*/ diff --git a/playerradio.h b/playerradio.h index 9cf5f70..07f9f41 100644 --- a/playerradio.h +++ b/playerradio.h @@ -74,6 +74,7 @@ class PlayerRadio : public Thread_TYPE, public Callback const static UCHAR S_PLAY = 1; const static UCHAR S_PAUSE_P = 2; + const static UCHAR S_PAUSE_I = 3; const static UCHAR S_STOP = 6; const static UCHAR S_JUMP = 7; diff --git a/playervideorec.cc b/playervideorec.cc new file mode 100644 index 0000000..0d138bf --- /dev/null +++ b/playervideorec.cc @@ -0,0 +1,1402 @@ +/* + Copyright 2004-2008 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP. If not, see . +*/ + +#include "log.h" +#include "audio.h" +#include "video.h" +#include "demuxervdr.h" +#include "demuxerts.h" +#include "vdr.h" +#include "messagequeue.h" +#include "input.h" +#include "message.h" +#include "dvbsubtitles.h" +#include "osdreceiver.h" + +#include "playervideorec.h" + +#define USER_RESPONSE_TIME 500 // Milliseconds + +// ----------------------------------- Called from outside, one offs or info funcs + +PlayerVideoRec::PlayerVideoRec(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver) +: vfeed(this), afeed(this), tfeed(this), messageQueue(tmessageQueue), + messageReceiver(tmessageReceiver), osdReceiver(tosdReceiver) +{ + audio = Audio::getInstance(); + video = Video::getInstance(); + logger = Log::getInstance(); + vdr = VDR::getInstance(); + + video->turnVideoOn(); +} + +PlayerVideoRec::~PlayerVideoRec() +{ + if (initted) shutdown(); +} + +int PlayerVideoRec::init(bool p_isPesRecording, double framespersecond) +{ + if (initted) return 0; + is_pesrecording = p_isPesRecording; + fps = framespersecond; + if (is_pesrecording) + demuxer = new DemuxerVDR(); + else + demuxer = new DemuxerTS(); + if (!demuxer) return 0; + subtitles = new DVBSubtitles(osdReceiver); + if (!subtitles) return 0; + + teletext = new TeletextDecoderVBIEBU(); + if (!teletext) return 0; + teletext->setRecordigMode(true); + unsigned int demux_video_size = 2097152; + unsigned int demux_audio_size = 524288; + if (video->supportsh264()) + { + demux_video_size *= 5 * 2; + } + if (audio->maysupportAc3()) + { + //demux_audio_size*=2; + } + + if (!demuxer->init(this, audio, video,teletext, demux_video_size,demux_audio_size,65536, framespersecond, subtitles)) + { + logger->log("Player", Log::ERR, "Demuxer failed to init"); + shutdown(); + return 0; + } + + vfeed.init(); + afeed.init(); + tfeed.init(); + + video->stop(); + video->blank(); + audio->stop(); + + if (Command::getInstance()->getSubDefault()) + turnSubtitlesOn(true); + else + turnSubtitlesOn(false); + + initted = true; + return 1; +} + +int PlayerVideoRec::shutdown() +{ + if (!initted) return 0; + switchState(S_STOP); + initted = false; + + delete demuxer; + demuxer = NULL; + delete subtitles; + subtitles = NULL; + delete teletext; + teletext = NULL; + + return 1; +} + +void PlayerVideoRec::setStartFrame(ULONG startFrame) +{ + ULONG nextiframeNumber; + ULONG iframeLength; + ULONG iframeNumber; + ULLONG filePos; + + // newFrame could be anywhere, go forwards to next I-Frame + if (!vdr->getNextIFrame(startFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return; + + // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame + vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength); + + logger->log("Player", Log::DEBUG, "setStartFrame %lu %lu %lu", startFrame, nextiframeNumber,iframeNumber); + currentFrameNumber = iframeNumber; +} + +void PlayerVideoRec::setLengthBytes(ULLONG length) +{ + lengthBytes = length; + logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes); +} + +void PlayerVideoRec::setLengthFrames(ULONG length) +{ + lengthFrames = length; + logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames); +} + +ULONG PlayerVideoRec::getLengthFrames() +{ + return lengthFrames; +} + +ULONG PlayerVideoRec::getCurrentFrameNum() +{ + if (startup) return 0; + switch(state) + { + case S_PLAY: + case S_PAUSE_P: + return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp()); + case S_PAUSE_I: + case S_FFWD: + case S_FBWD: + return currentFrameNumber; + default: + return 0; // shouldn't happen + } +} + +bool* PlayerVideoRec::getDemuxerMpegAudioChannels() +{ + return demuxer->getmpAudioChannels(); +} + +bool* PlayerVideoRec::getDemuxerAc3AudioChannels() +{ + return demuxer->getac3AudioChannels(); +} + +bool* PlayerVideoRec::getDemuxerSubtitleChannels() +{ + return demuxer->getSubtitleChannels(); +} + +int PlayerVideoRec::getCurrentAudioChannel() +{ + if (is_pesrecording) + return demuxer->getselAudioChannel(); + else + return dynamic_cast(demuxer)->getAID(); +} + +int PlayerVideoRec::getCurrentSubtitleChannel() +{ + if (is_pesrecording) + return demuxer->getselSubtitleChannel(); + else + return dynamic_cast(demuxer)->getSubID(); +} + +void PlayerVideoRec::setSubtitleChannel(int newChannel) +{ + if (is_pesrecording) + demuxer->setDVBSubtitleStream(newChannel); + else + dynamic_cast(demuxer)->setSubID(newChannel); +} + +int *PlayerVideoRec::getTeletxtSubtitlePages() +{ + return teletext->getSubtitlePages(); +} + +void PlayerVideoRec::setAudioChannel(int newChannel, int type, int streamtype) +{ + if (is_pesrecording) + { + demuxer->setAudioStream(newChannel); + return; + } + else + { + dynamic_cast(demuxer)->setAID(newChannel,type,streamtype,false); + return; + } +} + +bool PlayerVideoRec::toggleSubtitles() +{ + if (!subtitlesShowing) + { + subtitlesShowing = true; + subtitles->show(); + } + else + { + subtitlesShowing = false; + subtitles->hide(); + } + return subtitlesShowing; +} + +void PlayerVideoRec::turnSubtitlesOn(bool ison) +{ + if (ison) + { + subtitlesShowing = true; + subtitles->show(); + } + else + { + subtitlesShowing = false; + subtitles->hide(); + } +} + +void PlayerVideoRec::tellSubtitlesOSDVisible(bool visible) +{ + subtitles->setOSDMenuVisibility(visible); +} + +Channel * PlayerVideoRec::getDemuxerChannel() +{ + if (!is_pesrecording) + { + return dynamic_cast(demuxer)->getChannelInfo(); + } + return NULL; //Should not happen! +} + + +// ----------------------------------- Externally called events + +void PlayerVideoRec::play() +{ + if (!initted) return; + if (state == S_PLAY) return; + stateMutex.lock(); + + bool doUnlock = false; + if (state == S_PAUSE_P) doUnlock = true; + switchState(S_PLAY); + if (doUnlock) stateMutex.unlock(); +} + +void PlayerVideoRec::playpause() +{ + if (!initted) return; + stateMutex.lock(); + + bool doUnlock = false; + if (state==S_PLAY) + { + doUnlock=true; + switchState(S_PAUSE_P); + } + else + { + if (state == S_PAUSE_P) doUnlock = true; + switchState(S_PLAY); + } + if (doUnlock) stateMutex.unlock(); +} + +void PlayerVideoRec::stop() +{ + if (!initted) return; + if (state == S_STOP) return; + stateMutex.lock(); + logger->log("Player", Log::DEBUG, "Stop called lock"); + switchState(S_STOP); + stateMutex.unlock(); +} + +void PlayerVideoRec::pause() +{ + if (!initted) return; + stateMutex.lock(); + + if ((state == S_FFWD) || (state == S_FBWD)) + { + switchState(S_PAUSE_I); + } + else if ((state == S_PAUSE_I) || (state == S_PAUSE_P)) + { + switchState(S_PLAY); + } + else + { + switchState(S_PAUSE_P); + } + + stateMutex.unlock(); +} + +void PlayerVideoRec::fastForward() +{ + if (!initted) return; + stateMutex.lock(); + + if (state == S_FFWD) + { + // change the rate + switch(ifactor) + { + case 4: ifactor = 8; break; + case 8: ifactor = 16; break; + case 16: ifactor = 32; break; + case 32: ifactor = 4; break; + } + } + else + { + ifactor = 4; + switchState(S_FFWD); + } + stateMutex.unlock(); +} + +void PlayerVideoRec::fastBackward() +{ + if (!initted) return; + stateMutex.lock(); + + if (state == S_FBWD) + { + // change the rate + switch(ifactor) + { + case 4: ifactor = 8; break; + case 8: ifactor = 16; break; + case 16: ifactor = 32; break; + case 32: ifactor = 4; break; + } + } + else + { + ifactor = 4; + switchState(S_FBWD); + } + stateMutex.unlock(); +} + +void PlayerVideoRec::jumpToPercent(double percent) +{ + stateMutex.lock(); + logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent); + ULONG newFrame = static_cast(percent * lengthFrames / 100); + switchState(S_JUMP, newFrame); +// stateMutex.unlock(); - let thread unlock this +} + +void PlayerVideoRec::jumpToMark(int mark) +{ + stateMutex.lock(); + logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark); + switchState(S_JUMP, mark); +// stateMutex.unlock(); - let thread unlock this +} + +void PlayerVideoRec::jumpToFrameP(int newFrame) +{ + stateMutex.lock(); + logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame); + switchState(S_JUMP_PI, newFrame); + stateMutex.unlock(); +} + +void PlayerVideoRec::skipForward(int seconds) +{ + stateMutex.lock(); + logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); + ULONG newFrame = getCurrentFrameNum(); + if (newFrame == 0) { stateMutex.unlock(); return; } // Current pos from demuxer is not valid + newFrame += static_cast(static_cast(seconds) * fps); + if (newFrame > lengthFrames) { switchState(S_PLAY); stateMutex.unlock(); } + else switchState(S_JUMP, newFrame); +// stateMutex.unlock(); - let thread unlock this +} + +void PlayerVideoRec::skipBackward(int seconds) +{ + stateMutex.lock(); + logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); + long newFrame = getCurrentFrameNum(); + if (newFrame == 0) { stateMutex.unlock(); return; } // Current pos from demuxer is not valid + newFrame -= static_cast(static_cast(seconds) * fps); + if (newFrame < 0) newFrame = 0; + switchState(S_JUMP, newFrame); +// stateMutex.unlock(); - let thread unlock this +} + +// ----------------------------------- Implementations called events + +void PlayerVideoRec::switchState(UCHAR toState, ULONG jumpFrame) +{ + if (!initted) return; + + logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState); + + switch(state) // current state selector + { + case S_PLAY: // from S_PLAY ----------------------------------- + { + switch(toState) + { + case S_PLAY: // to S_PLAY + { + return; + } + case S_PAUSE_P: // to S_PAUSE_P + { + #ifdef VOMP_PLATFORM_RASPBERRY + vfeed.stop(); // can't vfeed during pause + #endif + + video->pause(); + audio->pause(); + state = S_PAUSE_P; + return; + } + case S_PAUSE_I: // to S_PAUSE_I + { + // can't occur + return; + } + case S_FFWD: // to S_FFWD + { + currentFrameNumber = getCurrentFrameNum(); + audio->systemMuteOn(); + threadStop(); + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + demuxer->flush(); + state = S_FFWD; + threadStart(); + return; + } + case S_FBWD: // to S_FBWD + { + currentFrameNumber = getCurrentFrameNum(); + audio->systemMuteOn(); + threadStop(); + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + demuxer->flush(); + state = S_FBWD; + threadStart(); + return; + } + case S_STOP: // to S_STOP + { + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + audio->unPause(); + video->reset(); + demuxer->reset(); + state = S_STOP; + return; + } + case S_JUMP: // to S_JUMP + { + restartAtFrame(jumpFrame); + return; + } + case S_JUMP_PI: // to S_JUMP_PI + { + audio->systemMuteOn(); + threadStop(); + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + demuxer->flush(); + state = S_PAUSE_I; + video->reset(); + video->play(); + restartAtFramePI(jumpFrame); + return; + } + } + } + FALLTHROUGH // keep compiler happy (all posibilities return) + case S_PAUSE_P: // from S_PAUSE_P ----------------------------------- + { + switch(toState) + { + case S_PLAY: // to S_PLAY + { + video->unPause(); + audio->unPause(); + + #ifdef VOMP_PLATFORM_RASPBERRY + vfeed.start(false); + #endif + + state = S_PLAY; + return; + } + case S_PAUSE_P: // to S_PAUSE_P + { + return; + } + case S_PAUSE_I: // to S_PAUSE_I + { + return; + } + case S_FFWD: // to S_FFWD + { + currentFrameNumber = getCurrentFrameNum(); + audio->systemMuteOn(); + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + threadStop(); + video->unPause(); + audio->unPause(); + state = S_FFWD; + threadStart(); + return; + } + case S_FBWD: // to S_FBWD + { + currentFrameNumber = getCurrentFrameNum(); + audio->systemMuteOn(); + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + threadStop(); + video->unPause(); + audio->unPause(); + state = S_FBWD; + threadStart(); + return; + } + case S_STOP: // to S_STOP + { + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + video->reset(); + audio->unPause(); + demuxer->reset(); + audio->systemMuteOff(); + state = S_STOP; + return; + } + case S_JUMP: // to S_JUMP + { + state = S_PLAY; + audio->systemMuteOn(); + audio->unPause(); + restartAtFrame(jumpFrame); + return; + } + case S_JUMP_PI: // to S_JUMP_PI + { + audio->systemMuteOn(); + audio->unPause(); + threadStop(); + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + demuxer->flush(); + state = S_PAUSE_I; + video->reset(); + video->play(); + restartAtFramePI(jumpFrame); + return; + } + } + } + FALLTHROUGH // keep compiler happy (all posibilities return) + case S_PAUSE_I: // from S_PAUSE_I ----------------------------------- + { + switch(toState) + { + case S_PLAY: // to S_PLAY + { + state = S_PLAY; + restartAtFrame(currentFrameNumber); + return; + } + case S_PAUSE_P: // to S_PAUSE_P + { + return; + } + case S_PAUSE_I: // to S_PAUSE_I + { + return; + } + case S_FFWD: // to S_FFWD + { + state = S_FFWD; + threadStart(); + return; + } + case S_FBWD: // to S_FBWD + { + state = S_FBWD; + threadStart(); + return; + } + case S_STOP: // to S_STOP + { + video->stop(); + video->blank(); + audio->stop(); + video->reset(); + demuxer->reset(); + audio->systemMuteOff(); + state = S_STOP; + return; + } + case S_JUMP: // to S_JUMP + { + state = S_PLAY; + restartAtFrame(jumpFrame); + return; + } + case S_JUMP_PI: // to S_JUMP_PI + { + restartAtFramePI(jumpFrame); + return; + } + } + } + FALLTHROUGH // keep compiler happy (all posibilities return) + case S_FFWD: // from S_FFWD ----------------------------------- + { + switch(toState) + { + case S_PLAY: // to S_PLAY + { + state = S_PLAY; + ULONG stepback = static_cast(USER_RESPONSE_TIME * ifactor * fps / 1000); + if (stepback < currentFrameNumber) + currentFrameNumber -= stepback; + else + currentFrameNumber = 0; + restartAtFrame(currentFrameNumber); + return; + } + case S_PAUSE_P: // to S_PAUSE_P + { + // can't occur + return; + } + case S_PAUSE_I: // to S_PAUSE_I + { + threadStop(); + state = S_PAUSE_I; + return; + } + case S_FFWD: // to S_FFWD + { + return; + } + case S_FBWD: // to S_FBWD + { + threadStop(); + state = S_FBWD; + threadStart(); + return; + } + case S_STOP: // to S_STOP + { + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + video->reset(); + demuxer->reset(); + state = S_STOP; + return; + } + case S_JUMP: // to S_JUMP + { + state = S_PLAY; + restartAtFrame(jumpFrame); + return; + } + case S_JUMP_PI: // to S_JUMP_PI + { + threadStop(); + state = S_PAUSE_I; + restartAtFramePI(jumpFrame); + return; + } + } + } + FALLTHROUGH // keep compiler happy (all posibilities return) + case S_FBWD: // from S_FBWD ----------------------------------- + { + switch(toState) + { + case S_PLAY: // to S_PLAY + { + state = S_PLAY; + restartAtFrame(currentFrameNumber); + return; + } + case S_PAUSE_P: // to S_PAUSE_P + { + // can't occur + return; + } + case S_PAUSE_I: // to S_PAUSE_I + { + threadStop(); + state = S_PAUSE_I; + return; + } + case S_FFWD: // to S_FFWD + { + threadStop(); + state = S_FFWD; + threadStart(); + return; + } + case S_FBWD: // to S_FBWD + { + return; + } + case S_STOP: // to S_STOP + { + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + video->reset(); + demuxer->reset(); + state = S_STOP; + return; + } + case S_JUMP: // to S_JUMP + { + state = S_PLAY; + restartAtFrame(jumpFrame); + return; + } + case S_JUMP_PI: // to S_JUMP_PI + { + threadStop(); + state = S_PAUSE_I; + restartAtFramePI(jumpFrame); + return; + } + } + } + FALLTHROUGH // keep compiler happy (all posibilities return) + case S_STOP: // from S_STOP ----------------------------------- + { + switch(toState) + { + case S_PLAY: // to S_PLAY + { + startup = true; + + audio->reset(); + audio->setStreamType(Audio::MPEG2_PES); + audio->systemMuteOff(); + video->reset(); + demuxer->reset(); + // FIXME use restartAtFrame here? + if (currentFrameNumber > lengthFrames) currentFrameNumber = 0; + demuxer->setFrameNum(currentFrameNumber); + demuxer->seek(); + videoStartup = true; + state = S_PLAY; + threadStart(); + logger->log("Player", Log::DEBUG, "Immediate play"); + afeed.start(); + vfeed.start(); + tfeed.start(); + subtitles->start(); + video->sync(); + audio->sync(); + audio->play(); + video->pause(); + return; + } + case S_PAUSE_P: // to S_PAUSE_P + { + return; + } + case S_PAUSE_I: // to S_PAUSE_I + { + return; + } + case S_FFWD: // to S_FFWD + { + return; + } + case S_FBWD: // to S_FBWD + { + return; + } + case S_STOP: // to S_STOP + { + return; + } + case S_JUMP: // to S_JUMP + { + return; + } + case S_JUMP_PI: // to S_JUMP_PI + { + return; + } + } + } + // case S_JUMP cannot be a start state because it auto flips to play + // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I + } +} + +// ----------------------------------- Internal functions + +void PlayerVideoRec::restartAtFrame(ULONG newFrame) +{ + vfeed.stop(); + afeed.stop(); + tfeed.stop(); + subtitles->stop(); + threadStop(); + video->stop(); + video->reset(); + audio->reset(); + audio->setStreamType(Audio::MPEG2_PES); + demuxer->flush(); + demuxer->seek(); + currentFrameNumber = newFrame; + demuxer->setFrameNum(newFrame); + videoStartup = true; + afeed.start(); + tfeed.start(); + vfeed.start(); + subtitles->start(); + threadStart(); + audio->play(); + video->sync(); + audio->sync(); + audio->systemMuteOff(); + audio->doMuting(); +} + + +void PlayerVideoRec::restartAtFramePI(ULONG newFrame) +{ + ULLONG filePos; + ULONG nextiframeNumber; + ULONG iframeLength; + ULONG iframeNumber; + + UCHAR* buffer; + UINT amountReceived; + UINT videoLength; + + // newFrame could be anywhere, go forwards to next I-Frame + if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return; + + // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame + vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength); + + buffer = vdr->getBlock(filePos, iframeLength, &amountReceived); + if (!vdr->isConnected()) + { + if (buffer) free(buffer); + doConnectionLost(); + } + else + { + videoLength = demuxer->stripAudio(buffer, amountReceived); + video->displayIFrame(buffer, videoLength); + video->displayIFrame(buffer, videoLength); // If you do it twice, it works :) + free(buffer); + currentFrameNumber = iframeNumber; + } +} + +void PlayerVideoRec::doConnectionLost() +{ + logger->log("Player", Log::DEBUG, "Connection lost, sending message"); + Message* m = new Message(); + m->to = messageReceiver; + m->from = this; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoRec::CONNECTION_LOST; + messageQueue->postMessage(m); +} + +// ----------------------------------- Callback + +void PlayerVideoRec::call(void* caller) +{ + if (caller == demuxer) + { + logger->log("Player", Log::DEBUG, "Callback from demuxer"); + + if (video->getTVsize() == Video::ASPECT4X3) + { + logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching"); + return; + } + + int parx,pary; + int dxCurrentAspect = demuxer->getAspectRatio(&parx,&pary); + if (dxCurrentAspect == Demuxer::ASPECT_4_3) + { + logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV"); + video->setAspectRatio(Video::ASPECT4X3,parx,pary); + + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoRec::ASPECT43; + messageQueue->postMessage(m); + } + else if (dxCurrentAspect == Demuxer::ASPECT_16_9) + { + logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV"); + video->setAspectRatio(Video::ASPECT16X9,parx,pary); + + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoRec::ASPECT169; + messageQueue->postMessage(m); + } + else + { + logger->log("Player", Log::DEBUG, "Demuxer said video is something else... setting it anyway"); + video->setAspectRatio(static_cast(dxCurrentAspect), parx, pary); + } + + } + else + { + if (videoStartup) + { + videoStartup = false; + video->reset(); + video->play(); + video->sync(); + vfeed.release(); + stateMutex.unlock(); + } + + threadSignalNoLock(); + } +} + +// ----------------------------------- Feed thread + +void PlayerVideoRec::threadMethod() +{ + // this method used to be simple, the only thing it does + // is farm out to threadFeed Live/Play/Scan + // All the guff is to support scan hitting one end + + if ((state == S_FFWD) || (state == S_FBWD)) + { + if (video->PTSIFramePlayback()) threadPTSFeedScan(); + else threadFeedScan(); + // if this returns then scan hit one end + if (state == S_FFWD) // scan hit the end. stop + { + threadCheckExit(); + Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex + m->to = messageReceiver; + m->from = this; + m->message = Message::PLAYER_EVENT; + m->parameter = STOP_PLAYBACK; + logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue); + messageQueue->postMessage(m); + logger->log("Player", Log::DEBUG, "Message posted..."); + return; + } + // if execution gets to here, threadFeedScan hit the start, go to play mode + state = S_PLAY; + audio->reset(); + audio->setStreamType(Audio::MPEG2_PES); + demuxer->flush(); + demuxer->seek(); + demuxer->setFrameNum(currentFrameNumber); + videoStartup = true; + afeed.start(); + tfeed.start(); + vfeed.start(); + subtitles->start(); + audio->play(); + audio->sync(); + audio->systemMuteOff(); + audio->doMuting(); + } + + if (state == S_PLAY) threadFeedPlay(); +} + +void PlayerVideoRec::threadFeedPlay() +{ + ULLONG feedPosition; + UINT thisRead, writeLength, thisWrite, askFor; + time_t lastRescan = time(NULL); + + feedPosition = vdr->positionFromFrameNumber(currentFrameNumber); + if (!vdr->isConnected()) { doConnectionLost(); return; } + logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition); + + + while(1) + { + thisRead = 0; + writeLength = 0; + thisWrite = 0; + + threadCheckExit(); + + // If we havn't rescanned for a while.. + if ((lastRescan + 60) < time(NULL)) + { + lengthBytes = vdr->rescanRecording(&lengthFrames); + if (!vdr->isConnected()) { doConnectionLost(); return; } + logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes); + lastRescan = time(NULL); + } + + if (feedPosition >= lengthBytes) break; // finished playback + + if (startup) + { + if (startupBlockSize > lengthBytes) + askFor = static_cast(lengthBytes); // is a very small recording! + else + askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams + } + else + { + if ((feedPosition + blockSize) > lengthBytes) // last block of recording + askFor = static_cast(lengthBytes - feedPosition); + else // normal + askFor = blockSize; + } + //logger->log("Player", Log::DEBUG, "Get Block in"); + + threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead); + //logger->log("Player", Log::DEBUG, "Get Block out"); + + feedPosition += thisRead; + + if (!vdr->isConnected()) + { + doConnectionLost(); + return; + } + + if (!threadBuffer) break; + + if (startup) + { + int a_stream = demuxer->scan(threadBuffer, thisRead); + demuxer->setAudioStream(a_stream); + logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream); + startup = false; + } + + threadCheckExit(); + + while(writeLength < thisRead) + { + //logger->log("Player", Log::DEBUG, "Put in"); + thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength); + //logger->log("Player", Log::DEBUG, "Put out"); + writeLength += thisWrite; + + if (!thisWrite) + { + // demuxer is full and can't take anymore + threadLock(); + if (!threadActive) { threadUnlock(); threadCheckExit(); } + threadWaitForSignal(); + threadUnlock(); + } + + threadCheckExit(); + } + + free(threadBuffer); + threadBuffer = NULL; + + } + + // end of recording + logger->log("Player", Log::DEBUG, "Recording playback ends"); + + if (videoStartup) // oh woe. there never was a stream, I was conned! + { + videoStartup = false; + stateMutex.unlock(); + MILLISLEEP(500); // I think this will solve a race + } + + threadCheckExit(); + + + Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex + m->to = messageReceiver; + m->from = this; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoRec::STOP_PLAYBACK; + logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue); + messageQueue->postMessage(m); +} + + +void PlayerVideoRec::threadPTSFeedScan() +{ + // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows? + + ULONG direction = 0; + int dir_fac=-1; + ULONG baseFrameNumber = 0; + ULONG iframeNumber = 0; + ULONG iframeLength = 0; + ULONG currentfeedFrameNumber=currentFrameNumber; + ULONG firstFrameNumber=currentFrameNumber; + ULLONG filePos; + UINT amountReceived; + UINT videoLength; + + UINT playtime=0; + + int frameTimeOffset = 0; // Time in msec between frames + + if (state == S_FFWD) + { + direction = 1; // and 0 for backward + dir_fac = 1; + } + video->EnterIframePlayback(); + + while(1) + { + baseFrameNumber = currentfeedFrameNumber; + + threadCheckExit(); + if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength)) + return; + + if (iframeNumber >= lengthFrames) return; + // scan has got to the end of what we knew to be there before we started scanning + + baseFrameNumber = iframeNumber; + + frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor)); + + logger->log("Player", Log::DEBUG, "XXX Got frame"); + + threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived); + + if (!vdr->isConnected()) + { + if (threadBuffer) free(threadBuffer); + doConnectionLost(); + break; + } + + + threadCheckExit(); + + + videoLength = demuxer->stripAudio(threadBuffer, amountReceived); + demuxer->changeTimes(threadBuffer,videoLength,playtime); + int count=0; + while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block + { + MILLISLEEP(20); + threadCheckExit(); + count++; + if (count%300==0) { + ULLONG cur_time=video->getCurrentTimestamp(); + // logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g", + // firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps); + if (cur_time!=0) { + currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.)); + } + } + + } + playtime +=frameTimeOffset; + currentfeedFrameNumber = iframeNumber; + { + ULLONG cur_time=video->getCurrentTimestamp(); + // logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g", + // firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps); + if (cur_time!=0) { + currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.)); + } + } + + free(threadBuffer); + threadBuffer = NULL; + } +} + + + +void PlayerVideoRec::threadFeedScan() +{ + // This method is actually really simple - get frame from vdr, + // spit it at the video chip, wait for a time. Most of the code here + // is to get the wait right so that the scan occurs at the correct rate. + + ULONG direction = 0; + ULONG baseFrameNumber = 0; + ULONG iframeNumber = 0; + ULONG iframeLength = 0; + ULLONG filePos; + UINT amountReceived; + UINT videoLength; + +#ifndef WIN32 + struct timeval clock0 = {0,0}; // Time stamp after fetching I-frame info + struct timeval clock1 = {0,0}; // Time stamp after fetching I-frame data + struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame +#else + DWORD clock0 = 0, clock1 = 0, clock2 = 0; +#endif + + int frameTimeOffset = 0; // Time in msec between frames + int disp_msec = 0; // Time taken to display data + int total_msec = 0; // Time taken to fetch data and display it + int sleepTime = 0; + + if (state == S_FFWD) direction = 1; // and 0 for backward + + while(1) + { + // Fetch I-frames until we get one that can be displayed in good time + // Repeat while clock0 + total_msec > clock2 + frameTimeOffset + + baseFrameNumber = currentFrameNumber; + do + { + threadCheckExit(); + if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength)) + return; + + if (iframeNumber >= lengthFrames) return; + // scan has got to the end of what we knew to be there before we started scanning + + baseFrameNumber = iframeNumber; + frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor)); +#ifndef WIN32 + gettimeofday(&clock0, NULL); +#else + clock0 = timeGetTime(); +#endif + } +#ifndef WIN32 + while (clock2.tv_sec != 0 && + (clock0.tv_sec - clock2.tv_sec) * 1000 + + (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec); +#else + while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset); +#endif + logger->log("Player", Log::DEBUG, "XXX Got frame"); + + threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived); + + if (!vdr->isConnected() || !amountReceived) + { + if (threadBuffer) free(threadBuffer); + doConnectionLost(); + break; + } + +#ifndef WIN32 + gettimeofday(&clock1, NULL); + if (clock2.tv_sec != 0) + sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000 + + (clock2.tv_usec - clock1.tv_usec) / 1000 + + frameTimeOffset - disp_msec; +#else + clock1 = timeGetTime(); + if (clock2 != 0) + sleepTime = clock2 + frameTimeOffset - disp_msec - clock1; +#endif + if (sleepTime < 0) sleepTime = 0; + threadCheckExit(); + MILLISLEEP(sleepTime); + logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime); + + videoLength = demuxer->stripAudio(threadBuffer, amountReceived); + video->displayIFrame(threadBuffer, videoLength); + currentFrameNumber = iframeNumber; + free(threadBuffer); + threadBuffer = NULL; + +#ifndef WIN32 + gettimeofday(&clock2, NULL); + total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000 + + (clock2.tv_usec - clock0.tv_usec) / 1000 + - sleepTime; + disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000 + + (clock2.tv_usec - clock1.tv_usec) / 1000 + - sleepTime; +#else + clock2 = timeGetTime(); + total_msec = clock2 - clock0 - sleepTime; + disp_msec = clock2 - clock1 - sleepTime; +#endif + logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec); + } +} + +void PlayerVideoRec::threadPostStopCleanup() +{ + if (threadBuffer) + { + free(threadBuffer); + threadBuffer = NULL; + } +} + +// ----------------------------------- Dev + +#ifdef DEV +void PlayerVideoRec::test1() +{ + logger->log("Player", Log::DEBUG, "PLAYER TEST 1"); +} + +void PlayerVideoRec::test2() +{ + logger->log("Player", Log::DEBUG, "PLAYER TEST 2"); +} +#endif diff --git a/playervideorec.h b/playervideorec.h new file mode 100644 index 0000000..05e47b8 --- /dev/null +++ b/playervideorec.h @@ -0,0 +1,231 @@ +/* + Copyright 2004-2008 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef PLAYERVIDEOREC_H +#define PLAYERVIDEOREC_H + +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include + +#include "threadsystem.h" + +#include "callback.h" +#include "defines.h" +#include "vfeed.h" +#include "afeed.h" +#include "tfeed.h" + +#include "teletextdecodervbiebu.h" + +class MessageQueue; +class Audio; +class Video; +class VDR; +class Log; +class Demuxer; +class OSDReceiver; +class DVBSubtitles; +class Channel; + +class PlayerVideoRec : public Thread_TYPE, public Callback +{ + public: + PlayerVideoRec(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver); + virtual ~PlayerVideoRec(); + + int init(bool p_isPesRecording,double framespersec); + int shutdown(); + void setStartFrame(ULONG frameNum); + void setLengthBytes(ULLONG length); + void setLengthFrames(ULONG length); + void setAudioChannel(int newChannel, int type, int streamtype); + void setSubtitleChannel(int newChannel); + bool toggleSubtitles(); + void turnSubtitlesOn(bool ison); + bool isSubtitlesOn() { return subtitlesShowing; } + void tellSubtitlesOSDVisible(bool visible); + + void play(); + void stop(); + void pause(); + void playpause(); + void fastForward(); + void fastBackward(); + void jumpToPercent(double percent); + void skipForward(int seconds); + void skipBackward(int seconds); + void jumpToMark(int mark); + void jumpToFrameP(int newFrame); + + UCHAR getState() { return state; } + ULONG getCurrentFrameNum(); + ULONG getLengthFrames(); + UCHAR getIScanRate() { return ifactor; } + bool* getDemuxerMpegAudioChannels(); + bool* getDemuxerAc3AudioChannels(); + bool* getDemuxerSubtitleChannels(); + int *getTeletxtSubtitlePages(); + int getCurrentAudioChannel(); + int getCurrentSubtitleChannel(); + bool isPesRecording() { return is_pesrecording; } + Channel *getDemuxerChannel(); + + TeletextDecoderVBIEBU * getTeletextDecoder() { return teletext; } + + void call(void*); // for callback interface + + const static UCHAR S_PLAY = 1; + const static UCHAR S_PAUSE_P = 2; + const static UCHAR S_PAUSE_I = 3; + const static UCHAR S_FFWD = 4; + const static UCHAR S_FBWD = 5; + const static UCHAR S_STOP = 6; + const static UCHAR S_JUMP = 7; + const static UCHAR S_JUMP_PI = 8; // Jump to Pause_I mode + + // Player events + + // FIXME so far this just duplicates the old system + the wss + + const static UCHAR CONNECTION_LOST = 1; + const static UCHAR STOP_PLAYBACK = 2; + const static UCHAR STREAM_END = 3; + const static UCHAR ASPECT43 = 4; + const static UCHAR ASPECT169 = 5; + +#ifdef DEV + void test1(); + void test2(); +#endif + + protected: + void threadMethod(); + void threadPostStopCleanup(); + + private: + void switchState(UCHAR newState, ULONG jumpFrame=0); + + void threadFeedPlay(); + void threadFeedScan(); + void threadPTSFeedScan(); + + void doConnectionLost(); + void restartAtFrame(ULONG newFrame); + void restartAtFramePI(ULONG newFrame); + + bool subtitlesShowing{}; + MessageQueue* messageQueue; + void* messageReceiver; + OSDReceiver* osdReceiver; + Log* logger; + Audio* audio; + Video* video; + Demuxer* demuxer; + DVBSubtitles* subtitles; + VDR* vdr; + VFeed vfeed; + AFeed afeed; + TFeed tfeed; + TeletextDecoderVBIEBU *teletext; + + bool initted{}; + bool startup; + bool videoStartup{}; + + bool is_pesrecording{true}; + double fps; + + std::mutex stateMutex; + + ULLONG lengthBytes{}; + ULONG lengthFrames{}; + ULONG currentFrameNumber{}; + UINT blockSize{100000}; + UINT startupBlockSize{250000}; + UCHAR* threadBuffer{}; + UCHAR state{S_STOP}; + UCHAR ifactor{4}; // 4, 8, 16, 32 +}; + +#endif + + +/* + +Possible states: + +Play, Pause, FFwd, FBwd, (Stop), [Jump] + + Possible Working + +Play -> PauseP * * + -> PauseI + -> FFwd * * + -> FBwd * * + -> Stop * * + -> Jump * * + -> Jump_PI * * + +PauseP -> Play * * + -> PauseI + -> FFwd * * + -> FBwd * * + -> Stop * * + -> Jump * * + -> Jump_PI * * + +PauseI -> Play * * + -> PauseP + -> FFwd * * + -> FBwd * * + -> Stop * * + -> Jump * * + -> Jump_PI * * + +FFwd -> Play * * + -> PauseP + -> PauseI * * + -> FBwd * * + -> Stop * * + -> Jump * * + -> Jump_PI * * + +FBwd -> Play * * + -> PauseP + -> PauseI * * + -> FFwd * * + -> Stop * * + -> Jump * * + -> Jump_PI * * + +Stop -> Play * * + -> PauseP + -> PauseI + -> FFwd + -> FBwd + -> Jump + -> Jump_PI + +*/ diff --git a/vdr.cc b/vdr.cc index c54e8f4..dc2820d 100644 --- a/vdr.cc +++ b/vdr.cc @@ -409,7 +409,7 @@ void VDR::threadMethod() vresp = new VDR_ResponsePacket(); vresp->setResponse(requestID, reinterpret_cast(userData), userDataLength); - logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength); +// logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength); if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() ) { diff --git a/vradiorec.cc b/vradiorec.cc index d53b7fa..f574ef3 100644 --- a/vradiorec.cc +++ b/vradiorec.cc @@ -19,7 +19,6 @@ #include "command.h" #include "osd.h" -#include "player.h" #include "wsymbol.h" #include "recording.h" #include "recinfo.h" @@ -312,7 +311,7 @@ void VRadioRec::processMessage(Message* m) switch(m->parameter) { - case Player::CONNECTION_LOST: // connection lost detected + case PlayerRadio::CONNECTION_LOST: // connection lost detected { // I can't handle this, send it to command Message* m2 = new Message(); @@ -321,7 +320,7 @@ void VRadioRec::processMessage(Message* m) MessageQueue::getInstance()->postMessage(m2); break; } - case Player::STOP_PLAYBACK: + case PlayerRadio::STOP_PLAYBACK: { // FIXME Obselete ish - improve this Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex @@ -386,9 +385,9 @@ void VRadioRec::doBar(int action) else { playerState = player->getState(); - if (playerState == Player::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE; - else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE; - else w.nextSymbol = WSymbol::PLAY; + if (playerState == PlayerRadio::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE; + else if (playerState == PlayerRadio::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE; + else w.nextSymbol = WSymbol::PLAY; } w.draw(); diff --git a/vvideorec.cc b/vvideorec.cc index f212b94..e71fa0d 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -25,7 +25,7 @@ #include "audio.h" #include "vdr.h" #include "video.h" -#include "player.h" +#include "playervideorec.h" #include "recording.h" #include "vaudioselector.h" #include "message.h" @@ -56,7 +56,7 @@ VVideoRec::VVideoRec(Recording* rec, bool ish264) video->seth264mode(ish264); - player = new Player(Command::getInstance(), this, this); + player = new PlayerVideoRec(Command::getInstance(), this, this); player->init(myRec->IsPesRecording,myRec->recInfo->fps); char* cstartMargin = vdr->configLoad("Timers", "Start margin"); @@ -518,7 +518,7 @@ void VVideoRec::processMessage(Message* m) if (m->message != Message::PLAYER_EVENT) return; switch(m->parameter) { - case Player::CONNECTION_LOST: // connection lost detected + case PlayerVideoRec::CONNECTION_LOST: // connection lost detected { // I can't handle this, send it to command Message* m2 = new Message(); @@ -527,7 +527,7 @@ void VVideoRec::processMessage(Message* m) MessageQueue::getInstance()->postMessage(m2); break; } - case Player::STOP_PLAYBACK: + case PlayerVideoRec::STOP_PLAYBACK: { // FIXME Obselete ish - improve this Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex @@ -536,11 +536,11 @@ void VVideoRec::processMessage(Message* m) MessageQueue::getInstance()->postMessage(m2); break; } - case Player::ASPECT43: + case PlayerVideoRec::ASPECT43: { break; } - case Player::ASPECT169: + case PlayerVideoRec::ASPECT169: { break; } @@ -559,7 +559,7 @@ void VVideoRec::processMessage(Message* m) case 0x10: { //dvbsubtitle player->setSubtitleChannel((m->parameter & 0xFFFF)); player->turnSubtitlesOn(true); - VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView(); + VTeletextView *vtxt = player->getTeletextDecoder()->getTeletxtView(); if (vtxt && vtxt->isInSubtitleMode()) { BoxStack::getInstance()->remove(vtxt); } @@ -567,7 +567,7 @@ void VVideoRec::processMessage(Message* m) case 0xFF: { //nosubtitles player->turnSubtitlesOn(false); - VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView(); + VTeletextView *vtxt = player->getTeletextDecoder()->getTeletxtView(); if (vtxt && vtxt->isInSubtitleMode()) { BoxStack::getInstance()->remove(vtxt); } @@ -576,7 +576,7 @@ void VVideoRec::processMessage(Message* m) case 0x11: { //videotext player->turnSubtitlesOn(false); doTeletext(); - ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF)); + player->getTeletextDecoder()->setPage((m->parameter & 0xFFFF)); } break; }; if (vas) { @@ -815,16 +815,16 @@ void VVideoRec::doBar(int action_in) else { playerState = player->getState(); - if (playerState == Player::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE; - else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE; - else if (playerState == Player::S_FFWD) w.nextSymbol = WSymbol::FFWD; - else if (playerState == Player::S_FBWD) w.nextSymbol = WSymbol::FBWD; + if (playerState == PlayerVideoRec::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE; + else if (playerState == PlayerVideoRec::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE; + else if (playerState == PlayerVideoRec::S_FFWD) w.nextSymbol = WSymbol::FFWD; + else if (playerState == PlayerVideoRec::S_FBWD) w.nextSymbol = WSymbol::FBWD; else w.nextSymbol = WSymbol::PLAY; } w.draw(); - if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) + if ((playerState == PlayerVideoRec::S_FFWD) || (playerState == PlayerVideoRec::S_FBWD)) { // draw blips to show how fast the scan is UCHAR scanrate = player->getIScanRate(); @@ -844,7 +844,7 @@ void VVideoRec::doBar(int action_in) timers->cancelTimer(this, 1); - if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true; + if ((playerState == PlayerVideoRec::S_FFWD) || (playerState == PlayerVideoRec::S_FBWD)) barScanHold = true; else barScanHold = false; if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4); @@ -889,7 +889,7 @@ void VVideoRec::drawBarClocks() // will repaint all the bar (it will call this function again, but // this section won't run because stickyBarF will then == false) - if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD)) + if ((playerState != PlayerVideoRec::S_FFWD) && (playerState != PlayerVideoRec::S_FBWD)) { barScanHold = false; doBar(0); diff --git a/vvideorec.h b/vvideorec.h index 9dfa4fd..2a68ee6 100644 --- a/vvideorec.h +++ b/vvideorec.h @@ -31,7 +31,7 @@ #include "video.h" class VDR; -class Player; +class PlayerVideoRec; class Recording; class VAudioSelector; class Message; @@ -65,7 +65,7 @@ class VVideoRec : public Boxx, public TimerReceiver, public OSDReceiver VDR* vdr; Video* video; Timers* timers; - Player* player; + PlayerVideoRec* player; Recording* myRec; VAudioSelector* vas;