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/>.
31 #include "demuxerts.h"
33 #include "messagequeue.h"
37 #include "dvbsubtitles.h"
38 #include "osdreceiver.h"
41 #include "playervideolive.h"
43 static const char* TAG = "PlayerVideoLive";
45 // ----------------------------------- Called from outside, one offs or info funcs
47 PlayerVideoLive::PlayerVideoLive(MessageQueue* tmessageQueue, MessageReceiver* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
48 : vfeed(this), afeed(this), tfeed(this),
49 messageQueue(tmessageQueue), messageReceiver(tmessageReceiver), osdReceiver(tosdReceiver), chanList(tchanList)
51 audio = Audio::getInstance();
52 video = Video::getInstance();
53 logger = LogNT::getInstance();
54 vdr = VDR::getInstance();
59 PlayerVideoLive::~PlayerVideoLive()
61 if (initted) shutdown();
64 int PlayerVideoLive::init()
66 if (initted) return 0;
68 demuxer = new DemuxerTS();
69 if (!demuxer) return 0;
70 subtitles = new DVBSubtitles(osdReceiver);
71 if (!subtitles) return 0;
73 teletext = new TeletextDecoderVBIEBU();
75 unsigned int demux_video_size = 2097152;
76 unsigned int demux_audio_size = 524288;
78 if (video->supportsh264())
80 demux_video_size *= 5 * 1;//5;
83 if (audio->maysupportAc3())
85 //demux_audio_size*=2;
88 int text_fak = video->getTeletextBufferFaktor();
90 if (!demuxer->init(this, audio, video, teletext, demux_video_size, demux_audio_size, 65536 * text_fak, 25./*unimportant*/, subtitles))
92 logger->error(TAG, "Demuxer failed to init");
105 int PlayerVideoLive::shutdown()
107 if (!initted) return 0;
108 logger->debug(TAG, "Shutdown");
111 logger->debug(TAG, "state is not stop, calling");
124 bool* PlayerVideoLive::getDemuxerMpegAudioChannels()
126 return demuxer->getmpAudioChannels();
129 bool* PlayerVideoLive::getDemuxerAc3AudioChannels()
131 return demuxer->getac3AudioChannels();
134 int PlayerVideoLive::getCurrentAudioChannel()
136 return demuxer->getAID();
139 void PlayerVideoLive::setAudioChannel(int newChannel, int type,int streamtype)
141 demuxer->setAID(newChannel, type, streamtype, true);
144 void PlayerVideoLive::setSubtitleChannel(int newChannel)
146 demuxer->setSubID(newChannel);
149 int* PlayerVideoLive::getTeletxtSubtitlePages()
151 return teletext->getSubtitlePages();
154 int PlayerVideoLive::getCurrentSubtitleChannel()
156 return demuxer->getSubID();
159 bool PlayerVideoLive::toggleSubtitles()
161 if (!subtitlesShowing)
163 subtitlesShowing = true;
168 subtitlesShowing = false;
171 return subtitlesShowing;
174 void PlayerVideoLive::turnSubtitlesOn(bool ison)
178 subtitlesShowing = true;
183 subtitlesShowing = false;
188 void PlayerVideoLive::tellSubtitlesOSDVisible(bool visible)
190 subtitles->setOSDMenuVisibility(visible);
193 // ----------------------------------- Externally called events
195 void PlayerVideoLive::go(ULONG index)
197 playerThreadMutex.lock();
199 struct PLInstruction i;
200 i.instruction = I_SETCHANNEL;
201 i.channelIndex = index;
202 instructions.push(i);
204 playerThread = std::thread([this]
206 playerThreadMutex.lock();
207 playerThreadMutex.unlock();
210 playerThreadMutex.unlock();
213 void PlayerVideoLive::setChannel(ULONG index)
215 logger->debug(TAG, "setChannel");
216 struct PLInstruction i;
217 i.instruction = I_SETCHANNEL;
218 i.channelIndex = index;
219 instructions.push(i);
220 playerThreadCond.notify_one();
223 void PlayerVideoLive::stop()
225 logger->debug(TAG, "stop");
227 playerThreadMutex.lock();
229 struct PLInstruction i;
230 i.instruction = I_STOP;
231 instructions.push(i);
233 playerThreadCond.notify_one();
234 playerThreadMutex.unlock();
237 logger->debug(TAG, "stop succesfull");
240 // ----------------------------------- Callback
242 void PlayerVideoLive::call(void* caller)
244 if (caller == demuxer)
246 logger->debug(TAG, "Callback from demuxer");
249 UCHAR dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary);
250 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
252 if (video->getTVsize() == Video::ASPECT16X9)
254 logger->debug(TAG, "Demuxer said video is 4:3 aspect, switching TV");
255 video->setAspectRatio(Video::ASPECT4X3, parx, pary);
259 logger->debug(TAG, "TV is 4:3, ignoring aspect switching");
262 Message* m = new Message();
264 m->to = messageReceiver;
265 m->message = Message::PLAYER_EVENT;
266 m->parameter = PlayerVideoLive::ASPECT43;
267 messageQueue->postMessage(m);
269 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
271 if (video->getTVsize() == Video::ASPECT16X9)
273 logger->debug(TAG, "Demuxer said video is 16:9 aspect, switching TV");
274 video->setAspectRatio(Video::ASPECT16X9, parx, pary);
278 logger->debug(TAG, "TV is 4:3, ignoring aspect switching");
281 Message* m = new Message();
283 m->to = messageReceiver;
284 m->message = Message::PLAYER_EVENT;
285 m->parameter = PlayerVideoLive::ASPECT169;
286 messageQueue->postMessage(m);
290 logger->debug(TAG, "Demuxer said video is something else... switch anyway");
291 video->setAspectRatio(dxCurrentAspect, parx, pary);
294 else if (caller == &afeed)
296 if (state == S_VIDEOSTARTUP)
298 logger->debug(TAG, "afeed video startup");
300 playerThreadCond.notify_one();
305 // -----------------------------------
307 void PlayerVideoLive::streamReceive(ULONG flag, void* data, ULONG len)
310 // 0 = normal stream packet
312 // 2 = connection lost
314 //logger->log("PlayerVideoLive", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
320 Message* m = new Message();
322 m->to = messageReceiver;
323 m->message = Message::PLAYER_EVENT;
324 m->parameter = PlayerVideoLive::STREAM_END;
325 messageQueue->postMessage(m);
328 if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
333 streamChunks.push(s);
334 playerThreadCond.notify_one();
338 // Too many chunks in streamChunks, drop this chunk
340 logger->debug(TAG, "Dropped chunk");
344 void PlayerVideoLive::clearStreamChunks()
346 while(streamChunks.size())
348 logger->debug(TAG, "Dropping chunk from old stream");
349 struct StreamChunk s = streamChunks.front();
355 void PlayerVideoLive::chunkToDemuxer()
357 StreamChunk s = streamChunks.front();
359 // logger->log("PlayerVideoLive", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
360 /* int a =*/ demuxer->put(static_cast<UCHAR*>(s.data), s.len);
361 // logger->log("PlayerVideoLive", Log::DEBUG, "put %i to demuxer", a);
363 if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
368 //audio->setStreamType(Audio::MPEG2_PES);
372 pendingAudioPlay = false;
376 void PlayerVideoLive::switchState(UCHAR newState)
378 logger->debug(TAG, "Switch from state {} to state {}", state, newState);
382 case S_STOP: // FROM S_STOP
397 //audio->setStreamType(Audio::MPEG2_PES);
399 // I make this modification, since the video/audio devices needs to know at least
400 // which kind of video is embedded inside the stream
401 // therefore the demuxer needs to feeded at least with enough data
402 // to have one video header
403 // This is crucial, if we have mixed h264/mpeg2 channels
404 // the information from channels is not enough since some directshow decoders need
405 // width and height information before startup
406 pendingAudioPlay = true;
420 if (!video->independentAVStartUp())
423 playerThreadCond.notify_one();
429 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
436 case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
442 pendingAudioPlay=false;
449 vdr->stopStreaming();
464 //audio->setStreamType(Audio::MPEG2_PES);
466 pendingAudioPlay = true;
478 if (!video->independentAVStartUp())
481 playerThreadCond.notify_one();
487 vdr->stopStreaming();
488 pendingAudioPlay=false;
504 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
511 case S_PREBUFFERING: // FROM S_PREBUFFERING
517 pendingAudioPlay=false;
525 vdr->stopStreaming();
542 //audio->setStreamType(Audio::MPEG2_PES);
544 pendingAudioPlay = true;
561 pendingAudioPlay=false;
562 vdr->stopStreaming();
578 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
585 case S_PLAY: // FROM S_PLAY
591 pendingAudioPlay=false;
592 vdr->stopStreaming();
608 vdr->stopStreaming();
626 //audio->setStreamType(Audio::MPEG2_PES);
630 pendingAudioPlay = true;
639 if (!video->independentAVStartUp())
642 playerThreadCond.notify_one();
648 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
657 bool PlayerVideoLive::checkError()
659 if (!vdr->isConnected())
661 if (state != S_STOP) switchState(S_STOP);
663 Message* m = new Message();
665 m->to = messageReceiver;
666 m->message = Message::PLAYER_EVENT;
667 m->parameter = PlayerVideoLive::CONNECTION_LOST;
668 messageQueue->postMessage(m);
675 void PlayerVideoLive::optimizeInstructionQueue()
679 // Currently there are only 2 instruction types, so this is a bit overkill...
681 struct PLInstruction i;
682 while(instructions.size() > 1)
684 i = instructions.front();
685 if (i.instruction == I_SETCHANNEL)
687 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
689 else if (i.instruction == I_STOP)
691 return; // return here and ensure the next instruction will be stop
696 void PlayerVideoLive::threadMethod()
698 std::unique_lock<std::mutex> ul(playerThreadMutex, std::defer_lock);
702 //logger->log("PlayerVideoLive", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
703 if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
705 logger->debug(TAG, "Enter prebuffering");
706 switchState(S_PREBUFFERING);
707 videoStartup = false;
712 while (!instructions.empty())
714 if (instructions.size() > 1) optimizeInstructionQueue();
716 struct PLInstruction i = instructions.front();
719 if (i.instruction == I_SETCHANNEL)
721 logger->debug(TAG, "start new stream");
723 bool subsRestore = subtitles->isShowing();
725 switchState(S_VIDEOSTARTUP);
729 Channel* chan = (*chanList)[i.channelIndex];
731 h264 = (chan->vstreamtype == 0x1b);
732 demuxer->seth264(h264);
733 video->seth264mode(h264);
734 demuxer->setVID(chan->vpid);
735 video->seth264mode(h264);
741 Control* control = Control::getInstance();
743 if (chan->numDPids > 0 && audio->maysupportAc3())
746 while (j < chan->numDPids)
748 int newpref = control->getLangPref(false, chan->dpids[j].desc);
749 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type) && (prefered < 0 || newpref < prefered))
759 if (chan->numAPids > 0)
762 while (j < chan->numAPids)
764 int newpref = control->getLangPref(false, chan->apids[j].desc);
765 if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type) && (prefered < 0 || newpref < prefered))
779 demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true);
780 audio->setStreamType(Audio::MPEG2_PES);
781 logger->debug(TAG, "Demuxer pids: {} {} (ac3) {}",
782 chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type);
786 demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true);
787 audio->setStreamType(Audio::MPEG2_PES);
788 logger->debug(TAG, "Demuxer pids: {} {} {}", chan->vpid, chan->apids[selected].pid,
789 chan->apids[selected].type);
794 logger->warn(TAG, "Demuxer video pid only: {}", chan->vpid);
802 while (j < chan->numSPids)
804 int newpref = control->getLangPref(true, chan->spids[j].desc);
805 if ((prefered < 0 || newpref < prefered))
816 demuxer->setSubID(chan->spids[selected].pid);
823 Config::getInstance()->getInt("subtitles", "default", subDefault);
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->debug(TAG, "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->debug(TAG, "Prebuffering {}%", 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());
892 if (!instructions.empty()) { ul.unlock(); continue; }
893 playerThreadCond.wait(ul);
896 //logger->log("PlayerVideoLive", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
899 logger->debug(TAG, "End of thread");