]> git.vomp.tv Git - vompclient-marten.git/blob - playerlivetv.cc
dvbsubtitles fixup part 2
[vompclient-marten.git] / playerlivetv.cc
1 /*
2     Copyright 2007 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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.
19 */
20
21 #include "playerlivetv.h"
22
23 #include "log.h"
24 #include "audio.h"
25 #include "video.h"
26 #include "demuxerts.h"
27 #include "vdr.h"
28 #include "messagequeue.h"
29 #include "remote.h"
30 #include "message.h"
31 #include "channel.h"
32 #include "dvbsubtitles.h"
33 #include "osdreceiver.h"
34
35 // ----------------------------------- Called from outside, one offs or info funcs
36
37 PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
38 : vfeed(this), afeed(this), tfeed(this)
39 {
40   messageQueue = tmessageQueue;
41   messageReceiver = tmessageReceiver;
42   osdReceiver = tosdReceiver;
43   chanList = tchanList;
44   
45   audio = Audio::getInstance();
46   video = Video::getInstance();
47   logger = Log::getInstance();
48   vdr = VDR::getInstance();
49   initted = false;
50
51   subtitlesShowing = false;
52   videoStartup = false;
53   pendingAudioPlay = false;
54
55   stopNow = false;
56   state = S_STOP;
57
58   video->turnVideoOn();
59 }
60
61 PlayerLiveTV::~PlayerLiveTV()
62 {
63   if (initted) shutdown();
64 }
65
66 int PlayerLiveTV::init()
67 {
68   if (initted) return 0;
69
70   demuxer = new DemuxerTS();
71   if (!demuxer) return 0;
72   subtitles = new DVBSubtitles(osdReceiver);
73   if (!subtitles) return 0;
74
75   teletext = new TeletextDecoderVBIEBU();
76   
77   unsigned int demux_video_size=2097152;
78    unsigned int demux_audio_size=524288;
79    if (video->supportsh264()) {
80           demux_video_size*=5*1;//5;
81
82    }
83    if (audio->maysupportAc3()) {
84           //demux_audio_size*=2;
85    }
86
87   int text_fak=video->getTeletextBufferFaktor();
88
89  
90   if (!demuxer->init(this, audio, video, teletext, demux_video_size,demux_audio_size, 65536*text_fak,25./*unimportant*/,subtitles))
91   {
92     logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
93     shutdown();
94     return 0;
95   }
96
97   vfeed.init();
98   afeed.init();
99   tfeed.init();
100
101   video->stop();
102   video->blank();
103   audio->stop();
104
105   initted = true;
106   return 1;
107 }
108
109 int PlayerLiveTV::shutdown()
110 {
111   if (!initted) return 0;
112   logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown");
113   stop();
114   initted = false;
115
116   delete demuxer;
117   delete subtitles;
118   delete teletext;
119   teletext = NULL;
120   return 1;
121 }
122
123 bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
124 {
125   return demuxer->getmpAudioChannels();
126 }
127
128 bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
129 {
130   return demuxer->getac3AudioChannels();
131 }
132
133 int PlayerLiveTV::getCurrentAudioChannel()
134 {
135   return demuxer->getAID();
136 }
137
138 void PlayerLiveTV::setAudioChannel(int newChannel, int type,int streamtype)
139 {
140   demuxer->setAID(newChannel,type,streamtype,true);
141 }
142
143 void PlayerLiveTV::setSubtitleChannel(int newChannel)
144 {
145    demuxer->setSubID(newChannel);
146 }
147
148 int *PlayerLiveTV::getTeletxtSubtitlePages()
149 {
150     return teletext->getSubtitlePages();
151 }
152
153 int PlayerLiveTV::getCurrentSubtitleChannel(){
154     return demuxer->getSubID();
155 }
156
157 bool PlayerLiveTV::toggleSubtitles()
158 {
159   if (!subtitlesShowing)
160   {
161     subtitlesShowing = true;
162     subtitles->show();
163   }
164   else
165   {
166     subtitlesShowing = false;
167     subtitles->hide();
168   }
169   return subtitlesShowing;
170 }
171
172
173 void  PlayerLiveTV::turnSubtitlesOn(bool ison) {
174  if (ison)
175   {
176     subtitlesShowing = true;
177     subtitles->show();
178   }
179   else
180   {
181     subtitlesShowing = false;
182     subtitles->hide();
183   }
184
185 }
186
187 void PlayerLiveTV::tellSubtitlesOSDVisible(bool visible)
188 {
189 subtitles->setOSDMenuVisibility(visible);
190 }
191
192 // ----------------------------------- Externally called events
193
194 void PlayerLiveTV::go(ULONG index)
195 {
196   struct PLInstruction i;
197   i.instruction = I_SETCHANNEL;
198   i.channelIndex = index;
199   instructions.push(i);
200   threadStart();
201 }
202
203 void PlayerLiveTV::setChannel(ULONG index)
204 {
205   logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
206   struct PLInstruction i;
207   i.instruction = I_SETCHANNEL;
208   i.channelIndex = index;
209   instructions.push(i);  
210   threadSignalNoLock();
211 }
212
213 void PlayerLiveTV::stop()
214 {
215   logger->log("PlayerLiveTV", Log::DEBUG, "stop");
216   struct PLInstruction i;
217   i.instruction = I_STOP;
218   instructions.push(i);
219   threadSignal();
220   threadStop();
221   logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");
222 }
223
224 // ----------------------------------- Callback
225
226 void PlayerLiveTV::call(void* caller)
227 {
228   if (caller == demuxer)
229   {
230     logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
231
232     int parx,pary;
233     int dxCurrentAspect = demuxer->getAspectRatio(&parx,&pary);
234     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
235     {
236       if (video->getTVsize() == Video::ASPECT16X9)
237       {
238         logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
239         video->setAspectRatio(Video::ASPECT4X3,parx,pary);
240       }
241       else
242       {
243         logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
244       }
245
246       Message* m = new Message();
247       m->from = this;
248       m->to = messageReceiver;
249       m->message = Message::PLAYER_EVENT;
250       m->parameter = PlayerLiveTV::ASPECT43;
251       messageQueue->postMessageFromOuterSpace(m);
252     }
253     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
254     {
255       if (video->getTVsize() == Video::ASPECT16X9)
256       {
257         logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
258         video->setAspectRatio(Video::ASPECT16X9,parx,pary);
259       }
260       else
261       {
262         logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
263       }    
264
265       Message* m = new Message();
266       m->from = this;
267       m->to = messageReceiver;
268       m->message = Message::PLAYER_EVENT;
269       m->parameter = PlayerLiveTV::ASPECT169;
270       messageQueue->postMessageFromOuterSpace(m);
271     }
272     else
273     {
274       logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... switch anyway");
275       video->setAspectRatio( dxCurrentAspect,parx,pary);
276     }
277   }
278   else if (caller == &afeed)
279   {
280     if (state == S_VIDEOSTARTUP)
281     {
282       logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
283       videoStartup = true;
284       threadSignalNoLock();
285     }
286   }
287 }
288
289 // -----------------------------------
290
291 void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
292 {
293   // Flag:
294   // 0 = normal stream packet
295   // 1 = stream end
296   // 2 = connection lost
297
298   //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
299
300   if (flag == 1)
301   {
302     if (data) abort();
303     
304     Message* m = new Message();
305     m->from = this;
306     m->to = messageReceiver;
307     m->message = Message::PLAYER_EVENT;
308     m->parameter = PlayerLiveTV::STREAM_END;
309     messageQueue->postMessageFromOuterSpace(m);
310   }
311         
312   if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
313   {
314     StreamChunk s;
315     s.data = data;
316     s.len = len;
317     streamChunks.push(s);
318     threadSignalNoLock();
319   }
320   else
321   {
322     // Too many chunks in streamChunks, drop this chunk
323     free(data);
324     logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
325   }
326 }
327
328 void PlayerLiveTV::clearStreamChunks()
329 {
330   while(streamChunks.size())
331   {
332     logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
333     struct StreamChunk s = streamChunks.front();
334     streamChunks.pop();
335     free(s.data);
336   }
337 }
338
339 void PlayerLiveTV::chunkToDemuxer()
340 {
341   StreamChunk s = streamChunks.front();
342   streamChunks.pop();
343 //  logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
344  /* int a =*/ demuxer->put((UCHAR*)s.data, s.len);
345 //  logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
346   free(s.data);  
347   if (pendingAudioPlay && (demuxer->getHorizontalSize()|| !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
348   {
349       video->sync();
350       video->play();
351       video->pause();
352       //audio->setStreamType(Audio::MPEG2_PES);
353       audio->sync();
354       audio->play();
355       audio->pause();
356       pendingAudioPlay = false;
357   }
358 }
359
360 void PlayerLiveTV::switchState(UCHAR newState)
361 {
362   logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
363
364   switch(state)
365   {
366     case S_STOP:   // FROM S_STOP
367     {
368       switch(newState)
369       {
370         case S_VIDEOSTARTUP:
371         {
372           video->blank();
373           video->reset();
374           //video->sync();
375           //video->play();
376           //video->pause();
377
378           audio->stop();
379           audio->unPause();
380           audio->reset();
381           //audio->setStreamType(Audio::MPEG2_PES);
382           //audio->sync();
383           // I make this modification, since the video/audio devices needs to know at least
384           // which kind of video is embedded inside the stream
385           // therefore the demuxer needs to feeded at least with enough data
386           // to have one video header
387           // This is crucial, if we have mixed h264/mpeg2 channels
388           // the information from channels is not enough since some directshow decoders need
389           // width and height information before startup
390           pendingAudioPlay = true;
391
392           //audio->play();
393           //audio->pause();
394
395           demuxer->reset();
396           demuxer->seek();
397
398           afeed.start();
399           vfeed.start();
400           subtitles->start();
401           tfeed.start();
402           
403           state = newState;
404           if (!video->independentAVStartUp()){
405                   videoStartup = true;
406                   threadSignalNoLock();
407           }
408           return;
409         }
410         default:
411         {
412           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
413           abort();
414           break;
415         }
416       }
417     }
418
419     case S_VIDEOSTARTUP:     // FROM S_VIDEOSTARTUP
420     {
421       switch(newState)
422       {
423         case S_PREBUFFERING:
424         {
425           pendingAudioPlay=false;
426           vfeed.release();
427           state = newState;
428           return;
429         }
430         
431         case S_VIDEOSTARTUP:
432         {
433
434           vdr->stopStreaming();
435           clearStreamChunks(); 
436           vfeed.stop();
437           afeed.stop();
438           subtitles->stop();
439           tfeed.stop();
440                            
441           video->blank();
442           video->reset();
443           //video->sync();
444           //video->play();
445           //video->pause();
446           audio->stop();
447           audio->unPause();
448           audio->reset();
449           //audio->setStreamType(Audio::MPEG2_PES);
450           //audio->sync();
451           pendingAudioPlay = true;
452           //audio->play();
453           //audio->pause();
454
455           demuxer->reset();
456           demuxer->seek();
457
458           afeed.start();
459           vfeed.start();
460           subtitles->start();     
461           tfeed.start();
462           state = newState;
463           if (!video->independentAVStartUp()){
464               videoStartup = true;
465               threadSignalNoLock();
466           }
467           return;
468         }        
469         case S_STOP:
470         { 
471           vdr->stopStreaming();
472           pendingAudioPlay=false;
473           clearStreamChunks();
474           vfeed.stop();
475           afeed.stop();
476           subtitles->stop();
477           tfeed.stop();
478           video->stop();
479           video->blank();
480           audio->stop();
481           audio->reset();
482           video->reset();
483           state = newState;
484           return;
485         }
486         default:
487         {
488           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
489           abort();
490           break;
491         }        
492       }
493     }
494     
495     case S_PREBUFFERING:    // FROM S_PREBUFFERING
496     {
497       switch(newState)
498       {
499         case S_PLAY:
500         {
501           pendingAudioPlay=false;
502           audio->unPause();
503           video->unPause();
504           state = newState;
505           return;
506         }
507         case S_VIDEOSTARTUP:
508         {
509           vdr->stopStreaming();
510           clearStreamChunks();
511           vfeed.stop();
512           afeed.stop();
513           subtitles->stop();
514           tfeed.stop();
515           video->stop();
516           video->blank();
517           audio->stop();
518           audio->unPause();
519           audio->reset();
520
521           video->reset();
522           //video->sync();
523           //video->play();
524           //video->pause();
525
526           //audio->setStreamType(Audio::MPEG2_PES);
527           //audio->sync();
528           pendingAudioPlay = true;
529           //audio->play();
530           //audio->pause();
531
532           demuxer->reset();
533           demuxer->seek();
534
535           afeed.start();
536           vfeed.start();
537           subtitles->start();
538           tfeed.start();
539
540           state = newState;
541           return;
542         }
543         case S_STOP:
544         {
545           pendingAudioPlay=false;
546           vdr->stopStreaming();
547           clearStreamChunks();
548           vfeed.stop();
549           afeed.stop();
550           subtitles->stop();
551           tfeed.stop();
552           video->stop();
553           video->blank();
554           audio->stop();
555           audio->reset();
556           video->reset();
557           state = newState;
558           return;        
559         }
560         default:
561         {
562           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
563           abort();
564           break;
565         }        
566       }
567     }
568     
569     case S_PLAY:     // FROM S_PLAY
570     {
571       switch(newState)
572       {
573         case S_STOP:
574         { 
575           pendingAudioPlay=false;
576           vdr->stopStreaming();
577           clearStreamChunks();
578           vfeed.stop();
579           afeed.stop();
580           subtitles->stop();
581           tfeed.stop();
582           video->stop();
583           video->blank();
584           audio->stop();
585           audio->reset();
586           video->reset();
587           state = newState;
588           return;
589         }
590         case S_VIDEOSTARTUP:
591         {
592           vdr->stopStreaming();
593           clearStreamChunks();
594           vfeed.stop();
595           afeed.stop();
596           subtitles->stop();
597           tfeed.stop();
598           video->stop();
599           video->blank();
600           audio->stop();
601           audio->unPause();
602           audio->reset();
603
604           video->reset();
605           
606           //video->sync();
607          // video->play();
608           //video->pause();
609
610           //audio->setStreamType(Audio::MPEG2_PES);
611           //audio->sync();
612           //audio->play();
613           //audio->pause();
614           pendingAudioPlay = true;
615           demuxer->reset();
616           demuxer->seek();
617
618           afeed.start();
619           vfeed.start();
620           subtitles->start();
621           tfeed.start();
622           state = newState;
623           if (!video->independentAVStartUp()){
624                   videoStartup = true;
625               threadSignalNoLock();
626           }
627           return;
628         }
629         default:
630         {
631           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
632           abort();
633           break;
634         }        
635       }
636     }    
637   }  
638 }
639
640 bool PlayerLiveTV::checkError()
641 {
642   if (!vdr->isConnected())
643   {
644     if (state != S_STOP) switchState(S_STOP);
645     
646     Message* m = new Message();
647     m->from = this;
648     m->to = messageReceiver;
649     m->message = Message::PLAYER_EVENT;
650     m->parameter = PlayerLiveTV::CONNECTION_LOST;
651     messageQueue->postMessageFromOuterSpace(m);
652     
653     return true;
654   }   
655   return false;
656 }
657
658 void PlayerLiveTV::optimizeInstructionQueue()
659 {
660   // Walk the list
661   
662   // Currently there are only 2 instruction types, so this is a bit overkill...
663
664   struct PLInstruction i;
665   while(instructions.size() > 1)
666   {
667     i = instructions.front();
668     if (i.instruction == I_SETCHANNEL)
669     {
670       instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant
671     }
672     else if (i.instruction == I_STOP)
673     {
674       return; // return here and ensure the next instruction will be stop
675     }
676   }
677 }
678
679 void PlayerLiveTV::threadMethod()
680 {
681   while(1)
682   {
683
684         //logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
685     if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
686     {
687            logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");
688       switchState(S_PREBUFFERING);
689       videoStartup = false;
690       preBufferCount = 0;
691       
692       checkError();
693     }  
694   
695     while(!instructions.empty())
696     {
697       if (instructions.size() > 1) optimizeInstructionQueue();
698
699       struct PLInstruction i = instructions.front();
700       instructions.pop();
701     
702       if (i.instruction == I_SETCHANNEL)
703       {
704         logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
705        
706         
707         switchState(S_VIDEOSTARTUP);
708         
709         if (!checkError())
710         {
711            Channel* chan = (*chanList)[i.channelIndex];
712            chan->loadPids();
713            h264=chan->vstreamtype==0x1b;
714            demuxer->seth264(h264);
715            video->seth264mode(chan->vstreamtype==0x1b);
716            demuxer->setVID(chan->vpid);
717            video->seth264mode(chan->vstreamtype==0x1b);
718
719            bool found=false;
720
721           if (chan->numAPids > 0) 
722           {
723                   int j=0;
724                   while (j<chan->numAPids && !found) {
725                           if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)) {
726                                   demuxer->setAID(chan->apids[j].pid,0,chan->apids[j].type,true);
727                                   audio->setStreamType(Audio::MPEG2_PES);
728                                   logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid,chan->apids[j].type);
729                                   found=true;
730                           }
731                           j++;
732                   }
733           }
734
735           if (!found)
736           {
737               if (chan->numDPids > 0  && audio->maysupportAc3()) 
738               {
739                   int j=0;
740                   while (j<chan->numDPids && !found) {
741                           if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)) {
742                                   demuxer->setAID(chan->dpids[j].pid,1,chan->dpids[j].type,true);
743                                   audio->setStreamType(Audio::MPEG2_PES);
744                                   logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid,chan->dpids[j].type);
745                                   found=true;
746                           }
747                           j++;
748                   }
749               } 
750               else
751               {
752                   logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
753               }
754           }
755           if (chan->numSPids > 0)
756             demuxer->setSubID(chan->spids[0].pid);
757           demuxer->setTID(chan->tpid);
758           teletext->ResetDecoder();
759           int streamSuccess = vdr->streamChannel(chan->number, this);
760           if (!checkError() && !streamSuccess)
761           {      
762             Message* m = new Message();
763             m->from = this;
764             m->to = messageReceiver;
765             m->message = Message::PLAYER_EVENT;
766             m->parameter = PlayerLiveTV::STREAM_END;
767             messageQueue->postMessageFromOuterSpace(m);
768           }
769         }
770       }
771       else if (i.instruction == I_STOP)
772       {
773         logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
774         switchState(S_STOP);
775         checkError();
776
777         stopNow = true;
778         break;
779       }
780     }
781
782         threadCheckExit();
783
784     if (stopNow) break;
785
786     while(streamChunks.size())
787     {
788         //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
789       chunkToDemuxer();
790       //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
791
792       if (state == S_PREBUFFERING)
793       {
794          // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3");
795         ++preBufferCount;
796         ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
797         logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
798         
799         Message* m = new Message();
800         m->from = this;
801         m->to = messageReceiver;
802         m->message = Message::PLAYER_EVENT;
803         m->parameter = PlayerLiveTV::PREBUFFERING;
804         m->tag = percentDone;
805         messageQueue->postMessageFromOuterSpace(m);
806
807         if (preBufferCount == preBufferAmount)
808         {
809           switchState(S_PLAY);
810           checkError();
811         }
812       }
813     }
814   //  logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size());
815     threadLock();
816     threadWaitForSignal(); // unlocks and waits for signal
817     threadUnlock();
818     //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
819   }
820
821   logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");
822 }
823