2 Copyright 2007-2020 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/>.
24 #include "demuxerts.h"
26 #include "messagequeue.h"
30 #include "dvbsubtitles.h"
31 #include "osdreceiver.h"
34 #include "playervideolive.h"
36 // ----------------------------------- Called from outside, one offs or info funcs
38 PlayerVideoLive::PlayerVideoLive(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;
61 PlayerVideoLive::~PlayerVideoLive()
63 if (initted) shutdown();
66 int PlayerVideoLive::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 unsigned int demux_audio_size = 524288;
80 if (video->supportsh264())
82 demux_video_size *= 5 * 1;//5;
85 if (audio->maysupportAc3())
87 //demux_audio_size*=2;
90 int text_fak = video->getTeletextBufferFaktor();
92 if (!demuxer->init(this, audio, video, teletext, demux_video_size, demux_audio_size, 65536 * text_fak, 25./*unimportant*/, subtitles))
94 logger->log("PlayerVideoLive", Log::ERR, "Demuxer failed to init");
108 int PlayerVideoLive::shutdown()
110 if (!initted) return 0;
111 logger->log("PlayerVideoLive", Log::DEBUG, "Shutdown");
114 logger->log("PlayerVideoLive", Log::DEBUG, "state is not stop, calling");
127 bool* PlayerVideoLive::getDemuxerMpegAudioChannels()
129 return demuxer->getmpAudioChannels();
132 bool* PlayerVideoLive::getDemuxerAc3AudioChannels()
134 return demuxer->getac3AudioChannels();
137 int PlayerVideoLive::getCurrentAudioChannel()
139 return demuxer->getAID();
142 void PlayerVideoLive::setAudioChannel(int newChannel, int type,int streamtype)
144 demuxer->setAID(newChannel, type, streamtype, true);
147 void PlayerVideoLive::setSubtitleChannel(int newChannel)
149 demuxer->setSubID(newChannel);
152 int* PlayerVideoLive::getTeletxtSubtitlePages()
154 return teletext->getSubtitlePages();
157 int PlayerVideoLive::getCurrentSubtitleChannel()
159 return demuxer->getSubID();
162 bool PlayerVideoLive::toggleSubtitles()
164 if (!subtitlesShowing)
166 subtitlesShowing = true;
171 subtitlesShowing = false;
174 return subtitlesShowing;
177 void PlayerVideoLive::turnSubtitlesOn(bool ison)
181 subtitlesShowing = true;
186 subtitlesShowing = false;
191 void PlayerVideoLive::tellSubtitlesOSDVisible(bool visible)
193 subtitles->setOSDMenuVisibility(visible);
196 // ----------------------------------- Externally called events
198 void PlayerVideoLive::go(ULONG index)
200 playerThreadMutex.lock();
202 struct PLInstruction i;
203 i.instruction = I_SETCHANNEL;
204 i.channelIndex = index;
205 instructions.push(i);
207 playerThread = std::thread([this]
209 playerThreadMutex.lock();
210 playerThreadMutex.unlock();
213 playerThreadMutex.unlock();
216 void PlayerVideoLive::setChannel(ULONG index)
218 logger->log("PlayerVideoLive", Log::DEBUG, "setChannel");
219 struct PLInstruction i;
220 i.instruction = I_SETCHANNEL;
221 i.channelIndex = index;
222 instructions.push(i);
223 playerThreadCond.notify_one();
226 void PlayerVideoLive::stop()
228 logger->log("PlayerVideoLive", Log::DEBUG, "stop");
230 playerThreadMutex.lock();
232 struct PLInstruction i;
233 i.instruction = I_STOP;
234 instructions.push(i);
236 playerThreadCond.notify_one();
237 playerThreadMutex.unlock();
240 logger->log("PlayerVideoLive", Log::DEBUG, "stop succesfull");
243 // ----------------------------------- Callback
245 void PlayerVideoLive::call(void* caller)
247 if (caller == demuxer)
249 logger->log("PlayerVideoLive", Log::DEBUG, "Callback from demuxer");
252 UCHAR dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary);
253 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
255 if (video->getTVsize() == Video::ASPECT16X9)
257 logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
258 video->setAspectRatio(Video::ASPECT4X3, parx, pary);
262 logger->log("PlayerVideoLive", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
265 Message* m = new Message();
267 m->to = messageReceiver;
268 m->message = Message::PLAYER_EVENT;
269 m->parameter = PlayerVideoLive::ASPECT43;
270 messageQueue->postMessage(m);
272 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
274 if (video->getTVsize() == Video::ASPECT16X9)
276 logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
277 video->setAspectRatio(Video::ASPECT16X9, parx, pary);
281 logger->log("PlayerVideoLive", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
284 Message* m = new Message();
286 m->to = messageReceiver;
287 m->message = Message::PLAYER_EVENT;
288 m->parameter = PlayerVideoLive::ASPECT169;
289 messageQueue->postMessage(m);
293 logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer said video is something else... switch anyway");
294 video->setAspectRatio(dxCurrentAspect, parx, pary);
297 else if (caller == &afeed)
299 if (state == S_VIDEOSTARTUP)
301 logger->log("PlayerVideoLive", Log::DEBUG, "afeed video startup");
303 playerThreadCond.notify_one();
308 // -----------------------------------
310 void PlayerVideoLive::streamReceive(ULONG flag, void* data, ULONG len)
313 // 0 = normal stream packet
315 // 2 = connection lost
317 //logger->log("PlayerVideoLive", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
323 Message* m = new Message();
325 m->to = messageReceiver;
326 m->message = Message::PLAYER_EVENT;
327 m->parameter = PlayerVideoLive::STREAM_END;
328 messageQueue->postMessage(m);
331 if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
336 streamChunks.push(s);
337 playerThreadCond.notify_one();
341 // Too many chunks in streamChunks, drop this chunk
343 logger->log("PlayerVideoLive", Log::WARN, "Dropped chunk");
347 void PlayerVideoLive::clearStreamChunks()
349 while(streamChunks.size())
351 logger->log("PlayerVideoLive", Log::DEBUG, "Dropping chunk from old stream");
352 struct StreamChunk s = streamChunks.front();
358 void PlayerVideoLive::chunkToDemuxer()
360 StreamChunk s = streamChunks.front();
362 // logger->log("PlayerVideoLive", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
363 /* int a =*/ demuxer->put(static_cast<UCHAR*>(s.data), s.len);
364 // logger->log("PlayerVideoLive", Log::DEBUG, "put %i to demuxer", a);
366 if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
371 //audio->setStreamType(Audio::MPEG2_PES);
375 pendingAudioPlay = false;
379 void PlayerVideoLive::switchState(UCHAR newState)
381 logger->log("PlayerVideoLive", Log::DEBUG, "Switch from state %u to state %u", state, newState);
385 case S_STOP: // FROM S_STOP
400 //audio->setStreamType(Audio::MPEG2_PES);
402 // I make this modification, since the video/audio devices needs to know at least
403 // which kind of video is embedded inside the stream
404 // therefore the demuxer needs to feeded at least with enough data
405 // to have one video header
406 // This is crucial, if we have mixed h264/mpeg2 channels
407 // the information from channels is not enough since some directshow decoders need
408 // width and height information before startup
409 pendingAudioPlay = true;
423 if (!video->independentAVStartUp())
426 playerThreadCond.notify_one();
432 logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
439 case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
445 pendingAudioPlay=false;
452 vdr->stopStreaming();
467 //audio->setStreamType(Audio::MPEG2_PES);
469 pendingAudioPlay = true;
481 if (!video->independentAVStartUp())
484 playerThreadCond.notify_one();
490 vdr->stopStreaming();
491 pendingAudioPlay=false;
507 logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
514 case S_PREBUFFERING: // FROM S_PREBUFFERING
520 pendingAudioPlay=false;
528 vdr->stopStreaming();
545 //audio->setStreamType(Audio::MPEG2_PES);
547 pendingAudioPlay = true;
564 pendingAudioPlay=false;
565 vdr->stopStreaming();
581 logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
588 case S_PLAY: // FROM S_PLAY
594 pendingAudioPlay=false;
595 vdr->stopStreaming();
611 vdr->stopStreaming();
629 //audio->setStreamType(Audio::MPEG2_PES);
633 pendingAudioPlay = true;
642 if (!video->independentAVStartUp())
645 playerThreadCond.notify_one();
651 logger->log("PlayerVideoLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
660 bool PlayerVideoLive::checkError()
662 if (!vdr->isConnected())
664 if (state != S_STOP) switchState(S_STOP);
666 Message* m = new Message();
668 m->to = messageReceiver;
669 m->message = Message::PLAYER_EVENT;
670 m->parameter = PlayerVideoLive::CONNECTION_LOST;
671 messageQueue->postMessage(m);
678 void PlayerVideoLive::optimizeInstructionQueue()
682 // Currently there are only 2 instruction types, so this is a bit overkill...
684 struct PLInstruction i;
685 while(instructions.size() > 1)
687 i = instructions.front();
688 if (i.instruction == I_SETCHANNEL)
690 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
692 else if (i.instruction == I_STOP)
694 return; // return here and ensure the next instruction will be stop
699 void PlayerVideoLive::threadMethod()
701 std::unique_lock<std::mutex> ul(playerThreadMutex, std::defer_lock);
705 //logger->log("PlayerVideoLive", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
706 if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
708 logger->log("PlayerVideoLive", Log::DEBUG, "Enter prebuffering");
709 switchState(S_PREBUFFERING);
710 videoStartup = false;
715 while (!instructions.empty())
717 if (instructions.size() > 1) optimizeInstructionQueue();
719 struct PLInstruction i = instructions.front();
722 if (i.instruction == I_SETCHANNEL)
724 logger->log("PlayerVideoLive", Log::DEBUG, "start new stream");
726 bool subsRestore = subtitles->isShowing();
728 switchState(S_VIDEOSTARTUP);
732 Channel* chan = (*chanList)[i.channelIndex];
734 h264=chan->vstreamtype==0x1b;
735 demuxer->seth264(h264);
736 video->seth264mode(chan->vstreamtype==0x1b);
737 demuxer->setVID(chan->vpid);
738 video->seth264mode(chan->vstreamtype==0x1b);
743 Command* command = Command::getInstance();
745 if (chan->numDPids > 0 && audio->maysupportAc3())
748 while (j < chan->numDPids)
750 int newpref = command->getLangPref(false, chan->dpids[j].desc);
751 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)
752 && (prefered < 0 || newpref < prefered))
764 if (chan->numAPids > 0)
767 while (j < chan->numAPids)
769 int newpref = command->getLangPref(false, chan->apids[j].desc);
770 if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)
771 && (prefered < 0 || newpref < prefered))
784 demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true);
785 audio->setStreamType(Audio::MPEG2_PES);
786 logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u",
787 chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type);
789 demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true);
790 audio->setStreamType(Audio::MPEG2_PES);
791 logger->log("PlayerVideoLive", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[selected].pid,
792 chan->apids[selected].type);
796 logger->log("PlayerVideoLive", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
802 if (chan->numSPids) {
804 while (j < chan->numSPids)
806 int newpref = command->getLangPref(true, chan->spids[j].desc);
807 if ( (prefered < 0 || newpref < prefered))
818 demuxer->setSubID(chan->spids[selected].pid);
824 if (command->getSubDefault())
825 turnSubtitlesOn(true);
827 turnSubtitlesOn(false);
832 turnSubtitlesOn(true);
834 turnSubtitlesOn(false);
838 demuxer->setTID(chan->tpid);
839 teletext->ResetDecoder();
840 int streamSuccess = vdr->streamChannel(chan->number, this);
841 if (!checkError() && !streamSuccess)
843 Message* m = new Message();
845 m->to = messageReceiver;
846 m->message = Message::PLAYER_EVENT;
847 m->parameter = PlayerVideoLive::STREAM_END;
848 messageQueue->postMessage(m);
852 else if (i.instruction == I_STOP)
854 logger->log("PlayerVideoLive", Log::DEBUG, "Stopping by instruction");
861 while(streamChunks.size())
863 //logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
865 //logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
867 if (state == S_PREBUFFERING)
869 // logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark3");
871 ULONG percentDone = (preBufferCount * 100) / preBufferAmount;
872 logger->log("PlayerVideoLive", Log::DEBUG, "Prebuffering %lu%%", percentDone);
874 Message* m = new Message();
876 m->to = messageReceiver;
877 m->message = Message::PLAYER_EVENT;
878 m->parameter = PlayerVideoLive::PREBUFFERING;
879 m->tag = percentDone;
880 messageQueue->postMessage(m);
882 if (preBufferCount == preBufferAmount)
889 //logger->log("PlayerVideoLive", Log::DEBUG, "wait for signal %d", streamChunks.size());
891 playerThreadMutex.lock();
892 if (!instructions.empty()) { playerThreadMutex.unlock(); continue; }
893 playerThreadCond.wait(ul);
894 playerThreadMutex.unlock();
896 //logger->log("PlayerVideoLive", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
899 logger->log("PlayerVideoLive", Log::DEBUG, "End of thread");