From: Chris Tallon Date: Tue, 3 Mar 2020 21:40:25 +0000 (+0000) Subject: Rename class: PlayerLiveTV to PlayerVideoLive X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=b39ba2352794818e59c351fa7ab213d3669cc2e3;p=vompclient.git Rename class: PlayerLiveTV to PlayerVideoLive --- diff --git a/objects.mk b/objects.mk index 1e81873..dd220df 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 playervideorec.o playerradio.o vfeed.o afeed.o \ + directory.o mark.o option.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 \ @@ -14,11 +14,12 @@ OBJ_COMMON = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.o woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o led.o \ inputman.o input.o inputudp.o vpicturebanner.o abstractoption.o \ eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o \ - vvideolivetv.o vsleeptimer.o playerlivetv.o playerliveradio.o \ + vvideolivetv.o vsleeptimer.o playerliveradio.o \ wprogressbar.o bitmap.o dvbsubtitles.o tfeed.o vteletextview.o \ teletextdecodervbiebu.o teletxt/txtfont.o movieinfo.o seriesinfo.o \ wmovieview.o wseriesview.o tvmedia.o wtvmedia.o wpictureview.o \ - osdvector.o surfacevector.o buffer.o + osdvector.o surfacevector.o buffer.o \ + playervideorec.o playervideolive.o OBJ_RASPBERRY = main.o threadp.o osdopenvg.o \ ledraspberry.o videoomx.o audioomx.o imageomx.o \ diff --git a/playerlivetv.cc b/playerlivetv.cc deleted file mode 100644 index 62004b0..0000000 --- a/playerlivetv.cc +++ /dev/null @@ -1,882 +0,0 @@ -/* - Copyright 2007 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 "playerlivetv.h" - -#include "defines.h" -#include "log.h" -#include "audio.h" -#include "video.h" -#include "demuxerts.h" -#include "vdr.h" -#include "messagequeue.h" -#include "input.h" -#include "message.h" -#include "channel.h" -#include "dvbsubtitles.h" -#include "osdreceiver.h" -#include "command.h" - -// ----------------------------------- Called from outside, one offs or info funcs - -PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList) -: vfeed(this), afeed(this), tfeed(this) -{ - messageQueue = tmessageQueue; - messageReceiver = tmessageReceiver; - osdReceiver = tosdReceiver; - chanList = tchanList; - - audio = Audio::getInstance(); - video = Video::getInstance(); - logger = Log::getInstance(); - vdr = VDR::getInstance(); - initted = false; - - subtitlesShowing = false; - videoStartup = false; - pendingAudioPlay = false; - - stopNow = false; - state = S_STOP; - - video->turnVideoOn(); -} - -PlayerLiveTV::~PlayerLiveTV() -{ - if (initted) shutdown(); -} - -int PlayerLiveTV::init() -{ - if (initted) return 0; - - demuxer = new DemuxerTS(); - if (!demuxer) return 0; - subtitles = new DVBSubtitles(osdReceiver); - if (!subtitles) return 0; - - teletext = new TeletextDecoderVBIEBU(); - - unsigned int demux_video_size = 2097152; - unsigned int demux_audio_size = 524288; - - if (video->supportsh264()) - { - demux_video_size *= 5 * 1;//5; - } - - if (audio->maysupportAc3()) - { - //demux_audio_size*=2; - } - - int text_fak = video->getTeletextBufferFaktor(); - - if (!demuxer->init(this, audio, video, teletext, demux_video_size, demux_audio_size, 65536 * text_fak, 25./*unimportant*/, subtitles)) - { - logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init"); - shutdown(); - return 0; - } - - - video->stop(); - video->blank(); - audio->stop(); - - initted = true; - return 1; -} - -int PlayerLiveTV::shutdown() -{ - if (!initted) return 0; - logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown"); - stop(); - initted = false; - - delete demuxer; - delete subtitles; - delete teletext; - teletext = NULL; - return 1; -} - -bool* PlayerLiveTV::getDemuxerMpegAudioChannels() -{ - return demuxer->getmpAudioChannels(); -} - -bool* PlayerLiveTV::getDemuxerAc3AudioChannels() -{ - return demuxer->getac3AudioChannels(); -} - -int PlayerLiveTV::getCurrentAudioChannel() -{ - return demuxer->getAID(); -} - -void PlayerLiveTV::setAudioChannel(int newChannel, int type,int streamtype) -{ - demuxer->setAID(newChannel, type, streamtype, true); -} - -void PlayerLiveTV::setSubtitleChannel(int newChannel) -{ - demuxer->setSubID(newChannel); -} - -int* PlayerLiveTV::getTeletxtSubtitlePages() -{ - return teletext->getSubtitlePages(); -} - -int PlayerLiveTV::getCurrentSubtitleChannel() -{ - return demuxer->getSubID(); -} - -bool PlayerLiveTV::toggleSubtitles() -{ - if (!subtitlesShowing) - { - subtitlesShowing = true; - subtitles->show(); - } - else - { - subtitlesShowing = false; - subtitles->hide(); - } - return subtitlesShowing; -} - -void PlayerLiveTV::turnSubtitlesOn(bool ison) -{ - if (ison) - { - subtitlesShowing = true; - subtitles->show(); - } - else - { - subtitlesShowing = false; - subtitles->hide(); - } -} - -void PlayerLiveTV::tellSubtitlesOSDVisible(bool visible) -{ - subtitles->setOSDMenuVisibility(visible); -} - -// ----------------------------------- Externally called events - -void PlayerLiveTV::go(ULONG index) -{ - struct PLInstruction i; - i.instruction = I_SETCHANNEL; - i.channelIndex = index; - instructions.push(i); - threadStart(); -} - -void PlayerLiveTV::setChannel(ULONG index) -{ - logger->log("PlayerLiveTV", Log::DEBUG, "setChannel"); - struct PLInstruction i; - i.instruction = I_SETCHANNEL; - i.channelIndex = index; - instructions.push(i); - threadSignalNoLock(); -} - -void PlayerLiveTV::stop() -{ - logger->log("PlayerLiveTV", Log::DEBUG, "stop"); - struct PLInstruction i; - i.instruction = I_STOP; - instructions.push(i); - threadSignal(); - threadStop(); - logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull"); -} - -// ----------------------------------- Callback - -void PlayerLiveTV::call(void* caller) -{ - if (caller == demuxer) - { - logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer"); - - int parx,pary; - UCHAR dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary); - if (dxCurrentAspect == Demuxer::ASPECT_4_3) - { - if (video->getTVsize() == Video::ASPECT16X9) - { - logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV"); - video->setAspectRatio(Video::ASPECT4X3, parx, pary); - } - else - { - logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching"); - } - - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = PlayerLiveTV::ASPECT43; - messageQueue->postMessage(m); - } - else if (dxCurrentAspect == Demuxer::ASPECT_16_9) - { - if (video->getTVsize() == Video::ASPECT16X9) - { - logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV"); - video->setAspectRatio(Video::ASPECT16X9, parx, pary); - } - else - { - logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching"); - } - - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = PlayerLiveTV::ASPECT169; - messageQueue->postMessage(m); - } - else - { - logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... switch anyway"); - video->setAspectRatio(dxCurrentAspect, parx, pary); - } - } - else if (caller == &afeed) - { - if (state == S_VIDEOSTARTUP) - { - logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup"); - videoStartup = true; - threadSignalNoLock(); - } - } -} - -// ----------------------------------- - -void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len) -{ - // Flag: - // 0 = normal stream packet - // 1 = stream end - // 2 = connection lost - - //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag); - - if (flag == 1) - { - if (data) abort(); - - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = PlayerLiveTV::STREAM_END; - messageQueue->postMessage(m); - } - - if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS) - { - StreamChunk s; - s.data = data; - s.len = len; - streamChunks.push(s); - threadSignalNoLock(); - } - else - { - // Too many chunks in streamChunks, drop this chunk - free(data); - logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk"); - } -} - -void PlayerLiveTV::clearStreamChunks() -{ - while(streamChunks.size()) - { - logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream"); - struct StreamChunk s = streamChunks.front(); - streamChunks.pop(); - free(s.data); - } -} - -void PlayerLiveTV::chunkToDemuxer() -{ - StreamChunk s = streamChunks.front(); - streamChunks.pop(); -// logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len); - /* int a =*/ demuxer->put(static_cast(s.data), s.len); -// logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a); - free(s.data); - if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed - { - video->sync(); - video->play(); - video->pause(); - //audio->setStreamType(Audio::MPEG2_PES); - audio->sync(); - audio->play(); - audio->pause(); - pendingAudioPlay = false; - } -} - -void PlayerLiveTV::switchState(UCHAR newState) -{ - logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState); - - switch(state) - { - case S_STOP: // FROM S_STOP - { - switch(newState) - { - case S_VIDEOSTARTUP: - { - video->blank(); - video->reset(); - //video->sync(); - //video->play(); - //video->pause(); - - audio->stop(); - audio->unPause(); - audio->reset(); - //audio->setStreamType(Audio::MPEG2_PES); - //audio->sync(); - // I make this modification, since the video/audio devices needs to know at least - // which kind of video is embedded inside the stream - // therefore the demuxer needs to feeded at least with enough data - // to have one video header - // This is crucial, if we have mixed h264/mpeg2 channels - // the information from channels is not enough since some directshow decoders need - // width and height information before startup - pendingAudioPlay = true; - - //audio->play(); - //audio->pause(); - - demuxer->reset(); - demuxer->seek(); - - afeed.start(); - vfeed.start(); - subtitles->start(); - tfeed.start(); - - state = newState; - if (!video->independentAVStartUp()) - { - videoStartup = true; - threadSignalNoLock(); - } - return; - } - default: - { - logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); - abort(); - break; - } - } - } - - case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP - { - switch(newState) - { - case S_PREBUFFERING: - { - pendingAudioPlay=false; - state = newState; - return; - } - - case S_VIDEOSTARTUP: - { - vdr->stopStreaming(); - clearStreamChunks(); - vfeed.stop(); - afeed.stop(); - subtitles->stop(); - tfeed.stop(); - - video->blank(); - video->reset(); - //video->sync(); - //video->play(); - //video->pause(); - audio->stop(); - audio->unPause(); - audio->reset(); - //audio->setStreamType(Audio::MPEG2_PES); - //audio->sync(); - pendingAudioPlay = true; - //audio->play(); - //audio->pause(); - - demuxer->reset(); - demuxer->seek(); - - afeed.start(); - vfeed.start(); - subtitles->start(); - tfeed.start(); - state = newState; - if (!video->independentAVStartUp()) - { - videoStartup = true; - threadSignalNoLock(); - } - return; - } - case S_STOP: - { - vdr->stopStreaming(); - pendingAudioPlay=false; - clearStreamChunks(); - vfeed.stop(); - afeed.stop(); - subtitles->stop(); - tfeed.stop(); - video->stop(); - video->blank(); - audio->stop(); - audio->reset(); - video->reset(); - state = newState; - return; - } - default: - { - logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); - abort(); - break; - } - } - } - - case S_PREBUFFERING: // FROM S_PREBUFFERING - { - switch(newState) - { - case S_PLAY: - { - pendingAudioPlay=false; - audio->unPause(); - video->unPause(); - state = newState; - return; - } - case S_VIDEOSTARTUP: - { - vdr->stopStreaming(); - clearStreamChunks(); - vfeed.stop(); - afeed.stop(); - subtitles->stop(); - tfeed.stop(); - video->stop(); - video->blank(); - audio->stop(); - audio->unPause(); - audio->reset(); - - video->reset(); - //video->sync(); - //video->play(); - //video->pause(); - - //audio->setStreamType(Audio::MPEG2_PES); - //audio->sync(); - pendingAudioPlay = true; - //audio->play(); - //audio->pause(); - - demuxer->reset(); - demuxer->seek(); - - afeed.start(); - vfeed.start(); - subtitles->start(); - tfeed.start(); - - state = newState; - return; - } - case S_STOP: - { - pendingAudioPlay=false; - vdr->stopStreaming(); - clearStreamChunks(); - vfeed.stop(); - afeed.stop(); - subtitles->stop(); - tfeed.stop(); - video->stop(); - video->blank(); - audio->stop(); - audio->reset(); - video->reset(); - state = newState; - return; - } - default: - { - logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); - abort(); - break; - } - } - } - - case S_PLAY: // FROM S_PLAY - { - switch(newState) - { - case S_STOP: - { - pendingAudioPlay=false; - vdr->stopStreaming(); - clearStreamChunks(); - vfeed.stop(); - afeed.stop(); - subtitles->stop(); - tfeed.stop(); - video->stop(); - video->blank(); - audio->stop(); - audio->reset(); - video->reset(); - state = newState; - return; - } - case S_VIDEOSTARTUP: - { - vdr->stopStreaming(); - clearStreamChunks(); - vfeed.stop(); - afeed.stop(); - subtitles->stop(); - tfeed.stop(); - video->stop(); - video->blank(); - audio->stop(); - audio->unPause(); - audio->reset(); - - video->reset(); - - //video->sync(); - // video->play(); - //video->pause(); - - //audio->setStreamType(Audio::MPEG2_PES); - //audio->sync(); - //audio->play(); - //audio->pause(); - pendingAudioPlay = true; - demuxer->reset(); - demuxer->seek(); - - afeed.start(); - vfeed.start(); - subtitles->start(); - tfeed.start(); - state = newState; - if (!video->independentAVStartUp()) - { - videoStartup = true; - threadSignalNoLock(); - } - return; - } - default: - { - logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); - abort(); - break; - } - } - } - } -} - -bool PlayerLiveTV::checkError() -{ - if (!vdr->isConnected()) - { - if (state != S_STOP) switchState(S_STOP); - - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = PlayerLiveTV::CONNECTION_LOST; - messageQueue->postMessage(m); - - return true; - } - return false; -} - -void PlayerLiveTV::optimizeInstructionQueue() -{ - // Walk the list - - // Currently there are only 2 instruction types, so this is a bit overkill... - - struct PLInstruction i; - while(instructions.size() > 1) - { - i = instructions.front(); - if (i.instruction == I_SETCHANNEL) - { - instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant - } - else if (i.instruction == I_STOP) - { - return; // return here and ensure the next instruction will be stop - } - } -} - -void PlayerLiveTV::threadMethod() -{ - while(1) - { - //logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay); - if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data - { - logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering"); - switchState(S_PREBUFFERING); - videoStartup = false; - preBufferCount = 0; - checkError(); - } - - while(!instructions.empty()) - { - if (instructions.size() > 1) optimizeInstructionQueue(); - - struct PLInstruction i = instructions.front(); - instructions.pop(); - - if (i.instruction == I_SETCHANNEL) - { - logger->log("PlayerLiveTV", Log::DEBUG, "start new stream"); - - bool subsRestore = subtitles->isShowing(); - - switchState(S_VIDEOSTARTUP); - - if (!checkError()) - { - Channel* chan = (*chanList)[i.channelIndex]; - chan->loadPids(); - h264=chan->vstreamtype==0x1b; - demuxer->seth264(h264); - video->seth264mode(chan->vstreamtype==0x1b); - demuxer->setVID(chan->vpid); - video->seth264mode(chan->vstreamtype==0x1b); - - bool dolby=false; - int selected=-1; - int prefered=-1; - Command* command = Command::getInstance(); - - if (chan->numDPids > 0 && audio->maysupportAc3()) - { - ULONG j = 0; - while (j < chan->numDPids) - { - int newpref = command->getLangPref(false, chan->dpids[j].desc); - if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type) - && (prefered < 0 || newpref < prefered)) - { - selected = j; - dolby=true; - prefered = newpref; - } - j++; - } - } - - - - if (chan->numAPids > 0) - { - ULONG j = 0; - while (j < chan->numAPids) - { - int newpref = command->getLangPref(false, chan->apids[j].desc); - if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type) - && (prefered < 0 || newpref < prefered)) - { - selected = j; - dolby=false; - prefered = newpref; - } - j++; - } - } - - - if (selected >= 0) { - if (dolby) { - demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true); - audio->setStreamType(Audio::MPEG2_PES); - logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", - chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type); - } else { - demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true); - audio->setStreamType(Audio::MPEG2_PES); - logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[selected].pid, - chan->apids[selected].type); - } - - } else { - logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid); - } - - - selected = -1; - prefered=-1; - if (chan->numSPids) { - ULONG j = 0; - while (j < chan->numSPids) - { - int newpref = command->getLangPref(true, chan->spids[j].desc); - if ( (prefered < 0 || newpref < prefered)) - { - selected = j; - prefered = newpref; - } - j++; - } - } - - if (selected >= 0) - { - demuxer->setSubID(chan->spids[selected].pid); - - if (firstStart) - { - firstStart = false; - - if (command->getSubDefault()) - turnSubtitlesOn(true); - else - turnSubtitlesOn(false); - } - else - { - if (subsRestore) - turnSubtitlesOn(true); - else - turnSubtitlesOn(false); - } - } - - demuxer->setTID(chan->tpid); - teletext->ResetDecoder(); - int streamSuccess = vdr->streamChannel(chan->number, this); - if (!checkError() && !streamSuccess) - { - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = PlayerLiveTV::STREAM_END; - messageQueue->postMessage(m); - } - } - } - else if (i.instruction == I_STOP) - { - logger->log("PlayerLiveTV", Log::DEBUG, "Stopping"); - switchState(S_STOP); - checkError(); - - stopNow = true; - break; - } - } - - threadCheckExit(); - - if (stopNow) break; - - while(streamChunks.size()) - { - //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size()); - chunkToDemuxer(); - //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size()); - - if (state == S_PREBUFFERING) - { - // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3"); - ++preBufferCount; - ULONG percentDone = (preBufferCount * 100) / preBufferAmount; - logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone); - - Message* m = new Message(); - m->from = this; - m->to = messageReceiver; - m->message = Message::PLAYER_EVENT; - m->parameter = PlayerLiveTV::PREBUFFERING; - m->tag = percentDone; - messageQueue->postMessage(m); - - if (preBufferCount == preBufferAmount) - { - switchState(S_PLAY); - checkError(); - } - } - } - //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size()); - threadLock(); - threadWaitForSignal(); // unlocks and waits for signal - threadUnlock(); - //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size()); - } - - logger->log("PlayerLiveTV", Log::DEBUG, "End of thread"); -} diff --git a/playerlivetv.h b/playerlivetv.h deleted file mode 100644 index 75fe986..0000000 --- a/playerlivetv.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - 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, see . -*/ - -#ifndef PLAYERLIVETV_H -#define PLAYERLIVETV_H - -#include -#include -#ifndef WIN32 -#include -#endif -#include - -#include - -#include "playerlive.h" - -#ifdef WIN32 -#include "threadwin.h" -#else -#include "threadp.h" -#endif - -#include "callback.h" -#include "defines.h" -#include "vfeed.h" -#include "afeed.h" -#include "tfeed.h" -#include "vdr.h" - -#include "teletextdecodervbiebu.h" - -class MessageQueue; -class Audio; -class Video; -class Log; -class DemuxerTS; -class OSDReceiver; -class DVBSubtitles; - -class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver -{ - public: - PlayerLiveTV(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* tosdReceiver, ChannelList* chanList); - virtual ~PlayerLiveTV(); - - virtual int init(); - virtual int shutdown(); - - virtual void go(ULONG index); - virtual void setChannel(ULONG index); - virtual void stop(); - virtual void setAudioChannel(int newChannel,int type,int streamtype); - virtual void setSubtitleChannel(int newChannel); - virtual bool toggleSubtitles(); - virtual void turnSubtitlesOn(bool ison); - virtual bool isSubtitlesOn() {return subtitlesShowing;}; - virtual void tellSubtitlesOSDVisible(bool visible); - - virtual bool* getDemuxerMpegAudioChannels(); - virtual bool* getDemuxerAc3AudioChannels(); - virtual int getCurrentAudioChannel(); - virtual int getCurrentSubtitleChannel(); - virtual int *getTeletxtSubtitlePages(); - - TeletextDecoderVBIEBU * getTeletextDecoder(){return teletext;}; - - void call(void*); // for callback interface - - virtual void streamReceive(ULONG, void*, ULONG); // stream receiver interface - - // 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; - const static UCHAR PREBUFFERING = 6; - - protected: - void threadMethod(); - - private: - bool subtitlesShowing; - MessageQueue* messageQueue; - void* messageReceiver; - OSDReceiver* osdReceiver; - Log* logger; - Audio* audio; - Video* video; - DemuxerTS* demuxer; - DVBSubtitles* subtitles; - TeletextDecoderVBIEBU *teletext; - VDR* vdr; - VFeed vfeed; - AFeed afeed; - TFeed tfeed; - ChannelList* chanList; - bool firstStart{true}; - - std::queue instructions; - const static UCHAR I_SETCHANNEL = 1; - const static UCHAR I_STOP = 2; - - std::queue streamChunks; - - bool initted; - - UCHAR state; - const static UCHAR S_STOP = 1; - const static UCHAR S_VIDEOSTARTUP = 2; - const static UCHAR S_PREBUFFERING = 3; - const static UCHAR S_PLAY = 4; - void switchState(UCHAR newState); - bool checkError(); - - bool videoStartup; - bool pendingAudioPlay; - bool stopNow; - bool h264; - int preBufferCount; - const static int preBufferAmount = 3; - - void clearStreamChunks(); - void chunkToDemuxer(); - void optimizeInstructionQueue(); -}; - -#endif - diff --git a/playervideolive.cc b/playervideolive.cc new file mode 100644 index 0000000..bd68b07 --- /dev/null +++ b/playervideolive.cc @@ -0,0 +1,882 @@ +/* + Copyright 2007 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 "defines.h" +#include "log.h" +#include "audio.h" +#include "video.h" +#include "demuxerts.h" +#include "vdr.h" +#include "messagequeue.h" +#include "input.h" +#include "message.h" +#include "channel.h" +#include "dvbsubtitles.h" +#include "osdreceiver.h" +#include "command.h" + +#include "playervideolive.h" + +// ----------------------------------- Called from outside, one offs or info funcs + +PlayerVideoLive::PlayerVideoLive(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList) +: vfeed(this), afeed(this), tfeed(this) +{ + messageQueue = tmessageQueue; + messageReceiver = tmessageReceiver; + osdReceiver = tosdReceiver; + chanList = tchanList; + + audio = Audio::getInstance(); + video = Video::getInstance(); + logger = Log::getInstance(); + vdr = VDR::getInstance(); + initted = false; + + subtitlesShowing = false; + videoStartup = false; + pendingAudioPlay = false; + + stopNow = false; + state = S_STOP; + + video->turnVideoOn(); +} + +PlayerVideoLive::~PlayerVideoLive() +{ + if (initted) shutdown(); +} + +int PlayerVideoLive::init() +{ + if (initted) return 0; + + demuxer = new DemuxerTS(); + if (!demuxer) return 0; + subtitles = new DVBSubtitles(osdReceiver); + if (!subtitles) return 0; + + teletext = new TeletextDecoderVBIEBU(); + + unsigned int demux_video_size = 2097152; + unsigned int demux_audio_size = 524288; + + if (video->supportsh264()) + { + demux_video_size *= 5 * 1;//5; + } + + if (audio->maysupportAc3()) + { + //demux_audio_size*=2; + } + + int text_fak = video->getTeletextBufferFaktor(); + + if (!demuxer->init(this, audio, video, teletext, demux_video_size, demux_audio_size, 65536 * text_fak, 25./*unimportant*/, subtitles)) + { + logger->log("PlayerVideoLive", Log::ERR, "Demuxer failed to init"); + shutdown(); + return 0; + } + + + video->stop(); + video->blank(); + audio->stop(); + + initted = true; + return 1; +} + +int PlayerVideoLive::shutdown() +{ + if (!initted) return 0; + logger->log("PlayerVideoLive", Log::DEBUG, "Shutdown"); + stop(); + initted = false; + + delete demuxer; + delete subtitles; + delete teletext; + teletext = NULL; + return 1; +} + +bool* PlayerVideoLive::getDemuxerMpegAudioChannels() +{ + return demuxer->getmpAudioChannels(); +} + +bool* PlayerVideoLive::getDemuxerAc3AudioChannels() +{ + return demuxer->getac3AudioChannels(); +} + +int PlayerVideoLive::getCurrentAudioChannel() +{ + return demuxer->getAID(); +} + +void PlayerVideoLive::setAudioChannel(int newChannel, int type,int streamtype) +{ + demuxer->setAID(newChannel, type, streamtype, true); +} + +void PlayerVideoLive::setSubtitleChannel(int newChannel) +{ + demuxer->setSubID(newChannel); +} + +int* PlayerVideoLive::getTeletxtSubtitlePages() +{ + return teletext->getSubtitlePages(); +} + +int PlayerVideoLive::getCurrentSubtitleChannel() +{ + return demuxer->getSubID(); +} + +bool PlayerVideoLive::toggleSubtitles() +{ + if (!subtitlesShowing) + { + subtitlesShowing = true; + subtitles->show(); + } + else + { + subtitlesShowing = false; + subtitles->hide(); + } + return subtitlesShowing; +} + +void PlayerVideoLive::turnSubtitlesOn(bool ison) +{ + if (ison) + { + subtitlesShowing = true; + subtitles->show(); + } + else + { + subtitlesShowing = false; + subtitles->hide(); + } +} + +void PlayerVideoLive::tellSubtitlesOSDVisible(bool visible) +{ + subtitles->setOSDMenuVisibility(visible); +} + +// ----------------------------------- Externally called events + +void PlayerVideoLive::go(ULONG index) +{ + struct PLInstruction i; + i.instruction = I_SETCHANNEL; + i.channelIndex = index; + instructions.push(i); + threadStart(); +} + +void PlayerVideoLive::setChannel(ULONG index) +{ + logger->log("PlayerVideoLive", Log::DEBUG, "setChannel"); + struct PLInstruction i; + i.instruction = I_SETCHANNEL; + i.channelIndex = index; + instructions.push(i); + threadSignalNoLock(); +} + +void PlayerVideoLive::stop() +{ + logger->log("PlayerVideoLive", Log::DEBUG, "stop"); + struct PLInstruction i; + i.instruction = I_STOP; + instructions.push(i); + threadSignal(); + threadStop(); + logger->log("PlayerVideoLive", Log::DEBUG, "stop succesfull"); +} + +// ----------------------------------- Callback + +void PlayerVideoLive::call(void* caller) +{ + if (caller == demuxer) + { + logger->log("PlayerVideoLive", Log::DEBUG, "Callback from demuxer"); + + int parx,pary; + UCHAR dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary); + if (dxCurrentAspect == Demuxer::ASPECT_4_3) + { + if (video->getTVsize() == Video::ASPECT16X9) + { + logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV"); + video->setAspectRatio(Video::ASPECT4X3, parx, pary); + } + else + { + logger->log("PlayerVideoLive", Log::DEBUG, "TV is 4:3, ignoring aspect switching"); + } + + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoLive::ASPECT43; + messageQueue->postMessage(m); + } + else if (dxCurrentAspect == Demuxer::ASPECT_16_9) + { + if (video->getTVsize() == Video::ASPECT16X9) + { + logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV"); + video->setAspectRatio(Video::ASPECT16X9, parx, pary); + } + else + { + logger->log("PlayerVideoLive", Log::DEBUG, "TV is 4:3, ignoring aspect switching"); + } + + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoLive::ASPECT169; + messageQueue->postMessage(m); + } + else + { + logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer said video is something else... switch anyway"); + video->setAspectRatio(dxCurrentAspect, parx, pary); + } + } + else if (caller == &afeed) + { + if (state == S_VIDEOSTARTUP) + { + logger->log("PlayerVideoLive", Log::DEBUG, "afeed video startup"); + videoStartup = true; + threadSignalNoLock(); + } + } +} + +// ----------------------------------- + +void PlayerVideoLive::streamReceive(ULONG flag, void* data, ULONG len) +{ + // Flag: + // 0 = normal stream packet + // 1 = stream end + // 2 = connection lost + + //logger->log("PlayerVideoLive", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag); + + if (flag == 1) + { + if (data) abort(); + + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoLive::STREAM_END; + messageQueue->postMessage(m); + } + + if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS) + { + StreamChunk s; + s.data = data; + s.len = len; + streamChunks.push(s); + threadSignalNoLock(); + } + else + { + // Too many chunks in streamChunks, drop this chunk + free(data); + logger->log("PlayerVideoLive", Log::WARN, "Dropped chunk"); + } +} + +void PlayerVideoLive::clearStreamChunks() +{ + while(streamChunks.size()) + { + logger->log("PlayerVideoLive", Log::DEBUG, "Dropping chunk from old stream"); + struct StreamChunk s = streamChunks.front(); + streamChunks.pop(); + free(s.data); + } +} + +void PlayerVideoLive::chunkToDemuxer() +{ + StreamChunk s = streamChunks.front(); + streamChunks.pop(); +// logger->log("PlayerVideoLive", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len); + /* int a =*/ demuxer->put(static_cast(s.data), s.len); +// logger->log("PlayerVideoLive", Log::DEBUG, "put %i to demuxer", a); + free(s.data); + if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed + { + video->sync(); + video->play(); + video->pause(); + //audio->setStreamType(Audio::MPEG2_PES); + audio->sync(); + audio->play(); + audio->pause(); + pendingAudioPlay = false; + } +} + +void PlayerVideoLive::switchState(UCHAR newState) +{ + logger->log("PlayerVideoLive", Log::DEBUG, "Switch from state %u to state %u", state, newState); + + switch(state) + { + case S_STOP: // FROM S_STOP + { + switch(newState) + { + case S_VIDEOSTARTUP: + { + video->blank(); + video->reset(); + //video->sync(); + //video->play(); + //video->pause(); + + audio->stop(); + audio->unPause(); + audio->reset(); + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + // I make this modification, since the video/audio devices needs to know at least + // which kind of video is embedded inside the stream + // therefore the demuxer needs to feeded at least with enough data + // to have one video header + // This is crucial, if we have mixed h264/mpeg2 channels + // the information from channels is not enough since some directshow decoders need + // width and height information before startup + pendingAudioPlay = true; + + //audio->play(); + //audio->pause(); + + demuxer->reset(); + demuxer->seek(); + + afeed.start(); + vfeed.start(); + subtitles->start(); + tfeed.start(); + + state = newState; + if (!video->independentAVStartUp()) + { + videoStartup = true; + threadSignalNoLock(); + } + return; + } + default: + { + logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); + abort(); + break; + } + } + } + + case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP + { + switch(newState) + { + case S_PREBUFFERING: + { + pendingAudioPlay=false; + state = newState; + return; + } + + case S_VIDEOSTARTUP: + { + vdr->stopStreaming(); + clearStreamChunks(); + vfeed.stop(); + afeed.stop(); + subtitles->stop(); + tfeed.stop(); + + video->blank(); + video->reset(); + //video->sync(); + //video->play(); + //video->pause(); + audio->stop(); + audio->unPause(); + audio->reset(); + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + pendingAudioPlay = true; + //audio->play(); + //audio->pause(); + + demuxer->reset(); + demuxer->seek(); + + afeed.start(); + vfeed.start(); + subtitles->start(); + tfeed.start(); + state = newState; + if (!video->independentAVStartUp()) + { + videoStartup = true; + threadSignalNoLock(); + } + return; + } + case S_STOP: + { + vdr->stopStreaming(); + pendingAudioPlay=false; + clearStreamChunks(); + vfeed.stop(); + afeed.stop(); + subtitles->stop(); + tfeed.stop(); + video->stop(); + video->blank(); + audio->stop(); + audio->reset(); + video->reset(); + state = newState; + return; + } + default: + { + logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); + abort(); + break; + } + } + } + + case S_PREBUFFERING: // FROM S_PREBUFFERING + { + switch(newState) + { + case S_PLAY: + { + pendingAudioPlay=false; + audio->unPause(); + video->unPause(); + state = newState; + return; + } + case S_VIDEOSTARTUP: + { + vdr->stopStreaming(); + clearStreamChunks(); + vfeed.stop(); + afeed.stop(); + subtitles->stop(); + tfeed.stop(); + video->stop(); + video->blank(); + audio->stop(); + audio->unPause(); + audio->reset(); + + video->reset(); + //video->sync(); + //video->play(); + //video->pause(); + + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + pendingAudioPlay = true; + //audio->play(); + //audio->pause(); + + demuxer->reset(); + demuxer->seek(); + + afeed.start(); + vfeed.start(); + subtitles->start(); + tfeed.start(); + + state = newState; + return; + } + case S_STOP: + { + pendingAudioPlay=false; + vdr->stopStreaming(); + clearStreamChunks(); + vfeed.stop(); + afeed.stop(); + subtitles->stop(); + tfeed.stop(); + video->stop(); + video->blank(); + audio->stop(); + audio->reset(); + video->reset(); + state = newState; + return; + } + default: + { + logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); + abort(); + break; + } + } + } + + case S_PLAY: // FROM S_PLAY + { + switch(newState) + { + case S_STOP: + { + pendingAudioPlay=false; + vdr->stopStreaming(); + clearStreamChunks(); + vfeed.stop(); + afeed.stop(); + subtitles->stop(); + tfeed.stop(); + video->stop(); + video->blank(); + audio->stop(); + audio->reset(); + video->reset(); + state = newState; + return; + } + case S_VIDEOSTARTUP: + { + vdr->stopStreaming(); + clearStreamChunks(); + vfeed.stop(); + afeed.stop(); + subtitles->stop(); + tfeed.stop(); + video->stop(); + video->blank(); + audio->stop(); + audio->unPause(); + audio->reset(); + + video->reset(); + + //video->sync(); + // video->play(); + //video->pause(); + + //audio->setStreamType(Audio::MPEG2_PES); + //audio->sync(); + //audio->play(); + //audio->pause(); + pendingAudioPlay = true; + demuxer->reset(); + demuxer->seek(); + + afeed.start(); + vfeed.start(); + subtitles->start(); + tfeed.start(); + state = newState; + if (!video->independentAVStartUp()) + { + videoStartup = true; + threadSignalNoLock(); + } + return; + } + default: + { + logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState); + abort(); + break; + } + } + } + } +} + +bool PlayerVideoLive::checkError() +{ + if (!vdr->isConnected()) + { + if (state != S_STOP) switchState(S_STOP); + + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoLive::CONNECTION_LOST; + messageQueue->postMessage(m); + + return true; + } + return false; +} + +void PlayerVideoLive::optimizeInstructionQueue() +{ + // Walk the list + + // Currently there are only 2 instruction types, so this is a bit overkill... + + struct PLInstruction i; + while(instructions.size() > 1) + { + i = instructions.front(); + if (i.instruction == I_SETCHANNEL) + { + instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant + } + else if (i.instruction == I_STOP) + { + return; // return here and ensure the next instruction will be stop + } + } +} + +void PlayerVideoLive::threadMethod() +{ + while(1) + { + //logger->log("PlayerVideoLive", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay); + if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data + { + logger->log("PlayerVideoLive", Log::DEBUG, "Enter prebuffering"); + switchState(S_PREBUFFERING); + videoStartup = false; + preBufferCount = 0; + checkError(); + } + + while(!instructions.empty()) + { + if (instructions.size() > 1) optimizeInstructionQueue(); + + struct PLInstruction i = instructions.front(); + instructions.pop(); + + if (i.instruction == I_SETCHANNEL) + { + logger->log("PlayerVideoLive", Log::DEBUG, "start new stream"); + + bool subsRestore = subtitles->isShowing(); + + switchState(S_VIDEOSTARTUP); + + if (!checkError()) + { + Channel* chan = (*chanList)[i.channelIndex]; + chan->loadPids(); + h264=chan->vstreamtype==0x1b; + demuxer->seth264(h264); + video->seth264mode(chan->vstreamtype==0x1b); + demuxer->setVID(chan->vpid); + video->seth264mode(chan->vstreamtype==0x1b); + + bool dolby=false; + int selected=-1; + int prefered=-1; + Command* command = Command::getInstance(); + + if (chan->numDPids > 0 && audio->maysupportAc3()) + { + ULONG j = 0; + while (j < chan->numDPids) + { + int newpref = command->getLangPref(false, chan->dpids[j].desc); + if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type) + && (prefered < 0 || newpref < prefered)) + { + selected = j; + dolby=true; + prefered = newpref; + } + j++; + } + } + + + + if (chan->numAPids > 0) + { + ULONG j = 0; + while (j < chan->numAPids) + { + int newpref = command->getLangPref(false, chan->apids[j].desc); + if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type) + && (prefered < 0 || newpref < prefered)) + { + selected = j; + dolby=false; + prefered = newpref; + } + j++; + } + } + + + if (selected >= 0) { + if (dolby) { + demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true); + audio->setStreamType(Audio::MPEG2_PES); + logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", + chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type); + } else { + demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true); + audio->setStreamType(Audio::MPEG2_PES); + logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[selected].pid, + chan->apids[selected].type); + } + + } else { + logger->log("PlayerVideoLive", Log::WARN, "Demuxer video pid only: %u", chan->vpid); + } + + + selected = -1; + prefered=-1; + if (chan->numSPids) { + ULONG j = 0; + while (j < chan->numSPids) + { + int newpref = command->getLangPref(true, chan->spids[j].desc); + if ( (prefered < 0 || newpref < prefered)) + { + selected = j; + prefered = newpref; + } + j++; + } + } + + if (selected >= 0) + { + demuxer->setSubID(chan->spids[selected].pid); + + if (firstStart) + { + firstStart = false; + + if (command->getSubDefault()) + turnSubtitlesOn(true); + else + turnSubtitlesOn(false); + } + else + { + if (subsRestore) + turnSubtitlesOn(true); + else + turnSubtitlesOn(false); + } + } + + demuxer->setTID(chan->tpid); + teletext->ResetDecoder(); + int streamSuccess = vdr->streamChannel(chan->number, this); + if (!checkError() && !streamSuccess) + { + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoLive::STREAM_END; + messageQueue->postMessage(m); + } + } + } + else if (i.instruction == I_STOP) + { + logger->log("PlayerVideoLive", Log::DEBUG, "Stopping"); + switchState(S_STOP); + checkError(); + + stopNow = true; + break; + } + } + + threadCheckExit(); + + if (stopNow) break; + + while(streamChunks.size()) + { + //logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark1 %d", streamChunks.size()); + chunkToDemuxer(); + //logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark2 %d", streamChunks.size()); + + if (state == S_PREBUFFERING) + { + // logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark3"); + ++preBufferCount; + ULONG percentDone = (preBufferCount * 100) / preBufferAmount; + logger->log("PlayerVideoLive", Log::DEBUG, "Prebuffering %lu%%", percentDone); + + Message* m = new Message(); + m->from = this; + m->to = messageReceiver; + m->message = Message::PLAYER_EVENT; + m->parameter = PlayerVideoLive::PREBUFFERING; + m->tag = percentDone; + messageQueue->postMessage(m); + + if (preBufferCount == preBufferAmount) + { + switchState(S_PLAY); + checkError(); + } + } + } + //logger->log("PlayerVideoLive", Log::DEBUG, "wait for signal %d", streamChunks.size()); + threadLock(); + threadWaitForSignal(); // unlocks and waits for signal + threadUnlock(); + //logger->log("PlayerVideoLive", Log::DEBUG, "wait for signal2 %d",streamChunks.size()); + } + + logger->log("PlayerVideoLive", Log::DEBUG, "End of thread"); +} diff --git a/playervideolive.h b/playervideolive.h new file mode 100644 index 0000000..5fe49c2 --- /dev/null +++ b/playervideolive.h @@ -0,0 +1,149 @@ +/* + 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, see . +*/ + +#ifndef PLAYERVIDEOLIVE_H +#define PLAYERVIDEOLIVE_H + +#include +#include +#ifndef WIN32 +#include +#endif +#include + +#include + +#include "playerlive.h" + +#ifdef WIN32 +#include "threadwin.h" +#else +#include "threadp.h" +#endif + +#include "callback.h" +#include "defines.h" +#include "vfeed.h" +#include "afeed.h" +#include "tfeed.h" +#include "vdr.h" + +#include "teletextdecodervbiebu.h" + +class MessageQueue; +class Audio; +class Video; +class Log; +class DemuxerTS; +class OSDReceiver; +class DVBSubtitles; + +class PlayerVideoLive : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver +{ + public: + PlayerVideoLive(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* tosdReceiver, ChannelList* chanList); + virtual ~PlayerVideoLive(); + + virtual int init(); + virtual int shutdown(); + + virtual void go(ULONG index); + virtual void setChannel(ULONG index); + virtual void stop(); + virtual void setAudioChannel(int newChannel,int type,int streamtype); + virtual void setSubtitleChannel(int newChannel); + virtual bool toggleSubtitles(); + virtual void turnSubtitlesOn(bool ison); + virtual bool isSubtitlesOn() {return subtitlesShowing;}; + virtual void tellSubtitlesOSDVisible(bool visible); + + virtual bool* getDemuxerMpegAudioChannels(); + virtual bool* getDemuxerAc3AudioChannels(); + virtual int getCurrentAudioChannel(); + virtual int getCurrentSubtitleChannel(); + virtual int *getTeletxtSubtitlePages(); + + TeletextDecoderVBIEBU * getTeletextDecoder(){return teletext;}; + + void call(void*); // for callback interface + + virtual void streamReceive(ULONG, void*, ULONG); // stream receiver interface + + // 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; + const static UCHAR PREBUFFERING = 6; + + protected: + void threadMethod(); + + private: + bool subtitlesShowing; + MessageQueue* messageQueue; + void* messageReceiver; + OSDReceiver* osdReceiver; + Log* logger; + Audio* audio; + Video* video; + DemuxerTS* demuxer; + DVBSubtitles* subtitles; + TeletextDecoderVBIEBU *teletext; + VDR* vdr; + VFeed vfeed; + AFeed afeed; + TFeed tfeed; + ChannelList* chanList; + bool firstStart{true}; + + std::queue instructions; + const static UCHAR I_SETCHANNEL = 1; + const static UCHAR I_STOP = 2; + + std::queue streamChunks; + + bool initted; + + UCHAR state; + const static UCHAR S_STOP = 1; + const static UCHAR S_VIDEOSTARTUP = 2; + const static UCHAR S_PREBUFFERING = 3; + const static UCHAR S_PLAY = 4; + void switchState(UCHAR newState); + bool checkError(); + + bool videoStartup; + bool pendingAudioPlay; + bool stopNow; + bool h264; + int preBufferCount; + const static int preBufferAmount = 3; + + void clearStreamChunks(); + void chunkToDemuxer(); + void optimizeInstructionQueue(); +}; + +#endif + diff --git a/vteletextview.cc b/vteletextview.cc index 15a1ce6..b45d19b 100644 --- a/vteletextview.cc +++ b/vteletextview.cc @@ -22,11 +22,11 @@ #include "video.h" #include "boxstack.h" #include "input.h" -#include "playerlivetv.h" +#include "playervideolive.h" #include "vteletextview.h" -VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview, PlayerLiveTV* playerObj) +VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview, PlayerVideoLive* playerObj) { ttdecoder = TTdecoder; pv = playerview; diff --git a/vteletextview.h b/vteletextview.h index 5e7ac45..819ebb0 100644 --- a/vteletextview.h +++ b/vteletextview.h @@ -24,12 +24,12 @@ #include "teletextdecodervbiebu.h" -class PlayerLiveTV; +class PlayerVideoLive; class VTeletextView : public Boxx { public: - VTeletextView(TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview, PlayerLiveTV* palyerObj); + VTeletextView(TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview, PlayerVideoLive* palyerObj); ~VTeletextView(); void draw(bool completedraw, bool onlyfirstline); void draw() { draw(true, false); } @@ -49,7 +49,7 @@ class VTeletextView : public Boxx int page; bool subtitlemode{}; Boxx* pv; - PlayerLiveTV* player; + PlayerVideoLive* player; }; #endif diff --git a/vvideolivetv.cc b/vvideolivetv.cc index 77a0aa1..2c9178e 100644 --- a/vvideolivetv.cc +++ b/vvideolivetv.cc @@ -23,7 +23,7 @@ #include "video.h" #include "audio.h" #include "playerlive.h" -#include "playerlivetv.h" +#include "playervideolive.h" #include "playerliveradio.h" #include "channel.h" #include "boxstack.h" @@ -89,7 +89,7 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO) { streamType = VDR::VIDEO; - player = new PlayerLiveTV(Command::getInstance(), this, this, chanList); + player = new PlayerVideoLive(Command::getInstance(), this, this, chanList); } else { @@ -436,7 +436,7 @@ int VVideoLiveTV::handleCommand(int command) } case Input::RECORD: if (streamType == VDR::VIDEO) - (static_cast(player))->toggleSubtitles(); + (static_cast(player))->toggleSubtitles(); return 2; } @@ -602,7 +602,7 @@ void VVideoLiveTV::doKey(int command) void VVideoLiveTV::doTeletext(bool subtitlemode) { if (streamType !=VDR::VIDEO) return; - (static_cast(player))->tellSubtitlesOSDVisible(true); + (static_cast(player))->tellSubtitlesOSDVisible(true); bool exists = true; // Cancel keying @@ -615,14 +615,14 @@ void VVideoLiveTV::doTeletext(bool subtitlemode) osdChanNum.setText(formatChanNum); osdChanName.setText((*chanList)[osdChannelIndex]->name); } - (static_cast(player))->tellSubtitlesOSDVisible(true); + (static_cast(player))->tellSubtitlesOSDVisible(true); if (osd.getVisible()) clearScreen(); // Draw the teletxt - VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView(); + VTeletextView *vtxv=((PlayerVideoLive*)player)->getTeletextDecoder()->getTeletxtView(); if (vtxv==NULL) { - vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this, (PlayerLiveTV*)player); - ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv); + vtxv= new VTeletextView(((PlayerVideoLive*)player)->getTeletextDecoder(),this, (PlayerVideoLive*)player); + ((PlayerVideoLive*)player)->getTeletextDecoder()->registerTeletextView(vtxv); exists=false; } @@ -655,13 +655,13 @@ void VVideoLiveTV::doAudioSelector() osdChanNum.setText(formatChanNum); osdChanName.setText((*chanList)[osdChannelIndex]->name); } - int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel(); + int subtitleChannel=((PlayerVideoLive*)player)->getCurrentSubtitleChannel(); int subtitleType=0x10; - if (!(static_cast(player))->isSubtitlesOn()) { - if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() && - ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() + if (!(static_cast(player))->isSubtitlesOn()) { + if (((PlayerVideoLive*)player)->getTeletextDecoder()->getTeletxtView() && + ((PlayerVideoLive*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() ) { - subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage(); + subtitleChannel=((PlayerVideoLive*)player)->getTeletextDecoder()->getPage(); subtitleType=0x11; } else { @@ -671,7 +671,7 @@ void VVideoLiveTV::doAudioSelector() } // Draw the selector - vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(), + vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerVideoLive*)player)->getCurrentAudioChannel(), subtitleType,subtitleChannel,NULL); vas->setBackgroundColour(DrawStyle::OSDBACKGROUND); @@ -758,7 +758,7 @@ void VVideoLiveTV::setNowNextData() void VVideoLiveTV::displayOSD(bool newNowNextData) { - PlayerLiveTV* playerlivetv = dynamic_cast(player); + PlayerVideoLive* playerlivetv = dynamic_cast(player); if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(true); osd.setVisible(true); if (newNowNextData) @@ -805,7 +805,7 @@ void VVideoLiveTV::clearScreen() draw(); boxstack->update(this); - PlayerLiveTV* playerlivetv = dynamic_cast(player); + PlayerVideoLive* playerlivetv = dynamic_cast(player); if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(false); } @@ -878,7 +878,7 @@ void VVideoLiveTV::timercall(int ref) else boxstack->update(this, osd.getRegion()); Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); - PlayerLiveTV* playerlivetv = dynamic_cast(player); + PlayerVideoLive* playerlivetv = dynamic_cast(player); if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(false); Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); } @@ -901,7 +901,7 @@ bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData) UINT newChannel = 0; if (streamType == VDR::VIDEO) { - VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView(); + VTeletextView *vtxt=((PlayerVideoLive*)player)->getTeletextDecoder()->getTeletxtView(); if (vtxt) { BoxStack::getInstance()->remove(vtxt); @@ -1069,8 +1069,8 @@ void VVideoLiveTV::processMessage(Message* m) if (streamType == VDR::VIDEO) { player->setSubtitleChannel((m->parameter & 0xFFFF)); - (static_cast(player))->turnSubtitlesOn(true); - VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView(); + (static_cast(player))->turnSubtitlesOn(true); + VTeletextView *vtxt=((PlayerVideoLive*)player)->getTeletextDecoder()->getTeletxtView(); if (vtxt && vtxt->isInSubtitleMode()) { BoxStack::getInstance()->remove(vtxt); @@ -1080,8 +1080,8 @@ void VVideoLiveTV::processMessage(Message* m) case 0xFF: { //nosubtitles if (streamType == VDR::VIDEO){ - (static_cast(player))->turnSubtitlesOn(false); - VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView(); + (static_cast(player))->turnSubtitlesOn(false); + VTeletextView *vtxt=((PlayerVideoLive*)player)->getTeletextDecoder()->getTeletxtView(); if (vtxt && vtxt->isInSubtitleMode()) { BoxStack::getInstance()->remove(vtxt); } @@ -1090,9 +1090,9 @@ void VVideoLiveTV::processMessage(Message* m) break; case 0x11: { //videotext - (static_cast(player))->turnSubtitlesOn(false); + (static_cast(player))->turnSubtitlesOn(false); doTeletext(true); - ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF)); + ((PlayerVideoLive*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF)); } break; }; @@ -1107,21 +1107,21 @@ void VVideoLiveTV::processMessage(Message* m) { switch (m->parameter) { - case PlayerLiveTV::CONNECTION_LOST: // connection lost detected + case PlayerVideoLive::CONNECTION_LOST: // connection lost detected { Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player"); Command::getInstance()->connectionLost(); break; } - case PlayerLiveTV::STREAM_END: + case PlayerVideoLive::STREAM_END: { // Message comes from playerlivetv through master mutex, so can do anything here showUnavailable(); break; } - case PlayerLiveTV::ASPECT43: + case PlayerVideoLive::ASPECT43: { OsdVector* osdv=dynamic_cast(Osd::getInstance()); if (osdv) @@ -1140,7 +1140,7 @@ void VVideoLiveTV::processMessage(Message* m) break; } - case PlayerLiveTV::ASPECT169: + case PlayerVideoLive::ASPECT169: { sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169; sAspectRatio.setVisible(true); @@ -1160,7 +1160,7 @@ void VVideoLiveTV::processMessage(Message* m) break; } - case PlayerLiveTV::PREBUFFERING: + case PlayerVideoLive::PREBUFFERING: { preBuffering = m->tag; Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);