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"
27 #include "demuxerts.h"
29 #include "messagequeue.h"
33 #include "dvbsubtitles.h"
34 #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");
112 int PlayerLiveTV::shutdown()
114 if (!initted) return 0;
115 logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown");
126 bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
128 return demuxer->getmpAudioChannels();
131 bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
133 return demuxer->getac3AudioChannels();
136 int PlayerLiveTV::getCurrentAudioChannel()
138 return demuxer->getAID();
141 void PlayerLiveTV::setAudioChannel(int newChannel, int type,int streamtype)
143 demuxer->setAID(newChannel, type, streamtype, true);
146 void PlayerLiveTV::setSubtitleChannel(int newChannel)
148 demuxer->setSubID(newChannel);
151 int* PlayerLiveTV::getTeletxtSubtitlePages()
153 return teletext->getSubtitlePages();
156 int PlayerLiveTV::getCurrentSubtitleChannel()
158 return demuxer->getSubID();
161 bool PlayerLiveTV::toggleSubtitles()
163 if (!subtitlesShowing)
165 subtitlesShowing = true;
170 subtitlesShowing = false;
173 return subtitlesShowing;
176 void PlayerLiveTV::turnSubtitlesOn(bool ison)
180 subtitlesShowing = true;
185 subtitlesShowing = false;
190 void PlayerLiveTV::tellSubtitlesOSDVisible(bool visible)
192 subtitles->setOSDMenuVisibility(visible);
195 // ----------------------------------- Externally called events
197 void PlayerLiveTV::go(ULONG index)
199 struct PLInstruction i;
200 i.instruction = I_SETCHANNEL;
201 i.channelIndex = index;
202 instructions.push(i);
206 void PlayerLiveTV::setChannel(ULONG index)
208 logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
209 struct PLInstruction i;
210 i.instruction = I_SETCHANNEL;
211 i.channelIndex = index;
212 instructions.push(i);
213 threadSignalNoLock();
216 void PlayerLiveTV::stop()
218 logger->log("PlayerLiveTV", Log::DEBUG, "stop");
219 struct PLInstruction i;
220 i.instruction = I_STOP;
221 instructions.push(i);
224 logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");
227 // ----------------------------------- Callback
229 void PlayerLiveTV::call(void* caller)
231 if (caller == demuxer)
233 logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
236 int dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary);
237 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
239 if (video->getTVsize() == Video::ASPECT16X9)
241 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
242 video->setAspectRatio(Video::ASPECT4X3, parx, pary);
246 logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
249 Message* m = new Message();
251 m->to = messageReceiver;
252 m->message = Message::PLAYER_EVENT;
253 m->parameter.num = PlayerLiveTV::ASPECT43;
254 messageQueue->postMessageFromOuterSpace(m);
256 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
258 if (video->getTVsize() == Video::ASPECT16X9)
260 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
261 video->setAspectRatio(Video::ASPECT16X9, parx, pary);
265 logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
268 Message* m = new Message();
270 m->to = messageReceiver;
271 m->message = Message::PLAYER_EVENT;
272 m->parameter.num = PlayerLiveTV::ASPECT169;
273 messageQueue->postMessageFromOuterSpace(m);
277 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... switch anyway");
278 video->setAspectRatio(dxCurrentAspect, parx, pary);
281 else if (caller == &afeed)
283 if (state == S_VIDEOSTARTUP)
285 logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
287 threadSignalNoLock();
292 // -----------------------------------
294 void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
297 // 0 = normal stream packet
299 // 2 = connection lost
301 //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
307 Message* m = new Message();
309 m->to = messageReceiver;
310 m->message = Message::PLAYER_EVENT;
311 m->parameter.num = PlayerLiveTV::STREAM_END;
312 messageQueue->postMessageFromOuterSpace(m);
315 if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
320 streamChunks.push(s);
321 threadSignalNoLock();
325 // Too many chunks in streamChunks, drop this chunk
327 logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
331 void PlayerLiveTV::clearStreamChunks()
333 while(streamChunks.size())
335 logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
336 struct StreamChunk s = streamChunks.front();
342 void PlayerLiveTV::chunkToDemuxer()
344 StreamChunk s = streamChunks.front();
346 // logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
347 /* int a =*/ demuxer->put((UCHAR*)s.data, s.len);
348 // logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
350 if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
355 //audio->setStreamType(Audio::MPEG2_PES);
359 pendingAudioPlay = false;
363 void PlayerLiveTV::switchState(UCHAR newState)
365 logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
369 case S_STOP: // FROM S_STOP
384 //audio->setStreamType(Audio::MPEG2_PES);
386 // I make this modification, since the video/audio devices needs to know at least
387 // which kind of video is embedded inside the stream
388 // therefore the demuxer needs to feeded at least with enough data
389 // to have one video header
390 // This is crucial, if we have mixed h264/mpeg2 channels
391 // the information from channels is not enough since some directshow decoders need
392 // width and height information before startup
393 pendingAudioPlay = true;
407 if (!video->independentAVStartUp())
410 threadSignalNoLock();
416 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
423 case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
429 pendingAudioPlay=false;
437 vdr->stopStreaming();
452 //audio->setStreamType(Audio::MPEG2_PES);
454 pendingAudioPlay = true;
466 if (!video->independentAVStartUp())
469 threadSignalNoLock();
475 vdr->stopStreaming();
476 pendingAudioPlay=false;
492 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
499 case S_PREBUFFERING: // FROM S_PREBUFFERING
505 pendingAudioPlay=false;
513 vdr->stopStreaming();
530 //audio->setStreamType(Audio::MPEG2_PES);
532 pendingAudioPlay = true;
549 pendingAudioPlay=false;
550 vdr->stopStreaming();
566 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
573 case S_PLAY: // FROM S_PLAY
579 pendingAudioPlay=false;
580 vdr->stopStreaming();
596 vdr->stopStreaming();
614 //audio->setStreamType(Audio::MPEG2_PES);
618 pendingAudioPlay = true;
627 if (!video->independentAVStartUp())
630 threadSignalNoLock();
636 logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
645 bool PlayerLiveTV::checkError()
647 if (!vdr->isConnected())
649 if (state != S_STOP) switchState(S_STOP);
651 Message* m = new Message();
653 m->to = messageReceiver;
654 m->message = Message::PLAYER_EVENT;
655 m->parameter.num = PlayerLiveTV::CONNECTION_LOST;
656 messageQueue->postMessageFromOuterSpace(m);
663 void PlayerLiveTV::optimizeInstructionQueue()
667 // Currently there are only 2 instruction types, so this is a bit overkill...
669 struct PLInstruction i;
670 while(instructions.size() > 1)
672 i = instructions.front();
673 if (i.instruction == I_SETCHANNEL)
675 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
677 else if (i.instruction == I_STOP)
679 return; // return here and ensure the next instruction will be stop
684 void PlayerLiveTV::threadMethod()
688 //logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
689 if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
691 logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");
692 switchState(S_PREBUFFERING);
693 videoStartup = false;
698 while(!instructions.empty())
700 if (instructions.size() > 1) optimizeInstructionQueue();
702 struct PLInstruction i = instructions.front();
705 if (i.instruction == I_SETCHANNEL)
707 logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
709 switchState(S_VIDEOSTARTUP);
713 Channel* chan = (*chanList)[i.channelIndex];
715 h264=chan->vstreamtype==0x1b;
716 demuxer->seth264(h264);
717 video->seth264mode(chan->vstreamtype==0x1b);
718 demuxer->setVID(chan->vpid);
719 video->seth264mode(chan->vstreamtype==0x1b);
724 Command* command = Command::getInstance();
726 if (chan->numDPids > 0 && audio->maysupportAc3())
729 while (j < chan->numDPids)
731 int newpref = command->getLangPref(false, chan->dpids[j].desc);
732 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)
733 && (prefered < 0 || newpref < prefered))
745 if (chan->numAPids > 0)
748 while (j < chan->numAPids)
750 int newpref = command->getLangPref(false, chan->apids[j].desc);
751 if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)
752 && (prefered < 0 || newpref < prefered))
765 demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true);
766 audio->setStreamType(Audio::MPEG2_PES);
767 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u",
768 chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type);
770 demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true);
771 audio->setStreamType(Audio::MPEG2_PES);
772 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[selected].pid,
773 chan->apids[selected].type);
777 logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
783 if (chan->numSPids) {
785 while (j < chan->numSPids)
787 int newpref = command->getLangPref(true, chan->spids[j].desc);
788 if ( (prefered < 0 || newpref < prefered))
798 demuxer->setSubID(chan->spids[selected].pid);
799 if (command->getSubDefault()) {
800 turnSubtitlesOn(true);
802 turnSubtitlesOn(false);
806 demuxer->setTID(chan->tpid);
807 teletext->ResetDecoder();
808 int streamSuccess = vdr->streamChannel(chan->number, this);
809 if (!checkError() && !streamSuccess)
811 Message* m = new Message();
813 m->to = messageReceiver;
814 m->message = Message::PLAYER_EVENT;
815 m->parameter.num = PlayerLiveTV::STREAM_END;
816 messageQueue->postMessageFromOuterSpace(m);
820 else if (i.instruction == I_STOP)
822 logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
835 while(streamChunks.size())
837 //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
839 //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
841 if (state == S_PREBUFFERING)
843 // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3");
845 ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
846 logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
848 Message* m = new Message();
850 m->to = messageReceiver;
851 m->message = Message::PLAYER_EVENT;
852 m->parameter.num = PlayerLiveTV::PREBUFFERING;
853 m->tag = percentDone;
854 messageQueue->postMessageFromOuterSpace(m);
856 if (preBufferCount == preBufferAmount)
863 //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size());
865 threadWaitForSignal(); // unlocks and waits for signal
867 //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
870 logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");