]> git.vomp.tv Git - vompclient.git/blob - vvideolive.cc
Demuxer::scanForVideo()
[vompclient.git] / vvideolive.cc
1 /*
2     Copyright 2004-2005 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "vvideolive.h"
22
23 VVideoLive* VVideoLive::instance = NULL;
24
25 VVideoLive::VVideoLive(ChannelList* tchanList, ULONG tstreamType, VChannelList* tvchannelList)
26 {
27   instance = this;
28   vdr = VDR::getInstance();
29   viewman = ViewMan::getInstance();
30   video = Video::getInstance();
31
32   chanList = tchanList;
33   vchannelList = tvchannelList;
34
35   currentChannel = 0;
36   previousChannel = 0;
37   unavailable = 0;
38   unavailableView = NULL;
39   streamType = tstreamType;
40   videoMode = video->getMode();
41   if (streamType == VDR::RADIO) player = new Player(Command::getInstance(), this, false, true);
42   else                          player = new Player(Command::getInstance(), this, false, false);
43
44   player->init();
45   create(video->getScreenWidth(), video->getScreenHeight());
46   Colour transparent(0, 0, 0, 0);
47   setBackgroundColour(transparent);
48
49   dowss = false;
50   char* optionWSS = vdr->configLoad("General", "WSS");
51   if (optionWSS)
52   {
53     if (strstr(optionWSS, "Yes")) dowss = true;
54     delete[] optionWSS;
55   }
56   Log::getInstance()->log("VVideoLive", Log::DEBUG, "Do WSS: %u", dowss);
57
58   wss.setFormat(video->getFormat());
59   wss.setSurface(surface);
60   wss.setWide(true);
61
62   wssRegion.x = 0;
63   wssRegion.y = 6;
64   wssRegion.w = video->getScreenWidth();
65   wssRegion.h = 2;
66 }
67
68 VVideoLive::~VVideoLive()
69 {
70   delete player;
71   instance = NULL;
72   video->setDefaultAspect();
73 }
74
75 VVideoLive* VVideoLive::getInstance()
76 {
77   return instance;
78 }
79
80 void VVideoLive::draw()
81 {
82   View::draw();
83 }
84
85 int VVideoLive::handleCommand(int command)
86 {
87   switch(command)
88   {
89     case Remote::STOP:
90     case Remote::BACK:
91     case Remote::MENU:
92     {
93       if (unavailable) showUnavailable(0);
94       else stop();
95
96       vchannelList->highlightChannel((*chanList)[currentChannel]);
97       return 4;
98     }
99     // Take up and down from new remote and do live banner
100     case Remote::UP:
101     case Remote::DOWN:
102     {
103       doBanner(true);
104       return 2;
105     }
106     case Remote::DF_UP:
107     case Remote::CHANNELUP:
108     {
109       if (unavailable) showUnavailable(0);
110       else stop();
111       channelChange(OFFSET, UP);
112       return 2;
113     }
114     case Remote::DF_DOWN:
115     case Remote::CHANNELDOWN:
116     {
117       if (unavailable) showUnavailable(0);
118       else stop();
119       channelChange(OFFSET, DOWN);
120       return 2;
121     }
122     case Remote::PREVCHANNEL:
123     {
124       if (unavailable) showUnavailable(0);
125       else stop();
126       channelChange(PREVIOUS, 0);
127       return 2;
128     }
129     case Remote::OK:
130     {
131       doBanner(true);
132       return 2;
133     }
134     case Remote::GUIDE:
135     case Remote::RED:
136     {
137       showEPG();
138       return 2;
139     }
140     case Remote::FULL:
141     case Remote::TV:
142     {
143       toggleChopSides();
144       return 2;
145     }
146
147     case Remote::ZERO:
148     case Remote::ONE:
149     case Remote::TWO:
150     case Remote::THREE:
151     case Remote::FOUR:
152     case Remote::FIVE:
153     case Remote::SIX:
154     case Remote::SEVEN:
155     case Remote::EIGHT:
156     case Remote::NINE:
157     {
158       VChannelSelect* v = new VChannelSelect(this, command);
159       v->draw();
160       viewman->add(v);
161       viewman->updateView(v);
162       return 2;
163     }
164 #ifdef DEV
165     case Remote::YELLOW:
166     {
167       player->test1();
168       break;
169     }
170     case Remote::BLUE:
171     {
172       player->test2();
173       break;
174     }
175 #endif
176   }
177
178   return 1;
179 }
180
181 void VVideoLive::channelChange(UCHAR changeType, UINT newData)
182 {
183   UINT newChannel = 0;
184
185   if (changeType == INDEX)
186   {
187     newChannel = newData;
188   }
189   else if (changeType == NUMBER)
190   {
191     UINT i;
192     for(i = 0; i < chanList->size(); i++)
193     {
194       if ((*chanList)[i]->number == (UINT)newData)
195       {
196         newChannel = i;
197         break;
198       }
199     }
200
201     if (i == chanList->size())
202     {
203       doNoSuchChannel();
204       return;
205     }
206   }
207   else if (changeType == OFFSET)
208   {
209     if (newData == UP) newChannel = upChannel();
210     else newChannel = downChannel();
211   }
212   else if (changeType == PREVIOUS)
213   {
214     newChannel = previousChannel;
215   }
216   else
217   {
218     return; // bad input!
219   }
220
221   previousChannel = currentChannel;
222   currentChannel = newChannel;
223
224   if (unavailable) showUnavailable(0);
225   else stop(1);
226
227   VEpg* vepg = VEpg::getInstance();
228   if(vepg) vepg->setCurrentChannel((*chanList)[currentChannel]->name);
229
230   VLiveBanner* vlb = VLiveBanner::getInstance();
231   if (vlb)
232   {
233     vlb->setChannel((*chanList)[currentChannel]);
234     vlb->draw();
235     viewman->updateView(vlb);
236   }
237
238   play();
239 }
240
241 void VVideoLive::streamEnd()
242 {
243   Log::getInstance()->log("VVideoLive", Log::DEBUG, "streamEnd");
244   stop(1);
245   showUnavailable(1);
246 }
247
248 void VVideoLive::processMessage(Message* m)
249 {
250   if (m->message == Message::CHANNEL_CHANGE)
251   {
252     channelChange(NUMBER, m->parameter);
253   }
254   else if (m->message == Message::EPG)
255   {
256     Log::getInstance()->log("VVideoLive", Log::DEBUG, "EPG requested from live banner");
257     showEPG();
258   }
259   else if (m->message == Message::EPG_CLOSE)
260   {
261     video->setMode(videoMode);
262     if (saveUnavailable) showUnavailable(1);
263   }
264   else if (m->message == Message::PLAYER_EVENT)
265   {
266     switch(m->parameter)
267     {
268       case Player::CONNECTION_LOST: // connection lost detected
269       {
270         Log::getInstance()->log("VVideoLive", Log::DEBUG, "Received connection lost from player");
271         // I can't handle this, send it to command
272         Message* m = new Message();
273         m->to = Command::getInstance();
274         m->message = Message::CONNECTION_LOST;
275         Command::getInstance()->postMessageNoLock(m);
276         break;
277       }
278       case Player::STREAM_END:
279       {
280         // I can't handle this, send it to command - improve this
281         Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
282         m->to = Command::getInstance();
283         m->message = Message::STREAM_END;
284         Command::getInstance()->postMessageNoLock(m);
285         break;
286       }
287       case Player::ASPECT43:
288       {
289         if (dowss)
290         {
291           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
292           wss.setWide(false);
293           wss.draw();
294           ViewMan::getInstance()->updateView(this, &wssRegion);
295         }
296         break;
297       }
298       case Player::ASPECT169:
299       {
300         if (dowss)
301         {
302           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
303           wss.setWide(true);
304           wss.draw();
305           ViewMan::getInstance()->updateView(this, &wssRegion);
306         }
307         break;
308       }
309     }
310   }
311 }
312
313 void VVideoLive::doBanner(bool bannerTakesCommands)
314 {
315   if (VEpg::getInstance()) return;
316
317   if (VLiveBanner::getInstance()) return; // there already is one
318
319   VLiveBanner* vlb = new VLiveBanner(this, (*chanList)[currentChannel], bannerTakesCommands);
320
321   vlb->draw();
322   viewman->add(vlb);
323   viewman->updateView(vlb);
324 }
325
326 void VVideoLive::doNoSuchChannel()
327 {
328   Log::getInstance()->log("VVideoLive", Log::ERR, "No such channel");
329   // FIXME do gui for this
330 }
331
332 void VVideoLive::showUnavailable(int active)
333 {
334   if (active == unavailable) return;
335
336   if (active)
337   {
338     unavailable = 1;
339
340     unavailableView = new VInfo();
341     unavailableView->create(400, 200);
342     if (video->getFormat() == Video::PAL)
343     {
344       unavailableView->setScreenPos(170, 200);
345     }
346     else
347     {
348       unavailableView->setScreenPos(160, 150);
349     }
350     unavailableView->setTitleText((*chanList)[currentChannel]->name);
351     unavailableView->setOneLiner(tr("Channel unavailable"));
352     unavailableView->setDropThrough();
353     unavailableView->draw();
354     viewman->add(unavailableView);
355     viewman->updateView(unavailableView);
356   }
357   else
358   {
359     unavailable = 0;
360     viewman->removeView(unavailableView);
361     unavailableView = NULL;
362   }
363 }
364
365 void VVideoLive::play(int noShowVLB)
366 {
367   showUnavailable(0);
368
369   int available = vdr->streamChannel((*chanList)[currentChannel]->number);
370
371   if (!available)
372   {
373     if (!noShowVLB) doBanner(false);
374     showUnavailable(1);
375     if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
376   }
377   else
378   {
379     if (!noShowVLB) doBanner(false);
380     player->play();
381   }
382 }
383
384 void VVideoLive::stop(int noRemoveVLB)
385 {
386   if (unavailable) return;
387   if (!noRemoveVLB && VLiveBanner::getInstance()) viewman->removeView(VLiveBanner::getInstance()); // if live banner is present, remove it. won't cause damage if its not present
388
389   player->stop();
390   Log::getInstance()->log("VVideoLive", Log::DEBUG, "Delay starts here due to time taken by plugin to stop");
391   vdr->stopStreaming();
392   if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
393   Log::getInstance()->log("VVideoLive", Log::DEBUG, "Delay ends here due to time taken by plugin to stop");
394 }
395
396 UINT VVideoLive::upChannel()
397 {
398   if (currentChannel == (chanList->size() - 1)) // at the end
399     return 0; // so go to start
400   else
401     return currentChannel + 1;
402 }
403
404 UINT VVideoLive::downChannel()
405 {
406   if (currentChannel == 0) // at the start
407     return chanList->size() - 1; // so go to end
408   else
409     return currentChannel - 1;
410 }
411
412 void VVideoLive::showEPG()
413 {
414   saveUnavailable = unavailable;
415   if (unavailable) showUnavailable(0);
416
417   if (VEpg::getInstance()) return; // already showing!
418
419   video->setMode(Video::QUARTER);
420   video->setPosition(170, 5); //TODO need to deal with 4:3 switching
421
422   VEpg* vepg = new VEpg(this, currentChannel);
423   vepg->draw();
424
425   viewman->add(vepg);
426   viewman->updateView(vepg);
427 }
428
429 void VVideoLive::toggleChopSides()
430 {
431   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
432
433   if (videoMode == Video::NORMAL)
434   {
435     videoMode = Video::LETTERBOX;
436     video->setMode(Video::LETTERBOX);
437   }
438   else
439   {
440     videoMode = Video::NORMAL;
441     video->setMode(Video::NORMAL);
442   }
443 }