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