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, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "vvideolivetv.h"
23 #include "vchannellist.h"
25 #include "playerlive.h"
26 #include "playerlivetv.h"
27 #include "playerliveradio.h"
36 #include "vaudioselector.h"
44 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
46 vdr = VDR::getInstance();
47 boxstack = BoxStack::getInstance();
48 video = Video::getInstance();
53 vchannelList = tvchannelList;
54 numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
56 currentChannelIndex = 0;
57 previousChannelIndex = 0;
64 // Convert channel number to index
66 for(i = 0; i < chanList->size(); i++)
68 if ((*chanList)[i]->number == (UINT)initialChannelNumber)
70 currentChannelIndex = i;
78 videoMode = video->getMode();
80 if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
82 streamType = VDR::VIDEO;
83 player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
87 streamType = VDR::RADIO;
88 player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
92 setSize(video->getScreenWidth(), video->getScreenHeight());
94 Colour transparent(0, 0, 0, 0);
95 setBackgroundColour(transparent);
98 char* optionWSS = vdr->configLoad("General", "WSS");
101 if (strstr(optionWSS, "Yes")) dowss = true;
104 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
108 wss.setFormat(video->getFormat());
114 wssRegion.w = video->getScreenWidth();
118 // This variable is set to true if the user pressed OK to bring the OSD on screen
119 // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling
120 okTriggeredOSD = false;
122 Colour osdBack = Colour(0, 0, 0, 128);
124 osd.setBackgroundColour(osdBack);
125 osd.setPosition(0, video->getScreenHeight() - 150);
126 osd.setSize(video->getScreenWidth(), 150);
127 osd.setVisible(false);
130 clock.setBackgroundColour(osdBack);
131 clock.setPosition(osd.getWidth() - 100, 4);
132 clock.setSize(90, 30);
135 osdChanNum.setBackgroundColour(osdBack);
136 osdChanNum.setPosition(50, 4);
137 osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
138 osd.add(&osdChanNum);
140 osdChanName.setBackgroundColour(osdBack);
141 osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
142 osdChanName.setSize(300, 30);
143 osd.add(&osdChanName);
145 boxRed.setBackgroundColour(Colour::RED);
146 boxRed.setPosition(54, 104);
147 boxRed.setSize(18, 16);
150 boxGreen.setBackgroundColour(Colour::GREEN);
151 boxGreen.setPosition(220, 104);
152 boxGreen.setSize(18, 16);
155 boxYellow.setBackgroundColour(Colour::YELLOW);
156 boxYellow.setPosition(390, 104);
157 boxYellow.setSize(18, 16);
160 boxBlue.setBackgroundColour(Colour::BLUE);
161 boxBlue.setPosition(560, 104);
162 boxBlue.setSize(18, 16);
165 textRed.setBackgroundColour(osdBack);
166 textRed.setPosition(boxRed.getX2(), 98);
167 textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);
168 textRed.setText(tr("Summary"));
171 if (streamType == VDR::VIDEO)
173 textGreen.setBackgroundColour(osdBack);
174 textGreen.setPosition(boxGreen.getX2(), 98);
175 textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);
176 textGreen.setText(tr("Audio"));
180 textYellow.setBackgroundColour(osdBack);
181 textYellow.setPosition(boxYellow.getX2(), 98);
182 textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
183 textYellow.setText("");
184 osd.add(&textYellow);
186 textBlue.setBackgroundColour(osdBack);
187 textBlue.setPosition(boxBlue.getX2(), 98);
188 textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);
189 textBlue.setText(tr("EPG"));
192 sl.setBackgroundColour(osdBack);
193 sl.setPosition(70, 36);
199 summary.setBackgroundColour(osdBack);
200 summary.setPosition(0, video->getScreenHeight() - 300);
201 summary.setSize(video->getScreenWidth(), 150);
202 summary.setVisible(false);
205 textSummary.setBackgroundColour(osdBack);
206 textSummary.setPosition(40, 10);
207 textSummary.setSize(video->getScreenWidth() - 80, 130);
208 textSummary.setParaMode(true);
209 summary.add(&textSummary);
211 summaryBlackLine.setBackgroundColour(Colour::BLACK);
212 summaryBlackLine.setPosition(0, summary.getHeight() - 4);
213 summaryBlackLine.setSize(summary.getWidth(), 4);
214 summary.add(&summaryBlackLine);
216 sAspectRatio.setPosition(osd.getWidth() - 90, 40);
217 sAspectRatio.nextColour = Colour::SELECTHIGHLIGHT;
218 sAspectRatio.setVisible(false);
219 osd.add(&sAspectRatio);
221 bufferBar.setPosition(osd.getWidth() - 90, 70);
222 bufferBar.setSize(40, 20);
223 bufferBar.setVisible(true);
226 sAudioChannels.setPosition(osd.getWidth() - 130, 40);
227 sAudioChannels.nextColour = Colour::SELECTHIGHLIGHT;
228 sAudioChannels.setVisible(false);
229 osd.add(&sAudioChannels);
231 textUnavailable.setBackgroundColour(osdBack);
232 textUnavailable.setPosition(60, 30);
233 textUnavailable.setSize(osd.getWidth() - 120, 30);
234 textUnavailable.setText(tr("Channel Unavailable"));
235 textUnavailable.setVisible(false);
236 add(&textUnavailable);
239 Region r1 = summary.getRegionR();
240 Region r2 = osd.getRegionR();
241 osdSummaryRegion = r1 + r2;
244 void VVideoLiveTV::preDelete()
249 VVideoLiveTV::~VVideoLiveTV()
252 video->setDefaultAspect();
256 void VVideoLiveTV::delData()
260 int eventListSize = eventList->size();
261 for(int i = 0; i < eventListSize; i++)
263 delete (*eventList)[i];
272 int VVideoLiveTV::handleCommand(int command)
278 if (osd.getVisible() && !textUnavailable.getVisible())
283 // else drop through to stop
288 vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
292 // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there
313 // Continue new remote only...
314 case Remote::CHANNELUP:
319 case Remote::CHANNELDOWN:
325 // END NEW REMOTE ONLY, START OLD REMOTE ONLY
327 // DF_LEFT and DF_RIGHT never get here because they are stolen
328 // by command as vol- and vol+
330 // Old remote. Decide what to do based on whether
331 // OK was pressed - osd shown manually, use up/down for epg nav
332 // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-
336 // Old remote, decide what to do based on okTriggeredOSD
337 if (okTriggeredOSD) doUpDown(false);
338 else doChanUpDown(UP);
341 case Remote::DF_DOWN:
343 // Old remote, decide what to do based on okTriggeredOSD
344 if (okTriggeredOSD) doUpDown(true);
345 else doChanUpDown(DOWN);
349 // END NEW/OLD REMOTE STUFF
351 case Remote::PREVCHANNEL:
353 channelChange(PREVIOUS, 0);
354 osdChannelIndex = currentChannelIndex;
387 // key in channel number
394 if (streamType == VDR::VIDEO) doAudioSelector();
408 if (streamType = VDR::VIDEO)
409 (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
416 void VVideoLiveTV::go()
420 boxstack->update(this);
425 player->go(currentChannelIndex);
428 void VVideoLiveTV::stop()
430 Timers::getInstance()->cancelTimer(this, 1);
431 Timers::getInstance()->cancelTimer(this, 2);
436 void VVideoLiveTV::doLeftRight(bool right)
438 if (osd.getVisible())
440 if (right) osdChannelIndex = upChannel(osdChannelIndex);
441 else osdChannelIndex = downChannel(osdChannelIndex);
445 osdChannelIndex = currentChannelIndex;
450 void VVideoLiveTV::doUpDown(bool down)
452 if (osd.getVisible())
466 void VVideoLiveTV::doChanUpDown(int which)
468 channelChange(OFFSET, which);
469 osdChannelIndex = currentChannelIndex;
473 void VVideoLiveTV::doOK()
475 if (osd.getVisible())
480 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
482 channelChange(NUMBER, newChannel);
483 osdChannelIndex = currentChannelIndex;
486 else if (osdChannelIndex == currentChannelIndex)
492 channelChange(INDEX, osdChannelIndex);
498 osdChannelIndex = currentChannelIndex;
500 okTriggeredOSD = true;
504 void VVideoLiveTV::doSummary()
506 if (summary.getVisible())
508 summary.setVisible(false);
510 boxstack->update(this, summary.getRegion());
511 Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
515 summary.setVisible(true);
517 if (osd.getVisible())
519 Timers::getInstance()->cancelTimer(this, 1);
528 void VVideoLiveTV::doKey(int command)
530 if (!osd.getVisible()) // First key. prep the data
537 for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
538 keyingInput[0] = command;
541 char* keyingString = new char[numberWidth + 1];
542 for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
543 keyingString[numberWidth] = '\0';
545 for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
547 if (keying == numberWidth)
550 for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
552 channelChange(NUMBER, newChannel);
553 osdChannelIndex = currentChannelIndex;
554 Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
555 displayOSD(true); // this will put one back if required
559 osdChanNum.setText(keyingString);
561 if (!osd.getVisible())
563 osd.setVisible(true);
570 boxstack->update(this, osd.getRegion());
571 Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input
573 delete[] keyingString;
576 void VVideoLiveTV::doAudioSelector()
578 // If the osd is already visisble there might be a timer for it
579 Timers::getInstance()->cancelTimer(this, 1);
585 // and reset the display - this is a copy from setNowNextData
586 char formatChanNum[20];
587 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
588 osdChanNum.setText(formatChanNum);
589 osdChanName.setText((*chanList)[osdChannelIndex]->name);
593 vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel());
594 Colour osdBack = Colour(0, 0, 0, 128);
595 vas->setBackgroundColour(osdBack);
596 vas->setPosition(0, osd.getScreenY() - vas->getHeight());
599 // make vas != null and displayOSD will not set a timer or do any boxstack update
600 summary.setVisible(false);
601 if (osd.getVisible()) displayOSD(false);
602 else displayOSD(true);
605 BoxStack::getInstance()->add(vas);
606 BoxStack::getInstance()->update(this);
607 BoxStack::getInstance()->update(vas);
610 void VVideoLiveTV::doEPG()
612 if (osd.getVisible()) clearScreen();
614 video->setMode(Video::QUARTER);
615 video->setPosition(170, 5); //TODO need to deal with 4:3 switching
617 VEpg* vepg = new VEpg(this, currentChannelIndex, streamType);
620 boxstack->update(vepg);
623 void VVideoLiveTV::setNowNextData()
627 Channel* currentChannel = (*chanList)[osdChannelIndex];
629 char formatChanNum[20];
630 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
631 osdChanNum.setText(formatChanNum);
632 osdChanName.setText(currentChannel->name);
634 eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
638 sl.addOption(tr("No channel data available"), 0, 1);
642 sort(eventList->begin(), eventList->end(), EventSorter());
644 char tempString[300];
645 char tempString2[300];
648 int eventListSize = eventList->size();
649 for(int i = 0; i < eventListSize; i++)
651 event = (*eventList)[i];
653 //btime = localtime((time_t*)&event->time);
654 time_t etime = event->time;
655 btime = localtime(&etime);
657 strftime(tempString2, 299, "%0H:%0M ", btime);
659 strftime(tempString2, 299, "%H:%M ", btime);
661 SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
663 sl.addOption(tempString, (ULONG)event, (i==0));
668 void VVideoLiveTV::setSummaryData()
670 // If osd is not being displayed, sl will be filled with now, current channel
671 // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
672 Event* selectedEvent = (Event*)sl.getCurrentOptionData();
676 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");
677 textSummary.setText(tr("No summary available"));
681 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);
682 textSummary.setText(selectedEvent->description);
686 void VVideoLiveTV::displayOSD(bool newNowNextData)
688 osd.setVisible(true);
696 if (summary.getVisible())
700 boxstack->update(this, &osdSummaryRegion);
704 boxstack->update(this, osd.getRegion());
707 bool setTimer = true;
708 if (vas) setTimer = false;
709 if (summary.getVisible()) setTimer = false;
710 if (textUnavailable.getVisible()) setTimer = false;
712 if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);
715 void VVideoLiveTV::clearScreen()
717 if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
719 textUnavailable.setVisible(false);
720 osd.setVisible(false);
721 summary.setVisible(false);
723 okTriggeredOSD = false;
726 boxstack->update(this);
729 void VVideoLiveTV::showUnavailable()
731 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");
732 textUnavailable.setVisible(true);
733 textUnavailable.draw();
735 if (!osd.getVisible()) displayOSD(true);
737 boxstack->update(this, textUnavailable.getRegion());
740 void VVideoLiveTV::setClock()
745 struct tm* tms = localtime(&t);
746 strftime(timeString, 19, "%H:%M", tms);
747 clock.setText(timeString);
749 time_t dt = 60 - (t % 60); // seconds to the next minute
750 if (dt == 0) dt = 60; // advance a whole minute if necessary
751 dt += t; // get a time_t value for it rather than using duration
752 // (so it will occur at the actual second and not second and a half)
754 Timers::getInstance()->setTimerT(this, 2, dt);
757 void VVideoLiveTV::timercall(int ref)
764 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
766 Message* m = new Message();
767 m->message = Message::CHANNEL_CHANGE;
769 m->parameter = newChannel;
770 m->tag = 1; // signal to call displayOSD();
771 Command::getInstance()->postMessageFromOuterSpace(m);
775 // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
776 if (preBuffering < 100)
778 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");
779 Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
783 osd.setVisible(false);
784 okTriggeredOSD = false;
786 boxstack->update(this, osd.getRegion());
792 if (osd.getVisible())
795 boxstack->update(this, osd.getRegion());
800 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
804 if (changeType == INDEX)
806 newChannel = newData;
808 else if (changeType == NUMBER)
811 for(i = 0; i < chanList->size(); i++)
813 if ((*chanList)[i]->number == (UINT)newData)
820 if (i == chanList->size())
826 else if (changeType == OFFSET)
828 if (newData == UP) newChannel = upChannel(currentChannelIndex);
829 else newChannel = downChannel(currentChannelIndex);
831 else if (changeType == PREVIOUS)
833 newChannel = previousChannelIndex;
837 return false; // bad input
840 if (newChannel == currentChannelIndex) return true;
842 previousChannelIndex = currentChannelIndex;
843 currentChannelIndex = newChannel;
847 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
848 player->setChannel(currentChannelIndex);
849 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
851 // Blank out the symbols
852 sAspectRatio.setVisible(false);
853 bufferBar.setPercent(0);
854 sAudioChannels.setVisible(false);
856 // Remove other stuff
857 if (textUnavailable.getVisible())
859 textUnavailable.setVisible(false);
861 BoxStack::getInstance()->update(this);
867 void VVideoLiveTV::processMessage(Message* m)
869 if (m->message == Message::MOUSE_LBDOWN)
871 //check if press is outside this view! then simulate cancel
872 int x=(m->parameter>>16)-osd.getScreenX();
873 int y=(m->parameter&0xFFFF)-osd.getScreenY();
874 if (osd.getVisible()) {
876 if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
877 (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
878 BoxStack::getInstance()->handleCommand(Remote::RED);
879 } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
880 (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
881 BoxStack::getInstance()->handleCommand(Remote::GREEN);
882 } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
883 (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
884 BoxStack::getInstance()->handleCommand(Remote::YELLOW);
885 } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
886 (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
887 BoxStack::getInstance()->handleCommand(Remote::BLUE);
889 BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
893 BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
896 else if (m->message == Message::CHANNEL_CHANGE)
898 channelChange(NUMBER, m->parameter);
899 osdChannelIndex = currentChannelIndex;
900 if (m->tag == 1) displayOSD(true);
902 else if (m->message == Message::EPG_CLOSE)
904 video->setMode(videoMode);
906 else if (m->message == Message::CHILD_CLOSE)
914 else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
916 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
917 player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16);
919 else if (m->message == Message::PLAYER_EVENT)
923 case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
925 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
926 Command::getInstance()->connectionLost();
930 case PlayerLiveTV::STREAM_END:
932 // Message comes from playerlivetv through master mutex, so can do anything here
937 case PlayerLiveTV::ASPECT43:
939 if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
941 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
944 BoxStack::getInstance()->update(this, &wssRegion);
947 sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
948 sAspectRatio.setVisible(true);
950 if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
953 BoxStack::getInstance()->update(this, osd.getRegion());
958 case PlayerLiveTV::ASPECT169:
960 if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
962 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
965 BoxStack::getInstance()->update(this, &wssRegion);
968 sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
969 sAspectRatio.setVisible(true);
971 if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
974 BoxStack::getInstance()->update(this, osd.getRegion());
979 case PlayerLiveTV::PREBUFFERING:
981 preBuffering = m->tag;
982 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);
983 bufferBar.setPercent(preBuffering);
985 if (osd.getVisible())
987 bufferBar.setVisible(true);
990 bufferBar.getRootBoxRegion(&r); ///////// FIXME !!!
991 BoxStack::getInstance()->update(this, &r);
993 if (preBuffering == 100)
995 doAudioChannelSymbol();
1003 void VVideoLiveTV::doAudioChannelSymbol()
1006 Channel* currentChannel = (*chanList)[osdChannelIndex];
1008 bool multiAudio = false;
1010 if (currentChannel->numDPids > 1) multiAudio = true;
1012 if (currentChannel->numAPids > 1) multiAudio = true;
1016 if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;
1017 else sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;
1018 sAudioChannels.setVisible(true);
1020 if (osd.getVisible())
1022 sAudioChannels.draw();
1024 sAudioChannels.getRootBoxRegion(&r); ///////// FIXME !!!
1028 BoxStack::getInstance()->update(this, &r);
1032 UINT VVideoLiveTV::upChannel(UINT index)
1034 if (index == (chanList->size() - 1)) // at the end
1035 return 0; // so go to start
1040 UINT VVideoLiveTV::downChannel(UINT index)
1042 if (index == 0) // at the start
1043 return chanList->size() - 1; // so go to end
1048 void VVideoLiveTV::toggleChopSides()
1050 if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
1052 if (videoMode == Video::NORMAL)
1054 videoMode = Video::LETTERBOX;
1055 video->setMode(Video::LETTERBOX);
1059 videoMode = Video::NORMAL;
1060 video->setMode(Video::NORMAL);
1064 void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
1066 drawBitmap(posX, posY, bm);
1068 r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
1069 boxstack->update(this, &r);
1072 void VVideoLiveTV::clearOSD()
1074 rectangle(area, Colour(0,0,0,0));
1075 boxstack->update(this, &area);
1078 void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
1081 r.x = posX; r.y = posY; r.w = width; r.h = height;
1082 rectangle(r, Colour(0,0,0,0));
1083 boxstack->update(this, &r);