2 Copyright 2007-2008 Chris Tallon
4 This file is part of VOMP.
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
22 #include "vchannellist.h"
25 #include "playerlive.h"
26 #include "playervideolive.h"
27 #include "playerradiolive.h"
37 #include "vaudioselector.h"
43 #include "vteletextview.h"
44 #include "vepgsummary.h"
45 #include "vepglistadvanced.h"
46 #include "staticartwork.h"
48 #include "messagequeue.h"
50 #include "vvideolivetv.h"
52 static const char* TAG = "VVideoLiveTV";
55 VVideoLiveTV::VVideoLiveTV(std::shared_ptr<ChannelList> tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
56 : chanList(tchanList), vchannelList(tvchannelList)
58 vdr = VDR::getInstance();
59 boxstack = BoxStack::getInstance();
60 video = Video::getInstance();
64 numberWidth = VDR::getInstance()->getChannelNumberWidth();
66 currentChannelIndex = 0;
67 previousChannelIndex = 0;
74 // Convert channel number to index
75 for(UINT i = 0; i < chanList->size(); i++)
77 if ((*chanList)[i]->number == initialChannelNumber)
79 currentChannelIndex = i;
87 videoMode = video->getMode();
89 if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
91 streamType = VDR::VIDEO;
92 player = new PlayerVideoLive(Control::getInstance(), this, this, chanList);
96 streamType = VDR::RADIO;
97 player = new PlayerRadioLive(Control::getInstance(), this, chanList);
101 setSize(video->getScreenWidth(), video->getScreenHeight());
103 setBackgroundColour(DrawStyle::TRANSPARENT);
105 OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
108 osdv->updateBackgroundColor(DrawStyle::BLACK);
111 // This variable is set to true if the user pressed OK to bring the OSD on screen
112 // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling
113 okTriggeredOSD = false;
116 info.setChannelLogo(initialChannelNumber);
118 if (osdv && streamType == VDR::RADIO) {
119 radioChannelLogo.setPosition(video->getScreenWidth()/4,video->getScreenHeight()/4);
120 radioChannelLogo.setSize(video->getScreenWidth()/2,video->getScreenHeight()/2);
121 radioChannelLogo.setVisible(true);
122 radioChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
123 add(&radioChannelLogo);
126 osdposterbanner.setPosition(20,20);
127 //osdposterbanner.setBackgroundColour(DrawStyle::OSDBACKGROUND);
128 osdposterbanner.setSize(video->getScreenWidth()*4/10,video->getScreenHeight()*4/10);
129 osdposterbanner.setVisible(false);
130 add(&osdposterbanner);
132 osd.setBackgroundColour(DrawStyle::OSDBACKGROUND);
133 osd.setPosition(0, video->getScreenHeight() - 150);
134 osd.setSize(video->getScreenWidth(), 150);
135 osd.setVisible(false);
138 int channellogomove=0;
142 //osdChannelLogo.setBackgroundColour(DrawStyle::OSDBACKGROUND);
143 osdChannelLogo.setPosition(30,5);
144 osdChannelLogo.setSize(60,60);
145 osdChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
146 osd.add(&osdChannelLogo);
147 channellogomove = 30-5;
151 //clock.setBackgroundColour(DrawStyle::OSDBACKGROUND);
152 clock.setPosition(osd.getWidth() - 100, 4);
153 clock.setSize(90, 30);
156 //osdChanNum.setBackgroundColour(DrawStyle::OSDBACKGROUND);
157 osdChanNum.setPosition(60 + channellogomove, 4);
158 osdChanNum.setSize((numberWidth * 10) + 22, getFontHeight() + 5); // 10 px = width of number chars in font
159 osd.add(&osdChanNum);
161 //osdChanName.setBackgroundColour(DrawStyle::OSDBACKGROUND);
162 osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
163 osdChanName.setSize(300, 30);
164 osd.add(&osdChanName);
166 boxRed.setBackgroundColour(DrawStyle::RED);
167 boxRed.setPosition(54+0*boxdiff, 104);
168 boxRed.setSize(18, 16);
171 boxGreen.setBackgroundColour(DrawStyle::GREEN);
172 boxGreen.setPosition(54+1*boxdiff, 104);
173 boxGreen.setSize(18, 16);
176 boxYellow.setBackgroundColour(DrawStyle::YELLOW);
177 boxYellow.setPosition(54+2*boxdiff, 104);
178 boxYellow.setSize(18, 16);
181 boxBlue.setBackgroundColour(DrawStyle::BLUE);
182 boxBlue.setPosition(54+3*boxdiff, 104);
183 boxBlue.setSize(18, 16);
186 //textRed.setBackgroundColour(DrawStyle::OSDBACKGROUND);
187 textRed.setPosition(boxRed.getX2(), 98);
188 textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);
189 textRed.setText(tr("Summary"));
192 if (streamType == VDR::VIDEO)
194 //textGreen.setBackgroundColour(DrawStyle::OSDBACKGROUND);
195 textGreen.setPosition(boxGreen.getX2(), 98);
196 textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);
197 textGreen.setText(tr("Audio"));
201 //textYellow.setBackgroundColour(DrawStyle::OSDBACKGROUND);
202 textYellow.setPosition(boxYellow.getX2(), 98);
203 textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
204 textYellow.setText(tr("Teletext"));
205 osd.add(&textYellow);
207 //textBlue.setBackgroundColour(DrawStyle::OSDBACKGROUND);
208 textBlue.setPosition(boxBlue.getX2(), 98);
209 textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);
210 textBlue.setText(tr("EPG"));
213 //sl.setBackgroundColour(DrawStyle::OSDBACKGROUND);
214 sl.setPosition(90, 36);
218 bufferBar.setPosition(osd.getWidth() - 90, 70);
219 bufferBar.setSize(40, 20);
220 bufferBar.setVisible(true);
225 sAspectRatio.setPosition(osd.getWidth() - 90, 40);
226 sAspectRatio.nextColour = DrawStyle::LIVETVSYMBOLS;
227 sAspectRatio.setVisible(false);
228 osd.add(&sAspectRatio);
230 sAudioChannels.setPosition(osd.getWidth() - 130, 40);
231 sAudioChannels.nextColour = DrawStyle::LIVETVSYMBOLS;
232 sAudioChannels.setVisible(false);
233 osd.add(&sAudioChannels);
239 ninfo.setStaticArtwork(sa_txtoff);
240 txtlogo.setPosition(54+4*boxdiff,104);
241 txtlogo.setSize(22,20);
242 txtlogo.setTVMedia(ninfo, WTVMedia::ZoomVertical);
245 ninfo.setStaticArtwork(sa_dolbyoff);
246 dolbylogo.setPosition(54+4*boxdiff+15,104);
247 dolbylogo.setSize(22,20);
248 dolbylogo.setTVMedia(ninfo, WTVMedia::ZoomVertical);
251 ninfo.setStaticArtwork(sa_sd576i);
252 reslogo.setPosition(54+4*boxdiff+30,104);
253 reslogo.setSize(22,20);
254 reslogo.setTVMedia(ninfo, WTVMedia::ZoomVertical);
257 reslogo.setVisible(false);
258 dolbylogo.setVisible(false);
259 txtlogo.setVisible(false);
262 //textUnavailable.setBackgroundColour(DrawStyle::OSDBACKGROUND);
263 textUnavailable.setPosition(60, 30);
264 textUnavailable.setSize(osd.getWidth() - 120, 30);
265 textUnavailable.setText(tr("Channel Unavailable"));
266 textUnavailable.setVisible(false);
267 add(&textUnavailable);
269 vdisplay.mode = Fullscreen;
270 vdisplay.fallbackMode = Fullscreen;
276 MessageQueue::getInstance()->addReceiver(this);
279 void VVideoLiveTV::preDelete()
284 VVideoLiveTV::~VVideoLiveTV()
286 MessageQueue::getInstance()->removeReceiver(this);
288 video->setDefaultAspect();
290 OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
293 osdv->updateBackgroundColor(DrawStyle::WALLPAPER);
297 void VVideoLiveTV::delData()
301 int eventListSize = eventList->size();
302 for(int i = 0; i < eventListSize; i++)
304 delete (*eventList)[i];
311 int VVideoLiveTV::handleCommand(int command)
317 if (osd.getVisible() && !textUnavailable.getVisible())
320 return BoxStack::COMMAND_HANDLED;
322 // else drop through to stop
328 if (vchannelList) vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
329 return BoxStack::DELETE_ME;
332 // navigate EPG, bring it onscreen if it's not there
335 if (InputMan::getInstance()->mayHaveFewButtons())
337 if (okTriggeredOSD) doUpDown(false);
338 else doChanUpDown(UP);
344 return BoxStack::COMMAND_HANDLED;
348 if (InputMan::getInstance()->mayHaveFewButtons())
350 if (okTriggeredOSD) doUpDown(true);
351 else doChanUpDown(DOWN);
357 return BoxStack::COMMAND_HANDLED;
362 return BoxStack::COMMAND_HANDLED;
367 return BoxStack::COMMAND_HANDLED;
369 case Input::CHANNELUP:
372 return BoxStack::COMMAND_HANDLED;
374 case Input::CHANNELDOWN:
377 return BoxStack::COMMAND_HANDLED;
379 case Input::PREVCHANNEL:
381 channelChange(PREVIOUS, 0);
382 osdChannelIndex = currentChannelIndex;
384 return BoxStack::COMMAND_HANDLED;
389 return BoxStack::COMMAND_HANDLED;
395 return BoxStack::COMMAND_HANDLED;
401 return BoxStack::COMMAND_HANDLED;
415 // key in channel number
417 return BoxStack::COMMAND_HANDLED;
422 if (streamType == VDR::VIDEO) doAudioSelector();
423 return BoxStack::COMMAND_HANDLED;
427 if (streamType ==VDR::VIDEO)
429 doTeletext(); //TODO: Add a selector for subtitles or teletext
431 return BoxStack::COMMAND_HANDLED;
437 return BoxStack::COMMAND_HANDLED;
440 if (streamType == VDR::VIDEO)
441 (static_cast<PlayerVideoLive*>(player))->toggleSubtitles();
442 return BoxStack::COMMAND_HANDLED;
445 return BoxStack::ABANDON_COMMAND;
448 void VVideoLiveTV::go()
452 boxstack->update(this);
457 player->go(currentChannelIndex);
460 void VVideoLiveTV::stop()
462 Timers::getInstance()->cancelTimer(this, 1);
463 Timers::getInstance()->cancelTimer(this, 2);
468 void VVideoLiveTV::doLeftRight(bool right)
470 if (osd.getVisible())
472 if (right) osdChannelIndex = upChannel(osdChannelIndex);
473 else osdChannelIndex = downChannel(osdChannelIndex);
477 osdChannelIndex = currentChannelIndex;
482 void VVideoLiveTV::doUpDown(bool /* down */)
484 if (osd.getVisible())
496 void VVideoLiveTV::doChanUpDown(int which)
498 channelChange(OFFSET, which);
499 osdChannelIndex = currentChannelIndex;
503 void VVideoLiveTV::doOK()
505 if (osd.getVisible())
510 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * static_cast<int>(pow(10.f, i));
512 channelChange(NUMBER, newChannel);
513 osdChannelIndex = currentChannelIndex;
516 else if (osdChannelIndex == currentChannelIndex)
522 channelChange(INDEX, osdChannelIndex);
528 osdChannelIndex = currentChannelIndex;
530 okTriggeredOSD = true;
534 void VVideoLiveTV::doSummary()
537 Channel* currentChannel = (*chanList)[osdChannelIndex];
538 eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
543 sort(eventList->begin(), eventList->end(), EventSorter());
545 if (eventList->size() < 1) return;
546 Event* event = (*eventList)[0];
547 event->loadinfos(currentChannel->number);
549 VEpgSummary* vr = new VEpgSummary(event,currentChannel);
552 boxstack->update(vr);
555 void VVideoLiveTV::doKey(int command)
557 if (!osd.getVisible()) // First key. prep the data
560 updatePosterBanner();
565 for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
566 keyingInput[0] = command;
569 char* keyingString = new char[numberWidth + 1];
570 for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
571 keyingString[numberWidth] = '\0';
573 for (i = 0; i < keying; i++) keyingString[i] = static_cast<char>(keyingInput[keying - 1 - i] + 48);
575 if (keying == numberWidth)
578 for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * static_cast<int>(pow(10.f, i));
580 channelChange(NUMBER, newChannel);
581 osdChannelIndex = currentChannelIndex;
582 Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
583 displayOSD(true); // this will put one back if required
587 osdChanNum.setText(keyingString);
589 if (!osd.getVisible())
591 osd.setVisible(true);
596 osdChanNum.fillColour(DrawStyle::VIEWBACKGROUND);
599 boxstack->update(this, osd.getRegion());
600 Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input
602 delete[] keyingString;
605 void VVideoLiveTV::doTeletext(bool subtitlemode)
607 if (streamType != VDR::VIDEO) return;
609 PlayerVideoLive* playervl = static_cast<PlayerVideoLive*>(player);
611 playervl->tellSubtitlesOSDVisible(true);
618 // and reset the display - this is a copy from setNowNextData
619 char formatChanNum[20];
620 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
621 osdChanNum.setText(formatChanNum);
622 osdChanName.setText((*chanList)[osdChannelIndex]->name);
624 playervl->tellSubtitlesOSDVisible(true);
625 if (osd.getVisible()) clearScreen();
627 VTeletextView* vtxv = playervl->getTeletextDecoder()->getTeletxtView();
630 vtxv = new VTeletextView(playervl->getTeletextDecoder(), this, playervl);
631 playervl->getTeletextDecoder()->registerTeletextView(vtxv);
635 vtxv->setSubtitleMode(subtitlemode);
641 BoxStack::getInstance()->add(vtxv);
644 BoxStack::getInstance()->update(this);
645 BoxStack::getInstance()->update(vtxv);
648 void VVideoLiveTV::doAudioSelector()
650 // Only called if streamtype == VDR::VIDEO
651 PlayerVideoLive* playervl = static_cast<PlayerVideoLive*>(player);
653 // If the osd is already visisble there might be a timer for it
654 Timers::getInstance()->cancelTimer(this, 1);
655 //This causes a deadlock with the timertrhread itself is locked
661 // and reset the display - this is a copy from setNowNextData
662 char formatChanNum[20];
663 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
664 osdChanNum.setText(formatChanNum);
665 osdChanName.setText((*chanList)[osdChannelIndex]->name);
667 int subtitleChannel = playervl->getCurrentSubtitleChannel();
668 int subtitleType = 0x10;
669 if (!playervl->isSubtitlesOn())
671 if (playervl->getTeletextDecoder()->getTeletxtView() &&
672 playervl->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode())
674 subtitleChannel = playervl->getTeletextDecoder()->getPage();
679 subtitleType = 0xFF; //turnedOff
685 vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], playervl->getCurrentAudioChannel(),
686 subtitleType,subtitleChannel,NULL);
688 vas->setBackgroundColour(DrawStyle::OSDBACKGROUND);
689 vas->setPosition(0, osd.getScreenY() - vas->getHeight());
692 // make vas != null and displayOSD will not set a timer or do any boxstack update
693 if (osd.getVisible()) displayOSD(false);
694 else displayOSD(true);
697 BoxStack::getInstance()->add(vas);
698 BoxStack::getInstance()->update(this);
699 BoxStack::getInstance()->update(vas);
702 void VVideoLiveTV::doEPG()
704 if (osd.getVisible()) clearScreen();
706 if (!Control::getInstance()->isAdvMenus())
708 VEpg* vepg = new VEpg(this, currentChannelIndex, chanList);
711 boxstack->update(vepg);
715 Channel* currentChannel = (*chanList)[osdChannelIndex];
716 VEpgListAdvanced *vepg= new VEpgListAdvanced(this, chanList, currentChannel->number);
719 boxstack->update(vepg);
723 void VVideoLiveTV::setNowNextData()
727 Channel* currentChannel = (*chanList)[osdChannelIndex];
729 char formatChanNum[20];
730 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
731 osdChanNum.setText(formatChanNum);
732 osdChanName.setText(currentChannel->name);
734 eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
738 sl.setText(tr("No channel data available"));
742 sort(eventList->begin(), eventList->end(), EventSorter());
744 char tempString[300];
747 int eventListSize = eventList->size();
748 std::stringstream ss;
749 for(int i = 0; i < eventListSize; i++)
751 event = (*eventList)[i];
753 time_t etime = event->time;
754 LOCALTIME_R(&etime, &btime);
755 // FIXME convert following to std::strftime
757 strftime(tempString, 299, "%0H:%0M ", &btime);
759 strftime(tempString, 299, "%H:%M ", &btime);
761 ss << tempString << " " << event->title << "\n";
763 sl.setText(ss.str().c_str());
769 void VVideoLiveTV::displayOSD(bool newNowNextData)
771 PlayerVideoLive* playerlivetv = dynamic_cast<PlayerVideoLive*>(player);
772 if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(true);
773 osd.setVisible(true);
777 updatePosterBanner();
781 if (osdposterbanner.getVisible()) osdposterbanner.draw();
786 toupdate=*osd.getRegion();
789 if (osdposterbanner.getVisible())
791 boxstack->update(this);
795 boxstack->update(this, &toupdate);
798 bool setTimer = true;
799 if (vas) setTimer = false;
800 if (textUnavailable.getVisible()) setTimer = false;
802 if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);
805 void VVideoLiveTV::clearScreen()
807 Timers::getInstance()->cancelTimer(this, 1);
809 textUnavailable.setVisible(false);
810 osd.setVisible(false);
811 osdposterbanner.setVisible(false);
813 okTriggeredOSD = false;
816 boxstack->update(this);
818 PlayerVideoLive* playerlivetv = dynamic_cast<PlayerVideoLive*>(player);
819 if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(false);
822 void VVideoLiveTV::showUnavailable()
824 LogNT::getInstance()->debug(TAG, "Show unavailable called");
825 textUnavailable.setVisible(true);
826 textUnavailable.draw();
828 if (!osd.getVisible()) displayOSD(true);
830 boxstack->update(this, textUnavailable.getRegion());
833 void VVideoLiveTV::setClock()
839 LOCALTIME_R(&t, &tms);
840 strftime(timeString, 19, "%H:%M", &tms);
841 clock.setText(timeString);
843 time_t dt = 60 - (t % 60); // seconds to the next minute
844 if (dt == 0) dt = 60; // advance a whole minute if necessary
845 dt += t; // get a time_t value for it rather than using duration
846 // (so it will occur at the actual second and not second and a half)
848 Timers::getInstance()->setTimerT(this, 2, dt);
851 void VVideoLiveTV::timercall(int ref)
857 LogNT::getInstance()->debug(TAG, "Timer Call 1 key start.");
859 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * static_cast<int>(pow(10.f, i));
861 Message* m = new Message();
862 m->message = Message::CHANNEL_CHANGE;
864 m->parameter = newChannel;
865 m->tag = 1; // signal to call displayOSD();
866 MessageQueue::getInstance()->postMessage(m);
867 LogNT::getInstance()->debug(TAG, "Timer Call 1 key end.");
871 LogNT::getInstance()->debug(TAG, "Timer Call 1 not key start.");
872 // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
873 if (preBuffering < 100)
875 LogNT::getInstance()->debug(TAG, "Still prebuffering, not removing osd...");
876 Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
879 bool osdpbvisible=osdposterbanner.getVisible();
880 LogNT::getInstance()->debug(TAG, "Timer Call 1 notkey 1.");
881 osd.setVisible(false);
882 osdposterbanner.setVisible(false);
883 okTriggeredOSD = false;
884 LogNT::getInstance()->debug(TAG, "Timer Call 1 notkey 2.");
886 LogNT::getInstance()->debug(TAG, "Timer Call 1 notkey 4.");
887 if (osdpbvisible) boxstack->update(this);
888 else boxstack->update(this, osd.getRegion());
890 LogNT::getInstance()->debug(TAG, "Timer Call 1 notkey 3.");
891 PlayerVideoLive* playerlivetv = dynamic_cast<PlayerVideoLive*>(player);
892 if (playerlivetv) playerlivetv->tellSubtitlesOSDVisible(false);
893 LogNT::getInstance()->debug(TAG, "Timer Call 1 notkey end.");
898 LogNT::getInstance()->debug(TAG, "Timer Call 2 start.");
900 if (osd.getVisible())
902 clock.fillColour(DrawStyle::OSDBACKGROUND);
904 boxstack->update(this, osd.getRegion());
906 LogNT::getInstance()->debug(TAG, "Timer Call 2 end.");
910 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
913 if (streamType == VDR::VIDEO)
915 VTeletextView* vtxt = static_cast<PlayerVideoLive*>(player)->getTeletextDecoder()->getTeletxtView();
918 BoxStack::getInstance()->remove(vtxt);
921 if (changeType == INDEX)
923 newChannel = newData;
925 else if (changeType == NUMBER)
928 for(i = 0; i < chanList->size(); i++)
930 if ((*chanList)[i]->number == newData)
937 if (i == chanList->size())
943 else if (changeType == OFFSET)
945 if (newData == UP) newChannel = upChannel(currentChannelIndex);
946 else newChannel = downChannel(currentChannelIndex);
948 else if (changeType == PREVIOUS)
950 newChannel = previousChannelIndex;
954 return false; // bad input
957 if (newChannel == currentChannelIndex) return true;
959 previousChannelIndex = currentChannelIndex;
960 currentChannelIndex = newChannel;
964 LogNT::getInstance()->debug(TAG, "Set player to channel {}", currentChannelIndex);
965 player->setChannel(currentChannelIndex);
966 LogNT::getInstance()->debug(TAG, "Done Set player to channel {}", currentChannelIndex);
968 // Blank out the symbols
969 OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
971 bufferBar.setPercent(0);
975 sAudioChannels.setVisible(false);
976 sAspectRatio.setVisible(false);
980 reslogo.setVisible(false);
981 dolbylogo.setVisible(false);
982 txtlogo.setVisible(false);
985 // Remove other stuff
986 if (textUnavailable.getVisible())
988 textUnavailable.setVisible(false);
994 Channel* currentChannel = (*chanList)[currentChannelIndex];
997 info.setChannelLogo(currentChannel->number);
998 if (streamType == VDR::RADIO)
1000 radioChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
1001 radioChannelLogo.setVisible(true);
1003 osdChannelLogo.setTVMedia(info, WTVMedia::ZoomVertical);
1008 BoxStack::getInstance()->update(this);
1013 void VVideoLiveTV::processMessage(Message* m)
1015 if (m->message == Message::MOUSE_LBDOWN)
1017 //check if press is outside this view! then simulate cancel
1018 int x = m->parameter - osd.getScreenX();
1019 int y = m->tag - osd.getScreenY();
1020 if (osd.getVisible())
1022 if ((boxRed.getX() <= x) && (boxRed.getX() + static_cast<int>(boxRed.getWidth()) >= x) &&
1023 (boxRed.getY() <= y) && (boxRed.getY() + static_cast<int>(boxRed.getHeight()) >= y))
1025 BoxStack::getInstance()->handleCommand(Input::RED);
1027 else if ((boxGreen.getX() <= x) && (boxGreen.getX() + static_cast<int>(boxGreen.getWidth()) >= x) &&
1028 (boxGreen.getY() <= y) && (boxGreen.getY() + static_cast<int>(boxGreen.getHeight()) >= y))
1030 BoxStack::getInstance()->handleCommand(Input::GREEN);
1032 else if ((boxYellow.getX() <= x) && (boxYellow.getX() + static_cast<int>(boxYellow.getWidth()) >= x) &&
1033 (boxYellow.getY() <= y) && (boxYellow.getY() + static_cast<int>(boxYellow.getHeight()) >= y))
1035 BoxStack::getInstance()->handleCommand(Input::YELLOW);
1037 else if ((boxBlue.getX() <= x) && (boxBlue.getX() + static_cast<int>(boxBlue.getWidth()) >= x) &&
1038 (boxBlue.getY() <= y) && (boxBlue.getY() + static_cast<int>(boxBlue.getHeight()) >= y))
1040 BoxStack::getInstance()->handleCommand(Input::BLUE);
1044 BoxStack::getInstance()->handleCommand(Input::OK); //simulate rok press
1049 BoxStack::getInstance()->handleCommand(Input::OK); //simulate rok press
1052 else if (m->message == Message::CHANNEL_CHANGE)
1054 channelChange(NUMBER, m->parameter);
1055 osdChannelIndex = currentChannelIndex;
1056 if (m->tag == 1) displayOSD(true);
1058 else if (m->message == Message::CHILD_CLOSE)
1066 else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
1068 LogNT::getInstance()->debug(TAG, "Received change audio channel to {:#x}", m->parameter);
1069 player->setAudioChannel((m->parameter & 0xFFFF), (m->parameter & 0xFF0000) >> 16, (m->parameter & 0xFF000000) >> 24);
1071 else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
1073 if (streamType != VDR::VIDEO) return;
1075 PlayerVideoLive* playervl = static_cast<PlayerVideoLive*>(player);
1077 LogNT::getInstance()->debug(TAG, "Received change subtitle channel to {:#x}", m->parameter);
1078 int type = (m->parameter & 0xFF0000) >> 16;
1084 playervl->setSubtitleChannel((m->parameter & 0xFFFF));
1085 playervl->turnSubtitlesOn(true);
1086 VTeletextView* vtxt = playervl->getTeletextDecoder()->getTeletxtView();
1087 if (vtxt && vtxt->isInSubtitleMode())
1089 BoxStack::getInstance()->remove(vtxt);
1096 playervl->turnSubtitlesOn(false);
1097 VTeletextView* vtxt = playervl->getTeletextDecoder()->getTeletxtView();
1098 if (vtxt && vtxt->isInSubtitleMode())
1100 BoxStack::getInstance()->remove(vtxt);
1107 playervl->turnSubtitlesOn(false);
1109 playervl->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
1116 BoxStack::getInstance()->update(vas);
1117 //BoxStack::getInstance()->update(&osd); //eveil error
1119 BoxStack::getInstance()->update(this, osd.getRegion());
1121 else if (m->message == Message::PLAYER_EVENT)
1123 switch (m->parameter)
1125 case PlayerVideoLive::CONNECTION_LOST: // connection lost detected
1127 LogNT::getInstance()->debug(TAG, "Received connection lost from player");
1128 Control::getInstance()->connectionLost();
1132 case PlayerVideoLive::STREAM_END:
1134 // Message comes from playerlivetv through master mutex, so can do anything here
1139 case PlayerVideoLive::ASPECT43:
1141 OsdVector* osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
1144 osdv->updateBackgroundColor(DrawStyle::BLACK);
1147 sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
1148 sAspectRatio.setVisible(true);
1150 if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
1153 BoxStack::getInstance()->update(this, osd.getRegion());
1158 case PlayerVideoLive::ASPECT169:
1160 sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
1161 sAspectRatio.setVisible(true);
1163 OsdVector* osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
1166 osdv->updateBackgroundColor(DrawStyle::BLACK);
1170 if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
1173 BoxStack::getInstance()->update(this, osd.getRegion());
1178 case PlayerVideoLive::PREBUFFERING:
1180 preBuffering = m->tag;
1181 LogNT::getInstance()->debug(TAG, "Prebuffering - {}", preBuffering);
1182 bufferBar.setPercent(preBuffering);
1184 if (osd.getVisible())
1186 bufferBar.setVisible(true);
1189 bufferBar.getRootBoxRegion(&r); ///////// FIXME !!!
1190 BoxStack::getInstance()->update(this, &r);
1192 if (preBuffering == 100)
1194 doAudioChannelSymbol();
1202 void VVideoLiveTV::doAudioChannelSymbol()
1204 OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
1206 Channel* currentChannel = (*chanList)[osdChannelIndex];
1208 bool multiAudio = false;
1209 if (Audio::getInstance()->supportsAc3()) {
1210 if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true;
1212 if (currentChannel->numAPids > 1) multiAudio = true;
1216 if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;
1217 else sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;
1218 sAudioChannels.setVisible(true);
1222 dolbylogo.setVisible(true);
1223 txtlogo.setVisible(true);
1225 if (currentChannel->tpid!=0) info.setStaticArtwork(sa_txton);
1226 else info.setStaticArtwork(sa_txtoff);
1227 txtlogo.setTVMedia(info, WTVMedia::ZoomVertical);
1230 if (Audio::getInstance()->supportsAc3() && currentChannel->numDPids>1)
1231 info.setStaticArtwork(sa_dolbyon);
1232 else info.setStaticArtwork(sa_dolbyoff);
1233 dolbylogo.setTVMedia(info, WTVMedia::ZoomVertical);
1235 Demuxer* demux=Demuxer::getInstance();
1237 int vertical_size=demux->getVerticalSize();
1238 LogNT::getInstance()->debug(TAG, "TVMedia vertical size {}", vertical_size);
1239 reslogo.setVisible(true);
1240 switch (vertical_size) {
1242 info.setStaticArtwork(sa_sd576i);
1243 reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break;
1245 info.setStaticArtwork(sa_hd720p);
1246 reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break;
1248 info.setStaticArtwork(sa_hd1080i);
1249 reslogo.setTVMedia(info, WTVMedia::ZoomVertical);break;
1250 default: // we assume sd
1251 reslogo.setVisible(false);
1255 reslogo.setVisible(false);
1261 if (osd.getVisible())
1263 sAudioChannels.draw();
1265 sAudioChannels.getRootBoxRegion(&r); ///////// FIXME !!!
1269 BoxStack::getInstance()->update(this, &r);
1273 UINT VVideoLiveTV::upChannel(UINT index)
1275 if (index == (chanList->size() - 1)) // at the end
1276 return 0; // so go to start
1281 UINT VVideoLiveTV::downChannel(UINT index)
1283 if (index == 0) // at the start
1284 return chanList->size() - 1; // so go to end
1289 void VVideoLiveTV::toggleChopSides()
1291 if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
1293 if (videoMode == Video::NORMAL)
1295 videoMode = Video::LETTERBOX;
1296 video->setMode(Video::LETTERBOX);
1300 videoMode = Video::NORMAL;
1301 video->setMode(Video::NORMAL);
1305 void VVideoLiveTV::updatePosterBanner()
1307 OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
1309 osdposterbanner.setVisible(false);
1312 Event* toShow = NULL;
1313 if (eventList && eventList->size()) {
1314 toShow = (*eventList)[0];
1315 Channel* currentChannel = (*chanList)[osdChannelIndex];
1316 toShow->loadinfos(currentChannel->number);
1323 bool posterscale=true;
1324 if (toShow->movieInfo) {
1325 poster=toShow->movieInfo->poster;
1327 if (toShow->seriesInfo) {
1328 if (toShow->seriesInfo->banners.size()) {
1329 poster=toShow->seriesInfo->banners[0];
1331 } else if (toShow->seriesInfo->seasonposter.height) {
1332 poster=toShow->seriesInfo->seasonposter;
1333 } else if (toShow->seriesInfo->posters.size()) {
1334 poster=toShow->seriesInfo->posters[0];
1337 if (poster.height) {
1338 osdposterbanner.setTVMedia(poster.info, posterscale ? WTVMedia::ZoomVertical : WTVMedia::ZoomHorizontal);
1339 osdposterbanner.setVisible(true);
1341 osdposterbanner.setVisible(false);
1344 osdposterbanner.setVisible(false);
1350 void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)
1352 drawBitmap(posX, posY, bm,region);
1354 r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
1355 boxstack->update(this, &r);
1358 void VVideoLiveTV::clearOSD()
1360 rectangle(area, DrawStyle::TRANSPARENT);
1361 boxstack->update(this, &area);
1364 void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)
1367 r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;
1368 //now convert to our display
1369 float scalex = 720.f / static_cast<float>(region.framewidth + 1);
1370 float scaley = 576.f / static_cast<float>(region.frameheight + 1);
1371 r.x = static_cast<UINT>(floor(scalex * static_cast<float>(r.x)));
1372 r.y = static_cast<UINT>(floor(scaley * static_cast<float>(r.y)));
1373 r.w = static_cast<UINT>(ceil(scalex * static_cast<float>(r.w)) + 1.f);
1374 r.h = static_cast<UINT>(ceil(scaley * static_cast<float>(r.h)) + 1.f);
1375 rectangle(r, DrawStyle::TRANSPARENT);
1376 boxstack->update(this, &r);