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, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "playerlivetv.h"
26 #include "demuxerts.h"
28 #include "messagequeue.h"
32 #include "dvbsubtitles.h"
33 #include "osdreceiver.h"
35 // ----------------------------------- Called from outside, one offs or info funcs
37 PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
38 : vfeed(this), afeed(this), tfeed(this)
40 messageQueue = tmessageQueue;
41 messageReceiver = tmessageReceiver;
42 osdReceiver = tosdReceiver;
45 audio = Audio::getInstance();
46 video = Video::getInstance();
47 logger = Log::getInstance();
48 vdr = VDR::getInstance();
51 subtitlesShowing = false;
53 pendingAudioPlay = false;
61 PlayerLiveTV::~PlayerLiveTV()
63 if (initted) shutdown();
66 int PlayerLiveTV::init()
68 if (initted) return 0;
70 demuxer = new DemuxerTS();
71 if (!demuxer) return 0;
72 subtitles = new DVBSubtitles(osdReceiver);
73 if (!subtitles) return 0;
75 teletext = new TeletextDecoderVBIEBU();
77 unsigned int demux_video_size=2097152;
78 if (video->supportsh264()) demux_video_size*=5;
80 if (!demuxer->init(this, audio, video, teletext, demux_video_size, 524288, 65536,25./*unimportant*/,subtitles))
82 logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
99 int PlayerLiveTV::shutdown()
101 if (!initted) return 0;
112 bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
114 return demuxer->getmpAudioChannels();
117 bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
119 return demuxer->getac3AudioChannels();
122 int PlayerLiveTV::getCurrentAudioChannel()
124 return demuxer->getAID();
127 void PlayerLiveTV::setAudioChannel(int newChannel, int type)
129 return demuxer->setAID(newChannel,type);
132 void PlayerLiveTV::setSubtitleChannel(int newChannel)
134 return demuxer->setSubID(newChannel);
137 int *PlayerLiveTV::getTeletxtSubtitlePages()
139 return teletext->getSubtitlePages();
142 int PlayerLiveTV::getCurrentSubtitleChannel(){
143 return demuxer->getSubID();
146 bool PlayerLiveTV::toggleSubtitles()
148 if (!subtitlesShowing)
150 subtitlesShowing = true;
155 subtitlesShowing = false;
158 return subtitlesShowing;
162 void PlayerLiveTV::turnSubtitlesOn(bool ison) {
165 subtitlesShowing = true;
170 subtitlesShowing = false;
175 // ----------------------------------- Externally called events
177 void PlayerLiveTV::go(ULONG index)
179 struct PLInstruction i;
180 i.instruction = I_SETCHANNEL;
181 i.channelIndex = index;
182 instructions.push(i);
186 void PlayerLiveTV::setChannel(ULONG index)
188 logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
189 struct PLInstruction i;
190 i.instruction = I_SETCHANNEL;
191 i.channelIndex = index;
192 instructions.push(i);
193 threadSignalNoLock();
196 void PlayerLiveTV::stop()
198 logger->log("PlayerLiveTV", Log::DEBUG, "stop");
199 struct PLInstruction i;
200 i.instruction = I_STOP;
201 instructions.push(i);
206 // ----------------------------------- Callback
208 void PlayerLiveTV::call(void* caller)
210 if (caller == demuxer)
212 logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
214 int dxCurrentAspect = demuxer->getAspectRatio();
215 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
217 if (video->getTVsize() == Video::ASPECT16X9)
219 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
220 video->setAspectRatio(Video::ASPECT4X3);
224 logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
227 Message* m = new Message();
229 m->to = messageReceiver;
230 m->message = Message::PLAYER_EVENT;
231 m->parameter = PlayerLiveTV::ASPECT43;
232 messageQueue->postMessageFromOuterSpace(m);
234 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
236 if (video->getTVsize() == Video::ASPECT16X9)
238 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
239 video->setAspectRatio(Video::ASPECT16X9);
243 logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
246 Message* m = new Message();
248 m->to = messageReceiver;
249 m->message = Message::PLAYER_EVENT;
250 m->parameter = PlayerLiveTV::ASPECT169;
251 messageQueue->postMessageFromOuterSpace(m);
255 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... ignoring");
258 else if (caller == &afeed)
260 if (state == S_VIDEOSTARTUP)
262 logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
264 threadSignalNoLock();
269 // -----------------------------------
271 void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
274 // 0 = normal stream packet
276 // 2 = connection lost
278 // logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
284 Message* m = new Message();
286 m->to = messageReceiver;
287 m->message = Message::PLAYER_EVENT;
288 m->parameter = PlayerLiveTV::STREAM_END;
289 messageQueue->postMessageFromOuterSpace(m);
292 if (streamChunks.size() < 11)
297 streamChunks.push(s);
298 threadSignalNoLock();
302 // Too many chunks in streamChunks, drop this chunk
304 logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
308 void PlayerLiveTV::clearStreamChunks()
310 while(streamChunks.size())
312 logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
313 struct StreamChunk s = streamChunks.front();
319 void PlayerLiveTV::chunkToDemuxer()
321 StreamChunk s = streamChunks.front();
323 //logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
324 /*int a = */demuxer->put((UCHAR*)s.data, s.len);
325 //logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
327 if (pendingAudioPlay && demuxer->getHorizontalSize()) //Horizontal Size is zero, if not parsed
332 //audio->setStreamType(Audio::MPEG2_PES);
336 pendingAudioPlay = false;
340 void PlayerLiveTV::switchState(UCHAR newState)
342 logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
346 case S_STOP: // FROM S_STOP
361 //audio->setStreamType(Audio::MPEG2_PES);
363 // I make this modification, since the video/audio devices needs to know at least
364 // which kind of video is embedded inside the stream
365 // therefore the demuxer needs to feeded at least with enough data
366 // to have one video header
367 // This is crucial, if we have mixed h264/mpeg2 channels
368 // the information from channels is not enough since some directshow decoders need
369 // width and height information before startup
370 pendingAudioPlay = true;
388 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
395 case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
401 pendingAudioPlay=false;
409 vdr->stopStreaming();
425 //audio->setStreamType(Audio::MPEG2_PES);
427 pendingAudioPlay = true;
443 vdr->stopStreaming();
444 pendingAudioPlay=false;
460 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
467 case S_PREBUFFERING: // FROM S_PREBUFFERING
473 pendingAudioPlay=false;
481 vdr->stopStreaming();
498 //audio->setStreamType(Audio::MPEG2_PES);
500 pendingAudioPlay = true;
517 pendingAudioPlay=false;
518 vdr->stopStreaming();
534 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
541 case S_PLAY: // FROM S_PLAY
547 pendingAudioPlay=false;
548 vdr->stopStreaming();
564 vdr->stopStreaming();
582 //audio->setStreamType(Audio::MPEG2_PES);
586 pendingAudioPlay = true;
601 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
610 bool PlayerLiveTV::checkError()
612 if (!vdr->isConnected())
614 if (state != S_STOP) switchState(S_STOP);
616 Message* m = new Message();
618 m->to = messageReceiver;
619 m->message = Message::PLAYER_EVENT;
620 m->parameter = PlayerLiveTV::CONNECTION_LOST;
621 messageQueue->postMessageFromOuterSpace(m);
628 void PlayerLiveTV::optimizeInstructionQueue()
632 // Currently there are only 2 instruction types, so this is a bit overkill...
634 struct PLInstruction i;
635 while(instructions.size() > 1)
637 i = instructions.front();
638 if (i.instruction == I_SETCHANNEL)
640 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
642 else if (i.instruction == I_STOP)
644 return; // return here and ensure the next instruction will be stop
649 void PlayerLiveTV::threadMethod()
653 if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
655 switchState(S_PREBUFFERING);
656 videoStartup = false;
662 while(!instructions.empty())
664 if (instructions.size() > 1) optimizeInstructionQueue();
666 struct PLInstruction i = instructions.front();
669 if (i.instruction == I_SETCHANNEL)
671 logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
674 switchState(S_VIDEOSTARTUP);
678 Channel* chan = (*chanList)[i.channelIndex];
680 h264=chan->vstreamtype==0x1b;
681 demuxer->seth264(h264);
682 video->seth264mode(chan->vstreamtype==0x1b);
683 demuxer->setVID(chan->vpid);
684 video->seth264mode(chan->vstreamtype==0x1b);
686 if (chan->numAPids > 0)
688 demuxer->setAID(chan->apids[0].pid,0);
689 audio->setStreamType(Audio::MPEG2_PES);
690 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
694 if (chan->numDPids > 0 && audio->maysupportAc3())
696 demuxer->setAID(chan->dpids[0].pid,1);
697 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3)", chan->vpid, chan->dpids[0].pid);
701 logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
704 if (chan->numSPids > 0)
705 demuxer->setSubID(chan->spids[0].pid);
706 demuxer->setTID(chan->tpid);
707 teletext->ResetDecoder();
708 int streamSuccess = vdr->streamChannel(chan->number, this);
709 if (!checkError() && !streamSuccess)
711 Message* m = new Message();
713 m->to = messageReceiver;
714 m->message = Message::PLAYER_EVENT;
715 m->parameter = PlayerLiveTV::STREAM_END;
716 messageQueue->postMessageFromOuterSpace(m);
720 else if (i.instruction == I_STOP)
722 logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
733 while(streamChunks.size())
737 if (state == S_PREBUFFERING)
740 ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
741 logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
743 Message* m = new Message();
745 m->to = messageReceiver;
746 m->message = Message::PLAYER_EVENT;
747 m->parameter = PlayerLiveTV::PREBUFFERING;
748 m->tag = percentDone;
749 messageQueue->postMessageFromOuterSpace(m);
751 if (preBufferCount == preBufferAmount)
760 threadWaitForSignal(); // unlocks and waits for signal
764 logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");