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