diff options
26 files changed, 1192 insertions, 246 deletions
diff --git a/data/Makefile.am b/data/Makefile.am index c866eacd..ed26ec5c 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -5,4 +5,4 @@ SUBDIRS = countries fonts defaults extensions installdir = $(DATADIR)/enigma2 install_DATA = \ - *.xml *.png encoding.conf + *.xml *.png encoding.conf radio.mvi diff --git a/data/keymap.xml b/data/keymap.xml index 835c5218..5c0cb54b 100644 --- a/data/keymap.xml +++ b/data/keymap.xml @@ -300,6 +300,18 @@ <key id="KEY_TEXT" mapto="startTeletext" flags="m" /> </map> + <map context="InfobarRdsActions"> + <key id="KEY_TEXT" mapto="startRassInteractive" flags="m" /> + </map> + + <map context="RassInteractiveActions"> + <key id="KEY_LEFT" mapto="prevSubPage" flags="mr" /> + <key id="KEY_RIGHT" mapto="nextSubPage" flags="mr" /> + <key id="KEY_UP" mapto="prevPage" flags="mr" /> + <key id="KEY_DOWN" mapto="nextPage" flags="mr" /> + <key id="KEY_EXIT" mapto="exit" flags="m" /> + </map> + <map context="ChannelSelectBaseActions"> <key id="KEY_RED" mapto="showAllServices" flags="m" /> <key id="KEY_GREEN" mapto="showSatellites" flags="m" /> diff --git a/data/radio.mvi b/data/radio.mvi Binary files differnew file mode 100755 index 00000000..bbd8016e --- /dev/null +++ b/data/radio.mvi diff --git a/lib/python/Components/Converter/RadioText.py b/data/rass_logo.png index e69de29b..e69de29b 100644 --- a/lib/python/Components/Converter/RadioText.py +++ b/data/rass_logo.png diff --git a/lib/python/Components/Sources/RadioText.py b/data/rass_page1.png index e69de29b..e69de29b 100644 --- a/lib/python/Components/Sources/RadioText.py +++ b/data/rass_page1.png diff --git a/data/rass_page2.png b/data/rass_page2.png new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/data/rass_page2.png diff --git a/data/rass_page3.png b/data/rass_page3.png new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/data/rass_page3.png diff --git a/data/rass_page4.png b/data/rass_page4.png new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/data/rass_page4.png diff --git a/data/skin.xml b/data/skin.xml index 36f73255..cf2d2c73 100644 --- a/data/skin.xml +++ b/data/skin.xml @@ -45,18 +45,13 @@ <font filename="ae_AlMateen.ttf" name="Replacement" scale="90" replacement="1" /> </fonts> - <screen name="InfoBar" flags="wfNoBorder" position="0,330" size="720,198" title="InfoBar" backgroundColor="transparent" > - - <widget source="RadioText" render="Label" position="50,0" size="620,50" font="LCD;25" backgroundColor="transparent"> - <convert type="RadioText">RadioText</convert> - </widget> - - <ePixmap position="0,50" zPosition="-1" size="720,148" pixmap="info-bg.png" /> + <screen name="InfoBar" flags="wfNoBorder" position="0,380" size="720,148" title="InfoBar" backgroundColor="transparent" > + <ePixmap position="0,0" zPosition="-1" size="720,148" pixmap="info-bg.png" /> <!-- not used in this skin yet --> - <widget name="NimA" position="0,50" size="0,0" /> - <widget name="NimB" position="0,50" size="0,0" /> - <widget name="NimA_Active" position="0,50" size="0,0" /> - <widget name="NimB_Active" position="0,50" size="0,0" /> + <widget name="NimA" position="0,0" size="0,0" /> + <widget name="NimB" position="0,0" size="0,0" /> + <widget name="NimA_Active" position="0,0" size="0,0" /> + <widget name="NimB_Active" position="0,0" size="0,0" /> <!-- 'teletext available' <widget source="CurrentService" render="Pixmap" pixmap="format.png" position="613,40" size="28,15"> @@ -66,113 +61,113 @@ --> <!-- ............................................................................. --> - <eLabel text="SNR:" position="195,50" size="40,22" font="Regular;15" transparent="1" /> - <eLabel text="AGC:" position="275,50" size="40,22" font="Regular;15" transparent="1" /> - <eLabel text="BER:" position="355,50" size="40,22" font="Regular;15" transparent="1" /> + <eLabel text="SNR:" position="195,0" size="40,22" font="Regular;15" transparent="1" /> + <eLabel text="AGC:" position="275,0" size="40,22" font="Regular;15" transparent="1" /> + <eLabel text="BER:" position="355,0" size="40,22" font="Regular;15" transparent="1" /> - <widget source="FrontendStatus" render="Label" position="232,50" size="40,22" font="Regular;15" transparent="1" > + <widget source="FrontendStatus" render="Label" position="232,0" size="40,22" font="Regular;15" transparent="1" > <convert type="FrontendInfo">SNR</convert> </widget> - <widget source="FrontendStatus" render="Label" position="314,50" size="40,22" font="Regular;15" transparent="1" > + <widget source="FrontendStatus" render="Label" position="314,0" size="40,22" font="Regular;15" transparent="1" > <convert type="FrontendInfo">AGC</convert> </widget> - <widget source="FrontendStatus" render="Label" position="392,50" size="53,22" font="Regular;15" transparent="1" > + <widget source="FrontendStatus" render="Label" position="392,0" size="53,22" font="Regular;15" transparent="1" > <convert type="FrontendInfo">BER</convert> </widget> - <widget source="FrontendStatus" render="Progress" position="447,51" size="88,6" pixmap="rtgbar.png" > + <widget source="FrontendStatus" render="Progress" position="447,1" size="88,6" pixmap="rtgbar.png" > <convert type="FrontendInfo">SNR</convert> </widget> - <widget source="FrontendStatus" render="Progress" position="447,58" size="88,6" pixmap="rtgbar.png" > + <widget source="FrontendStatus" render="Progress" position="447,8" size="88,6" pixmap="rtgbar.png" > <convert type="FrontendInfo">AGC</convert> </widget> - <widget source="FrontendStatus" render="Progress" position="447,65" size="88,6" > + <widget source="FrontendStatus" render="Progress" position="447,15" size="88,6" > <convert type="FrontendInfo">BER</convert> </widget> - <widget name="BlinkingPoint" pixmap="record.png" position="430,81" zPosition="2" size="58,25" alphatest="on" /> + <widget name="BlinkingPoint" pixmap="record.png" position="430,31" zPosition="2" size="58,25" alphatest="on" /> <!-- show 'is crypted' icon when service is crypted. --> - <widget source="CurrentService" render="Pixmap" pixmap="crypt.png" position="570,90" size="12,15" > + <widget source="CurrentService" render="Pixmap" pixmap="crypt.png" position="570,40" size="12,15" > <convert type="ServiceInfo">IsCrypted</convert> <convert type="ConditionalShowHide" /> </widget> <!-- show 'multichannel' icon when service has multichannel audio. --> - <widget source="CurrentService" render="Pixmap" pixmap="dolby.png" position="585,90" size="25,15"> + <widget source="CurrentService" render="Pixmap" pixmap="dolby.png" position="585,40" size="25,15"> <convert type="ServiceInfo">IsMultichannel</convert> <convert type="ConditionalShowHide" /> </widget> - <widget source="CurrentService" render="Pixmap" pixmap="format.png" position="613,90" size="28,15"> + <widget source="CurrentService" render="Pixmap" pixmap="format.png" position="613,40" size="28,15"> <convert type="ServiceInfo">IsWidescreen</convert> <convert type="ConditionalShowHide" /> </widget> - <widget source="CurrentService" render="Label" position="69,76" size="427,34" font="Regular;22" backgroundColor="#101258" > + <widget source="CurrentService" render="Label" position="69,26" size="427,34" font="Regular;22" backgroundColor="#101258" > <convert type="ServiceName">Name</convert> <!-- <convert type="ServiceName">Provider</convert> --> </widget> - <widget source="CurrentTime" render="Label" position="575,60" size="90,30" backgroundColor="dark" font="Regular;19" > + <widget source="CurrentTime" render="Label" position="575,10" size="90,30" backgroundColor="dark" font="Regular;19" > <convert type="ClockToText">WithSeconds</convert> </widget> - <widget source="Event_Now" render="Label" position="210,118" size="60,22" font="Regular;20" backgroundColor="dark"> + <widget source="Event_Now" render="Label" position="210,68" size="60,22" font="Regular;20" backgroundColor="dark"> <convert type="EventTime">StartTime</convert> <convert type="ClockToText">Default</convert> </widget> - <widget source="Event_Next" render="Label" position="210,148" size="60,22" font="Regular;20" backgroundColor="dark"> + <widget source="Event_Next" render="Label" position="210,98" size="60,22" font="Regular;20" backgroundColor="dark"> <convert type="EventTime">StartTime</convert> <convert type="ClockToText">Default</convert> </widget> - <widget source="Event_Now" render="Label" position="273,118" size="282,22" font="Regular;20" backgroundColor="dark"> + <widget source="Event_Now" render="Label" position="273,68" size="282,22" font="Regular;20" backgroundColor="dark"> <convert type="EventName">Name</convert> </widget> - <widget source="Event_Next" render="Label" position="273,148" size="282,22" font="Regular;20" backgroundColor="dark"> + <widget source="Event_Next" render="Label" position="273,98" size="282,22" font="Regular;20" backgroundColor="dark"> <convert type="EventName">Name</convert> </widget> - <widget source="Event_Now" render="Label" position="555,118" size="100,26" font="Regular;22" backgroundColor="dark" halign="right"> + <widget source="Event_Now" render="Label" position="555,68" size="100,26" font="Regular;22" backgroundColor="dark" halign="right"> <convert type="EventTime">Remaining</convert> <convert type="RemainingToText">InMinutes</convert> </widget> - <widget source="Event_Next" render="Label" position="555,148" size="100,26" font="Regular;22" backgroundColor="dark" halign="right"> + <widget source="Event_Next" render="Label" position="555,98" size="100,26" font="Regular;22" backgroundColor="dark" halign="right"> <convert type="EventTime">Duration</convert> <convert type="ClockToText">InMinutes</convert> </widget> - <widget source="Event_Now" render="Progress" position="304,110" size="121,8" zPosition="1"> + <widget source="Event_Now" render="Progress" position="304,60" size="121,8" zPosition="1"> <convert type="EventTime">Progress</convert> </widget> <!-- red button: is recording possible? --> - <widget source="RecordingPossible" render="Pixmap" pixmap="button_red.png" position="210,182" size="27,12" > + <widget source="RecordingPossible" render="Pixmap" pixmap="button_red.png" position="210,132" size="27,12" > <convert type="ConditionalShowHide" /> </widget> - <widget source="RecordingPossible" render="FixedLabel" text="Record" position="240,180" size="85,22" font="Regular;14" backgroundColor="blue" transparent="1"> + <widget source="RecordingPossible" render="FixedLabel" text="Record" position="240,130" size="85,22" font="Regular;14" backgroundColor="blue" transparent="1"> <convert type="ConditionalShowHide" /> </widget> - <widget source="CurrentService" render="Pixmap" pixmap="button_green.png" position="320,182" size="27,12" > + <widget source="CurrentService" render="Pixmap" pixmap="button_green.png" position="320,132" size="27,12" > <convert type="ServiceInfo">SubservicesAvailable</convert> <convert type="ConditionalShowHide" /> </widget> - <widget source="CurrentService" render="FixedLabel" text="Subservices" position="350,180" size="85,22" font="Regular;14" backgroundColor="blue" transparent="1" > + <widget source="CurrentService" render="FixedLabel" text="Subservices" position="350,130" size="85,22" font="Regular;14" backgroundColor="blue" transparent="1" > <convert type="ServiceInfo">SubservicesAvailable</convert> <convert type="ConditionalShowHide" /> </widget> - <widget source="TimeshiftPossible" render="Pixmap" pixmap="button_yellow.png" position="430,182" size="27,12" > + <widget source="TimeshiftPossible" render="Pixmap" pixmap="button_yellow.png" position="430,132" size="27,12" > <convert type="ConditionalShowHide" /> </widget> - <widget source="TimeshiftPossible" render="FixedLabel" text="Timeshift" position="460,180" size="85,22" font="Regular;14" backgroundColor="blue" transparent="1" > + <widget source="TimeshiftPossible" render="FixedLabel" text="Timeshift" position="460,130" size="85,22" font="Regular;14" backgroundColor="blue" transparent="1" > <convert type="ConditionalShowHide" /> </widget> - <widget source="ExtensionsAvailable" render="Pixmap" pixmap="button_blue.png" position="540,182" size="27,12" > + <widget source="ExtensionsAvailable" render="Pixmap" pixmap="button_blue.png" position="540,132" size="27,12" > <convert type="ConditionalShowHide" /> </widget> - <widget source="ExtensionsAvailable" render="FixedLabel" text="Extensions" position="570,180" size="95,22" font="Regular;14" backgroundColor="blue" transparent="1" > + <widget source="ExtensionsAvailable" render="FixedLabel" text="Extensions" position="570,130" size="95,22" font="Regular;14" backgroundColor="blue" transparent="1" > <convert type="ConditionalShowHide" /> </widget> </screen> diff --git a/data/skin_default.xml b/data/skin_default.xml index 4bdc5c16..65e810d9 100644 --- a/data/skin_default.xml +++ b/data/skin_default.xml @@ -3,8 +3,7 @@ <font filename="lcd.ttf" name="LCD" scale="100" /> </fonts> - <screen name="Standby" flags="wfNoBorder" position="0,0" size="720,576" title="Standby"> - </screen> + <screen name="Standby" flags="wfNoBorder" position="0,0" size="720,576" title="Standby" /> <screen name="Menu" position="210,150" size="300,285" title="Main menu"> <widget name="title" position="10,10" size="280,35" font="Regular;23" /> <!--<widget name="menu" position="10,55" size="280,150" font="Regular;23" />--> @@ -18,8 +17,7 @@ <screen name="ChannelContextMenu" position="210,150" size="300,250" title="Channellist menu"> <widget name="menu" position="10,10" size="300,230" scrollbarMode="showOnDemand" /> </screen> - <screen name="Scart" position="0,0" size="720,576"> - </screen> + <screen name="Scart" position="0,0" size="720,576" /> <screen name="MediaPlayer" position="104,83" size="512,442" title="MediaPlayer"> <eLabel position="11,9" zPosition="1" size="359,78" backgroundColor="#182C40" /> <widget name="artisttext" position="13,11" zPosition="3" size="65,17" font="Regular;16" valign="top" foregroundColor="#cccccc" backgroundColor="#33294a6b" shadowColor="#000000" shadowOffset="-2,-2"/> @@ -75,7 +73,7 @@ <widget name="model" position="20,10" size="380,25" font="Regular;23" /> <widget name="capacity" position="20,40" size="380,25" font="Regular;23" /> <widget name="bus" position="20,70" size="380,25" font="Regular;23" /> - <widget name="initialize" position="150,120" zPosition="1" size="120,30" pixmap="init.png" transparent="1" alphatest="on" /> + <widget name="initialize" position="150,120" zPosition="1" size="120,30" pixmap="init.png" transparent="1" alphatest="on" /> <widget name="initializetext" position="150,120" size="120,30" valign="center" halign="center" zPosition="2" font="Regular;20" transparent="1" /> </screen> <screen name="Setup" position="90,148" size="540,280" title="Setup"> @@ -248,41 +246,43 @@ <widget name="key_yellow" position="280,0" size="140,40" backgroundColor="yellow" font="Regular;21" /> <widget name="key_blue" position="420,0" size="140,40" backgroundColor="blue" font="Regular;21" /> <widget name="list" position="0,45" size="560,196" scrollbarMode="showOnDemand" /> - <widget source="RadioText" render="Label" position="0,241" size="560,66" font="LCD;25" > - <convert type="RadioText">RadioText</convert> + <widget source="RdsDecoder" render="Label" position="0,241" size="560,66" font="LCD;25" > + <convert type="RdsInfo">RadioText</convert> </widget> </screen> <screen name="RadioInfoBar" position="90,420" size="560,105" zPosition="-1"> <widget source="CurrentService" render="Label" position="0,0" size="390,26" font="Regular;22" backgroundColor="dark" > <convert type="ServiceName">Name</convert> </widget> - <widget name="BlinkingPoint" pixmap="record.png" position="400,0" zPosition="2" size="58,25" /> <widget source="CurrentTime" render="Label" position="465,0" size="95,28" font="Regular;22" backgroundColor="dark" > <convert type="ClockToText">WithSeconds</convert> </widget> <widget source="Event_Now" render="Progress" position="465,27" size="90,9" zPosition="1" borderWidth="2" > <convert type="EventTime">Progress</convert> </widget> - <widget source="Event_Now" render="Label" position="0,44" size="60,22" font="Regular;20" backgroundColor="dark" > - <convert type="EventTime">StartTime</convert> - <convert type="ClockToText">Default</convert> + <widget source="RdsDecoder" render="Pixmap" pixmap="rass_logo.png" position="0,27" size="50,21" > + <convert type="RdsInfo">RasInteractiveAvailable</convert> + <convert type="ConditionalShowHide" /> </widget> - <widget source="Event_Next" render="Label" position="0,74" size="60,22" font="Regular;20" backgroundColor="dark" > + <widget source="Event_Now" render="Label" position="0,49" size="60,22" font="Regular;20" backgroundColor="dark" > <convert type="EventTime">StartTime</convert> <convert type="ClockToText">Default</convert> </widget> - <widget source="Event_Now" render="Label" position="80,44" size="380,22" font="Regular;20" backgroundColor="dark" > - <convert type="EventName">Name</convert> - </widget> - <widget source="Event_Next" render="Label" position="80,74" size="380,22" font="Regular;20" backgroundColor="dark" > + <widget source="Event_Now" render="Label" position="80,49" size="380,22" font="Regular;20" backgroundColor="dark" > <convert type="EventName">Name</convert> </widget> - - <widget source="Event_Now" render="Label" position="470,44" size="150,22" font="Regular;20" backgroundColor="dark" > + <widget source="Event_Now" render="Label" position="470,49" size="150,22" font="Regular;20" backgroundColor="dark" > <convert type="EventTime">Remaining</convert> <convert type="RemainingToText">InMinutes</convert> </widget> - <widget source="Event_Next" render="Label" position="470,74" size="150,22" font="Regular;20" backgroundColor="dark" > + <widget source="Event_Next" render="Label" position="80,79" size="380,22" font="Regular;20" backgroundColor="dark" > + <convert type="EventName">Name</convert> + </widget> + <widget source="Event_Next" render="Label" position="0,79" size="60,22" font="Regular;20" backgroundColor="dark" > + <convert type="EventTime">StartTime</convert> + <convert type="ClockToText">Default</convert> + </widget> + <widget source="Event_Next" render="Label" position="470,79" size="150,22" font="Regular;20" backgroundColor="dark" > <convert type="EventTime">Duration</convert> <convert type="ClockToText">InMinutes</convert> </widget> @@ -331,11 +331,50 @@ <screen name="PictureInPicture" position="400,60" size="240,192" zPosition="-1" flags="wfNoBorder" > <widget name="video" position="0,0" size="240,192" /> </screen> - <screen name="SubtitleDisplay" position="0,0" size="720,568" zPosition="-1" flags="wfNoBorder" > + + <screen name="SubtitleDisplay" position="0,0" size="720,568" zPosition="-1" flags="wfNoBorder" /> + + <colors> + <color name="rds_bg" value="#77ffffff" /> + <color name="rds_fg" value="#000000" /> + <color name="rds_text_bg" value="#003258" /> + </colors> + + <screen name="RdsInfoDisplay" backgroundColor="transparent" position="0,0" size="720,568" zPosition="-2" flags="wfNoBorder" > + <widget name="RadioText" backgroundColor="rds_text_bg" position="50,481" size="620,29" font="Regular;21" noWrap="1" shadowOffset="-2,-2" shadowColor="transpBlack" /> + <widget name="RtpText" backgroundColor="rds_text_bg" position="50,510" size="620,29" font="Regular;21" halign="right" noWrap="1" shadowOffset="-2,-2" shadowColor="transpBlack" /> + <widget name="RassLogo" pixmap="rass_logo.png" position="50,445" size="50,21" /> </screen> + + <screen name="RassInteractive" backgroundColor="rds_bg" position="50,180" size="100,275" flags="wfNoBorder" > + <ePixmap pixmap="rass_logo.png" position="0,0" size="100,21" /> + <eLabel text="Index" position="36,25" size="60,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <eLabel text="0" position="5,25" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="Marker" position="21,25" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <eLabel text="1" position="5,50" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_1" position="35,50" size="36,20" alphatest="on" /> + <eLabel text="2" position="5,75" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_2" position="35,75" size="36,20" alphatest="on" /> + <eLabel text="3" position="5,100" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_3" position="35,100" size="36,20" alphatest="on" /> + <eLabel text="4" position="5,125" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_4" position="35,125" size="36,20" alphatest="on" /> + <eLabel text="5" position="5,150" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_5" position="35,150" size="36,20" alphatest="on" /> + <eLabel text="6" position="5,175" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_6" position="35,175" size="36,20" alphatest="on" /> + <eLabel text="7" position="5,200" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_7" position="35,200" size="36,20" alphatest="on" /> + <eLabel text="8" position="5,225" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_8" position="35,225" size="36,20" alphatest="on" /> + <eLabel text="9" position="5,250" size="16,25" font="Regular;21" foregroundColor="rds_fg" backgroundColor="rds_bg" /> + <widget name="subpages_9" position="35,250" size="36,20" alphatest="on" /> + </screen> + <screen name="PiPSetup" backgroundColor="transparent" position="70,400" size="600,150" title="PiPSetup" flags="wfNoBorder"> <widget name="text" position="0,0" size="600,150" font="Regular;23" /> </screen> + <screen name="MovieSelection" position="90,78" size="560,455" title="Select a movie"> <widget name="key_red" position="0,0" size="140,40" backgroundColor="red" font="Regular;21" /> <widget name="key_green" position="140,0" size="140,40" backgroundColor="green" font="Regular;21" /> diff --git a/lib/dvb/radiotext.cpp b/lib/dvb/radiotext.cpp index 87498da9..eff40e92 100644 --- a/lib/dvb/radiotext.cpp +++ b/lib/dvb/radiotext.cpp @@ -3,19 +3,45 @@ #include <lib/dvb/idemux.h> #include <lib/gdi/gpixmap.h> -DEFINE_REF(eDVBRadioTextParser); +DEFINE_REF(eDVBRdsDecoder); -eDVBRadioTextParser::eDVBRadioTextParser(iDVBDemux *demux) - :bytesread(0), ptr(0), p1(-1), p2(-1), msgPtr(0), state(0) +eDVBRdsDecoder::eDVBRdsDecoder(iDVBDemux *demux) + :msgPtr(0), bsflag(0), qdar_pos(0), t_ptr(0), qdarmvi_show(0), state(0) ,m_abortTimer(eApp) { setStreamID(0xC0, 0xC0); + memset(rass_picture_mask, 0, sizeof(rass_picture_mask)); + if (demux->createPESReader(eApp, m_pes_reader)) eDebug("failed to create PES reader!"); else - m_pes_reader->connectRead(slot(*this, &eDVBRadioTextParser::processData), m_read_connection); - CONNECT(m_abortTimer.timeout, eDVBRadioTextParser::abortNonAvail); + m_pes_reader->connectRead(slot(*this, &eDVBRdsDecoder::processData), m_read_connection); + CONNECT(m_abortTimer.timeout, eDVBRdsDecoder::abortNonAvail); +} + +eDVBRdsDecoder::~eDVBRdsDecoder() +{ + // delete cached rass slides + for (int page=0; page < 10; ++page) + { + unsigned char mask = rass_picture_mask[(page*4)/8]; + if (page % 2) + mask >>= 4; + int subpage=0; + while(mask) + { + if (mask & 1) + { + std::string filename = getRassPicture(page, subpage); + if (filename.length()) + remove(filename.c_str()); + } + mask >>= 1; + ++subpage; + } + } + remove("/tmp/RassLast.mvi"); } #define SWAP(x) ((x<<8)|(x>>8)) @@ -65,14 +91,54 @@ static int frequency[3][4] = { { 11025,12000,8000,0 } }; -void eDVBRadioTextParser::connectUpdatedRadiotext(const Slot0<void> &slot, ePtr<eConnection> &connection) +void eDVBRdsDecoder::connectEvent(const Slot1<void, int> &slot, ePtr<eConnection> &connection) { - connection = new eConnection(this, m_updated_radiotext.connect(slot)); + connection = new eConnection(this, m_event.connect(slot)); } -void eDVBRadioTextParser::processPESPacket(__u8 *data, int len) +void eDVBRdsDecoder::addToPictureMask(int id) +{ + int page = id / 1000; + int tmp = page > 0 ? id / page : id; + int subpage = 0; + while(tmp > 1000) + { + ++subpage; + tmp -= 1000; + tmp *= 10; + } + int index = (page*4+subpage)/8; + int val = (page%2) ? 16 * (1 << subpage) : (1 << subpage); + if (rass_picture_mask[index] & val) // already have this picture + return; + rass_picture_mask[index] |= val; + /* emit */ m_event(RassInteractivePicMaskChanged); +} + +void eDVBRdsDecoder::removeFromPictureMask(int id) +{ + int page = id / 1000; + int tmp = page > 0 ? id / page : id; + int subpage = 0; + while(tmp > 1000) + { + ++subpage; + tmp -= 1000; + tmp *= 10; + } + int index = (page*4)/8; + int val = (page%2) ? 16 * (1 << subpage) : (1 << subpage); + if (rass_picture_mask[index] & val) // have this picture + { + rass_picture_mask[index] &= ~val; + /* emit */ m_event(RassInteractivePicMaskChanged); + } +} + +void eDVBRdsDecoder::processPESPacket(__u8 *data, int len) { int pos=9+data[8];// skip pes header + int cnt=0; while (pos < len) { @@ -130,137 +196,440 @@ void eDVBRadioTextParser::processPESPacket(__u8 *data, int len) m_abortTimer.stop(); int ancillary_len = 1 + data[offs - 1]; offs -= ancillary_len; - while(offs < pos) - gotAncillaryByte(data[offs++]); + gotAncillaryData(data+offs, ancillary_len); } } } -inline void eDVBRadioTextParser::gotAncillaryByte(__u8 data) +void eDVBRdsDecoder::process_qdar(unsigned char *buf) { - buf[bytesread]=data; - bytesread+=1; - if ( bytesread == 128 ) + if (buf[0] == 0x40 && buf[1] == 0xDA) { - while(ptr<128) + unsigned int item,cnt,ctrl,item_type; + unsigned long item_length,id,item_no,ptr,tmp; + unsigned short crc_qdar,crc_read; + char fname[50]; + ptr=4;cnt=0; + item=buf[2]<<8; // Number of Items + item|=buf[3]; + + while ( cnt++ < item ) //read in items { - if ( buf[ptr] == 0xFD ) - { - if (p1 == -1) - p1 = ptr; - else - p2 = ptr; - } - if ( p1 != -1 && p2 != -1 ) + id=buf[ptr++]<<8; //QDarID + id|=buf[ptr++]; + + item_no=buf[ptr++]<<8; // Item Number + item_no|=buf[ptr++]; + + ctrl=buf[ptr++]; //controlbyte + item_type=buf[ptr++]; //item type + + item_length=buf[ptr++]<<24; // Item length + item_length|=buf[ptr++]<<16; + item_length|=buf[ptr++]<<8; + item_length|=buf[ptr++]; + + ptr=ptr+4; // rfu Bytes ... not used + tmp=ptr; // calc crc + crc_qdar=0xFFFF; + while (tmp < ptr+item_length) + crc_qdar = crc_ccitt_byte(crc_qdar, buf[tmp++]); + + crc_read=buf[ptr+item_length]<<8; + crc_read|=buf[ptr+item_length+1]; + //eDebug("[RDS/Rass] CRC read: %04X calculated: %04X",crc_read,crc_qdar^0xFFFF); + + if (crc_read == (crc_qdar^0xFFFF)) // process item { - int cnt=buf[--p2]; - while ( cnt-- > 0 ) + switch(item_type) { - unsigned char c = buf[--p2]; - if ( state == 1 ) - crc=0xFFFF; - if ( state >= 1 && state < 11 ) - crc = crc_ccitt_byte(crc, c); - - switch (state) - { - case 0: - if ( c==0xFE ) // Startkennung - state=1; - break; - case 1: // 10bit Site Address + 6bit Encoder Address - case 2: - case 3: // Sequence Counter - ++state; - break; - case 4: - leninfo=c; - ++state; - break; - case 5: - if ( c==0x0A ) // message element code 0x0A Radio Text - ++state; - else - state=0; - break; - case 6: // Data Set Number ... ignore - case 7: // Program Service Number ... ignore - ++state; - break; - case 8: // Message Element Length - todo=c; - if ( !todo || todo > 65 || todo > leninfo-4) - state=0; + case 0x01: //Stillframe + if (ctrl&0x01) // display slide + { + sprintf(fname,"/tmp/RassLast.mvi"); + FILE *fh=fopen(fname,"wb"); + fwrite(buf+ptr,1,item_length-2,fh); + fclose(fh); + /*emit*/ m_event(RecvRassSlidePic); + qdarmvi_show=1; + } + if (ctrl&0x02) // save slide for interactive mode + { + if (id == 0 || id >= 1000) + { + sprintf(fname,"/tmp/Rass%04d.mvi",(int)id); + FILE *fh=fopen(fname,"wb"); + fwrite(buf+ptr,1,item_length-2,fh); + fclose(fh); + addToPictureMask(id); + } else + eDebug("ignore recv interactive picture id %lu", id); + } + if (ctrl&0x04) // display slide if nothing had been displayed yet + { + if (qdarmvi_show != 1) { - ++state; - todo-=2; - msgPtr=0; + sprintf(fname,"/tmp/RassLast.mvi"); + FILE *fh=fopen(fname,"wb"); + fwrite(buf+ptr,1,item_length-2,fh); + fclose(fh); + /*emit*/ m_event(RecvRassSlidePic); + qdarmvi_show=1; } - break; - case 9: // Radio Text Status bit: - // 0 = AB-flagcontrol - // 1-4 = Transmission-Number - // 5-6 = Buffer-Config - ++state; // ignore ... - break; - case 10: - // TODO build a complete radiotext charcode to UTF8 conversion table for all character > 0x80 - switch (c) + } + if (ctrl&0x08) // delete slide + { + eDebug("delete slide id %lu, item_no %lu", id, item_no); + if (id == 0 || id >= 1000) { - case 0 ... 0x7f: break; - case 0x8d: c='ß'; break; - case 0x91: c='ä'; break; - case 0xd1: c='Ä'; break; - case 0x97: c='ö'; break; - case 0xd7: c='Ö'; break; - case 0x99: c='ü'; break; - case 0xd9: c='Ü'; break; - default: c=' '; break; // convert all unknown to space + eDebug("delete %lu", id); + removeFromPictureMask(id); + sprintf(fname,"/tmp/Rass%04d.mvi",(int)id); // was item_no ? ! ? + remove(fname); } - message[msgPtr++]=c; - if(todo) - --todo; else - ++state; - break; - case 11: - crc16=c<<8; + eDebug("ignore del interactive picture id %lu", id); + } + break; + default: //nothing more yet defined + break; + } + } + else + { + eDebug("[RDS/Rass] CRC error, skip Rass-Qdar-Item"); + } + + ptr=+item_length; + } + } + else + { + eDebug("[RDS/Rass] No Rass-QDAR archive (%02X %02X) so skipping !\n",buf[0],buf[1]); + } +} + +inline void eDVBRdsDecoder::gotAncillaryData(__u8 *buf, int len) +{ + int cnt=buf[--len]; + while ( cnt-- > 0 ) + { + unsigned char c = buf[--len]; + + if (bsflag == 1) // byte stuffing + { + bsflag=2; + switch (c) + { + case 0x00: c=0xFD; break; + case 0x01: c=0xFE; break; + case 0x02: c=0xFF; break; + } + } + + if (c == 0xFD && bsflag ==0) + bsflag=1; + else + bsflag=0; + + if (bsflag == 0) + { + if ( state == 1 ) + crc=0xFFFF; + if (( state >= 1 && state < 11 ) || ( state >=26 && state < 36 )) + crc = crc_ccitt_byte(crc, c); + + switch (state) + { + case 0: + if ( c==0xFE ) // Startkennung + state=1; + break; + case 1: // 10bit Site Address + 6bit Encoder Address + case 2: + case 3: // Sequence Counter + ++state; + break; + case 4: + leninfo=c; + ++state; + break; + case 5: + switch (c) + { + case 0x0A: // Radiotext ++state; break; - case 12: - crc16|=c; - message[msgPtr--]=0; - while(message[msgPtr] == ' ' && msgPtr > 0) - message[msgPtr--] = 0; - if ( crc16 == (crc^0xFFFF) ) + case 0x46: // Radiotext Plus tags + state=38; + break; + case 0xDA: // Rass + state=26; + break; + default: // reset to state 0 + state=0; + } + break; + + // process Radiotext + case 6: // Data Set Number ... ignore + case 7: // Program Service Number ... ignore + ++state; + break; + case 8: // Message Element Length + text_len=c; + if ( !text_len || text_len > 65 || text_len > leninfo-4) + state=0; + else + { + ++state; + text_len-=2; + msgPtr=0; + } + break; + case 9: // Radio Text Status bit: + // 0 = AB-flagcontrol + // 1-4 = Transmission-Number + // 5-6 = Buffer-Config + ++state; // ignore ... + break; + case 10: + // TODO build a complete radiotext charcode to UTF8 conversion table for all character > 0x80 + switch (c) + { + case 0 ... 0x7f: break; + case 0x8d: c='ß'; break; + case 0x91: c='ä'; break; + case 0xd1: c='Ä'; break; + case 0x97: c='ö'; break; + case 0xd7: c='Ö'; break; + case 0x99: c='ü'; break; + case 0xd9: c='Ü'; break; + default: c=' '; break; // convert all unknown to space + } + message[msgPtr++]=c; + if(text_len) + --text_len; + else + ++state; + break; + case 11: + crc16=c<<8; + ++state; + break; + case 12: + crc16|=c; + message[msgPtr--]=0; + while(message[msgPtr] == ' ' && msgPtr > 0) + message[msgPtr--] = 0; + if ( crc16 == (crc^0xFFFF) ) + { + eDebug("radiotext: (%s)", message); + /*emit*/ m_event(RadioTextChanged); + memcpy(lastmessage,message,66); + } + else + eDebug("invalid radiotext crc (%s)", message); + state=0; + break; + + // process Rass + case 26: //MEL + text_len = c; + text_len2 = c; + ++state; + text_len-=9; + text_len2-=9; + t_ptr=0; + break; + case 27: // SID not used atm + ++state; + break; + case 28: // SID not used atm + ++state; + break; + case 29: // PNR packet number + part=c<<16; + ++state; + break; + case 30: // PNR packet number + part|=c<<8; + ++state; + break; + case 31: // PNR packet number + part|=c; + ++state; + break; + case 32: // NOP number of packets + parts=c<<16; + ++state; + break; + case 33: // NOP number of packets + parts|=c<<8; + ++state; + break; + case 34: // NOP number of packets + parts|=c; + ++state; + break; + case 35: + datamessage[t_ptr++]=c; + if(text_len) + --text_len; + else + ++state; + break; + case 36: + crc16=c<<8; + ++state; + break; + case 37: + crc16|=c; + //eDebug("[RDS/Rass] CRC read: %04X CRC calculated: %04X",crc16,crc^0xFFFF); + state=0; + if ( crc16 == (crc^0xFFFF) ) + { + if (partcnt == -1) + partcnt=1; + if (partcnt == part) + { + memcpy(qdar+qdar_pos,datamessage,text_len2+1); + qdar_pos=qdar_pos+text_len2+1; + if (partcnt == parts) { - eDebug("radiotext: (%s)", message); - /*emit*/ m_updated_radiotext(); + process_qdar(qdar); // decode qdar archive + qdar_pos=0; + partcnt=-1; } else - eDebug("invalid radiotext crc (%s)", message); - state=0; - break; + ++partcnt; + } + else + { + qdar_pos=0; + partcnt=-1; + } } - } - p1=ptr; - p2=-1; + else + { + eDebug("[RDS/Rass] CRC error, skip Rass-Qdar-Packet"); + eDebug("[RDS/Rass] CRC read: %04X CRC calculated: %04X",crc16,crc^0xFFFF); + partcnt=-1; + } + state=0; + break; + + // process RT plus tags ... + case 38: // Message Element Length + text_len=c; + ++state; + break; + case 39: // Application ID + case 40: // always 0x4BD7 so we ignore it ;) + case 41: // Applicationgroup Typecode/PTY ... ignore + ++state; + break; + case 42: + rtp_buf[0]=c; + ++state; + break; + case 43: + rtp_buf[1]=c; + ++state; + break; + case 44: + rtp_buf[2]=c; + ++state; + break; + case 45: + rtp_buf[3]=c; + ++state; + break; + case 46: // bit 10#4 = Item Togglebit + // bit 10#3 = Item Runningbit + // Tag1: bit 10#2..11#5 = Contenttype, 11#4..12#7 = Startmarker, 12#6..12#1 = Length + rtp_buf[4]=c; + if (lastmessage[0] == 0) // no rds message till now ? quit ... + break; + int rtp_typ[2],rtp_start[2],rtp_len[2]; + rtp_typ[0] = (0x38 & rtp_buf[0]<<3) | rtp_buf[1]>>5; + rtp_start[0] = (0x3e & rtp_buf[1]<<1) | rtp_buf[2]>>7; + rtp_len[0] = 0x3f & rtp_buf[2]>>1; + // Tag2: bit 12#0..13#3 = Contenttype, 13#2..14#5 = Startmarker, 14#4..14#0 = Length(5bit) + rtp_typ[1] = (0x20 & rtp_buf[2]<<5) | rtp_buf[3]>>3; + rtp_start[1] = (0x38 & rtp_buf[3]<<3) | rtp_buf[4]>>5; + rtp_len[1] = 0x1f & rtp_buf[4]; + + unsigned char rtplus_osd_tmp[64]; + + memcpy(rtp_item[rtp_typ[0]],lastmessage+rtp_start[0],rtp_len[0]+1); + rtp_item[rtp_typ[0]][rtp_len[0]+1]=0; + + if (rtp_typ[0] != rtp_typ[1]) + { + memcpy(rtp_item[rtp_typ[1]],lastmessage+rtp_start[1],rtp_len[1]+1); + rtp_item[rtp_typ[1]][rtp_len[1]+1]=0; + } + + // main RTPlus item_types used by the radio stations: + // 1 title + // 4 artist + // 24 info.date_time + // 31 stationname + // 32 program.now + // 39 homepage + // 41 phone.hotline + // 46 email.hotline + // todo: make a window to display all saved items ... + + //create RTPlus OSD for title/artist + rtplus_osd[0]=0; + + if ( rtp_item[4][0] != 0 )//artist + sprintf((char*)rtplus_osd_tmp," (%s)",rtp_item[4]); + + if ( rtp_item[1][0] != 0 )//title + sprintf((char*)rtplus_osd,"%s%s",rtp_item[1],rtplus_osd_tmp); + + if ( rtplus_osd[0] != 0 ) + { + /*emit*/ m_event(RtpTextChanged); + eDebug("RTPlus: %s",rtplus_osd); + } + + state=0; + break; } - ++ptr; } - if (p1 != -1 && (128-p1) != 128) - { - bytesread=ptr=128-p1; - memcpy(buf, buf+p1, ptr); - p1=0; - } - else - bytesread=ptr=0; } } -int eDVBRadioTextParser::start(int pid) +std::string eDVBRdsDecoder::getRassPicture(int page, int subpage) +{ + int val=0; + + switch(subpage) + { + case 0: + val=page*1000; + break; + case 1: + val=page*1100; + break; + case 2: + val=page*1110; + break; + case 3: + val=page*1111; + break; + } + char fname[50]; + sprintf(fname,"/tmp/Rass%04d.mvi",val); + return fname; +} + +int eDVBRdsDecoder::start(int pid) { int ret = -1; if (m_pes_reader && !(ret = m_pes_reader->start(pid))) @@ -268,9 +637,20 @@ int eDVBRadioTextParser::start(int pid) return ret; } -void eDVBRadioTextParser::abortNonAvail() +void eDVBRdsDecoder::abortNonAvail() { eDebug("no ancillary data in audio stream... abort radiotext pes parser"); if (m_pes_reader) m_pes_reader->stop(); } + +ePyObject eDVBRdsDecoder::getRassPictureMask() +{ + ePyObject ret = PyTuple_New(5); + PyTuple_SET_ITEM(ret, 0, PyInt_FromLong(rass_picture_mask[0])); + PyTuple_SET_ITEM(ret, 1, PyInt_FromLong(rass_picture_mask[1])); + PyTuple_SET_ITEM(ret, 2, PyInt_FromLong(rass_picture_mask[2])); + PyTuple_SET_ITEM(ret, 3, PyInt_FromLong(rass_picture_mask[3])); + PyTuple_SET_ITEM(ret, 4, PyInt_FromLong(rass_picture_mask[4])); + return ret; +} diff --git a/lib/dvb/radiotext.h b/lib/dvb/radiotext.h index b4ae0e26..8c354ff1 100644 --- a/lib/dvb/radiotext.h +++ b/lib/dvb/radiotext.h @@ -6,24 +6,37 @@ #include <lib/dvb/pesparse.h> #include <lib/gdi/gpixmap.h> -class eDVBRadioTextParser: public iObject, public ePESParser, public Object +class eDVBRdsDecoder: public iObject, public ePESParser, public Object { - DECLARE_REF(eDVBRadioTextParser); - int bytesread, ptr, p1, p2, msgPtr; - unsigned char buf[128], message[66], leninfo, todo, state; + DECLARE_REF(eDVBRdsDecoder); + int msgPtr, bsflag, qdar_pos, t_ptr, qdarmvi_show; + unsigned char message[66], lastmessage[66], datamessage[256], rtp_buf[5], leninfo, text_len, text_len2, state; + unsigned char rtp_item[64][64], rtplus_osd[64]; //rtp + unsigned char qdar[60*1024]; //60 kB for holding Rass qdar archive unsigned short crc16, crc; + long part, parts, partcnt; + enum { RadioTextChanged, RtpTextChanged, RassInteractivePicMaskChanged, RecvRassSlidePic }; + unsigned char rass_picture_mask[5]; // 40 bits... (10 * 4 pictures) + void addToPictureMask(int id); + void removeFromPictureMask(int id); public: - eDVBRadioTextParser(iDVBDemux *demux); + eDVBRdsDecoder(iDVBDemux *demux); + ~eDVBRdsDecoder(); int start(int pid); - void connectUpdatedRadiotext(const Slot0<void> &slot, ePtr<eConnection> &connection); - const char *getCurrentText() { return msgPtr ? (const char*)message : ""; } + void connectEvent(const Slot1<void, int> &slot, ePtr<eConnection> &connection); + const char *getRadioText() { return (const char*)message; } + const char *getRtpText() { return (const char*)rtplus_osd; } + ePyObject getRassPictureMask(); + std::string getRassPicture(int page, int subpage); + std::string getRassSlideshowPicture() { return "/tmp/RassLast.mvi"; } private: void abortNonAvail(); void processPESPacket(__u8 *pkt, int len); - inline void gotAncillaryByte(__u8 data); + inline void gotAncillaryData(__u8 *data, int len); + void process_qdar(unsigned char*); ePtr<iDVBPESReader> m_pes_reader; ePtr<eConnection> m_read_connection; - Signal0<void> m_updated_radiotext; + Signal1<void, int> m_event; eTimer m_abortTimer; }; diff --git a/lib/python/Components/Converter/Makefile.am b/lib/python/Components/Converter/Makefile.am index b25a32d8..a5d95f53 100644 --- a/lib/python/Components/Converter/Makefile.am +++ b/lib/python/Components/Converter/Makefile.am @@ -3,5 +3,5 @@ installdir = $(LIBDIR)/enigma2/python/Components/Converter install_PYTHON = \ __init__.py ClockToText.py Converter.py EventName.py StaticText.py EventTime.py \ Poll.py RemainingToText.py StringList.py ServiceName.py FrontendInfo.py ServiceInfo.py \ - ConditionalShowHide.py ServicePosition.py ValueRange.py RadioText.py Streaming.py + ConditionalShowHide.py ServicePosition.py ValueRange.py RdsInfo.py Streaming.py diff --git a/lib/python/Components/Converter/RdsInfo.py b/lib/python/Components/Converter/RdsInfo.py new file mode 100644 index 00000000..3a7b2be3 --- /dev/null +++ b/lib/python/Components/Converter/RdsInfo.py @@ -0,0 +1,53 @@ +from enigma import iRdsDecoder, iPlayableService +from Components.Converter.Converter import Converter +from Components.Element import cached + +class RdsInfo(Converter, object): + RASS_INTERACTIVE_AVAILABLE = 0 + RTP_TEXT_CHANGED = 1 + RADIO_TEXT_CHANGED = 2 + + def __init__(self, type): + Converter.__init__(self, type) + self.type = { + "RadioText": self.RADIO_TEXT_CHANGED, + "RtpText": self.RTP_TEXT_CHANGED, + "RasInteractiveAvailable": self.RASS_INTERACTIVE_AVAILABLE + }[type] + + self.interesting_events = { + self.RADIO_TEXT_CHANGED: [iPlayableService.evUpdatedRadioText], + self.RTP_TEXT_CHANGED: [iPlayableService.evUpdatedRtpText], + self.RASS_INTERACTIVE_AVAILABLE: [iPlayableService.evUpdatedRassInteractivePicMask] + }[self.type] + + @cached + def getText(self): + decoder = self.source.decoder + text = "" + if decoder: + if self.type == self.RADIO_TEXT_CHANGED: + text = decoder.getText(iRdsDecoder.RadioText) + elif self.type == self.RTP_TEXT_CHANGED: + text = decoder.getText(iRdsDecoder.RtpText) + else: + print "unknown RdsInfo Converter type", self.type + return text + + text = property(getText) + + @cached + def getBoolean(self): + decoder = self.source.decoder + if self.type == self.RASS_INTERACTIVE_AVAILABLE: + mask = decoder and decoder.getRassInteractiveMask() + return (mask and mask[0] & 1 and True) or False + elif self.type == self.RADIO_TEXT_CHANGED: + return (len(decoder.getText(iRdsDecoder.RadioText)) and True) or False + elif self.type == self.RTP_TEXT_CHANGED: + return (len(decoder.getText(iRdsDecoder.RtpText)) and True) or False + boolean = property(getBoolean) + + def changed(self, what): + if what[0] != self.CHANGED_SPECIFIC or what[1] in self.interesting_events: + Converter.changed(self, what) diff --git a/lib/python/Components/Sources/Makefile.am b/lib/python/Components/Sources/Makefile.am index 5e6a30a5..b5e16d98 100644 --- a/lib/python/Components/Sources/Makefile.am +++ b/lib/python/Components/Sources/Makefile.am @@ -2,5 +2,5 @@ installdir = $(LIBDIR)/enigma2/python/Components/Sources install_PYTHON = \ __init__.py Clock.py EventInfo.py Source.py MenuList.py CurrentService.py \ - FrontendStatus.py Boolean.py Config.py ServiceList.py RadioText.py StreamService.py \ + FrontendStatus.py Boolean.py Config.py ServiceList.py RdsDecoder.py StreamService.py \ StaticText.py diff --git a/lib/python/Components/Sources/RdsDecoder.py b/lib/python/Components/Sources/RdsDecoder.py new file mode 100644 index 00000000..886f81f6 --- /dev/null +++ b/lib/python/Components/Sources/RdsDecoder.py @@ -0,0 +1,29 @@ +from Components.PerServiceDisplay import PerServiceBase +from Components.Element import cached +from enigma import iPlayableService +from Source import Source + +class RdsDecoder(PerServiceBase, Source, object): + def __init__(self, navcore): + Source.__init__(self) + PerServiceBase.__init__(self, navcore, + { + iPlayableService.evStart: self.gotEvent, + iPlayableService.evUpdatedRadioText: self.gotEvent, + iPlayableService.evUpdatedRtpText: self.gotEvent, + iPlayableService.evUpdatedRassInteractivePicMask: self.gotEvent, + iPlayableService.evEnd: self.gotEvent + }, with_event=True) + + @cached + def getDecoder(self): + service = self.navcore.getCurrentService() + return service and service.rdsDecoder() + + decoder = property(getDecoder) + + def gotEvent(self, what): + if what in [iPlayableService.evStart, iPlayableService.evEnd]: + self.changed((self.CHANGED_CLEAR,)) + else: + self.changed((self.CHANGED_SPECIFIC, what)) diff --git a/lib/python/Screens/ChannelSelection.py b/lib/python/Screens/ChannelSelection.py index 5a0f1177..7f9f797e 100644 --- a/lib/python/Screens/ChannelSelection.py +++ b/lib/python/Screens/ChannelSelection.py @@ -1,7 +1,7 @@ from Screen import Screen from Components.Button import Button from Components.ServiceList import ServiceList -from Components.ActionMap import NumberActionMap, ActionMap +from Components.ActionMap import NumberActionMap, ActionMap, HelpableActionMap from Components.MenuList import MenuList from Components.ServiceEventTracker import ServiceEventTracker from EpgSelection import EPGSelection @@ -11,11 +11,13 @@ from Screens.FixedMenu import FixedMenu from Tools.NumericalTextInput import NumericalTextInput from Components.NimManager import nimmanager from Components.Sources.Clock import Clock +from Components.Sources.RdsDecoder import RdsDecoder from Components.Input import Input from Components.ParentalControl import parentalControl from Screens.InputBox import InputBox, PinInput from Screens.MessageBox import MessageBox from Screens.ServiceInfo import ServiceInfo +from Screens.RdsDisplay import RassInteractive from ServiceReference import ServiceReference from Tools.BoundFunction import boundFunction from re import * @@ -1256,32 +1258,30 @@ class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelect self.revertMode = None self.close(None) -from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarRadioText +from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName -class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord): +class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName): def __init__(self, session): Screen.__init__(self, session) InfoBarEvent.__init__(self) InfoBarServiceName.__init__(self) - InfoBarInstantRecord.__init__(self) self["CurrentTime"] = Clock() + self["RdsDecoder"] = RdsDecoder(self.session.nav) -class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarRadioText): - +class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG): ALLOW_SUSPEND = True - def __init__(self, session): + def __init__(self, session, infobar): ChannelSelectionBase.__init__(self, session) ChannelSelectionEdit.__init__(self) ChannelSelectionEPG.__init__(self) - InfoBarRadioText.__init__(self) - + self.infobar = infobar config.radio = ConfigSubsection(); config.radio.lastservice = ConfigText() config.radio.lastroot = ConfigText() self.onLayoutFinish.append(self.onCreate) - self.info = session.instantiateDialog(RadioInfoBar) + self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"], { @@ -1297,6 +1297,37 @@ class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelS iPlayableService.evEnd: self.__evServiceEnd }) +########## RDS Radiotext / Rass Support BEGIN + self.infobar = infobar # reference to real infobar (the one and only) + self["RdsDecoder"] = self.info["RdsDecoder"] + self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions", + { + "startRassInteractive": (self.startRassInteractive, _("View Rass interactive...")) + },-1) + self["RdsActions"].setEnabled(False) + infobar.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged) + + def startRassInteractive(self): + self.info.hide(); + self.infobar.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive) + + def RassInteractiveClosed(self): + self.info.show() + self.infobar.rass_interactive = None + self.infobar.RassSlidePicChanged() + + def RassInteractivePossibilityChanged(self, state): + self["RdsActions"].setEnabled(state) +########## RDS Radiotext / Rass Support END + + def closeRadio(self): + self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged) + self.info.hide() + #set previous tv service + lastservice=eServiceReference(config.tv.lastservice.value) + self.session.nav.playService(lastservice) + self.close(None) + def __evServiceStart(self): service = self.session.nav.getCurrentService() if service: @@ -1371,13 +1402,6 @@ class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelS config.radio.lastservice.save() self.saveRoot() - def closeRadio(self): - self.info.hide() - #set previous tv service - lastservice=eServiceReference(config.tv.lastservice.value) - self.session.nav.playService(lastservice) - self.close(None) - class SimpleChannelSelection(ChannelSelectionBase): def __init__(self, session, title): ChannelSelectionBase.__init__(self, session) diff --git a/lib/python/Screens/InfoBar.py b/lib/python/Screens/InfoBar.py index 24c2b40b..ab40838d 100644 --- a/lib/python/Screens/InfoBar.py +++ b/lib/python/Screens/InfoBar.py @@ -12,7 +12,7 @@ from Components.config import config from Tools.Notifications import AddNotificationWithCallback from Screens.InfoBarGenerics import InfoBarShowHide, \ - InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarRadioText, \ + InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarRdsDecoder, \ InfoBarEPG, InfoBarEvent, InfoBarServiceName, InfoBarSeek, InfoBarInstantRecord, \ InfoBarAudioSelection, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, \ InfoBarSubserviceSelection, InfoBarTuner, InfoBarShowMovies, InfoBarTimeshift, \ @@ -23,7 +23,7 @@ from Screens.InfoBarGenerics import InfoBarShowHide, \ from Screens.HelpMenu import HelpableScreen, HelpMenu class InfoBar(InfoBarShowHide, - InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRadioText, + InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarAudioSelection, HelpableScreen, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarSubserviceSelection, InfoBarTuner, InfoBarTimeshift, InfoBarSeek, @@ -47,7 +47,7 @@ class InfoBar(InfoBarShowHide, for x in HelpableScreen, \ InfoBarShowHide, \ - InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRadioText, \ + InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder, \ InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarAudioSelection, \ InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarSubserviceSelection, \ InfoBarTuner, InfoBarTimeshift, InfoBarSeek, InfoBarSummarySupport, InfoBarTimeshiftState, \ @@ -67,7 +67,11 @@ class InfoBar(InfoBarShowHide, if config.usage.e1like_radio_mode.value: self.showRadioChannelList(True) else: - self.session.open(ChannelSelectionRadio) + self.rds_display.hide() # in InfoBarRdsDecoder + self.session.openWithCallback(self.ChannelSelectionRadioClosed, ChannelSelectionRadio, self) + + def ChannelSelectionRadioClosed(self, *arg): + self.rds_display.show() # in InfoBarRdsDecoder def showMovies(self): self.session.openWithCallback(self.movieSelected, MovieSelection) diff --git a/lib/python/Screens/InfoBarGenerics.py b/lib/python/Screens/InfoBarGenerics.py index 2ccd52de..78a67b7c 100644 --- a/lib/python/Screens/InfoBarGenerics.py +++ b/lib/python/Screens/InfoBarGenerics.py @@ -12,7 +12,6 @@ from Components.ProgressBar import * from Components.ServiceEventTracker import ServiceEventTracker from Components.Sources.CurrentService import CurrentService from Components.Sources.EventInfo import EventInfo -from Components.Sources.RadioText import RadioText from Components.Sources.FrontendStatus import FrontendStatus from Components.Sources.Boolean import Boolean from Components.Sources.Clock import Clock @@ -32,6 +31,7 @@ from Screens.MinuteInput import MinuteInput from Screens.TimerSelection import TimerSelection from Screens.PictureInPicture import PictureInPicture from Screens.SubtitleDisplay import SubtitleDisplay +from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive from Screens.SleepTimerEdit import SleepTimerEdit from ServiceReference import ServiceReference @@ -538,10 +538,53 @@ class InfoBarEvent: self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW) self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT) -class InfoBarRadioText: - """provides radio (RDS) text info display""" +class InfoBarRdsDecoder: + """provides RDS and Rass support/display""" def __init__(self): - self["RadioText"] = RadioText(self.session.nav) + self.rds_display = self.session.instantiateDialog(RdsInfoDisplay) + self.rass_interactive = None + + self.__event_tracker = ServiceEventTracker(screen=self, eventmap= + { + iPlayableService.evEnd: self.__serviceStopped, + iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged + }) + + self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions", + { + "startRassInteractive": (self.startRassInteractive, _("View Rass interactive...")) + },-1) + + self["RdsActions"].setEnabled(False) + + self.onLayoutFinish.append(self.rds_display.show) + self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged) + + def RassInteractivePossibilityChanged(self, state): + self["RdsActions"].setEnabled(state) + + def RassSlidePicChanged(self): + if not self.rass_interactive: + service = self.session.nav.getCurrentService() + decoder = service and service.rdsDecoder() + if decoder: + decoder.showRassSlidePicture() + + def __serviceStopped(self): + if self.rass_interactive is not None: + rass_interactive = self.rass_interactive + self.rass_interactive = None + rass_interactive.close() + + def startRassInteractive(self): + self.rds_display.hide() + self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive) + + def RassInteractiveClosed(self, *val): + if self.rass_interactive is not None: + self.rass_interactive = None + self.RassSlidePicChanged() + self.rds_display.show() class InfoBarServiceName: def __init__(self): diff --git a/lib/python/Screens/Makefile.am b/lib/python/Screens/Makefile.am index d5512e7e..920a97fb 100644 --- a/lib/python/Screens/Makefile.am +++ b/lib/python/Screens/Makefile.am @@ -12,4 +12,4 @@ install_PYTHON = \ Console.py InputBox.py ChoiceBox.py SimpleSummary.py ImageWizard.py \ MediaPlayer.py TimerSelection.py PictureInPicture.py TimeDateInput.py \ SubtitleDisplay.py SubservicesQuickzap.py ParentalControlSetup.py NumericalTextInputHelpDialog.py \ - SleepTimerEdit.py Ipkg.py + SleepTimerEdit.py Ipkg.py RdsDisplay.py diff --git a/lib/python/Screens/RdsDisplay.py b/lib/python/Screens/RdsDisplay.py new file mode 100644 index 00000000..4190b945 --- /dev/null +++ b/lib/python/Screens/RdsDisplay.py @@ -0,0 +1,272 @@ +from enigma import iPlayableService, loadPNG, iRdsDecoder, ePoint, gRGB +from Screens.Screen import Screen +from Components.Sources.RdsDecoder import RdsDecoder +from Components.ActionMap import NumberActionMap +from Components.ServiceEventTracker import ServiceEventTracker +from Components.Pixmap import Pixmap +from Components.Label import Label +from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE + +class RdsInfoDisplay(Screen): + ALLOW_SUSPEND = True + + def __init__(self, session): + Screen.__init__(self, session) + + self.__event_tracker = ServiceEventTracker(screen=self, eventmap= + { + iPlayableService.evEnd: self.__serviceStopped, + iPlayableService.evUpdatedRadioText: self.RadioTextChanged, + iPlayableService.evUpdatedRtpText: self.RtpTextChanged, + iPlayableService.evUpdatedRassInteractivePicMask: self.RassInteractivePicMaskChanged, + }) + + self["RadioText"] = Label() + self["RtpText"] = Label() + self["RassLogo"] = Pixmap() + + self.onLayoutFinish.append(self.hideWidgets) + self.rassInteractivePossible=False + self.onRassInteractivePossibilityChanged = [ ] + + def hideWidgets(self): + for x in (self["RadioText"],self["RtpText"],self["RassLogo"]): + x.hide() + + def RadioTextChanged(self): + service = self.session.nav.getCurrentService() + decoder = service and service.rdsDecoder() + rdsText = decoder and decoder.getText(iRdsDecoder.RadioText) + if rdsText and len(rdsText): + self["RadioText"].setText(rdsText) + self["RadioText"].show() + else: + self["RadioText"].hide() + + def RtpTextChanged(self): + service = self.session.nav.getCurrentService() + decoder = service and service.rdsDecoder() + rtpText = decoder and decoder.getText(iRdsDecoder.RtpText) + if rtpText and len(rtpText): + self["RtpText"].setText(rtpText) + self["RtpText"].show() + else: + self["RtpText"].hide() + + def RassInteractivePicMaskChanged(self): + if not self.rassInteractivePossible: + service = self.session.nav.getCurrentService() + decoder = service and service.rdsDecoder() + mask = decoder and decoder.getRassInteractiveMask() + if mask[0] & 1: #rass interactive index page available + self["RassLogo"].show() + self.rassInteractivePossible = True + for x in self.onRassInteractivePossibilityChanged: + x(True) + + def __serviceStopped(self): + self.hideWidgets() + if self.rassInteractivePossible: + self.rassInteractivePossible = False + for x in self.onRassInteractivePossibilityChanged: + x(False) + +class RassInteractive(Screen): + def __init__(self, session): + Screen.__init__(self, session) + + self["actions"] = NumberActionMap( [ "NumberActions", "RassInteractiveActions" ], + { + "exit": self.close, + "0": lambda x : self.numPressed(0), + "1": lambda x : self.numPressed(1), + "2": lambda x : self.numPressed(2), + "3": lambda x : self.numPressed(3), + "4": lambda x : self.numPressed(4), + "5": lambda x : self.numPressed(5), + "6": lambda x : self.numPressed(6), + "7": lambda x : self.numPressed(7), + "8": lambda x : self.numPressed(8), + "9": lambda x : self.numPressed(9), + "nextPage": self.nextPage, + "prevPage": self.prevPage, + "nextSubPage": self.nextSubPage, + "prevSubPage": self.prevSubPage + }) + + self.__event_tracker = ServiceEventTracker(screen=self, eventmap= + { + iPlayableService.evUpdatedRassInteractivePicMask: self.recvRassInteractivePicMaskChanged + }) + + self["subpages_1"] = Pixmap() + self["subpages_2"] = Pixmap() + self["subpages_3"] = Pixmap() + self["subpages_4"] = Pixmap() + self["subpages_5"] = Pixmap() + self["subpages_6"] = Pixmap() + self["subpages_7"] = Pixmap() + self["subpages_8"] = Pixmap() + self["subpages_9"] = Pixmap() + self["Marker"] = Label(">") + + self.subpage = { + 1 : self["subpages_1"], + 2 : self["subpages_2"], + 3 : self["subpages_3"], + 4 : self["subpages_4"], + 5 : self["subpages_5"], + 6 : self["subpages_6"], + 7 : self["subpages_7"], + 8 : self["subpages_8"], + 9 : self["subpages_9"] } + + self.subpage_png = { + 1 : loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "rass_page1.png")), + 2 : loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "rass_page2.png")), + 3 : loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "rass_page3.png")), + 4 : loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "rass_page4.png")) } + + self.current_page=0; + self.current_subpage=0; + self.showRassPage(0,0) + self.onLayoutFinish.append(self.updateSubPagePixmaps) + + def updateSubPagePixmaps(self): + service = self.session.nav.getCurrentService() + decoder = service and service.rdsDecoder() + if not decoder: # this should never happen + print "NO RDS DECODER in showRassPage" + else: + mask = decoder.getRassInteractiveMask() + page = 1 + while page < 10: + subpage_cnt = self.countAvailSubpages(page, mask) + subpage = self.subpage[page] + if subpage_cnt > 0: + if subpage.instance: + png = self.subpage_png[subpage_cnt] + if png: + subpage.instance.setPixmap(png) + subpage.show() + else: + print "rass png missing" + else: + subpage.hide() + page += 1 + + def recvRassInteractivePicMaskChanged(self): + self.updateSubPagePixmaps() + + def showRassPage(self, page, subpage): + service = self.session.nav.getCurrentService() + decoder = service and service.rdsDecoder() + if not decoder: # this should never happen + print "NO RDS DECODER in showRassPage" + else: + decoder.showRassInteractivePic(page, subpage) + page_diff = page - self.current_page + self.current_page = page + if page_diff: + current_pos = self["Marker"].getPosition() + y = current_pos[1] + y += page_diff * 25 + self["Marker"].setPosition(current_pos[0],y) + + def getMaskForPage(self, page, masks=None): + if not masks: + service = self.session.nav.getCurrentService() + decoder = service and service.rdsDecoder() + if not decoder: # this should never happen + print "NO RDS DECODER in getMaskForPage" + masks = decoder.getRassInteractiveMask() + if masks: + mask = masks[(page*4)/8] + if page % 2: + mask >>= 4 + else: + mask &= 0xF + return mask + + def countAvailSubpages(self, page, masks): + mask = self.getMaskForPage(page, masks) + cnt = 0 + while mask: + if mask & 1: + cnt += 1 + mask >>= 1 + return cnt + + def nextPage(self): + mask = 0 + page = self.current_page + while mask == 0: + page += 1 + if page > 9: + page = 0 + mask = self.getMaskForPage(page) + self.numPressed(page) + + def prevPage(self): + mask = 0 + page = self.current_page + while mask == 0: + if page > 0: + page -= 1 + else: + page = 9 + mask = self.getMaskForPage(page) + self.numPressed(page) + + def nextSubPage(self): + self.numPressed(self.current_page) + + def prevSubPage(self): + num = self.current_page + mask = self.getMaskForPage(num) + cur_bit = 1 << self.current_subpage + tmp = cur_bit + while True: + if tmp == 1: + tmp = 8 + else: + tmp >>= 1 + if tmp == cur_bit: # no other subpage avail + return + if mask & tmp: # next subpage found + subpage = 0 + while tmp > 1: # convert bit to subpage + subpage += 1 + tmp >>= 1 + self.current_subpage = subpage + self.showRassPage(num, subpage) + return + + def numPressed(self, num): + mask = self.getMaskForPage(num) + if self.current_page == num: + self.skip = 0 + cur_bit = 1 << self.current_subpage + tmp = cur_bit + else: + self.skip = 1 + cur_bit = 16 + tmp = 1 + while True: + if not self.skip: + if tmp == 8 and cur_bit < 16: + tmp = 1 + else: + tmp <<= 1 + else: + self.skip = 0 + if tmp == cur_bit: # no other subpage avail + return + if mask & tmp: # next subpage found + subpage = 0 + while tmp > 1: # convert bit to subpage + subpage += 1 + tmp >>= 1 + self.current_subpage = subpage + self.showRassPage(num, subpage) + return diff --git a/lib/service/iservice.h b/lib/service/iservice.h index feaa771e..df4e302f 100644 --- a/lib/service/iservice.h +++ b/lib/service/iservice.h @@ -483,17 +483,30 @@ public: }; SWIG_TEMPLATE_TYPEDEF(ePtr<iAudioDelay>, iAudioDelayPtr); -SWIG_IGNORE(iRadioText); -class iRadioText: public iObject +class iRdsDecoder_ENUMS { #ifdef SWIG - iRadioText(); - ~iRadioText(); + iRdsDecoder_ENUMS(); + ~iRdsDecoder_ENUMS(); #endif public: - virtual std::string getRadioText(int x=0)=0; + enum { RadioText, RtpText }; }; -SWIG_TEMPLATE_TYPEDEF(ePtr<iRadioText>, iRadioTextPtr); + +SWIG_IGNORE(iRdsDecoder); +class iRdsDecoder: public iObject, public iRdsDecoder_ENUMS +{ +#ifdef SWIG + iRdsDecoder(); + ~iRdsDecoder(); +#endif +public: + virtual std::string getText(int x=RadioText)=0; + virtual void showRassSlidePicture()=0; + virtual void showRassInteractivePic(int page, int subpage)=0; + virtual SWIG_PYOBJECT(ePyObject) getRassInteractiveMask()=0; +}; +SWIG_TEMPLATE_TYPEDEF(ePtr<iRdsDecoder>, iRdsDecoderPtr); SWIG_IGNORE(iSubserviceList); class iSubserviceList: public iObject @@ -676,8 +689,13 @@ public: /* when cueSheet is implemented */ evCuesheetChanged, - /* when radioText is implemented */ + /* when rdsDecoder is implemented */ evUpdatedRadioText, + evUpdatedRtpText, + + /* Radio Screenshow Support */ + evUpdatedRassSlidePic, + evUpdatedRassInteractivePicMask, evVideoSizeChanged, @@ -712,7 +730,7 @@ public: virtual SWIG_VOID(RESULT) cueSheet(ePtr<iCueSheet> &SWIG_OUTPUT)=0; virtual SWIG_VOID(RESULT) subtitle(ePtr<iSubtitleOutput> &SWIG_OUTPUT)=0; virtual SWIG_VOID(RESULT) audioDelay(ePtr<iAudioDelay> &SWIG_OUTPUT)=0; - virtual SWIG_VOID(RESULT) radioText(ePtr<iRadioText> &SWIG_OUTPUT)=0; + virtual SWIG_VOID(RESULT) rdsDecoder(ePtr<iRdsDecoder> &SWIG_OUTPUT)=0; }; SWIG_TEMPLATE_TYPEDEF(ePtr<iPlayableService>, iPlayableServicePtr); diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index 9d9f2d1f..e47ae52c 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -1475,7 +1475,7 @@ RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr) return 0; } -RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr) +RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr) { ptr = this; return 0; @@ -1705,8 +1705,8 @@ int eDVBServicePlay::selectAudioStream(int i) if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type)) return -4; - if (m_radiotext_parser) - m_radiotext_parser->start(program.audioStreams[i].pid); + if (m_rds_decoder) + m_rds_decoder->start(program.audioStreams[i].pid); if (m_dvb_service && !m_is_pvr) { @@ -1743,20 +1743,81 @@ RESULT eDVBServicePlay::selectChannel(int i) return 0; } -std::string eDVBServicePlay::getRadioText(int x) +std::string eDVBServicePlay::getText(int x) { - if (m_radiotext_parser) + if (m_rds_decoder) switch(x) { - case 0: - return convertLatin1UTF8(m_radiotext_parser->getCurrentText()); + case RadioText: + return convertLatin1UTF8(m_rds_decoder->getRadioText()); + case RtpText: + return convertLatin1UTF8(m_rds_decoder->getRtpText()); } return ""; } -void eDVBServicePlay::radioTextUpdated() +void eDVBServicePlay::rdsDecoderEvent(int what) { - m_event((iPlayableService*)this, evUpdatedRadioText); + switch(what) + { + case eDVBRdsDecoder::RadioTextChanged: + m_event((iPlayableService*)this, evUpdatedRadioText); + break; + case eDVBRdsDecoder::RtpTextChanged: + m_event((iPlayableService*)this, evUpdatedRtpText); + break; + case eDVBRdsDecoder::RassInteractivePicMaskChanged: + m_event((iPlayableService*)this, evUpdatedRassInteractivePicMask); + break; + case eDVBRdsDecoder::RecvRassSlidePic: + m_event((iPlayableService*)this, evUpdatedRassSlidePic); + break; + } +} + +void eDVBServicePlay::showRassSlidePicture() +{ + if (m_rds_decoder) + { + if (m_decoder) + { + std::string rass_slide_pic = m_rds_decoder->getRassSlideshowPicture(); + if (rass_slide_pic.length()) + m_decoder->showSinglePic(rass_slide_pic.c_str()); + else + eDebug("empty filename for rass slide picture received!!"); + } + else + eDebug("no MPEG Decoder to show iframes avail"); + } + else + eDebug("showRassSlidePicture called.. but not decoder"); +} + +void eDVBServicePlay::showRassInteractivePic(int page, int subpage) +{ + if (m_rds_decoder) + { + if (m_decoder) + { + std::string rass_interactive_pic = m_rds_decoder->getRassPicture(page, subpage); + if (rass_interactive_pic.length()) + m_decoder->showSinglePic(rass_interactive_pic.c_str()); + else + eDebug("empty filename for rass interactive picture %d/%d received!!", page, subpage); + } + else + eDebug("no MPEG Decoder to show iframes avail"); + } + else + eDebug("showRassInteractivePic called.. but not decoder"); +} + +ePyObject eDVBServicePlay::getRassInteractiveMask() +{ + if (m_rds_decoder) + return m_rds_decoder->getRassPictureMask(); + Py_RETURN_NONE; } int eDVBServiceBase::getFrontendInfo(int w) @@ -2089,11 +2150,11 @@ void eDVBServicePlay::switchToLive() m_decoder = 0; m_decode_demux = 0; m_teletext_parser = 0; - m_radiotext_parser = 0; + m_rds_decoder = 0; m_subtitle_parser = 0; m_new_dvb_subtitle_page_connection = 0; m_new_subtitle_page_connection = 0; - m_radiotext_updated_connection = 0; + m_rds_decoder_event_connection = 0; m_video_event_connection = 0; /* free the timeshift service handler, we need the resources */ @@ -2113,11 +2174,11 @@ void eDVBServicePlay::switchToTimeshift() m_decode_demux = 0; m_decoder = 0; m_teletext_parser = 0; - m_radiotext_parser = 0; + m_rds_decoder = 0; m_subtitle_parser = 0; m_new_subtitle_page_connection = 0; m_new_dvb_subtitle_page_connection = 0; - m_radiotext_updated_connection = 0; + m_rds_decoder_event_connection = 0; m_video_event_connection = 0; m_timeshift_active = 1; @@ -2259,9 +2320,9 @@ void eDVBServicePlay::updateDecoder() ePtr<iDVBDemux> data_demux; if (!h.getDataDemux(data_demux)) { - m_radiotext_parser = new eDVBRadioTextParser(data_demux); - m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection); - m_radiotext_parser->start(apid); + m_rds_decoder = new eDVBRdsDecoder(data_demux); + m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection); + m_rds_decoder->start(apid); } } } diff --git a/lib/service/servicedvb.h b/lib/service/servicedvb.h index 34ed9720..7c785c4e 100644 --- a/lib/service/servicedvb.h +++ b/lib/service/servicedvb.h @@ -89,7 +89,7 @@ class eDVBServicePlay: public eDVBServiceBase, public iAudioTrackSelection, public iAudioChannelSelection, public iSubserviceList, public iTimeshiftService, public iCueSheet, public iSubtitleOutput, public iAudioDelay, - public iRadioText + public iRdsDecoder { DECLARE_REF(eDVBServicePlay); public: @@ -112,7 +112,7 @@ public: RESULT cueSheet(ePtr<iCueSheet> &ptr); RESULT subtitle(ePtr<iSubtitleOutput> &ptr); RESULT audioDelay(ePtr<iAudioDelay> &ptr); - RESULT radioText(ePtr<iRadioText> &ptr); + RESULT rdsDecoder(ePtr<iRdsDecoder> &ptr); // iPauseableService RESULT pause(); @@ -144,8 +144,11 @@ public: int getCurrentChannel(); RESULT selectChannel(int i); - // iRadioText - std::string getRadioText(int i=0); + // iRdsDecoder + std::string getText(int i=0); + void showRassSlidePicture(); + void showRassInteractivePic(int page, int subpage); + ePyObject getRassInteractiveMask(); // iSubserviceList int getNumberOfSubservices(); @@ -267,9 +270,9 @@ private: void checkSubtitleTiming(); /* radiotext */ - ePtr<eDVBRadioTextParser> m_radiotext_parser; - ePtr<eConnection> m_radiotext_updated_connection; - void radioTextUpdated(); + ePtr<eDVBRdsDecoder> m_rds_decoder; + ePtr<eConnection> m_rds_decoder_event_connection; + void rdsDecoderEvent(int); ePtr<eConnection> m_video_event_connection; void video_event(struct iTSMPEGDecoder::videoEvent); diff --git a/lib/service/servicemp3.h b/lib/service/servicemp3.h index 4245c816..49964883 100644 --- a/lib/service/servicemp3.h +++ b/lib/service/servicemp3.h @@ -66,7 +66,7 @@ public: RESULT cueSheet(ePtr<iCueSheet> &ptr) { ptr = 0; return -1; } RESULT subtitle(ePtr<iSubtitleOutput> &ptr) { ptr = 0; return -1; } RESULT audioDelay(ePtr<iAudioDelay> &ptr) { ptr = 0; return -1; } - RESULT radioText(ePtr<iRadioText> &ptr) { ptr = 0; return -1; } + RESULT rdsDecoder(ePtr<iRdsDecoder> &ptr) { ptr = 0; return -1; } // iPausableService RESULT pause(); diff --git a/lib/service/servicexine.h b/lib/service/servicexine.h index 4a50b11f..b56a4858 100644 --- a/lib/service/servicexine.h +++ b/lib/service/servicexine.h @@ -69,7 +69,7 @@ public: RESULT cueSheet(ePtr<iCueSheet> &ptr) { ptr = 0; return -1; } RESULT subtitle(ePtr<iSubtitleOutput> &ptr) { ptr = 0; return -1; } RESULT audioDelay(ePtr<iAudioDelay> &ptr) { ptr = 0; return -1; } - RESULT radioText(ePtr<iRadioText> &ptr) { ptr = 0; return -1; } + RESULT rdsDecoder(ePtr<iRdsDecoder> &ptr) { ptr = 0; return -1; } // iPausableService RESULT pause(); |
