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