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/>.
30 #include "demuxerts.h"
32 #include "messagequeue.h"
36 #include "dvbsubtitles.h"
37 #include "osdreceiver.h"
40 #include "playervideolive.h"
42 static const char* TAG = "PlayerVideoLive";
44 // ----------------------------------- Called from outside, one offs or info funcs
46 PlayerVideoLive::PlayerVideoLive(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
47 : vfeed(this), afeed(this), tfeed(this),
48 messageQueue(tmessageQueue), messageReceiver(tmessageReceiver), osdReceiver(tosdReceiver), chanList(tchanList)
50 audio = Audio::getInstance();
51 video = Video::getInstance();
52 logger = LogNT::getInstance();
53 vdr = VDR::getInstance();
58 PlayerVideoLive::~PlayerVideoLive()
60 if (initted) shutdown();
63 int PlayerVideoLive::init()
65 if (initted) return 0;
67 demuxer = new DemuxerTS();
68 if (!demuxer) return 0;
69 subtitles = new DVBSubtitles(osdReceiver);
70 if (!subtitles) return 0;
72 teletext = new TeletextDecoderVBIEBU();
74 unsigned int demux_video_size = 2097152;
75 unsigned int demux_audio_size = 524288;
77 if (video->supportsh264())
79 demux_video_size *= 5 * 1;//5;
82 if (audio->maysupportAc3())
84 //demux_audio_size*=2;
87 int text_fak = video->getTeletextBufferFaktor();
89 if (!demuxer->init(this, audio, video, teletext, demux_video_size, demux_audio_size, 65536 * text_fak, 25./*unimportant*/, subtitles))
91 logger->error(TAG, "Demuxer failed to init");
104 int PlayerVideoLive::shutdown()
106 if (!initted) return 0;
107 logger->debug(TAG, "Shutdown");
110 logger->debug(TAG, "state is not stop, calling");
123 bool* PlayerVideoLive::getDemuxerMpegAudioChannels()
125 return demuxer->getmpAudioChannels();
128 bool* PlayerVideoLive::getDemuxerAc3AudioChannels()
130 return demuxer->getac3AudioChannels();
133 int PlayerVideoLive::getCurrentAudioChannel()
135 return demuxer->getAID();
138 void PlayerVideoLive::setAudioChannel(int newChannel, int type,int streamtype)
140 demuxer->setAID(newChannel, type, streamtype, true);
143 void PlayerVideoLive::setSubtitleChannel(int newChannel)
145 demuxer->setSubID(newChannel);
148 int* PlayerVideoLive::getTeletxtSubtitlePages()
150 return teletext->getSubtitlePages();
153 int PlayerVideoLive::getCurrentSubtitleChannel()
155 return demuxer->getSubID();
158 bool PlayerVideoLive::toggleSubtitles()
160 if (!subtitlesShowing)
162 subtitlesShowing = true;
167 subtitlesShowing = false;
170 return subtitlesShowing;
173 void PlayerVideoLive::turnSubtitlesOn(bool ison)
177 subtitlesShowing = true;
182 subtitlesShowing = false;
187 void PlayerVideoLive::tellSubtitlesOSDVisible(bool visible)
189 subtitles->setOSDMenuVisibility(visible);
192 // ----------------------------------- Externally called events
194 void PlayerVideoLive::go(ULONG index)
196 playerThreadMutex.lock();
198 struct PLInstruction i;
199 i.instruction = I_SETCHANNEL;
200 i.channelIndex = index;
201 instructions.push(i);
203 playerThread = std::thread([this]
205 playerThreadMutex.lock();
206 playerThreadMutex.unlock();
209 playerThreadMutex.unlock();
212 void PlayerVideoLive::setChannel(ULONG index)
214 logger->debug(TAG, "setChannel");
215 struct PLInstruction i;
216 i.instruction = I_SETCHANNEL;
217 i.channelIndex = index;
218 instructions.push(i);
219 playerThreadCond.notify_one();
222 void PlayerVideoLive::stop()
224 logger->debug(TAG, "stop");
226 playerThreadMutex.lock();
228 struct PLInstruction i;
229 i.instruction = I_STOP;
230 instructions.push(i);
232 playerThreadCond.notify_one();
233 playerThreadMutex.unlock();
236 logger->debug(TAG, "stop succesfull");
239 // ----------------------------------- Callback
241 void PlayerVideoLive::call(void* caller)
243 if (caller == demuxer)
245 logger->debug(TAG, "Callback from demuxer");
248 UCHAR dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary);
249 if (dxCurrentAspect == Demuxer::ASPECT_4_3)
251 if (video->getTVsize() == Video::ASPECT16X9)
253 logger->debug(TAG, "Demuxer said video is 4:3 aspect, switching TV");
254 video->setAspectRatio(Video::ASPECT4X3, parx, pary);
258 logger->debug(TAG, "TV is 4:3, ignoring aspect switching");
261 Message* m = new Message();
263 m->to = messageReceiver;
264 m->message = Message::PLAYER_EVENT;
265 m->parameter = PlayerVideoLive::ASPECT43;
266 messageQueue->postMessage(m);
268 else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
270 if (video->getTVsize() == Video::ASPECT16X9)
272 logger->debug(TAG, "Demuxer said video is 16:9 aspect, switching TV");
273 video->setAspectRatio(Video::ASPECT16X9, parx, pary);
277 logger->debug(TAG, "TV is 4:3, ignoring aspect switching");
280 Message* m = new Message();
282 m->to = messageReceiver;
283 m->message = Message::PLAYER_EVENT;
284 m->parameter = PlayerVideoLive::ASPECT169;
285 messageQueue->postMessage(m);
289 logger->debug(TAG, "Demuxer said video is something else... switch anyway");
290 video->setAspectRatio(dxCurrentAspect, parx, pary);
293 else if (caller == &afeed)
295 if (state == S_VIDEOSTARTUP)
297 logger->debug(TAG, "afeed video startup");
299 playerThreadCond.notify_one();
304 // -----------------------------------
306 void PlayerVideoLive::streamReceive(ULONG flag, void* data, ULONG len)
309 // 0 = normal stream packet
311 // 2 = connection lost
313 //logger->log("PlayerVideoLive", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
319 Message* m = new Message();
321 m->to = messageReceiver;
322 m->message = Message::PLAYER_EVENT;
323 m->parameter = PlayerVideoLive::STREAM_END;
324 messageQueue->postMessage(m);
327 if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
332 streamChunks.push(s);
333 playerThreadCond.notify_one();
337 // Too many chunks in streamChunks, drop this chunk
339 logger->debug(TAG, "Dropped chunk");
343 void PlayerVideoLive::clearStreamChunks()
345 while(streamChunks.size())
347 logger->debug(TAG, "Dropping chunk from old stream");
348 struct StreamChunk s = streamChunks.front();
354 void PlayerVideoLive::chunkToDemuxer()
356 StreamChunk s = streamChunks.front();
358 // logger->log("PlayerVideoLive", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
359 /* int a =*/ demuxer->put(static_cast<UCHAR*>(s.data), s.len);
360 // logger->log("PlayerVideoLive", Log::DEBUG, "put %i to demuxer", a);
362 if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
367 //audio->setStreamType(Audio::MPEG2_PES);
371 pendingAudioPlay = false;
375 void PlayerVideoLive::switchState(UCHAR newState)
377 logger->debug(TAG, "Switch from state {} to state {}", state, newState);
381 case S_STOP: // FROM S_STOP
396 //audio->setStreamType(Audio::MPEG2_PES);
398 // I make this modification, since the video/audio devices needs to know at least
399 // which kind of video is embedded inside the stream
400 // therefore the demuxer needs to feeded at least with enough data
401 // to have one video header
402 // This is crucial, if we have mixed h264/mpeg2 channels
403 // the information from channels is not enough since some directshow decoders need
404 // width and height information before startup
405 pendingAudioPlay = true;
419 if (!video->independentAVStartUp())
422 playerThreadCond.notify_one();
428 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
435 case S_VIDEOSTARTUP: // FROM S_VIDEOSTARTUP
441 pendingAudioPlay=false;
448 vdr->stopStreaming();
463 //audio->setStreamType(Audio::MPEG2_PES);
465 pendingAudioPlay = true;
477 if (!video->independentAVStartUp())
480 playerThreadCond.notify_one();
486 vdr->stopStreaming();
487 pendingAudioPlay=false;
503 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
510 case S_PREBUFFERING: // FROM S_PREBUFFERING
516 pendingAudioPlay=false;
524 vdr->stopStreaming();
541 //audio->setStreamType(Audio::MPEG2_PES);
543 pendingAudioPlay = true;
560 pendingAudioPlay=false;
561 vdr->stopStreaming();
577 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
584 case S_PLAY: // FROM S_PLAY
590 pendingAudioPlay=false;
591 vdr->stopStreaming();
607 vdr->stopStreaming();
625 //audio->setStreamType(Audio::MPEG2_PES);
629 pendingAudioPlay = true;
638 if (!video->independentAVStartUp())
641 playerThreadCond.notify_one();
647 logger->crit(TAG, "Thread called state {} to state {} which is not supported", state, newState);
656 bool PlayerVideoLive::checkError()
658 if (!vdr->isConnected())
660 if (state != S_STOP) switchState(S_STOP);
662 Message* m = new Message();
664 m->to = messageReceiver;
665 m->message = Message::PLAYER_EVENT;
666 m->parameter = PlayerVideoLive::CONNECTION_LOST;
667 messageQueue->postMessage(m);
674 void PlayerVideoLive::optimizeInstructionQueue()
678 // Currently there are only 2 instruction types, so this is a bit overkill...
680 struct PLInstruction i;
681 while(instructions.size() > 1)
683 i = instructions.front();
684 if (i.instruction == I_SETCHANNEL)
686 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
688 else if (i.instruction == I_STOP)
690 return; // return here and ensure the next instruction will be stop
695 void PlayerVideoLive::threadMethod()
697 std::unique_lock<std::mutex> ul(playerThreadMutex, std::defer_lock);
701 //logger->log("PlayerVideoLive", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
702 if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
704 logger->debug(TAG, "Enter prebuffering");
705 switchState(S_PREBUFFERING);
706 videoStartup = false;
711 while (!instructions.empty())
713 if (instructions.size() > 1) optimizeInstructionQueue();
715 struct PLInstruction i = instructions.front();
718 if (i.instruction == I_SETCHANNEL)
720 logger->debug(TAG, "start new stream");
722 bool subsRestore = subtitles->isShowing();
724 switchState(S_VIDEOSTARTUP);
728 Channel* chan = (*chanList)[i.channelIndex];
730 h264 = (chan->vstreamtype == 0x1b);
731 demuxer->seth264(h264);
732 video->seth264mode(h264);
733 demuxer->setVID(chan->vpid);
734 video->seth264mode(h264);
740 Control* control = Control::getInstance();
742 if (chan->numDPids > 0 && audio->maysupportAc3())
745 while (j < chan->numDPids)
747 int newpref = control->getLangPref(false, chan->dpids[j].desc);
748 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type) && (prefered < 0 || newpref < prefered))
758 if (chan->numAPids > 0)
761 while (j < chan->numAPids)
763 int newpref = control->getLangPref(false, chan->apids[j].desc);
764 if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type) && (prefered < 0 || newpref < prefered))
778 demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true);
779 audio->setStreamType(Audio::MPEG2_PES);
780 logger->debug(TAG, "Demuxer pids: {} {} (ac3) {}",
781 chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type);
785 demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true);
786 audio->setStreamType(Audio::MPEG2_PES);
787 logger->debug(TAG, "Demuxer pids: {} {} {}", chan->vpid, chan->apids[selected].pid,
788 chan->apids[selected].type);
793 logger->warn(TAG, "Demuxer video pid only: {}", chan->vpid);
801 while (j < chan->numSPids)
803 int newpref = control->getLangPref(true, chan->spids[j].desc);
804 if ((prefered < 0 || newpref < prefered))
815 demuxer->setSubID(chan->spids[selected].pid);
821 if (control->getSubDefault())
822 turnSubtitlesOn(true);
824 turnSubtitlesOn(false);
829 turnSubtitlesOn(true);
831 turnSubtitlesOn(false);
835 demuxer->setTID(chan->tpid);
836 teletext->ResetDecoder();
837 int streamSuccess = vdr->streamChannel(chan->number, this);
838 if (!checkError() && !streamSuccess)
840 Message* m = new Message();
842 m->to = messageReceiver;
843 m->message = Message::PLAYER_EVENT;
844 m->parameter = PlayerVideoLive::STREAM_END;
845 messageQueue->postMessage(m);
849 else if (i.instruction == I_STOP)
851 logger->debug(TAG, "Stopping by instruction");
858 while(streamChunks.size())
860 //logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
862 //logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
864 if (state == S_PREBUFFERING)
866 // logger->log("PlayerVideoLive", Log::DEBUG, "chunk mark3");
868 ULONG percentDone = (preBufferCount * 100) / preBufferAmount;
869 logger->debug(TAG, "Prebuffering {}%", percentDone);
871 Message* m = new Message();
873 m->to = messageReceiver;
874 m->message = Message::PLAYER_EVENT;
875 m->parameter = PlayerVideoLive::PREBUFFERING;
876 m->tag = percentDone;
877 messageQueue->postMessage(m);
879 if (preBufferCount == preBufferAmount)
886 //logger->log("PlayerVideoLive", Log::DEBUG, "wait for signal %d", streamChunks.size());
889 if (!instructions.empty()) { ul.unlock(); continue; }
890 playerThreadCond.wait(ul);
893 //logger->log("PlayerVideoLive", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
896 logger->debug(TAG, "End of thread");