From 4cc1cee53b2ee3c7ac4781408c244b23d09e2b6c Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sat, 13 Aug 2005 21:25:55 +0000 Subject: [PATCH] Whoops. --- playervideo.cc | 580 +++++++++++++++++++++++++++++++++++++++++++++++++ playervideo.h | 85 ++++++++ 2 files changed, 665 insertions(+) create mode 100644 playervideo.cc create mode 100644 playervideo.h diff --git a/playervideo.cc b/playervideo.cc new file mode 100644 index 0000000..8fc632f --- /dev/null +++ b/playervideo.cc @@ -0,0 +1,580 @@ +/* + Copyright 2004-2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "playervideo.h" + +PlayerVideo::PlayerVideo(MessageQueue* messageQueue, UCHAR tIsRecording) +: vfeed(this), afeed(this) +{ + commandMessageQueue = messageQueue; + + paused = 0; + playing = 0; + ffwd = 0; + fbwd = 0; + feedPosition = 0; + feedMode = MODE_NORMAL; + isRecording = tIsRecording; + lastRescan = 0; +} + +PlayerVideo::~PlayerVideo() +{ + if (initted) shutdown(); +} + +int PlayerVideo::init() +{ + if (initted) return 0; + + video = Video::getInstance(); + + if (demuxer.init()) // inverted + { + Log::getInstance()->log("Player", Log::ERR, "Demuxer failed to init"); + shutdown(); + return 0; + } + + vfeed.init(video->getFD()); + afeed.init(audio->getFD()); + + video->stop(); + video->blank(); + audio->stop(); + + startup = 0; + initted = 1; + return 1; +} + +int PlayerVideo::shutdown() +{ + if (!initted) return 0; + initted = 0; + + Log::getInstance()->log("Player", Log::DEBUG, "Player shutdown..."); + + // copy of stop + if (playing) + { + playing = 0; + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + vfeed.stop(); + afeed.stop(); + video->reset(); + demuxer.reset(); + feedPosition = 0; + } + + return 1; +} + +int PlayerVideo::play() +{ + if (!initted) return 0; + + // If we are just paused, unpause! + if (paused) + { + togglePause(); + return 1; + } + + // If we are fast forwarding, set to normal + if (ffwd) + { + toggleFastForward(); + return 1; + } + + // If we are fast backwarding, set to normal + if (fbwd) + { + toggleFastBackward(); + return 1; + } + + // If we are already playing, bail // FIXME - resync? + if (playing) + { + Log::getInstance()->log("Player", Log::DEBUG, "DOING RESYNC"); + +/* + vfeed.stop(); + afeed.stop(); + video->reset(); + audio->reset(); + demuxer.flush(); + demuxer.seek(); + vfeed.start(); + afeed.start(); + + + video->play(); + audio->play(); + video->sync(); + audio->sync(); + call(); +*/ + + // resync method 2.. + + video->pause(); + usleep(500000); + video->play(); + video->sync(); + + + return 1; + } + + // Standard play start + + audio->reset(); + video->reset(); + demuxer.reset(); + startup = 1; + +// ------------------------ This one works, but doesn't allow any pre-buffering. + threadStart(); + vfeed.start(); + afeed.start(); + audio->play(); + video->play(); + video->sync(); + audio->sync(); + + video->pause(); + usleep(500000); // SYNC + video->sync(); + video->unPause(); + video->sync(); + +// ------------------------ This one doesn't work, but it should, and would allow for prebuffering. + +/* + + threadStart(); + sleep(2); + +// struct timespec delay; +// delay.tv_sec = 1; +// delay.tv_nsec = 500000000; +// nanosleep(&delay, NULL); + + vfeed.start(); + afeed.start(); + video->play(); + audio->play(); + video->sync(); + audio->sync(); +*/ +// ------------------------------------------------------------------------------------------------ + + playing = 1; + return 1; +} + +void PlayerVideo::stop() +{ + if (!initted) return; + if (!playing) return; + + if (ffwd || fbwd) + { + ffwd = 0; + fbwd = 0; + afeed.enable(); + video->unFastForward(); + audio->systemMuteOff(); + feedMode = MODE_NORMAL; + } + + playing = 0; + paused = 0; + + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + audio->unPause(); + vfeed.stop(); + afeed.stop(); + video->reset(); + demuxer.reset(); + + feedPosition = 0; +} + +void PlayerVideo::togglePause() +{ + if (!initted) return; + if (!playing) return; + + if (ffwd) toggleFastForward(); + if (fbwd) toggleFastBackward(); + + if (paused) + { + video->unPause(); + audio->unPause(); + paused = 0; + } + else + { + video->pause(); + audio->pause(); + paused = 1; + } +} + +void PlayerVideo::test() +{ + Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST"); + +/* + +// video->test(); + + static int flipflop = 0; + + int a; + if (flipflop) a = video->setAspectRatio(Video::ASPECT16X9); + else a = video->setAspectRatio(Video::ASPECT4X3); + + flipflop = !flipflop; + + printf("A = %i\n", a); +*/ +} + +void PlayerVideo::test2() +{ + Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST"); + + video->test2(); +} + +void PlayerVideo::setPosition(ULLONG position) +{ + feedPosition = position; +} + +void PlayerVideo::setLength(ULLONG length) +{ + lastRescan = time(NULL); + streamLength = length; + Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Player has received length of %llu", streamLength); +} + +void PlayerVideo::skipForward(int seconds) +{ + // skip forward 1 minute + Log::getInstance()->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); + + if (paused) togglePause(); + + ULLONG moveBy = seconds * 500000; + + threadStop(); + vfeed.stop(); + afeed.stop(); + video->stop(); + video->reset(); + audio->reset(); + audio->doMuting(); // ??? + demuxer.flush(); + feedPosition += moveBy; + +// printf("Audio test %i\n", audio->test()); + + vfeed.start(); + afeed.start(); + threadStart(); + audio->play(); + video->play(); + video->sync(); + audio->sync(); + + video->pause(); + usleep(500000); // SYNC + video->sync(); + video->unPause(); + video->sync(); + +} + +void PlayerVideo::skipBackward(int seconds) +{ + // skip forward 1 minute + Log::getInstance()->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); + + if (paused) togglePause(); + + ULLONG moveBy = seconds * 500000; + + threadStop(); + vfeed.stop(); + afeed.stop(); + video->stop(); + audio->stop(); + video->reset(); + audio->reset(); + audio->doMuting(); // ??? + demuxer.flush(); + if (feedPosition > moveBy) feedPosition -= moveBy; + vfeed.start(); + afeed.start(); + threadStart(); + audio->play(); + video->play(); + video->sync(); + audio->sync(); + + video->pause(); + usleep(500000); // SYNC + video->sync(); + video->unPause(); + video->sync(); + +} + +void PlayerVideo::toggleFastForward() +{ + if (!initted) return; + if (!playing) return; + + if (paused) togglePause(); + if (fbwd) toggleFastBackward(); + + if (ffwd) + { + ffwd = 0; +// video->unFastForward(); + + + threadStop(); + vfeed.stop(); + afeed.stop(); + video->stop(); + audio->stop(); + video->reset(); + audio->reset(); + demuxer.flush(); +// demuxer.seek(); + vfeed.start(); + afeed.enable(); + afeed.start(); + threadStart(); + video->play(); + audio->play(); + video->sync(); + audio->sync(); + + audio->systemMuteOff(); + + video->pause(); + usleep(500000); // SYNC + video->sync(); + video->unPause(); + video->sync(); + +/* + demuxer.flushAudio(); + audio->reset(); + afeed.enable(); + //video->reset(); + audio->play(); + video->play(); + video->sync(); + audio->sync(); + audio->systemMuteOff(); +*/ + } + else + { + ffwd = 1; + afeed.disable(); + audio->systemMuteOn(); + video->fastForward(); + } +} + +void PlayerVideo::toggleFastBackward() +{ + if (!initted) return; + if (!playing) return; + + if (paused) togglePause(); + if (ffwd) toggleFastForward(); + + if (fbwd) + { + fbwd = 0; + afeed.enable(); + audio->systemMuteOff(); + +// threadStop(); + feedMode = MODE_NORMAL; +// threadStart(); + } + else + { + fbwd = 1; + afeed.disable(); + audio->systemMuteOn(); + + threadStop(); + feedMode = MODE_BACKWARDS; + video->reset(); + video->play(); + demuxer.flush(); + threadStart(); + } +} + +void PlayerVideo::jumpToPercent(int percent) +{ + threadStop(); + vfeed.stop(); + afeed.stop(); + video->stop(); + audio->stop(); + video->reset(); + audio->reset(); + demuxer.flush(); + demuxer.seek(); + feedPosition = streamLength * percent / 100; + vfeed.start(); + afeed.start(); + threadStart(); + audio->play(); + video->play(); + video->sync(); + audio->sync(); + + video->pause(); + usleep(500000); // SYNC + video->sync(); + video->unPause(); + video->sync(); +} + + +void PlayerVideo::call() +{ + threadSignalNoLock(); +} + +// Feed thread + +void PlayerVideo::threadMethod() +{ + UCHAR buf[blockSize]; + int thisRead; + int writeLength; + int thisWrite; + + VDR* vdr = VDR::getInstance(); + + int askFor; + while(1) + { + thisRead = 0; + writeLength = 0; + thisWrite = 0; + + threadCheckExit(); + + // If we havn't rescanned for a while.. + if (isRecording && ((lastRescan + 60) < time(NULL))) + { + streamLength = vdr->rescanRecording(); + Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Rescanned and reset length: %llu", streamLength); + lastRescan = time(NULL); + } + + // a bit hackey. this needs to be split to live and rec players + if (streamLength && (feedPosition >= streamLength)) break; + askFor = blockSize; + if (streamLength && ((feedPosition + blockSize) > streamLength)) + { + askFor = streamLength - feedPosition; + } + thisRead = vdr->getBlock(buf, feedPosition, askFor); + if (startup) + { + int a_stream = demuxer.scan(buf, thisRead); + demuxer.setAudioStream(a_stream); + Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream); + startup = 0; + } + + if (feedMode == MODE_NORMAL) + { + feedPosition += thisRead; + } + else if (feedMode == MODE_BACKWARDS) + { + if (feedPosition >= 100000) + { + feedPosition -= 100000; + demuxer.seek(); + } + else + { + // got to the start of the recording.. revert to play mode? how? + feedPosition += thisRead; + } + } + + threadCheckExit(); + + while(writeLength < thisRead) + { + thisWrite = demuxer.put(buf + writeLength, thisRead - writeLength); + writeLength += thisWrite; + + if (!thisWrite) + { +// Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!"); + // demuxer is full and cant take anymore + threadWaitForSignal(); +// Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT"); + } + + threadCheckExit(); + } + } + + // end of recording + Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends"); + Message* m = new Message(); + m->message = Message::STOP_PLAYBACK; + Log::getInstance()->log("Player", Log::DEBUG, "Posting message..."); + commandMessageQueue->postMessage(m); + Log::getInstance()->log("Player", Log::DEBUG, "Message posted..."); + + +} diff --git a/playervideo.h b/playervideo.h new file mode 100644 index 0000000..08e5ae5 --- /dev/null +++ b/playervideo.h @@ -0,0 +1,85 @@ +/* + Copyright 2004-2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef PLAYERVIDEO_H +#define PLAYERVIDEO_H + +#include + +#include "player.h" +#include "audio.h" +#include "video.h" +#include "demuxer.h" +#include "vfeed.h" +#include "afeed.h" +#include "remote.h" +#include "thread.h" +#include "vdr.h" +#include "callback.h" +#include "message.h" +#include "messagequeue.h" + +class PlayerVideo : public Player +{ + public: + PlayerVideo(MessageQueue* messageQueue, UCHAR isRecording); + virtual ~PlayerVideo(); + + int init(); + int shutdown(); + + int play(); + void stop(); + void togglePause(); + void toggleFastForward(); + void toggleFastBackward(); + void jumpToPercent(int percent); + void skipForward(int seconds); + void skipBackward(int seconds); + void test(); + void test2(); + void call(); // for callback interface + void setPosition(ULLONG position); + void setLength(ULLONG length); + + void threadMethod(); + + private: + MessageQueue* commandMessageQueue; + Video* video; + Demuxer demuxer; + int startup; + VFeed vfeed; + AFeed afeed; + ULLONG feedPosition; + UCHAR feedMode; + UCHAR isRecording; + time_t lastRescan; + const static UCHAR MODE_NORMAL = 1; + const static UCHAR MODE_BACKWARDS = 2; + const static int blockSize = 100000; + + UCHAR playing; // As in not stopped, (playing && paused) can == TRUE + UCHAR paused; // Must be in playing state as well + UCHAR ffwd; // Must be in playing state as well + UCHAR fbwd; // Must be in playing state as well +}; + +#endif -- 2.39.5