]> git.vomp.tv Git - vompclient.git/blob - vvideolivetv.cc
Added Vector based OSD for windows (Vista and later)
[vompclient.git] / vvideolivetv.cc
1 /*
2     Copyright 2007-2008 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 "vvideolivetv.h"
22
23 #include "vchannellist.h"
24 #include "video.h"
25 #include "audio.h"
26 #include "playerlive.h"
27 #include "playerlivetv.h"
28 #include "playerliveradio.h"
29 #include "channel.h"
30 #include "boxstack.h"
31 #include "colour.h"
32 #include "osd.h"
33 #include "command.h"
34 #include "i18n.h"
35 #include "wtextbox.h"
36 #include "remote.h"
37 #include "vaudioselector.h"
38 #include "colour.h"
39 #include "event.h"
40 #include "timers.h"
41 #include "vepg.h"
42 #include "bitmap.h"
43 #include "log.h"
44 #include "vteletextview.h"
45 #include "vepgsummary.h"
46 #include "vepglistadvanced.h"
47 #include "staticartwork.h"
48 #include "demuxer.h"
49
50 #include <sstream>
51
52 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
53 {
54   vdr = VDR::getInstance();
55   boxstack = BoxStack::getInstance();
56   video = Video::getInstance();
57   
58   vas = NULL;
59
60   chanList = tchanList;
61   vchannelList = tvchannelList;
62   numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
63
64   currentChannelIndex = 0;
65   previousChannelIndex = 0;
66   osdChannelIndex = 0;
67   keying = 0;
68   preBuffering = 0;
69
70   playing = false;
71
72   // Convert channel number to index
73   UINT i;
74   for(i = 0; i < chanList->size(); i++)
75   {
76     if ((*chanList)[i]->number == (UINT)initialChannelNumber)
77     {
78       currentChannelIndex = i;
79       osdChannelIndex = i;
80       break;
81     }
82   }
83
84   eventList = NULL;
85
86   videoMode = video->getMode();
87   
88   if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
89   {
90     streamType = VDR::VIDEO;
91     player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
92   }
93   else
94   {
95     streamType = VDR::RADIO;
96     player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
97   }
98   player->init();
99
100   setSize(video->getScreenWidth(), video->getScreenHeight());
101   createBuffer();
102   DrawStyle transparent(0, 0, 0, 0);
103   setBackgroundColour(transparent);
104 #ifdef PAL_WSS
105   dowss = false;
106   char* optionWSS = vdr->configLoad("General", "WSS");
107   if (optionWSS)
108   {
109     if (strstr(optionWSS, "Yes")) dowss = true;
110     delete[] optionWSS;
111   }
112   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
113
114   if (dowss)
115   {
116     wss.setFormat(video->getFormat());
117     wss.setWide(true);
118     add(&wss);
119     
120     wssRegion.x = 0;
121     wssRegion.y = 6;
122     wssRegion.w = video->getScreenWidth();
123     wssRegion.h = 2;
124   }
125 #endif
126   // This variable is set to true if the user pressed OK to bring the OSD on screen
127   // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling
128   okTriggeredOSD = false;
129
130   TVMediaInfo info;
131   info.setChannelLogo(initialChannelNumber);
132   OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
133
134   if (osdv && streamType == VDR::RADIO) {
135           radioChannelLogo.setPosition(video->getScreenWidth()/4,video->getScreenHeight()/4);
136           radioChannelLogo.setSize(video->getScreenWidth()/2,video->getScreenHeight()/2);
137           radioChannelLogo.setVisible(true);
138           radioChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
139           add(&radioChannelLogo);
140   }
141
142   osdposterbanner.setPosition(20,20);
143   //osdposterbanner.setBackgroundColour(DrawStyle::OSDBACKGROUND);
144   osdposterbanner.setSize(video->getScreenWidth()*4/10,video->getScreenHeight()*4/10);
145   osdposterbanner.setVisible(false);
146   add(&osdposterbanner);
147
148
149
150   osd.setBackgroundColour(DrawStyle::OSDBACKGROUND);
151   osd.setPosition(0, video->getScreenHeight() - 150);
152   osd.setSize(video->getScreenWidth(), 150);
153   osd.setVisible(false);
154   add(&osd);
155   
156   int channellogomove=0;
157   int boxdiff=166;
158   if (osdv) {
159           //osdChannelLogo.setBackgroundColour(DrawStyle::OSDBACKGROUND);
160           osdChannelLogo.setPosition(30,5);
161           osdChannelLogo.setSize(60,60);
162           osdChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
163           osd.add(&osdChannelLogo);
164           channellogomove=30-5;
165           boxdiff=145;
166   }
167
168
169   //clock.setBackgroundColour(DrawStyle::OSDBACKGROUND);
170   clock.setPosition(osd.getWidth() - 100, 4);
171   clock.setSize(90, 30);
172   osd.add(&clock);
173
174   //osdChanNum.setBackgroundColour(DrawStyle::OSDBACKGROUND);
175   osdChanNum.setPosition(60+channellogomove, 4);
176   osdChanNum.setSize((numberWidth*10) + 22, getFontHeight()+5); // 10 px = width of number chars in font
177   osd.add(&osdChanNum);  
178
179   //osdChanName.setBackgroundColour(DrawStyle::OSDBACKGROUND);
180   osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
181   osdChanName.setSize(300, 30);
182   osd.add(&osdChanName);
183   
184   boxRed.setBackgroundColour(DrawStyle::RED);
185   boxRed.setPosition(54+0*boxdiff, 104);
186   boxRed.setSize(18, 16);
187   osd.add(&boxRed);
188
189   boxGreen.setBackgroundColour(DrawStyle::GREEN);
190   boxGreen.setPosition(54+1*boxdiff, 104);
191   boxGreen.setSize(18, 16);
192   osd.add(&boxGreen);
193
194   boxYellow.setBackgroundColour(DrawStyle::YELLOW);
195   boxYellow.setPosition(54+2*boxdiff, 104);
196   boxYellow.setSize(18, 16);
197   osd.add(&boxYellow);
198
199   boxBlue.setBackgroundColour(DrawStyle::BLUE);
200   boxBlue.setPosition(54+3*boxdiff, 104);
201   boxBlue.setSize(18, 16);
202   osd.add(&boxBlue);  
203   
204   //textRed.setBackgroundColour(DrawStyle::OSDBACKGROUND);
205   textRed.setPosition(boxRed.getX2(), 98);
206   textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);
207   textRed.setText(tr("Summary"));
208   osd.add(&textRed);  
209     
210   if (streamType == VDR::VIDEO)
211   {
212     //textGreen.setBackgroundColour(DrawStyle::OSDBACKGROUND);
213     textGreen.setPosition(boxGreen.getX2(), 98);
214     textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);
215     textGreen.setText(tr("Audio"));
216     osd.add(&textGreen);  
217   }
218     
219   //textYellow.setBackgroundColour(DrawStyle::OSDBACKGROUND);
220   textYellow.setPosition(boxYellow.getX2(), 98);
221   textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
222   textYellow.setText(tr("Teletext"));
223   osd.add(&textYellow);  
224     
225   //textBlue.setBackgroundColour(DrawStyle::OSDBACKGROUND);
226   textBlue.setPosition(boxBlue.getX2(), 98);
227   textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);
228   textBlue.setText(tr("EPG"));
229   osd.add(&textBlue);  
230     
231   //sl.setBackgroundColour(DrawStyle::OSDBACKGROUND);
232   sl.setPosition(90, 36);
233   sl.setSize(480, 58);
234   osd.add(&sl);
235   
236   
237
238   bufferBar.setPosition(osd.getWidth() - 90, 70);
239   bufferBar.setSize(40, 20);
240   bufferBar.setVisible(true);
241   osd.add(&bufferBar);
242
243   if (!osdv) {
244           sAspectRatio.setPosition(osd.getWidth() - 90, 40);
245           sAspectRatio.nextColour = DrawStyle::LIVETVSYMBOLS;
246           sAspectRatio.setVisible(false);
247           osd.add(&sAspectRatio);
248   
249           sAudioChannels.setPosition(osd.getWidth() - 130, 40);
250           sAudioChannels.nextColour = DrawStyle::LIVETVSYMBOLS;
251           sAudioChannels.setVisible(false);
252           osd.add(&sAudioChannels);
253   }
254   
255   if (osdv) {
256           TVMediaInfo ninfo;
257           ninfo.setStaticArtwork(sa_txtoff);
258           txtlogo.setPosition(54+4*boxdiff,104);
259           txtlogo.setSize(22,20);
260           txtlogo.setTVMedia(ninfo, WTVMedia::ZoomVertical);
261           osd.add(&txtlogo);
262
263           ninfo.setStaticArtwork(sa_dolbyoff);
264           dolbylogo.setPosition(54+4*boxdiff+15,104);
265           dolbylogo.setSize(22,20);
266           dolbylogo.setTVMedia(ninfo, WTVMedia::ZoomVertical);
267           osd.add(&dolbylogo);
268
269           ninfo.setStaticArtwork(sa_sd576i);
270           reslogo.setPosition(54+4*boxdiff+30,104);
271           reslogo.setSize(22,20);
272           reslogo.setTVMedia(ninfo, WTVMedia::ZoomVertical);
273           osd.add(&reslogo);
274
275           reslogo.setVisible(false);
276           dolbylogo.setVisible(false);
277           txtlogo.setVisible(false);
278   }
279
280
281   //textUnavailable.setBackgroundColour(DrawStyle::OSDBACKGROUND);
282   textUnavailable.setPosition(60, 30);
283   textUnavailable.setSize(osd.getWidth() - 120, 30);
284   textUnavailable.setText(tr("Channel Unavailable"));
285   textUnavailable.setVisible(false);
286   add(&textUnavailable);
287   
288
289   vdisplay.mode=Fullscreen;
290   vdisplay.fallbackMode=Fullscreen;
291   vdisplay.x=0;
292   vdisplay.y=0;
293   vdisplay.width=0;
294   vdisplay.height=0;
295
296 }
297
298 void VVideoLiveTV::preDelete()
299 {
300   if (playing) stop();
301 }
302
303 VVideoLiveTV::~VVideoLiveTV()
304 {
305   delete player;
306   video->setDefaultAspect();
307   delData();
308 }
309
310 void VVideoLiveTV::delData()
311 {
312   if (eventList)
313   {
314     int eventListSize = eventList->size();
315     for(int i = 0; i < eventListSize; i++)
316     {
317       delete (*eventList)[i];
318     }
319     eventList->clear();
320     delete eventList;
321
322   }
323 }
324
325 int VVideoLiveTV::handleCommand(int command)
326 {
327   switch(command)
328   {
329     case Remote::BACK:
330     {
331       if (osd.getVisible() && !textUnavailable.getVisible())
332       {
333         clearScreen();
334         return 2;
335       }
336       // else drop through to stop
337     }
338     case Remote::STOP:
339     {
340       stop();
341       vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
342       return 4;
343     }
344     
345     // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there
346     case Remote::UP:
347     {
348         if (Remote::getInstance()->mayHaveFewButtons()) {
349               if (okTriggeredOSD) doUpDown(false);
350               else doChanUpDown(UP);
351         } else {
352                 doUpDown(false);
353         }
354       return 2;
355     }
356     case Remote::DOWN:
357     {
358       if (Remote::getInstance()->mayHaveFewButtons()) {
359           if (okTriggeredOSD) doUpDown(true);
360           else doChanUpDown(DOWN);
361       } else {
362           doUpDown(true);
363       }
364       return 2;
365     }
366     case Remote::LEFT:
367     {
368       doLeftRight(false);
369       return 2;
370     }
371     case Remote::RIGHT:
372     {
373       doLeftRight(true);
374       return 2;
375     }
376     // Continue new remote only...
377     case Remote::CHANNELUP:
378     {
379       doChanUpDown(UP);
380       return 2;
381     }
382     case Remote::CHANNELDOWN:
383     {
384       doChanUpDown(DOWN);
385       return 2;
386     }
387
388     // END NEW REMOTE ONLY, START OLD REMOTE ONLY
389     
390     // DF_LEFT and DF_RIGHT never get here because they are stolen
391     // by command as vol- and vol+
392     
393     // Old remote. Decide what to do based on whether
394     // OK was pressed - osd shown manually, use up/down for epg nav
395     // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-
396     
397     case Remote::DF_UP:
398     {
399       // Old remote, decide what to do based on okTriggeredOSD
400       if (okTriggeredOSD) doUpDown(false);
401       else doChanUpDown(UP);
402       return 2;
403     }
404     case Remote::DF_DOWN:
405     {
406       // Old remote, decide what to do based on okTriggeredOSD
407       if (okTriggeredOSD) doUpDown(true);
408       else doChanUpDown(DOWN);
409       return 2;
410     }
411
412     // END NEW/OLD REMOTE STUFF
413
414     case Remote::PREVCHANNEL:
415     {
416       channelChange(PREVIOUS, 0);
417       osdChannelIndex = currentChannelIndex;
418       displayOSD(true);
419       return 2;
420     }
421     case Remote::OK:
422     {
423       doOK();
424       return 2;
425     }
426     case Remote::RED:
427     case Remote::MENU:
428     {
429       doSummary();
430       return 2;
431     }
432     case Remote::FULL:
433     case Remote::TV:
434     {
435       toggleChopSides();
436       return 2;
437     }
438
439     case Remote::ZERO:
440     case Remote::ONE:
441     case Remote::TWO:
442     case Remote::THREE:
443     case Remote::FOUR:
444     case Remote::FIVE:
445     case Remote::SIX:
446     case Remote::SEVEN:
447     case Remote::EIGHT:
448     case Remote::NINE:
449     {
450       // key in channel number
451       doKey(command);
452       return 2;
453     }
454
455     case Remote::GREEN:
456     {
457       if (streamType == VDR::VIDEO) doAudioSelector();
458       return 2;   
459     }
460     case Remote::YELLOW:
461     {
462       if (streamType ==VDR::VIDEO) 
463       {
464         doTeletext(); //TODO: Add a selector for subtitles or teletext
465       }
466       return 2;
467     }
468     case Remote::GUIDE:
469     case Remote::BLUE:
470     {
471       doEPG();
472       return 2;
473     }
474     case Remote::RECORD:
475       if (streamType == VDR::VIDEO)
476         (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
477       return 2;
478   }
479
480   return 1;
481 }
482
483 void VVideoLiveTV::go()
484 {
485   playing = true;
486   draw();
487   boxstack->update(this);
488
489   setClock();
490   displayOSD(true);
491   
492   player->go(currentChannelIndex);
493 }
494
495 void VVideoLiveTV::stop()
496 {
497   Timers::getInstance()->cancelTimer(this, 1);
498   Timers::getInstance()->cancelTimer(this, 2);
499   player->stop();
500   playing = false;
501 }
502
503 void VVideoLiveTV::doLeftRight(bool right)
504 {
505   if (osd.getVisible())
506   {
507     if (right) osdChannelIndex = upChannel(osdChannelIndex);
508     else       osdChannelIndex = downChannel(osdChannelIndex);
509   }
510   else
511   {
512     osdChannelIndex = currentChannelIndex;
513   }
514   displayOSD(true);
515 }
516
517 void VVideoLiveTV::doUpDown(bool down)
518 {
519   if (osd.getVisible())
520   {
521     sl.draw();
522     
523     displayOSD(false);
524   }
525   else
526   {
527     displayOSD(true);
528   }
529 }
530
531 void VVideoLiveTV::doChanUpDown(int which)
532 {
533   channelChange(OFFSET, which);
534   osdChannelIndex = currentChannelIndex;
535   displayOSD(true);
536 }
537
538 void VVideoLiveTV::doOK()
539 {
540   if (osd.getVisible())
541   {
542     if (keying)
543     {
544       UINT newChannel = 0;
545       for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
546       
547       channelChange(NUMBER, newChannel);
548       osdChannelIndex = currentChannelIndex;
549       displayOSD(true);
550     }
551     else if (osdChannelIndex == currentChannelIndex)
552     {
553       clearScreen();
554     }
555     else
556     {
557       channelChange(INDEX, osdChannelIndex);
558       displayOSD(true);
559     }
560   }
561   else
562   {
563     osdChannelIndex = currentChannelIndex;
564     displayOSD(true);
565     okTriggeredOSD = true;
566   }
567 }
568
569 void VVideoLiveTV::doSummary()
570 {
571         displayOSD(false);
572         Channel* currentChannel = (*chanList)[osdChannelIndex];
573         eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
574         if (!eventList)
575         {
576                 return;
577         }
578         sort(eventList->begin(), eventList->end(), EventSorter());
579
580         if (eventList->size() < 1) return;
581         Event* event = (*eventList)[0];
582         event->loadinfos(currentChannel->number);
583
584         VEpgSummary* vr = new VEpgSummary(event,currentChannel);
585         vr->draw();
586         boxstack->add(vr);
587         boxstack->update(vr);
588
589 }
590
591 void VVideoLiveTV::doKey(int command)
592 {
593   if (!osd.getVisible()) // First key. prep the data
594   {
595     setNowNextData();
596     updatePosterBanner();
597     keying = 0;    
598   }
599
600   int i;
601   for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
602   keyingInput[0] = command;
603   keying++;
604
605   char* keyingString = new char[numberWidth + 1];
606   for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
607   keyingString[numberWidth] = '\0';
608
609   for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
610   
611   if (keying == numberWidth)
612   {
613     UINT newChannel = 0;
614     for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
615     
616     channelChange(NUMBER, newChannel);
617     osdChannelIndex = currentChannelIndex;
618     Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
619     displayOSD(true); // this will put one back if required
620   }
621   else
622   {
623     osdChanNum.setText(keyingString);
624
625     if (!osd.getVisible())
626     {
627       osd.setVisible(true);
628       draw();
629     }
630     else
631     {
632       osdChanNum.draw();
633     }
634     boxstack->update(this, osd.getRegion());
635     Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input
636   }
637   delete[] keyingString;
638 }
639
640 void VVideoLiveTV::doTeletext(bool subtitlemode)
641 {
642   if (streamType !=VDR::VIDEO) return;
643   (static_cast<PlayerLiveTV*>(player))->tellSubtitlesOSDVisible(true);
644   bool exists=true;
645
646   // Cancel keying
647   if (keying)
648   {
649     keying = 0;
650     // and reset the display - this is a copy from setNowNextData
651     char formatChanNum[20];
652     SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
653     osdChanNum.setText(formatChanNum);
654     osdChanName.setText((*chanList)[osdChannelIndex]->name);
655   }
656   (static_cast<PlayerLiveTV*>(player))->tellSubtitlesOSDVisible(true);
657   if (osd.getVisible()) clearScreen();
658   // Draw the teletxt
659   VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
660   if (vtxv==NULL) {
661        vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this, (PlayerLiveTV*)player);
662       ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);
663       exists=false;
664   }
665   vtxv->setSubtitleMode(subtitlemode);
666   vtxv->draw();
667   draw();
668   
669   if (!exists) {
670       BoxStack::getInstance()->add(vtxv);
671   }
672   BoxStack::getInstance()->update(this);
673   BoxStack::getInstance()->update(vtxv); 
674 }
675
676 void VVideoLiveTV::doAudioSelector()
677 {
678   // If the osd is already visisble there might be a timer for it
679   Timers::getInstance()->cancelTimer(this, 1);
680   //This causes a deadlock with the timertrhread itself is locked
681
682
683   // Cancel keying
684   if (keying)
685   {
686     keying = 0;
687     // and reset the display - this is a copy from setNowNextData
688     char formatChanNum[20];
689     SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
690     osdChanNum.setText(formatChanNum);
691     osdChanName.setText((*chanList)[osdChannelIndex]->name);
692   }
693   int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();
694   int subtitleType=0x10;
695   if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {
696       if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&
697           ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
698           ) {
699               subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();
700               subtitleType=0x11;
701           
702       } else {
703           subtitleType=0xFF; //turnedOff
704           subtitleChannel=0;
705       }
706   }
707
708   // Draw the selector
709   vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),
710       subtitleType,subtitleChannel,NULL);
711
712   vas->setBackgroundColour(DrawStyle::OSDBACKGROUND);
713   vas->setPosition(0, osd.getScreenY() - vas->getHeight());
714   vas->draw();
715
716   // make vas != null and displayOSD will not set a timer or do any boxstack update
717   if (osd.getVisible()) displayOSD(false);
718   else displayOSD(true);
719   draw();
720
721   BoxStack::getInstance()->add(vas);
722   BoxStack::getInstance()->update(this);        
723   BoxStack::getInstance()->update(vas);     
724 }      
725       
726 void VVideoLiveTV::doEPG()
727 {
728   if (osd.getVisible()) clearScreen();
729
730   if (!Command::getInstance()->advMenues()) {
731
732           VEpg* vepg = new VEpg(this, currentChannelIndex, chanList);
733           vepg->draw();
734           boxstack->add(vepg);
735           boxstack->update(vepg);
736   } else {
737           Channel* currentChannel = (*chanList)[osdChannelIndex];
738           VEpgListAdvanced  *vepg= new VEpgListAdvanced(this, chanList, currentChannel->number);
739           vepg->draw();
740           boxstack->add(vepg);
741           boxstack->update(vepg);
742   }
743 }
744
745 void VVideoLiveTV::setNowNextData()
746 {
747   delData();
748   
749   Channel* currentChannel = (*chanList)[osdChannelIndex];
750
751   char formatChanNum[20];
752   SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
753   osdChanNum.setText(formatChanNum);
754   osdChanName.setText(currentChannel->name);
755
756   eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
757
758   if (!eventList)
759   {
760     sl.setText(tr("No channel data available"));
761   }
762   else
763   {
764     sort(eventList->begin(), eventList->end(), EventSorter());
765
766     char tempString[300];
767     char tempString2[300];
768     struct tm* btime;
769     Event* event;
770     int eventListSize = eventList->size();
771     std::stringstream string;
772     for(int i = 0; i < eventListSize; i++)
773     {
774       event = (*eventList)[i];
775
776       time_t etime = event->time;
777       btime = localtime(&etime);
778 #ifndef _MSC_VER
779       strftime(tempString2, 299, "%0H:%0M ", btime);
780 #else
781       strftime(tempString2, 299, "%H:%M ", btime);
782 #endif
783       SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
784       string << tempString << "\n";
785     }
786     sl.setText(string.str().c_str());
787   }
788 }
789
790
791
792 void VVideoLiveTV::displayOSD(bool newNowNextData)
793 {
794   PlayerLiveTV* playerlivetv = dynamic_cast<PlayerLiveTV*>(player);
795   if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(true);
796   osd.setVisible(true);
797   if (newNowNextData)
798   {
799     setNowNextData();
800     updatePosterBanner();
801     keying = 0;
802   }
803   osd.draw();
804   if (osdposterbanner.getVisible()) osdposterbanner.draw();
805   
806
807   Region  toupdate;
808
809   toupdate=*osd.getRegion();
810
811
812   if (osdposterbanner.getVisible()) {
813           boxstack->update(this);
814   } else {
815           boxstack->update(this, &toupdate);
816   }
817   
818   bool setTimer = true;
819   if (vas) setTimer = false;
820   if (textUnavailable.getVisible()) setTimer = false;
821
822   if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);
823 }
824
825 void VVideoLiveTV::clearScreen()
826 {  
827   Timers::getInstance()->cancelTimer(this, 1);
828
829   textUnavailable.setVisible(false);
830   osd.setVisible(false);
831   osdposterbanner.setVisible(false);
832
833   okTriggeredOSD = false;
834
835   draw();
836   boxstack->update(this);
837
838   PlayerLiveTV* playerlivetv = dynamic_cast<PlayerLiveTV*>(player);
839   if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(false);
840 }
841
842 void VVideoLiveTV::showUnavailable()
843 {
844   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");  
845   textUnavailable.setVisible(true);
846   textUnavailable.draw();
847   
848   if (!osd.getVisible()) displayOSD(true);
849
850   boxstack->update(this, textUnavailable.getRegion());  
851 }
852
853 void VVideoLiveTV::setClock()
854 {
855   char timeString[20];
856   time_t t;
857   time(&t);
858   struct tm* tms = localtime(&t);
859   strftime(timeString, 19, "%H:%M", tms);
860   clock.setText(timeString);
861
862   time_t dt = 60 - (t % 60);  // seconds to the next minute
863   if (dt == 0) dt = 60; // advance a whole minute if necessary
864   dt += t;  // get a time_t value for it rather than using duration
865   // (so it will occur at the actual second and not second and a half)
866
867   Timers::getInstance()->setTimerT(this, 2, dt);
868 }
869
870 void VVideoLiveTV::timercall(int ref)
871 {
872   if (ref == 1)
873   {
874     if (keying)
875     {
876          Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start."); 
877       UINT newChannel = 0;
878       for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
879       
880       Message* m = new Message();
881       m->message = Message::CHANNEL_CHANGE;
882       m->to = this;
883           m->parameter.num = newChannel;
884       m->tag = 1; // signal to call displayOSD();
885       Command::getInstance()->postMessageFromOuterSpace(m);
886       Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end."); 
887     }
888     else
889     {
890         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start."); 
891       // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
892       if (preBuffering < 100)
893       {
894         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");  
895         Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
896         return;
897       }
898       bool osdpbvisible=osdposterbanner.getVisible();
899       Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1."); 
900       osd.setVisible(false);
901       osdposterbanner.setVisible(false);
902       okTriggeredOSD = false;
903       Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2."); 
904       draw();
905       Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4."); 
906       if (osdpbvisible) boxstack->update(this);
907       else  boxstack->update(this, osd.getRegion());
908
909       Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); 
910           PlayerLiveTV* playerlivetv = dynamic_cast<PlayerLiveTV*>(player);
911           if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(false);
912       Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); 
913     }
914   }
915   else if (ref == 2)
916   {
917       Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2  start."); 
918     setClock();
919     if (osd.getVisible())
920     {
921       clock.draw();
922       boxstack->update(this, osd.getRegion());
923     }
924     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end."); 
925   }
926 }
927
928 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
929 {
930   UINT newChannel = 0;
931   if (streamType ==VDR::VIDEO) {
932           VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
933           if (vtxt ) {
934                   BoxStack::getInstance()->remove(vtxt);
935
936           }
937   }
938   if (changeType == INDEX)
939   {
940     newChannel = newData;
941   }
942   else if (changeType == NUMBER)
943   {
944     UINT i;
945     for(i = 0; i < chanList->size(); i++)
946     {
947       if ((*chanList)[i]->number == (UINT)newData)
948       {
949         newChannel = i;
950         break;
951       }
952     }
953
954     if (i == chanList->size())
955     {
956       // no such channel
957       return false;
958     }
959   }
960   else if (changeType == OFFSET)
961   {
962     if (newData == UP) newChannel = upChannel(currentChannelIndex);
963     else newChannel = downChannel(currentChannelIndex);
964   }
965   else if (changeType == PREVIOUS)
966   {
967     newChannel = previousChannelIndex;
968   }
969   else
970   {
971     return false; // bad input
972   }
973
974   if (newChannel == currentChannelIndex) return true;
975
976   previousChannelIndex = currentChannelIndex;
977   currentChannelIndex = newChannel;
978   
979   preBuffering = 0;
980   
981   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
982   player->setChannel(currentChannelIndex);
983   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
984
985   // Blank out the symbols
986   OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
987
988   bufferBar.setPercent(0);
989   
990   if (!osdv) {
991           sAudioChannels.setVisible(false);
992           sAspectRatio.setVisible(false);
993   } else {
994           reslogo.setVisible(false);
995           dolbylogo.setVisible(false);
996           txtlogo.setVisible(false);
997   }
998
999   // Remove other stuff
1000   if (textUnavailable.getVisible())
1001   {
1002     textUnavailable.setVisible(false);
1003     
1004   }
1005
1006   if (osdv) {
1007           TVMediaInfo info;
1008           Channel* currentChannel = (*chanList)[currentChannelIndex];
1009           if (currentChannel) {
1010                   info.setChannelLogo(currentChannel->number);
1011                   if (streamType == VDR::RADIO) {
1012                           radioChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
1013                           radioChannelLogo.setVisible(true);
1014                   }
1015                   osdChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
1016
1017           }
1018   }
1019
1020   draw();
1021   BoxStack::getInstance()->update(this);
1022   
1023   return true;
1024 }
1025
1026 void VVideoLiveTV::processMessage(Message* m)
1027 {
1028   if (m->message == Message::MOUSE_LBDOWN)
1029   {
1030     //check if press is outside this view! then simulate cancel
1031         int x = (m->parameter.num >> 16) - osd.getScreenX();
1032         int y = (m->parameter.num & 0xFFFF) - osd.getScreenY();
1033     if (osd.getVisible()) {
1034     
1035         if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
1036             (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
1037             BoxStack::getInstance()->handleCommand(Remote::RED);
1038         } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
1039             (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
1040             BoxStack::getInstance()->handleCommand(Remote::GREEN);
1041         } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
1042             (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
1043             BoxStack::getInstance()->handleCommand(Remote::YELLOW);
1044         } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
1045             (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
1046             BoxStack::getInstance()->handleCommand(Remote::BLUE);
1047         } else {
1048             BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
1049         }
1050
1051     } else {
1052         BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
1053     }
1054   }
1055   else if (m->message == Message::CHANNEL_CHANGE)
1056   {
1057         channelChange(NUMBER, m->parameter.num);
1058     osdChannelIndex = currentChannelIndex;
1059     if (m->tag == 1) displayOSD(true);
1060   }
1061   else if (m->message == Message::CHILD_CLOSE)
1062   {
1063     if (m->from == vas)
1064     {
1065       vas = NULL;
1066       displayOSD(false);
1067     }
1068   }
1069   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
1070   {
1071         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %x", m->parameter.num);
1072         player->setAudioChannel((m->parameter.num & 0xFFFF), (m->parameter.num & 0xFF0000) >> 16, (m->parameter.num & 0xFF000000) >> 24);
1073   } 
1074   else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
1075   {
1076     if (streamType !=VDR::VIDEO) return;
1077           Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %x", m->parameter.num);
1078       int type=((m->parameter.num & 0xFF0000)>>16);
1079       switch (type) {
1080       case 0x10: { //dvbsubtitle
1081           if (streamType == VDR::VIDEO){
1082               player->setSubtitleChannel((m->parameter.num & 0xFFFF));
1083               (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);
1084               VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
1085               if (vtxt && vtxt->isInSubtitleMode()) {
1086                   BoxStack::getInstance()->remove(vtxt);
1087               }
1088           }
1089                  } break;
1090       case 0xFF: { //nosubtitles
1091           if (streamType == VDR::VIDEO){
1092               (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
1093               VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
1094               if (vtxt && vtxt->isInSubtitleMode()) {
1095                   BoxStack::getInstance()->remove(vtxt);
1096               }  
1097           }
1098                  } break;
1099       case 0x11: { //videotext
1100           (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
1101           doTeletext(true);
1102           ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter.num & 0xFFFF));
1103                  } break;
1104       };
1105       if (vas) {
1106         BoxStack::getInstance()->update(vas);
1107         //BoxStack::getInstance()->update(&osd); //eveil error
1108       }
1109       BoxStack::getInstance()->update(this, osd.getRegion());
1110
1111       
1112   }
1113   else if (m->message == Message::PLAYER_EVENT)
1114   {
1115         switch (m->parameter.num)
1116     {
1117       case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
1118       {
1119         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
1120         Command::getInstance()->connectionLost();
1121         break;
1122       }
1123       
1124       case PlayerLiveTV::STREAM_END:
1125       {
1126         // Message comes from playerlivetv through master mutex, so can do anything here
1127         showUnavailable();        
1128         break;
1129       }
1130       
1131       case PlayerLiveTV::ASPECT43:
1132       {
1133 #ifdef PAL_WSS
1134         if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
1135         {
1136           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
1137           wss.setWide(false);
1138           wss.draw();
1139           BoxStack::getInstance()->update(this, &wssRegion);
1140         }
1141 #endif
1142         
1143         sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
1144         sAspectRatio.setVisible(true);
1145         
1146         if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
1147         {
1148           osd.draw();
1149           BoxStack::getInstance()->update(this, osd.getRegion());
1150         }
1151         
1152         break;
1153       }
1154       case PlayerLiveTV::ASPECT169:
1155       {
1156 #ifdef PAL_WSS
1157         if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
1158         {
1159           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
1160           wss.setWide(true);
1161           wss.draw();
1162           BoxStack::getInstance()->update(this, &wssRegion);
1163         }
1164 #endif
1165         
1166         sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
1167         sAspectRatio.setVisible(true);
1168
1169         if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
1170         {
1171           osd.draw();
1172           BoxStack::getInstance()->update(this, osd.getRegion());
1173         }
1174                 
1175         break;
1176       }
1177       case PlayerLiveTV::PREBUFFERING:
1178       {
1179         preBuffering = m->tag;
1180         Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);
1181         bufferBar.setPercent(preBuffering);
1182
1183         if (osd.getVisible())
1184         {
1185           bufferBar.setVisible(true);
1186           bufferBar.draw();
1187           Region r;
1188           bufferBar.getRootBoxRegion(&r);                       ///////// FIXME !!!
1189           BoxStack::getInstance()->update(this, &r);
1190
1191           if (preBuffering == 100)
1192           {
1193             doAudioChannelSymbol();
1194           }
1195         }
1196       }
1197     }
1198   }
1199 }
1200
1201 void VVideoLiveTV::doAudioChannelSymbol()
1202 {
1203   OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
1204   // get the doobery
1205   Channel* currentChannel = (*chanList)[osdChannelIndex];
1206     
1207   bool multiAudio = false;
1208   if (Audio::getInstance()->supportsAc3()) {
1209           if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true;
1210   }
1211   if (currentChannel->numAPids > 1) multiAudio = true;
1212   
1213   // draw the doobery
1214   if (!osdv) {
1215           if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;
1216           else            sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;
1217           sAudioChannels.setVisible(true);
1218   }
1219   if (osdv)
1220   {
1221           dolbylogo.setVisible(true);
1222           txtlogo.setVisible(true);
1223           TVMediaInfo info;
1224           if (currentChannel->tpid!=0) info.setStaticArtwork(sa_txton);
1225           else info.setStaticArtwork(sa_txtoff);
1226           txtlogo.setTVMedia(info, WTVMedia::ZoomVertical);
1227
1228
1229           if (Audio::getInstance()->supportsAc3() && currentChannel->numDPids>1)
1230                   info.setStaticArtwork(sa_dolbyon);
1231           else info.setStaticArtwork(sa_dolbyoff);
1232           dolbylogo.setTVMedia(info, WTVMedia::ZoomVertical);
1233
1234          Demuxer* demux=Demuxer::getInstance();
1235          if (demux) {
1236                  int vertical_size=demux->getVerticalSize();
1237                  Log::getInstance()->log("VVideoRec", Log::DEBUG, "TVMedia vertical size %d", vertical_size);
1238                  reslogo.setVisible(true);
1239                  switch (vertical_size) {
1240                  case 576:
1241                          info.setStaticArtwork(sa_sd576i);
1242                          reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break;
1243                  case 720:
1244                          info.setStaticArtwork(sa_hd720p);
1245                          reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break;
1246                  case 1080:
1247                          info.setStaticArtwork(sa_hd1080i);
1248                          reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break;
1249                  default: // we assume sd
1250                          reslogo.setVisible(false);
1251                  };
1252
1253          } else {
1254                  reslogo.setVisible(false);
1255          }
1256
1257
1258   }
1259   
1260   if (osd.getVisible())
1261   {
1262     sAudioChannels.draw();
1263     Region r;
1264     sAudioChannels.getRootBoxRegion(&r);                       ///////// FIXME !!!
1265     // Fix this n'all.
1266     r.w = 32;
1267     r.h = 16;
1268     BoxStack::getInstance()->update(this, &r);
1269   }
1270 }
1271
1272 UINT VVideoLiveTV::upChannel(UINT index)
1273 {
1274   if (index == (chanList->size() - 1)) // at the end
1275     return 0; // so go to start
1276   else
1277     return index + 1;
1278 }
1279
1280 UINT VVideoLiveTV::downChannel(UINT index)
1281 {
1282   if (index == 0) // at the start
1283     return chanList->size() - 1; // so go to end
1284   else
1285     return index - 1;
1286 }
1287
1288 void VVideoLiveTV::toggleChopSides()
1289 {
1290   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
1291
1292   if (videoMode == Video::NORMAL)
1293   {
1294     videoMode = Video::LETTERBOX;
1295     video->setMode(Video::LETTERBOX);
1296   }
1297   else
1298   {
1299     videoMode = Video::NORMAL;
1300     video->setMode(Video::NORMAL);
1301   }
1302 }
1303
1304 void VVideoLiveTV::updatePosterBanner()
1305 {
1306         OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
1307         if (!osdv) {
1308                 osdposterbanner.setVisible(false);
1309                 return;
1310         }
1311         Event* toShow = NULL;
1312         if (eventList && eventList->size()) {
1313                 toShow = (*eventList)[0];
1314                 Channel* currentChannel = (*chanList)[osdChannelIndex];
1315                 toShow->loadinfos(currentChannel->number);
1316         }
1317
1318         if (toShow)
1319         {
1320                 TVMedia poster;
1321                 poster.height=0;
1322                 bool posterscale=true;
1323                 if (toShow->movieInfo) {
1324                         poster=toShow->movieInfo->poster;
1325                 }
1326                 if (toShow->seriesInfo) {
1327                         if (toShow->seriesInfo->banners.size()) {
1328                                 poster=toShow->seriesInfo->banners[0];
1329                                 posterscale=false;
1330                         } else if (toShow->seriesInfo->seasonposter.height) {
1331                                 poster=toShow->seriesInfo->seasonposter;
1332                         } else if (toShow->seriesInfo->posters.size()) {
1333                                 poster=toShow->seriesInfo->posters[0];
1334                         }
1335                 }
1336                 if (poster.height) {
1337                         osdposterbanner.setTVMedia(poster.info, posterscale ? WTVMedia::ZoomVertical : WTVMedia::ZoomHorizontal);
1338                         osdposterbanner.setVisible(true);
1339                 } else {
1340                         osdposterbanner.setVisible(false);
1341                 }
1342         } else {
1343                 osdposterbanner.setVisible(false);
1344         }
1345
1346 }
1347
1348
1349 void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)
1350 {
1351   drawBitmap(posX, posY, bm,region);
1352   Region r;
1353   r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
1354   boxstack->update(this, &r);
1355 }
1356
1357 void VVideoLiveTV::clearOSD()
1358 {
1359   rectangle(area, DrawStyle(0,0,0,0));
1360   boxstack->update(this, &area);
1361 }
1362
1363 void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)
1364 {
1365   Region r;
1366   r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;
1367   //now convert to our display
1368   float scalex=720.f/((float) (region.framewidth+1));
1369   float scaley=576.f/((float) (region.frameheight+1));
1370   r.x=floor(scalex*((float)r.x));
1371   r.y=floor(scaley*((float)r.y));
1372   r.w=ceil(scalex*((float)r.w))+1.f;
1373   r.h=ceil(scaley*((float)r.h))+1.f;
1374   rectangle(r, DrawStyle(0,0,0,0));
1375   boxstack->update(this, &r);
1376 }