2 Copyright 2007 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
20 #include "playerlivetv.h"
26 #include "demuxerts.h"
28 #include "messagequeue.h"
32 #include "dvbsubtitles.h"
33 #include "osdreceiver.h"
36 // ----------------------------------- Called from outside, one offs or info funcs
38 PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
39 : vfeed(this), afeed(this), tfeed(this)
41 messageQueue = tmessageQueue;
42 messageReceiver = tmessageReceiver;
43 osdReceiver = tosdReceiver;
46 audio = Audio::getInstance();
47 video = Video::getInstance();
48 logger = Log::getInstance();
49 vdr = VDR::getInstance();
52 subtitlesShowing = false;
54 pendingAudioPlay = false;
62 PlayerLiveTV::~PlayerLiveTV()
64 if (initted) shutdown();
67 int PlayerLiveTV::init()
69 if (initted) return 0;
71 demuxer = new DemuxerTS();
72 if (!demuxer) return 0;
73 subtitles = new DVBSubtitles(osdReceiver);
74 if (!subtitles) return 0;
76 teletext = new TeletextDecoderVBIEBU();
78 unsigned int demux_video_size = 2097152;
79 unsigned int demux_audio_size = 524288;
81 if (video->supportsh264())
83 demux_video_size *= 5 * 1;//5;
86 if (audio->maysupportAc3())
88 //demux_audio_size*=2;
91 int text_fak = video->getTeletextBufferFaktor();
93 if (!demuxer->init(this, audio, video, teletext, demux_video_size, demux_audio_size, 65536 * text_fak, 25./*unimportant*/, subtitles))
95 logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
111 int PlayerLiveTV::shutdown()
113 if (!initted) return 0;
114 logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown");
125 bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
127 return demuxer->getmpAudioChannels();
130 bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
132 return demuxer->getac3AudioChannels();
135 int PlayerLiveTV::getCurrentAudioChannel()
137 return demuxer->getAID();
140 void PlayerLiveTV::setAudioChannel(int newChannel, int type,int streamtype)
142 demuxer->setAID(newChannel, type, streamtype, true);
145 void PlayerLiveTV::setSubtitleChannel(int newChannel)
147 demuxer->setSubID(newChannel);
150 int* PlayerLiveTV::getTeletxtSubtitlePages()
152 return teletext->getSubtitlePages();
155 int PlayerLiveTV::getCurrentSubtitleChannel()
157 return demuxer->getSubID();
160 bool PlayerLiveTV::toggleSubtitles()
162 if (!subtitlesShowing)
164 subtitlesShowing = true;
169 subtitlesShowing = false;
172 return subtitlesShowing;
175 void PlayerLiveTV::turnSubtitlesOn(bool ison)
179 subtitlesShowing = true;
184 subtitlesShowing = false;
189 void PlayerLiveTV::tellSubtitlesOSDVisible(bool visible)
191 subtitles->setOSDMenuVisibility(visible);
194 // ----------------------------------- Externally called events
196 void PlayerLiveTV::go(ULONG index)
198 struct PLInstruction i;
199 i.instruction = I_SETCHANNEL;
200 i.channelIndex = index;
201 instructions.push(i);
205 void PlayerLiveTV::setChannel(ULONG index)
207 logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
208 struct PLInstruction i;
209 i.instruction = I_SETCHANNEL;
210 i.channelIndex = index;
211 instructions.push(i);
212 threadSignalNoLock();
215 void PlayerLiveTV::stop()
217 logger->log("PlayerLiveTV", Log::DEBUG, "stop");
218 struct PLInstruction i;
219 i.instruction = I_STOP;
220 instructions.push(i);
223 logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");
226 // ----------------------------------- Callback
228 void PlayerLiveTV::call(void* caller)
230 if (caller == demuxer)
232 logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
235 int dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary);
236 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
238 if (video->getTVsize() == Video::ASPECT16X9)
240 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
241 video->setAspectRatio(Video::ASPECT4X3, parx, pary);
245 logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
248 Message* m = new Message();
250 m->to = messageReceiver;
251 m->message = Message::PLAYER_EVENT;
252 m->parameter = PlayerLiveTV::ASPECT43;
253 messageQueue->postMessage(m);
255 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
257 if (video->getTVsize() == Video::ASPECT16X9)
259 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
260 video->setAspectRatio(Video::ASPECT16X9, parx, pary);
264 logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
267 Message* m = new Message();
269 m->to = messageReceiver;
270 m->message = Message::PLAYER_EVENT;
271 m->parameter = PlayerLiveTV::ASPECT169;
272 messageQueue->postMessage(m);
276 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... switch anyway");
277 video->setAspectRatio(dxCurrentAspect, parx, pary);
280 else if (caller == &afeed)
282 if (state == S_VIDEOSTARTUP)
284 logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
286 threadSignalNoLock();
291 // -----------------------------------
293 void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
296 // 0 = normal stream packet
298 // 2 = connection lost
300 //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
306 Message* m = new Message();
308 m->to = messageReceiver;
309 m->message = Message::PLAYER_EVENT;
310 m->parameter = PlayerLiveTV::STREAM_END;
311 messageQueue->postMessage(m);
314 if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
319 streamChunks.push(s);
320 threadSignalNoLock();
324 // Too many chunks in streamChunks, drop this chunk
326 logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
330 void PlayerLiveTV::clearStreamChunks()
332 while(streamChunks.size())
334 logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
335 struct StreamChunk s = streamChunks.front();
341 void PlayerLiveTV::chunkToDemuxer()
343 StreamChunk s = streamChunks.front();
345 // logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
346 /* int a =*/ demuxer->put((UCHAR*)s.data, s.len);
347 // logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
349 if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
354 //audio->setStreamType(Audio::MPEG2_PES);
358 pendingAudioPlay = false;
362 void PlayerLiveTV::switchState(UCHAR newState)
364 logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
368 case S_STOP: // FROM S_STOP
383 //audio->setStreamType(Audio::MPEG2_PES);
385 // I make this modification, since the video/audio devices needs to know at least
386 // which kind of video is embedded inside the stream
387 // therefore the demuxer needs to feeded at least with enough data
388 // to have one video header
389 // This is crucial, if we have mixed h264/mpeg2 channels
390 // the information from channels is not enough since some directshow decoders need
391 // width and height information before startup
392 pendingAudioPlay = true;
406 if (!video->independentAVStartUp())
409 threadSignalNoLock();
415 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
422 case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
428 pendingAudioPlay=false;
435 vdr->stopStreaming();
450 //audio->setStreamType(Audio::MPEG2_PES);
452 pendingAudioPlay = true;
464 if (!video->independentAVStartUp())
467 threadSignalNoLock();
473 vdr->stopStreaming();
474 pendingAudioPlay=false;
490 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
497 case S_PREBUFFERING: // FROM S_PREBUFFERING
503 pendingAudioPlay=false;
511 vdr->stopStreaming();
528 //audio->setStreamType(Audio::MPEG2_PES);
530 pendingAudioPlay = true;
547 pendingAudioPlay=false;
548 vdr->stopStreaming();
564 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
571 case S_PLAY: // FROM S_PLAY
577 pendingAudioPlay=false;
578 vdr->stopStreaming();
594 vdr->stopStreaming();
612 //audio->setStreamType(Audio::MPEG2_PES);
616 pendingAudioPlay = true;
625 if (!video->independentAVStartUp())
628 threadSignalNoLock();
634 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
643 bool PlayerLiveTV::checkError()
645 if (!vdr->isConnected())
647 if (state != S_STOP) switchState(S_STOP);
649 Message* m = new Message();
651 m->to = messageReceiver;
652 m->message = Message::PLAYER_EVENT;
653 m->parameter = PlayerLiveTV::CONNECTION_LOST;
654 messageQueue->postMessage(m);
661 void PlayerLiveTV::optimizeInstructionQueue()
665 // Currently there are only 2 instruction types, so this is a bit overkill...
667 struct PLInstruction i;
668 while(instructions.size() > 1)
670 i = instructions.front();
671 if (i.instruction == I_SETCHANNEL)
673 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
675 else if (i.instruction == I_STOP)
677 return; // return here and ensure the next instruction will be stop
682 void PlayerLiveTV::threadMethod()
686 //logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
687 if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
689 logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");
690 switchState(S_PREBUFFERING);
691 videoStartup = false;
696 while(!instructions.empty())
698 if (instructions.size() > 1) optimizeInstructionQueue();
700 struct PLInstruction i = instructions.front();
703 if (i.instruction == I_SETCHANNEL)
705 logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
707 switchState(S_VIDEOSTARTUP);
711 Channel* chan = (*chanList)[i.channelIndex];
713 h264=chan->vstreamtype==0x1b;
714 demuxer->seth264(h264);
715 video->seth264mode(chan->vstreamtype==0x1b);
716 demuxer->setVID(chan->vpid);
717 video->seth264mode(chan->vstreamtype==0x1b);
722 Command* command = Command::getInstance();
724 if (chan->numDPids > 0 && audio->maysupportAc3())
727 while (j < chan->numDPids)
729 int newpref = command->getLangPref(false, chan->dpids[j].desc);
730 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)
731 && (prefered < 0 || newpref < prefered))
743 if (chan->numAPids > 0)
746 while (j < chan->numAPids)
748 int newpref = command->getLangPref(false, chan->apids[j].desc);
749 if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)
750 && (prefered < 0 || newpref < prefered))
763 demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true);
764 audio->setStreamType(Audio::MPEG2_PES);
765 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u",
766 chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type);
768 demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true);
769 audio->setStreamType(Audio::MPEG2_PES);
770 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[selected].pid,
771 chan->apids[selected].type);
775 logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
781 if (chan->numSPids) {
783 while (j < chan->numSPids)
785 int newpref = command->getLangPref(true, chan->spids[j].desc);
786 if ( (prefered < 0 || newpref < prefered))
796 demuxer->setSubID(chan->spids[selected].pid);
797 if (command->getSubDefault()) {
798 turnSubtitlesOn(true);
800 turnSubtitlesOn(false);
804 demuxer->setTID(chan->tpid);
805 teletext->ResetDecoder();
806 int streamSuccess = vdr->streamChannel(chan->number, this);
807 if (!checkError() && !streamSuccess)
809 Message* m = new Message();
811 m->to = messageReceiver;
812 m->message = Message::PLAYER_EVENT;
813 m->parameter = PlayerLiveTV::STREAM_END;
814 messageQueue->postMessage(m);
818 else if (i.instruction == I_STOP)
820 logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
833 while(streamChunks.size())
835 //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
837 //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
839 if (state == S_PREBUFFERING)
841 // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3");
843 ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
844 logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
846 Message* m = new Message();
848 m->to = messageReceiver;
849 m->message = Message::PLAYER_EVENT;
850 m->parameter = PlayerLiveTV::PREBUFFERING;
851 m->tag = percentDone;
852 messageQueue->postMessage(m);
854 if (preBufferCount == preBufferAmount)
861 //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size());
863 threadWaitForSignal(); // unlocks and waits for signal
865 //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
868 logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");