]> git.vomp.tv Git - vompclient-marten.git/blob - playerlivetv.cc
Let vomp handle aspect ratio change, better aspect ratio control for HD and SD
[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);
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 // ----------------------------------- Externally called events
187
188 void PlayerLiveTV::go(ULONG index)
189 {
190   struct PLInstruction i;
191   i.instruction = I_SETCHANNEL;
192   i.channelIndex = index;
193   instructions.push(i);
194   threadStart();
195 }
196
197 void PlayerLiveTV::setChannel(ULONG index)
198 {
199   logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
200   struct PLInstruction i;
201   i.instruction = I_SETCHANNEL;
202   i.channelIndex = index;
203   instructions.push(i);  
204   threadSignalNoLock();
205 }
206
207 void PlayerLiveTV::stop()
208 {
209   logger->log("PlayerLiveTV", Log::DEBUG, "stop");
210   struct PLInstruction i;
211   i.instruction = I_STOP;
212   instructions.push(i);
213   threadSignal();
214   threadStop();
215   logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");
216 }
217
218 // ----------------------------------- Callback
219
220 void PlayerLiveTV::call(void* caller)
221 {
222   if (caller == demuxer)
223   {
224     logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
225
226     int parx,pary;
227     int dxCurrentAspect = demuxer->getAspectRatio(&parx,&pary);
228     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
229     {
230       if (video->getTVsize() == Video::ASPECT16X9)
231       {
232         logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
233         video->setAspectRatio(Video::ASPECT4X3,parx,pary);
234       }
235       else
236       {
237         logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
238       }
239
240       Message* m = new Message();
241       m->from = this;
242       m->to = messageReceiver;
243       m->message = Message::PLAYER_EVENT;
244       m->parameter = PlayerLiveTV::ASPECT43;
245       messageQueue->postMessageFromOuterSpace(m);
246     }
247     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
248     {
249       if (video->getTVsize() == Video::ASPECT16X9)
250       {
251         logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
252         video->setAspectRatio(Video::ASPECT16X9,parx,pary);
253       }
254       else
255       {
256         logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
257       }    
258
259       Message* m = new Message();
260       m->from = this;
261       m->to = messageReceiver;
262       m->message = Message::PLAYER_EVENT;
263       m->parameter = PlayerLiveTV::ASPECT169;
264       messageQueue->postMessageFromOuterSpace(m);
265     }
266     else
267     {
268       logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... switch anyway");
269       video->setAspectRatio( dxCurrentAspect,parx,pary);
270     }
271   }
272   else if (caller == &afeed)
273   {
274     if (state == S_VIDEOSTARTUP)
275     {
276       logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
277       videoStartup = true;
278       threadSignalNoLock();
279     }
280   }
281 }
282
283 // -----------------------------------
284
285 void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
286 {
287   // Flag:
288   // 0 = normal stream packet
289   // 1 = stream end
290   // 2 = connection lost
291
292   //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
293
294   if (flag == 1)
295   {
296     if (data) abort();
297     
298     Message* m = new Message();
299     m->from = this;
300     m->to = messageReceiver;
301     m->message = Message::PLAYER_EVENT;
302     m->parameter = PlayerLiveTV::STREAM_END;
303     messageQueue->postMessageFromOuterSpace(m);
304   }
305         
306   if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
307   {
308     StreamChunk s;
309     s.data = data;
310     s.len = len;
311     streamChunks.push(s);
312     threadSignalNoLock();
313   }
314   else
315   {
316     // Too many chunks in streamChunks, drop this chunk
317     free(data);
318     logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
319   }
320 }
321
322 void PlayerLiveTV::clearStreamChunks()
323 {
324   while(streamChunks.size())
325   {
326     logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
327     struct StreamChunk s = streamChunks.front();
328     streamChunks.pop();
329     free(s.data);
330   }
331 }
332
333 void PlayerLiveTV::chunkToDemuxer()
334 {
335   StreamChunk s = streamChunks.front();
336   streamChunks.pop();
337 //  logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
338  /* int a =*/ demuxer->put((UCHAR*)s.data, s.len);
339 //  logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
340   free(s.data);  
341   if (pendingAudioPlay && (demuxer->getHorizontalSize()|| !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
342   {
343       video->sync();
344       video->play();
345       video->pause();
346       //audio->setStreamType(Audio::MPEG2_PES);
347       audio->sync();
348       audio->play();
349       audio->pause();
350       pendingAudioPlay = false;
351   }
352 }
353
354 void PlayerLiveTV::switchState(UCHAR newState)
355 {
356   logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
357
358   switch(state)
359   {
360     case S_STOP:   // FROM S_STOP
361     {
362       switch(newState)
363       {
364         case S_VIDEOSTARTUP:
365         {
366           video->blank();
367           video->reset();
368           //video->sync();
369           //video->play();
370           //video->pause();
371
372           audio->stop();
373           audio->unPause();
374           audio->reset();
375           //audio->setStreamType(Audio::MPEG2_PES);
376           //audio->sync();
377           // I make this modification, since the video/audio devices needs to know at least
378           // which kind of video is embedded inside the stream
379           // therefore the demuxer needs to feeded at least with enough data
380           // to have one video header
381           // This is crucial, if we have mixed h264/mpeg2 channels
382           // the information from channels is not enough since some directshow decoders need
383           // width and height information before startup
384           pendingAudioPlay = true;
385
386           //audio->play();
387           //audio->pause();
388
389           demuxer->reset();
390           demuxer->seek();
391
392           afeed.start();
393           vfeed.start();
394           subtitles->start();
395           tfeed.start();
396           
397           state = newState;
398           if (!video->independentAVStartUp()){
399                   videoStartup = true;
400                   threadSignalNoLock();
401           }
402           return;
403         }
404         default:
405         {
406           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
407           abort();
408           break;
409         }
410       }
411     }
412
413     case S_VIDEOSTARTUP:     // FROM S_VIDEOSTARTUP
414     {
415       switch(newState)
416       {
417         case S_PREBUFFERING:
418         {
419           pendingAudioPlay=false;
420           vfeed.release();
421           state = newState;
422           return;
423         }
424         
425         case S_VIDEOSTARTUP:
426         {
427
428           vdr->stopStreaming();
429           clearStreamChunks(); 
430           vfeed.stop();
431           afeed.stop();
432           subtitles->stop();
433           tfeed.stop();
434                            
435           video->blank();
436           video->reset();
437           //video->sync();
438           //video->play();
439           //video->pause();
440           audio->stop();
441           audio->unPause();
442           audio->reset();
443           //audio->setStreamType(Audio::MPEG2_PES);
444           //audio->sync();
445           pendingAudioPlay = true;
446           //audio->play();
447           //audio->pause();
448
449           demuxer->reset();
450           demuxer->seek();
451
452           afeed.start();
453           vfeed.start();
454           subtitles->start();     
455           tfeed.start();
456           state = newState;
457           if (!video->independentAVStartUp()){
458               videoStartup = true;
459               threadSignalNoLock();
460           }
461           return;
462         }        
463         case S_STOP:
464         { 
465           vdr->stopStreaming();
466           pendingAudioPlay=false;
467           clearStreamChunks();
468           vfeed.stop();
469           afeed.stop();
470           subtitles->stop();
471           tfeed.stop();
472           video->stop();
473           video->blank();
474           audio->stop();
475           audio->reset();
476           video->reset();
477           state = newState;
478           return;
479         }
480         default:
481         {
482           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
483           abort();
484           break;
485         }        
486       }
487     }
488     
489     case S_PREBUFFERING:    // FROM S_PREBUFFERING
490     {
491       switch(newState)
492       {
493         case S_PLAY:
494         {
495           pendingAudioPlay=false;
496           audio->unPause();
497           video->unPause();
498           state = newState;
499           return;
500         }
501         case S_VIDEOSTARTUP:
502         {
503           vdr->stopStreaming();
504           clearStreamChunks();
505           vfeed.stop();
506           afeed.stop();
507           subtitles->stop();
508           tfeed.stop();
509           video->stop();
510           video->blank();
511           audio->stop();
512           audio->unPause();
513           audio->reset();
514
515           video->reset();
516           //video->sync();
517           //video->play();
518           //video->pause();
519
520           //audio->setStreamType(Audio::MPEG2_PES);
521           //audio->sync();
522           pendingAudioPlay = true;
523           //audio->play();
524           //audio->pause();
525
526           demuxer->reset();
527           demuxer->seek();
528
529           afeed.start();
530           vfeed.start();
531           subtitles->start();
532           tfeed.start();
533
534           state = newState;
535           return;
536         }
537         case S_STOP:
538         {
539           pendingAudioPlay=false;
540           vdr->stopStreaming();
541           clearStreamChunks();
542           vfeed.stop();
543           afeed.stop();
544           subtitles->stop();
545           tfeed.stop();
546           video->stop();
547           video->blank();
548           audio->stop();
549           audio->reset();
550           video->reset();
551           state = newState;
552           return;        
553         }
554         default:
555         {
556           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
557           abort();
558           break;
559         }        
560       }
561     }
562     
563     case S_PLAY:     // FROM S_PLAY
564     {
565       switch(newState)
566       {
567         case S_STOP:
568         { 
569           pendingAudioPlay=false;
570           vdr->stopStreaming();
571           clearStreamChunks();
572           vfeed.stop();
573           afeed.stop();
574           subtitles->stop();
575           tfeed.stop();
576           video->stop();
577           video->blank();
578           audio->stop();
579           audio->reset();
580           video->reset();
581           state = newState;
582           return;
583         }
584         case S_VIDEOSTARTUP:
585         {
586           vdr->stopStreaming();
587           clearStreamChunks();
588           vfeed.stop();
589           afeed.stop();
590           subtitles->stop();
591           tfeed.stop();
592           video->stop();
593           video->blank();
594           audio->stop();
595           audio->unPause();
596           audio->reset();
597
598           video->reset();
599           
600           //video->sync();
601          // video->play();
602           //video->pause();
603
604           //audio->setStreamType(Audio::MPEG2_PES);
605           //audio->sync();
606           //audio->play();
607           //audio->pause();
608           pendingAudioPlay = true;
609           demuxer->reset();
610           demuxer->seek();
611
612           afeed.start();
613           vfeed.start();
614           subtitles->start();
615           tfeed.start();
616           state = newState;
617           if (!video->independentAVStartUp()){
618                   videoStartup = true;
619               threadSignalNoLock();
620           }
621           return;
622         }
623         default:
624         {
625           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
626           abort();
627           break;
628         }        
629       }
630     }    
631   }  
632 }
633
634 bool PlayerLiveTV::checkError()
635 {
636   if (!vdr->isConnected())
637   {
638     if (state != S_STOP) switchState(S_STOP);
639     
640     Message* m = new Message();
641     m->from = this;
642     m->to = messageReceiver;
643     m->message = Message::PLAYER_EVENT;
644     m->parameter = PlayerLiveTV::CONNECTION_LOST;
645     messageQueue->postMessageFromOuterSpace(m);
646     
647     return true;
648   }   
649   return false;
650 }
651
652 void PlayerLiveTV::optimizeInstructionQueue()
653 {
654   // Walk the list
655   
656   // Currently there are only 2 instruction types, so this is a bit overkill...
657
658   struct PLInstruction i;
659   while(instructions.size() > 1)
660   {
661     i = instructions.front();
662     if (i.instruction == I_SETCHANNEL)
663     {
664       instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant
665     }
666     else if (i.instruction == I_STOP)
667     {
668       return; // return here and ensure the next instruction will be stop
669     }
670   }
671 }
672
673 void PlayerLiveTV::threadMethod()
674 {
675   while(1)
676   {
677
678         //logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
679     if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
680     {
681            logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");
682       switchState(S_PREBUFFERING);
683       videoStartup = false;
684       preBufferCount = 0;
685       
686       checkError();
687     }  
688   
689     while(!instructions.empty())
690     {
691       if (instructions.size() > 1) optimizeInstructionQueue();
692
693       struct PLInstruction i = instructions.front();
694       instructions.pop();
695     
696       if (i.instruction == I_SETCHANNEL)
697       {
698         logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
699        
700         
701         switchState(S_VIDEOSTARTUP);
702         
703         if (!checkError())
704         {
705            Channel* chan = (*chanList)[i.channelIndex];
706            chan->loadPids();
707            h264=chan->vstreamtype==0x1b;
708            demuxer->seth264(h264);
709            video->seth264mode(chan->vstreamtype==0x1b);
710            demuxer->setVID(chan->vpid);
711            video->seth264mode(chan->vstreamtype==0x1b);
712
713            bool found=false;
714
715           if (chan->numAPids > 0) 
716           {
717                   int j=0;
718                   while (j<chan->numAPids && !found) {
719                           if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)) {
720                                   demuxer->setAID(chan->apids[j].pid,0,chan->apids[j].type);
721                                   audio->setStreamType(Audio::MPEG2_PES);
722                                   logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid,chan->apids[j].type);
723                                   found=true;
724                           }
725                           j++;
726                   }
727           }
728
729           if (!found)
730           {
731               if (chan->numDPids > 0  && audio->maysupportAc3()) 
732               {
733                   int j=0;
734                   while (j<chan->numDPids && !found) {
735                           if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)) {
736                                   demuxer->setAID(chan->dpids[j].pid,1,chan->dpids[j].type);
737                                   audio->setStreamType(Audio::MPEG2_PES);
738                                   logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid,chan->dpids[j].type);
739                                   found=true;
740                           }
741                           j++;
742                   }
743               } 
744               else
745               {
746                   logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
747               }
748           }
749           if (chan->numSPids > 0)
750             demuxer->setSubID(chan->spids[0].pid);
751           demuxer->setTID(chan->tpid);
752           teletext->ResetDecoder();
753           int streamSuccess = vdr->streamChannel(chan->number, this);
754           if (!checkError() && !streamSuccess)
755           {      
756             Message* m = new Message();
757             m->from = this;
758             m->to = messageReceiver;
759             m->message = Message::PLAYER_EVENT;
760             m->parameter = PlayerLiveTV::STREAM_END;
761             messageQueue->postMessageFromOuterSpace(m);
762           }
763         }
764       }
765       else if (i.instruction == I_STOP)
766       {
767         logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
768         switchState(S_STOP);
769         checkError();
770
771         stopNow = true;
772         break;
773       }
774     }
775
776         threadCheckExit();
777
778     if (stopNow) break;
779
780     while(streamChunks.size())
781     {
782         //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
783       chunkToDemuxer();
784       //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
785
786       if (state == S_PREBUFFERING)
787       {
788          // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3");
789         ++preBufferCount;
790         ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
791         logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
792         
793         Message* m = new Message();
794         m->from = this;
795         m->to = messageReceiver;
796         m->message = Message::PLAYER_EVENT;
797         m->parameter = PlayerLiveTV::PREBUFFERING;
798         m->tag = percentDone;
799         messageQueue->postMessageFromOuterSpace(m);
800
801         if (preBufferCount == preBufferAmount)
802         {
803           switchState(S_PLAY);
804           checkError();
805         }
806       }
807     }
808   //  logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size());
809     threadLock();
810     threadWaitForSignal(); // unlocks and waits for signal
811     threadUnlock();
812     //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
813   }
814
815   logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");
816 }
817