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