diff --git a/addons/pvr.vdr.vnsi/Makefile.am b/addons/pvr.vdr.vnsi/Makefile.am index 9dd398ddf..45ffb9089 100644 --- a/addons/pvr.vdr.vnsi/Makefile.am +++ b/addons/pvr.vdr.vnsi/Makefile.am @@ -19,6 +19,7 @@ libvdrvnsi_addon_la_SOURCES = src/client.cpp \ src/VNSIRecording.cpp \ src/VNSISession.cpp \ src/VNSIAdmin.cpp \ + src/VNSIChannels.cpp \ src/requestpacket.cpp \ src/responsepacket.cpp \ src/tools.cpp diff --git a/addons/pvr.vdr.vnsi/addon/addon.xml.in b/addons/pvr.vdr.vnsi/addon/addon.xml.in index b4f727111..4fd4ad2be 100644 --- a/addons/pvr.vdr.vnsi/addon/addon.xml.in +++ b/addons/pvr.vdr.vnsi/addon/addon.xml.in @@ -1,7 +1,7 @@ diff --git a/addons/pvr.vdr.vnsi/addon/resources/language/English/strings.po b/addons/pvr.vdr.vnsi/addon/resources/language/English/strings.po index 40a69e025..cb8bbbe92 100644 --- a/addons/pvr.vdr.vnsi/addon/resources/language/English/strings.po +++ b/addons/pvr.vdr.vnsi/addon/resources/language/English/strings.po @@ -241,4 +241,32 @@ msgstr "" msgctxt "#30107" msgid "VDR Admin" -msgstr "" \ No newline at end of file +msgstr "" + +msgctxt "#30108" +msgid "Channels" +msgstr "" + +msgctxt "#30109" +msgid "Provider whitelist" +msgstr "" + +msgctxt "#30110" +msgid "Channel blacklist" +msgstr "" + +msgctxt "#30111" +msgid "Channel filters" +msgstr "" + +msgctxt "#30112" +msgid "Radio Channels" +msgstr "" + +msgctxt "#30113" +msgid "Save filters" +msgstr "" + +msgctxt "#30114" +msgid "Provider Unknown" +msgstr "" diff --git a/addons/pvr.vdr.vnsi/addon/resources/skins/skin.aeon.nox/1080i/Admin.xml b/addons/pvr.vdr.vnsi/addon/resources/skins/skin.aeon.nox/1080i/Admin.xml index 74e3aa869..20e0f5acc 100644 --- a/addons/pvr.vdr.vnsi/addon/resources/skins/skin.aeon.nox/1080i/Admin.xml +++ b/addons/pvr.vdr.vnsi/addon/resources/skins/skin.aeon.nox/1080i/Admin.xml @@ -2,69 +2,80 @@ 10 SetProperty(menu,osd) no + 36 AutoConfig - - + + - + - + - - CommonSettingsBackground - CommonMediaPlayingBackground - Furniture_SettingsFloor - - - Conditional - Furniture_SettingsBackPanel + + CommonSettingsBackground + CommonMediaPlayingBackground + Furniture_SettingsFloor + + + Conditional + Furniture_SettingsBackPanel 1 - 63 - 180 - 326 - 768 - 10 - 11 - 10 - 9000 - - - 300 - - - 334 - 74 - Font_Bold20 + 63 + 180 + 326 + 768 + 10 + 11 + 10 + 9000 + - + 300 + + + 334 + 74 + Font_Bold20 grey2 - - - - + + + + 334 74 views/tripanel/listselect_fo.png - Conditional + Conditional $VAR[FocusTextureColorVar] - - + + 334 74 Font_Bold20 - - - - - - SetProperty(menu,osd) - - - - SetProperty(menu,setup) - + + + + + + SetProperty(menu,osd) + + + + SetProperty(menu,setup) + + + + SetProperty(menu,channels) + @@ -87,9 +98,9 @@ stretch GlassTitleBar.png - - StringCompare(Window.Property(menu),osd) - + + StringCompare(Window.Property(menu),osd) + osd control label 25 10 @@ -102,33 +113,19 @@ font16caps grey white2 - 10 - - - not focused label - Control.HasFocus(11) - 300 - 20 - 1380 - 30 - font16caps - - left - center - white - black + 10 - + 5 50 1453 740 - - - StringCompare(Window.Property(menu),setup) - 21 - + + + StringCompare(Window.Property(menu),setup) + 21 + Source Type 10 50 @@ -143,9 +140,9 @@ center 10 - 22 - - + 22 + + Source Type 10 100 @@ -160,10 +157,10 @@ center 10 - 21 - 23 - - + 21 + 23 + + Source Type 10 150 @@ -178,11 +175,217 @@ center 10 - 22 + 22 + + + + StringCompare(Window.Property(menu),channels) + 33 + + Channels label + 25 + 10 + 1000 + 30 + font16caps + + posx + center + white + black + + + 1090 + 30 + 30 + 30 + stretch + FFCC0000 + views/scrollbarnub-focus.png + StringCompare(Window.Property(IsDirty),1) + + + 1090 + 30 + 30 + 30 + stretch + FF00FF00 + views/scrollbarnub-focus.png + !StringCompare(Window.Property(IsDirty),1) + + + Is Radio + 75 + 150 + 375 + 30 + font16caps + grey3 + white + views/tripanel/listselect_fo.png + $VAR[FocusTextureColorVar] + settings/settings_radiobuttonoff.png + + 10 + 33 + 36 + + + providers + 75 + 250 + 375 + 30 + views/tripanel/listselect_fo.png + settings/settings_radiobuttonoff.png + + font16caps + grey3 + 10 + 36 + 32 + 34 + + + channels + 75 + 350 + 375 + 30 + views/tripanel/listselect_fo.png + settings/settings_radiobuttonoff.png + + font16caps + grey3 + 10 + 36 + 33 + 35 + + + save + 75 + 450 + 375 + 30 + views/tripanel/listselect_fo.png + settings/settings_radiobuttonoff.png + + font16caps + grey3 + 10 + 36 + 34 + + + background image + 700 + 75 + 740 + 670 + $INFO[Container(9000).ListItem.Icon] + + + 720 + 95 + 650 + 630 + 33 + 37 + list + 37 + 200 + + + 2 + 2 + 18 + 18 + stretch + 7790EE90 + arrowright.png + ListItem.Property(IsWhitelist) + + + 2 + 2 + 18 + 18 + stretch + 77FF0000 + arrowright.png + ListItem.Property(IsBlacklist) + + + 40 + 0 + 550 + 20 + Font_Reg10 + posx + center + grey2 + selected + ListItem.Label + + + + + 0 + 0 + 650 + 20 + stretch + views/tripanel/listselect_fo.png + $VAR[FocusTextureColorVar] + Control.HasFocus(36) + + + 2 + 2 + 18 + 18 + stretch + 7790EE90 + arrowright.png + ListItem.Property(IsWhitelist) + + + 2 + 2 + 18 + 18 + stretch + 77FF0000 + arrowright.png + ListItem.Property(IsBlacklist) + + + 40 + 0 + 550 + 20 + Font_Reg10 + posx + center + grey2 + selected + ListItem.Label + + + + + 1400 + 75 + 25 + 630 + 36 + false + vertical + - - - Clock + diff --git a/addons/pvr.vdr.vnsi/addon/resources/skins/skin.confluence/720p/Admin.xml b/addons/pvr.vdr.vnsi/addon/resources/skins/skin.confluence/720p/Admin.xml index 910de6d82..d81f85a8b 100644 --- a/addons/pvr.vdr.vnsi/addon/resources/skins/skin.confluence/720p/Admin.xml +++ b/addons/pvr.vdr.vnsi/addon/resources/skins/skin.confluence/720p/Admin.xml @@ -2,157 +2,162 @@ 10 SetProperty(menu,osd) no + 36 CommonBackground - - 0 - 100r - 1280 - 100 - floor.png - VisibleFadeEffect - - - 90 - 30 - - - - - - - - - - 5 - 5 - 1090 - 630 - ContentPanel.png - - - 5 - 625 - 1090 - 64 - ContentPanelMirror.png - - - Close Window button - 980 - 11 - 64 - 32 - - - - PreviousMenu - DialogCloseButton-focus.png - DialogCloseButton.png - 1 - 1 - 1 - 1 - system.getbool(input.enablemouse) - VisibleFadeEffect - - - LOGO - 30 - 15 - 220 - 80 - keep - Confluence_Logo.png - + + 0 + 100r + 1280 + 100 + floor.png + VisibleFadeEffect + + + 90 + 30 + + + + + + + + + + 5 + 5 + 1090 + 630 + ContentPanel.png + + + 5 + 625 + 1090 + 64 + ContentPanelMirror.png + + + Close Window button + 980 + 11 + 64 + 32 + + - + PreviousMenu + DialogCloseButton-focus.png + DialogCloseButton.png + 1 + 1 + 1 + 1 + system.getbool(input.enablemouse) + VisibleFadeEffect + + + LOGO + 30 + 15 + 220 + 80 + keep + Confluence_Logo.png + 1 - 10 - 90 - 260 - 481 - 10 - 11 - 10 - 9000 - - - 300 - - - 0 - 0 - 260 - 55 - MenuItemNF.png - - - 250 - 0 - 380 - 55 - font24_title - grey3 - right - center - - - - - - 0 - 0 - 260 - 55 - MenuItemFO.png - - - 250 - 0 - 380 - 55 - font24_title - white - right - center - - - - - - - SetProperty(menu,osd) - - - - SetProperty(menu,setup) - + 10 + 90 + 260 + 481 + 10 + 11 + 10 + 9000 + - + 300 + + + 0 + 0 + 260 + 55 + MenuItemNF.png + + + 250 + 0 + 380 + 55 + font24_title + grey3 + right + center + + + + + + 0 + 0 + 260 + 55 + MenuItemFO.png + + + 250 + 0 + 380 + 55 + font24_title + white + right + center + + + + + + + SetProperty(menu,osd) + + + + SetProperty(menu,setup) + + + + SetProperty(menu,channels) + - 268 - 10 + 268 + 10 Background - 0 - 0 + 0 + 0 790 620 black-back2.png Background Title - 0 - 0 + 0 + 0 790 50 stretch GlassTitleBar.png - - StringCompare(Window.Property(menu),osd) - + + StringCompare(Window.Property(menu),osd) + osd control label - 25 - 20 + 25 + 20 765 30 MenuItemFO.png @@ -160,36 +165,22 @@ font16caps white - 10 - - - not focused label - Control.HasFocus(11) - 300 - 30 - 740 - 30 - font16caps - - left - center - white - black + 10 - 5 - 50 + 5 + 50 780 515 - - - StringCompare(Window.Property(menu),setup) - 21 - + + + StringCompare(Window.Property(menu),setup) + 21 + Source Type - 10 - 50 + 10 + 50 770 40 font13 @@ -200,12 +191,12 @@ center 10 - 22 - - + 22 + + Source Type - 10 - 100 + 10 + 100 770 40 font13 @@ -216,13 +207,13 @@ center 10 - 21 - 23 - - + 21 + 23 + + Source Type - 10 - 150 + 10 + 150 770 40 font13 @@ -233,11 +224,240 @@ center 10 - 22 + 22 + + + + StringCompare(Window.Property(menu),channels) + 33 + + Channels label + 30 + 20 + 500 + 30 + font16caps + + left + center + white + black + + + 730 + 20 + 30 + 30 + stretch + FFCC0000 + radiobutton-nofocus.png + StringCompare(Window.Property(IsDirty),1) + + + 730 + 20 + 30 + 30 + stretch + FF00FF00 + radiobutton-nofocus.png + !StringCompare(Window.Property(IsDirty),1) + + + Is Radio + 50 + 100 + 250 + 30 + font16caps + grey3 + white + MenuItemFO.png + MenuItemNF.png + + 10 + 33 + 36 + + + providers + 50 + 150 + 250 + 30 + MenuItemFO.png + MenuItemNF.png + + font16caps + grey3 + 10 + 36 + 32 + 34 + + + channels + 50 + 200 + 250 + 30 + MenuItemFO.png + MenuItemNF.png + + font16caps + grey3 + 10 + 36 + 33 + 35 + + + save + 50 + 250 + 250 + 30 + MenuItemFO.png + MenuItemNF.png + + font16caps + grey3 + 10 + 36 + 34 + + + background image + 320 + 50 + 440 + 540 + DialogBack2.png + + + 340 + 70 + 400 + 500 + 33 + 37 + list + 37 + 200 + + + 0 + 0 + 400 + 20 + stretch + MenuItemNF.png + + + 2 + 2 + 18 + 18 + stretch + 7790EE90 + arrow-big-right.png + ListItem.Property(IsWhitelist) + + + 2 + 2 + 18 + 18 + stretch + 77FF0000 + arrow-big-right.png + ListItem.Property(IsBlacklist) + + + 40 + 0 + 340 + 20 + font10 + left + center + grey2 + selected + ListItem.Label + + + + + 0 + 0 + 400 + 20 + stretch + MenuItemNF.png + !Control.HasFocus(36) + VisibleFadeEffect + + + 0 + 0 + 400 + 20 + stretch + MenuItemFO.png + Control.HasFocus(36) + VisibleFadeEffect + + + 2 + 2 + 18 + 18 + stretch + 7790EE90 + arrow-big-right.png + ListItem.Property(IsWhitelist) + + + 2 + 2 + 18 + 18 + stretch + 77FF0000 + arrow-big-right.png + ListItem.Property(IsBlacklist) + + + 40 + 0 + 340 + 20 + font10 + left + center + grey2 + selected + ListItem.Label + + + + + 760 + 50 + 25 + 540 + ScrollBarV.png + ScrollBarV_bar.png + ScrollBarV_bar_focus.png + ScrollBarNib.png + ScrollBarNib.png + 36 + false + vertical + - - + Clock diff --git a/addons/pvr.vdr.vnsi/src/VNSIAdmin.cpp b/addons/pvr.vdr.vnsi/src/VNSIAdmin.cpp index 29549f98b..a8b54032f 100644 --- a/addons/pvr.vdr.vnsi/src/VNSIAdmin.cpp +++ b/addons/pvr.vdr.vnsi/src/VNSIAdmin.cpp @@ -96,6 +96,12 @@ CVisGUIShader *vis_shader = NULL; #define CONTROL_SPIN_TIMESHIFT_MODE 21 #define CONTROL_SPIN_TIMESHIFT_BUFFER_RAM 22 #define CONTROL_SPIN_TIMESHIFT_BUFFER_FILE 23 +#define CONTROL_LABEL_FILTERS 31 +#define CONTROL_RADIO_ISRADIO 32 +#define CONTROL_PROVIDERS_BUTTON 33 +#define CONTROL_CHANNELS_BUTTON 34 +#define CONTROL_FILTERSAVE_BUTTON 35 +#define CONTROL_ITEM_LIST 36 #define ACTION_NONE 0 #define ACTION_MOVE_LEFT 1 @@ -840,8 +846,12 @@ bool cVNSIAdmin::Open(const std::string& hostname, int port, const char* name) m_window->CBOnFocus = OnFocusCB; m_window->CBOnClick = OnClickCB; m_window->CBOnAction= OnActionCB; + m_window->DoModal(); + ClearListItems(); + m_window->ClearProperties(); + #if defined(XBMC_GUI_API_VERSION) GUI->Control_releaseRendering(m_renderControl); #endif @@ -849,7 +859,9 @@ bool cVNSIAdmin::Open(const std::string& hostname, int port, const char* name) GUI->Control_releaseSpin(m_spinTimeshiftMode); GUI->Control_releaseSpin(m_spinTimeshiftBufferRam); GUI->Control_releaseSpin(m_spinTimeshiftBufferFile); + GUI->Control_releaseRadioButton(m_ratioIsRadio); GUI->Window_destroy(m_window); + StopThread(); Close(); if (m_osdRender) @@ -901,6 +913,89 @@ bool cVNSIAdmin::OnClick(int controlId) } return true; } + else if (controlId == CONTROL_PROVIDERS_BUTTON) + { + if(!m_channels.m_loaded || m_ratioIsRadio->IsSelected() != m_channels.m_radio) + { + ReadChannelList(m_ratioIsRadio->IsSelected()); + ReadChannelWhitelist(m_ratioIsRadio->IsSelected()); + ReadChannelBlacklist(m_ratioIsRadio->IsSelected()); + m_channels.CreateProviders(); + m_channels.LoadProviderWhitelist(); + m_channels.LoadChannelBlacklist(); + m_channels.m_loaded = true; + m_channels.m_radio = m_ratioIsRadio->IsSelected(); + m_window->SetProperty("IsDirty", "0"); + } + LoadListItemsProviders(); + m_channels.m_mode = CVNSIChannels::PROVIDER; + } + else if (controlId == CONTROL_CHANNELS_BUTTON) + { + if(!m_channels.m_loaded || m_ratioIsRadio->IsSelected() != m_channels.m_radio) + { + ReadChannelList(m_ratioIsRadio->IsSelected()); + ReadChannelWhitelist(m_ratioIsRadio->IsSelected()); + ReadChannelBlacklist(m_ratioIsRadio->IsSelected()); + m_channels.CreateProviders(); + m_channels.LoadProviderWhitelist(); + m_channels.LoadChannelBlacklist(); + m_channels.m_loaded = true; + m_channels.m_radio = m_ratioIsRadio->IsSelected(); + m_window->SetProperty("IsDirty", "0"); + } + LoadListItemsChannels(); + m_channels.m_mode = CVNSIChannels::CHANNEL; + } + else if (controlId == CONTROL_FILTERSAVE_BUTTON) + { + if(m_channels.m_loaded) + { + SaveChannelWhitelist(m_ratioIsRadio->IsSelected()); + SaveChannelBlacklist(m_ratioIsRadio->IsSelected()); + m_window->SetProperty("IsDirty", "0"); + } + } + else if (controlId == CONTROL_ITEM_LIST) + { + if(m_channels.m_mode == CVNSIChannels::PROVIDER) + { + int pos = m_window->GetCurrentListPosition(); + GUIHANDLE hdl = m_window->GetListItem(pos); + int idx = m_listItemsMap[hdl]; + CAddonListItem *item = m_listItems[idx]; + if (m_channels.m_providers[idx].m_whitelist) + { + item->SetProperty("IsWhitelist", "false"); + m_channels.m_providers[idx].m_whitelist = false; + } + else + { + item->SetProperty("IsWhitelist", "true"); + m_channels.m_providers[idx].m_whitelist = true; + } + m_window->SetProperty("IsDirty", "1"); + } + else if(m_channels.m_mode == CVNSIChannels::CHANNEL) + { + int pos = m_window->GetCurrentListPosition(); + GUIHANDLE hdl = m_window->GetListItem(pos); + int idx = m_listItemsMap[hdl]; + CAddonListItem *item = m_listItems[idx]; + int channelidx = m_listItemsChannelsMap[hdl]; + if (m_channels.m_channels[channelidx].m_blacklist) + { + item->SetProperty("IsBlacklist", "false"); + m_channels.m_channels[channelidx].m_blacklist = false; + } + else + { + item->SetProperty("IsBlacklist", "true"); + m_channels.m_channels[channelidx].m_blacklist = true; + } + m_window->SetProperty("IsDirty", "1"); + } + } return false; } @@ -1022,6 +1117,10 @@ bool cVNSIAdmin::OnInit() m_spinTimeshiftBufferFile->SetValue(mode); delete resp; } + + // channel filters + m_ratioIsRadio = GUI->Control_getRadioButton(m_window, CONTROL_RADIO_ISRADIO); + return true; } @@ -1067,10 +1166,11 @@ bool cVNSIAdmin::OnAction(int actionId) if (actionId == ACTION_SELECT_ITEM) { - int controlID = m_window->GetFocusId(); - if (controlID == CONTROL_MENU) + if (m_window->GetFocusId() == CONTROL_MENU) { - if (strncmp(m_window->GetProperty("menu"), "osd", 3) == 0) + const char *tmp = m_window->GetProperty("menu"); + //if (strncmp(m_window->GetProperty("menu"), "osd", 3) == 0) + if (strncmp(tmp, "osd", 3) == 0) { #if defined(XBMC_GUI_API_VERSION) m_window->MarkDirtyRegion(); @@ -1289,3 +1389,276 @@ bool cVNSIAdmin::ConnectOSD() return true; } + +bool cVNSIAdmin::ReadChannelList(bool radio) +{ + cRequestPacket vrp; + if (!vrp.init(VNSI_CHANNELS_GETCHANNELS)) + { + XBMC->Log(LOG_ERROR, "%s - Can't init cRequestPacket", __FUNCTION__); + return false; + } + if (!vrp.add_U32(radio)) + { + XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); + return false; + } + if (!vrp.add_U8(0)) // apply no filter + { + XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); + return false; + } + + cResponsePacket* vresp = ReadResult(&vrp); + if (!vresp) + { + XBMC->Log(LOG_ERROR, "%s - Can't get response packed", __FUNCTION__); + return false; + } + + m_channels.m_channels.clear(); + m_channels.m_channelsMap.clear(); + while (!vresp->end()) + { + CChannel channel; + channel.m_blacklist = false; + + channel.m_number = vresp->extract_U32(); + char *strChannelName = vresp->extract_String(); + channel.m_name = strChannelName; + char *strProviderName = vresp->extract_String(); + channel.m_provider = strProviderName; + channel.m_id = vresp->extract_U32(); + vresp->extract_U32(); // first caid + char *strCaids = vresp->extract_String(); + channel.SetCaids(strCaids); + channel.m_radio = radio; + + delete[] strChannelName; + delete[] strProviderName; + delete[] strCaids; + m_channels.m_channels.push_back(channel); + m_channels.m_channelsMap[channel.m_id] = m_channels.m_channels.size() - 1; + } + delete vresp; + + return true; +} + +bool cVNSIAdmin::ReadChannelWhitelist(bool radio) +{ + cRequestPacket vrp; + if (!vrp.init(VNSI_CHANNELS_GETWHITELIST)) + { + XBMC->Log(LOG_ERROR, "%s - Can't init cRequestPacket", __FUNCTION__); + return false; + } + if (!vrp.add_U8(radio)) + { + XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); + return false; + } + + cResponsePacket* vresp = ReadResult(&vrp); + if (!vresp) + { + XBMC->Log(LOG_ERROR, "%s - Can't get response packed", __FUNCTION__); + return false; + } + + m_channels.m_providerWhitelist.clear(); + CProvider provider; + while (!vresp->end()) + { + char *strProviderName = vresp->extract_String(); + provider.m_name = strProviderName; + provider.m_caid = vresp->extract_U32(); + m_channels.m_providerWhitelist.push_back(provider); + delete [] strProviderName; + } + delete vresp; + + return true; +} + +bool cVNSIAdmin::SaveChannelWhitelist(bool radio) +{ + m_channels.ExtractProviderWhitelist(); + + cRequestPacket vrp; + if (!vrp.init(VNSI_CHANNELS_SETWHITELIST)) + { + XBMC->Log(LOG_ERROR, "%s - Can't init cRequestPacket", __FUNCTION__); + return false; + } + if (!vrp.add_U8(radio)) + { + XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); + return false; + } + + for(unsigned int i=0; iLog(LOG_ERROR, "%s - Can't get response packed", __FUNCTION__); + return false; + } + + return true; +} + +bool cVNSIAdmin::ReadChannelBlacklist(bool radio) +{ + cRequestPacket vrp; + if (!vrp.init(VNSI_CHANNELS_GETBLACKLIST)) + { + XBMC->Log(LOG_ERROR, "%s - Can't init cRequestPacket", __FUNCTION__); + return false; + } + if (!vrp.add_U8(radio)) + { + XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); + return false; + } + + cResponsePacket* vresp = ReadResult(&vrp); + if (!vresp) + { + XBMC->Log(LOG_ERROR, "%s - Can't get response packed", __FUNCTION__); + return false; + } + + m_channels.m_channelBlacklist.clear(); + while (!vresp->end()) + { + int id = vresp->extract_U32(); + m_channels.m_channelBlacklist.push_back(id); + } + delete vresp; + + return true; +} + +bool cVNSIAdmin::SaveChannelBlacklist(bool radio) +{ + m_channels.ExtractChannelBlacklist(); + + cRequestPacket vrp; + if (!vrp.init(VNSI_CHANNELS_SETBLACKLIST)) + { + XBMC->Log(LOG_ERROR, "%s - Can't init cRequestPacket", __FUNCTION__); + return false; + } + if (!vrp.add_U8(radio)) + { + XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); + return false; + } + + for(unsigned int i=0; iLog(LOG_ERROR, "%s - Can't get response packed", __FUNCTION__); + return false; + } + + return true; +} + +void cVNSIAdmin::ClearListItems() +{ + m_window->ClearList(); + std::vector::iterator it; + for(it=m_listItems.begin(); it!=m_listItems.end(); ++it) + { + GUI->ListItem_destroy(*it); + } + m_listItems.clear(); + m_listItemsMap.clear(); + m_listItemsChannelsMap.clear(); +} + +void cVNSIAdmin::LoadListItemsProviders() +{ + ClearListItems(); + + std::vector::iterator it; + int count = 0; + for(it=m_channels.m_providers.begin(); it!=m_channels.m_providers.end(); ++it) + { + std::string tmp; + if(!it->m_name.empty()) + tmp = it->m_name; + else + tmp = XBMC->GetLocalizedString(30114); + if (it->m_caid == 0) + { + tmp += " - FTA"; + } + else + { + tmp += " - CAID: "; + char buf[16]; + sprintf(buf, "%04x", it->m_caid); + tmp += buf; + } + + CAddonListItem *item = GUI->ListItem_create(tmp.c_str(), NULL, NULL, NULL, NULL); + m_window->AddItem(item, count); + GUIHANDLE hdl = m_window->GetListItem(count); + m_listItems.push_back(item); + m_listItemsMap[hdl] = count; + + if (it->m_whitelist) + item->SetProperty("IsWhitelist", "true"); + else + item->SetProperty("IsWhitelist", "false"); + + count++; + } +} + +void cVNSIAdmin::LoadListItemsChannels() +{ + ClearListItems(); + + int count = 0; + std::string tmp; + for(unsigned int i=0; iGetLocalizedString(30114); + tmp += ")"; + CAddonListItem *item = GUI->ListItem_create(tmp.c_str(), NULL, NULL, NULL, NULL); + m_window->AddItem(item, count); + GUIHANDLE hdl = m_window->GetListItem(count); + m_listItems.push_back(item); + m_listItemsMap[hdl] = count; + m_listItemsChannelsMap[hdl] = i; + + if (m_channels.m_channels[i].m_blacklist) + item->SetProperty("IsBlacklist", "true"); + else + item->SetProperty("IsBlacklist", "false"); + + count++; + } +} diff --git a/addons/pvr.vdr.vnsi/src/VNSIAdmin.h b/addons/pvr.vdr.vnsi/src/VNSIAdmin.h index 3494abb25..0c6129a0d 100644 --- a/addons/pvr.vdr.vnsi/src/VNSIAdmin.h +++ b/addons/pvr.vdr.vnsi/src/VNSIAdmin.h @@ -21,6 +21,7 @@ */ #include "VNSIData.h" +#include "VNSIChannels.h" #include "client.h" class cOSDRender; @@ -60,6 +61,14 @@ class cVNSIAdmin : public cVNSIData virtual void OnReconnect() {}; bool ConnectOSD(); bool IsVdrAction(int action); + bool ReadChannelList(bool radio); + bool ReadChannelWhitelist(bool radio); + bool ReadChannelBlacklist(bool radio); + bool SaveChannelWhitelist(bool radio); + bool SaveChannelBlacklist(bool radio); + void ClearListItems(); + void LoadListItemsProviders(); + void LoadListItemsChannels(); private: @@ -70,6 +79,11 @@ class cVNSIAdmin : public cVNSIData CAddonGUISpinControl *m_spinTimeshiftMode; CAddonGUISpinControl *m_spinTimeshiftBufferRam; CAddonGUISpinControl *m_spinTimeshiftBufferFile; + CAddonGUIRadioButton *m_ratioIsRadio; + std::vector m_listItems; + std::map m_listItemsMap; + std::map m_listItemsChannelsMap; + CVNSIChannels m_channels; bool m_bIsOsdControl; bool m_bIsOsdDirty; int m_width, m_height; diff --git a/addons/pvr.vdr.vnsi/src/VNSIChannels.cpp b/addons/pvr.vdr.vnsi/src/VNSIChannels.cpp new file mode 100644 index 000000000..70a8caa93 --- /dev/null +++ b/addons/pvr.vdr.vnsi/src/VNSIChannels.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "VNSIChannels.h" +#include + +CProvider::CProvider() + :m_name(""), m_caid(0), m_whitelist(false) +{ + +} + +CProvider::CProvider(std::string name, int caid) + :m_name(name), m_caid(caid), m_whitelist(false) +{ +}; + +bool CProvider::operator==(const CProvider &rhs) +{ + if (rhs.m_caid != m_caid) + return false; + if (rhs.m_name.compare(m_name) != 0) + return false; + return true; +} + +void CChannel::SetCaids(char *caids) +{ + m_caids.clear(); + std::string strCaids = caids; + size_t pos = strCaids.find("caids:"); + if(pos == strCaids.npos) + return; + + strCaids.erase(0,6); + std::string token; + int caid; + char *pend; + while ((pos = strCaids.find(";")) != strCaids.npos) + { + token = strCaids.substr(0, pos); + caid = strtol(token.c_str(), &pend, 10); + m_caids.push_back(caid); + strCaids.erase(0, pos+1); + } + if (strCaids.length() > 1) + { + caid = strtol(strCaids.c_str(), &pend, 10); + m_caids.push_back(caid); + } +} + +CVNSIChannels::CVNSIChannels() +{ + m_loaded = false; + m_mode = NONE; + m_radio = false; +} + +void CVNSIChannels::CreateProviders() +{ + std::vector::iterator c_it; + std::vector::iterator p_it; + CProvider provider; + m_providers.clear(); + for (c_it=m_channels.begin(); c_it!=m_channels.end(); ++c_it) + { + provider.m_name = c_it->m_provider; + for(unsigned int i=0; im_caids.size(); i++) + { + provider.m_caid = c_it->m_caids[i]; + p_it = std::find(m_providers.begin(), m_providers.end(), provider); + if (p_it == m_providers.end()) + { + m_providers.push_back(provider); + } + } + if (c_it->m_caids.size() == 0) + { + provider.m_caid = 0; + p_it = std::find(m_providers.begin(), m_providers.end(), provider); + if (p_it == m_providers.end()) + { + m_providers.push_back(provider); + } + } + } +} + +void CVNSIChannels::LoadProviderWhitelist() +{ + std::vector::iterator p_it; + + bool select = m_providerWhitelist.empty(); + for(p_it=m_providers.begin(); p_it!=m_providers.end(); ++p_it) + { + p_it->m_whitelist = select; + } + + std::vector::iterator w_it; + for(w_it=m_providerWhitelist.begin(); w_it!=m_providerWhitelist.end(); ++w_it) + { + p_it = std::find(m_providers.begin(), m_providers.end(), *w_it); + if(p_it != m_providers.end()) + { + p_it->m_whitelist = true; + } + } +} + +void CVNSIChannels::LoadChannelBlacklist() +{ + std::map::iterator it; + for(unsigned int i=0; isecond; + m_channels[idx].m_blacklist = true; + } + } +} + +void CVNSIChannels::ExtractProviderWhitelist() +{ + std::vector::iterator it; + m_providerWhitelist.clear(); + for(it=m_providers.begin(); it!=m_providers.end(); ++it) + { + if(it->m_whitelist) + m_providerWhitelist.push_back(*it); + } + if(m_providerWhitelist.size() == m_providers.size()) + { + m_providerWhitelist.clear(); + } + else if (m_providerWhitelist.size() == 0) + { + m_providerWhitelist.clear(); + CProvider provider; + provider.m_name = "no whitelist"; + provider.m_caid = 0; + m_providerWhitelist.push_back(provider); + } +} + +void CVNSIChannels::ExtractChannelBlacklist() +{ + m_channelBlacklist.clear(); + for(unsigned int i=0; i::iterator p_it; + provider.m_name = channel.m_provider; + if (channel.m_caids.empty()) + { + provider.m_caid = 0; + p_it = std::find(m_providers.begin(), m_providers.end(), provider); + if(p_it!=m_providers.end() && p_it->m_whitelist) + return true; + } + for(unsigned int i=0; im_whitelist) + return true; + } + return false; +} diff --git a/addons/pvr.vdr.vnsi/src/VNSIChannels.h b/addons/pvr.vdr.vnsi/src/VNSIChannels.h new file mode 100644 index 000000000..87d0bc27a --- /dev/null +++ b/addons/pvr.vdr.vnsi/src/VNSIChannels.h @@ -0,0 +1,73 @@ +#pragma once + +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "VNSIData.h" + +class CProvider +{ +public: + CProvider(); + CProvider(std::string name, int caid); + bool operator==(const CProvider &rhs); + std::string m_name; + int m_caid; + bool m_whitelist; +}; + +class CChannel +{ +public: + void SetCaids(char *caids); + unsigned int m_id; + unsigned int m_number; + std::string m_name; + std::string m_provider; + bool m_radio; + std::vector m_caids; + bool m_blacklist; +}; + +class CVNSIChannels +{ +public: + CVNSIChannels(); + void CreateProviders(); + void LoadProviderWhitelist(); + void LoadChannelBlacklist(); + void ExtractProviderWhitelist(); + void ExtractChannelBlacklist(); + bool IsWhitelist(CChannel &channel); + std::vector m_channels; + std::map m_channelsMap; + std::vector m_providers; + std::vector m_providerWhitelist; + std::vector m_channelBlacklist; + bool m_loaded; + bool m_radio; + + enum + { + NONE, + PROVIDER, + CHANNEL + }m_mode; +}; diff --git a/addons/pvr.vdr.vnsi/src/VNSIData.cpp b/addons/pvr.vdr.vnsi/src/VNSIData.cpp index 20f25f3c4..4f0947d03 100644 --- a/addons/pvr.vdr.vnsi/src/VNSIData.cpp +++ b/addons/pvr.vdr.vnsi/src/VNSIData.cpp @@ -210,6 +210,11 @@ bool cVNSIData::GetChannelsList(ADDON_HANDLE handle, bool radio) XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); return false; } + if (!vrp.add_U8(1)) // apply filter + { + XBMC->Log(LOG_ERROR, "%s - Can't add parameter to cRequestPacket", __FUNCTION__); + return false; + } cResponsePacket* vresp = ReadResult(&vrp); if (!vresp) @@ -224,16 +229,18 @@ bool cVNSIData::GetChannelsList(ADDON_HANDLE handle, bool radio) memset(&tag, 0 , sizeof(tag)); tag.iChannelNumber = vresp->extract_U32(); - char *strChannelName = vresp->extract_String(); + char *strChannelName = vresp->extract_String(); strncpy(tag.strChannelName, strChannelName, sizeof(tag.strChannelName) - 1); + char *strProviderName = vresp->extract_String(); tag.iUniqueId = vresp->extract_U32(); - vresp->extract_U32(); // still here for compatibility tag.iEncryptionSystem = vresp->extract_U32(); - vresp->extract_U32(); // uint32_t vtype - currently unused + char *strCaids = vresp->extract_String(); tag.bIsRadio = radio; PVR->TransferChannelEntry(handle, &tag); delete[] strChannelName; + delete[] strProviderName; + delete[] strCaids; } delete vresp; @@ -744,6 +751,39 @@ PVR_ERROR cVNSIData::DeleteRecording(const PVR_RECORDING& recinfo) return PVR_ERROR_NO_ERROR; } +PVR_ERROR cVNSIData::GetRecordingEdl(const PVR_RECORDING& recinfo, PVR_EDL_ENTRY edl[], int *size) +{ + cRequestPacket vrp; + if (!vrp.init(VNSI_RECORDINGS_GETEDL)) + { + XBMC->Log(LOG_ERROR, "%s - Can't init cRequestPacket", __FUNCTION__); + return PVR_ERROR_UNKNOWN; + } + + if (!vrp.add_U32(atoi(recinfo.strRecordingId))) + return PVR_ERROR_UNKNOWN; + + cResponsePacket* vresp = ReadResult(&vrp); + if (vresp == NULL || vresp->noResponse()) + { + delete vresp; + return PVR_ERROR_UNKNOWN; + } + + *size = 0; + while (!vresp->end() && *size < PVR_ADDON_EDL_LENGTH) + { + edl[*size].start = vresp->extract_S64(); + edl[*size].end = vresp->extract_S64(); + edl[*size].type = (PVR_EDL_TYPE)vresp->extract_S32(); + (*size)++; + } + + delete vresp; + + return PVR_ERROR_NO_ERROR; +} + bool cVNSIData::OnResponsePacket(cResponsePacket* pkt) { return false; @@ -934,6 +974,7 @@ bool cVNSIData::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GR vrp.add_String(group.strGroupName); vrp.add_U8(group.bIsRadio); + vrp.add_U8(1); // filter channels cResponsePacket* vresp = ReadResult(&vrp); if (vresp == NULL || vresp->noResponse()) diff --git a/addons/pvr.vdr.vnsi/src/VNSIData.h b/addons/pvr.vdr.vnsi/src/VNSIData.h index 8dc5eada8..615e5bce6 100644 --- a/addons/pvr.vdr.vnsi/src/VNSIData.h +++ b/addons/pvr.vdr.vnsi/src/VNSIData.h @@ -63,6 +63,7 @@ class cVNSIData : public cVNSISession, public PLATFORM::CThread PVR_ERROR GetRecordingsList(ADDON_HANDLE handle); PVR_ERROR RenameRecording(const PVR_RECORDING& recinfo, const char* newname); PVR_ERROR DeleteRecording(const PVR_RECORDING& recinfo); + PVR_ERROR GetRecordingEdl(const PVR_RECORDING& recinfo, PVR_EDL_ENTRY edl[], int *size); cResponsePacket* ReadResult(cRequestPacket* vrp); diff --git a/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp b/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp index f3fa1b461..389357a0c 100644 --- a/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp +++ b/addons/pvr.vdr.vnsi/src/VNSIDemux.cpp @@ -121,6 +121,10 @@ DemuxPacket* cVNSIDemux::Read() p->iStreamId = iStreamId; delete resp; + if (p->dts != DVD_NOPTS_VALUE) + m_CurrentDTS = p->dts; + else if (p->pts != DVD_NOPTS_VALUE) + m_CurrentDTS = p->pts; return p; } else if (iStreamId != -1 && resp->getMuxSerial() != m_MuxPacketSerial) @@ -136,6 +140,13 @@ DemuxPacket* cVNSIDemux::Read() else if (resp->getOpCodeID() == VNSI_STREAM_BUFFERSTATS) { m_bTimeshift = resp->extract_U8(); + m_BufferTimeStart = resp->extract_U32(); + m_BufferTimeEnd = resp->extract_U32(); + } + else if (resp->getOpCodeID() == VNSI_STREAM_REFTIME) + { + m_ReferenceTime = resp->extract_U32(); + m_ReferenceDTS = (double)resp->extract_U64() * DVD_TIME_BASE / 1000000; } delete resp; @@ -210,6 +221,9 @@ bool cVNSIDemux::SwitchChannel(const PVR_CHANNEL &channelinfo) m_channelinfo = channelinfo; m_streams.Clear(); m_MuxPacketSerial = 0; + m_ReferenceTime = 0; + m_BufferTimeStart = 0; + m_BufferTimeEnd = 0; return true; } @@ -232,6 +246,23 @@ bool cVNSIDemux::GetSignalStatus(PVR_SIGNAL_STATUS &qualityinfo) return true; } +time_t cVNSIDemux::GetPlayingTime() +{ + time_t ret; + ret = m_ReferenceTime + (m_CurrentDTS - m_ReferenceDTS) / DVD_TIME_BASE; + return ret; +} + +time_t cVNSIDemux::GetBufferTimeStart() +{ + return m_BufferTimeStart; +} + +time_t cVNSIDemux::GetBufferTimeEnd() +{ + return m_BufferTimeEnd; +} + void cVNSIDemux::StreamChange(cResponsePacket *resp) { std::vector newStreams; diff --git a/addons/pvr.vdr.vnsi/src/VNSIDemux.h b/addons/pvr.vdr.vnsi/src/VNSIDemux.h index b92144e7d..6779cbfd7 100644 --- a/addons/pvr.vdr.vnsi/src/VNSIDemux.h +++ b/addons/pvr.vdr.vnsi/src/VNSIDemux.h @@ -54,6 +54,9 @@ class cVNSIDemux : public cVNSISession bool GetSignalStatus(PVR_SIGNAL_STATUS &qualityinfo); bool IsTimeshift() { return m_bTimeshift; } bool SeekTime(int time, bool backwards, double *startpts); + time_t GetPlayingTime(); + time_t GetBufferTimeStart(); + time_t GetBufferTimeEnd(); protected: @@ -69,4 +72,9 @@ class cVNSIDemux : public cVNSISession SQuality m_Quality; bool m_bTimeshift; uint32_t m_MuxPacketSerial; + time_t m_ReferenceTime; + double m_ReferenceDTS; + double m_CurrentDTS; + time_t m_BufferTimeStart; + time_t m_BufferTimeEnd; }; diff --git a/addons/pvr.vdr.vnsi/src/client.cpp b/addons/pvr.vdr.vnsi/src/client.cpp index 1a7962602..58986159a 100644 --- a/addons/pvr.vdr.vnsi/src/client.cpp +++ b/addons/pvr.vdr.vnsi/src/client.cpp @@ -355,6 +355,7 @@ PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES* pCapabilities) { pCapabilities->bSupportsEPG = true; pCapabilities->bSupportsRecordings = true; + pCapabilities->bSupportsRecordingEdl = true; pCapabilities->bSupportsTimers = true; pCapabilities->bSupportsTV = true; pCapabilities->bSupportsRadio = true; @@ -647,6 +648,30 @@ bool SeekTime(int time, bool backwards, double *startpts) return ret; } +time_t GetPlayingTime() +{ + time_t time = 0; + if (VNSIDemuxer) + time = VNSIDemuxer->GetPlayingTime(); + return time; +} + +time_t GetBufferTimeStart() +{ + time_t time = 0; + if (VNSIDemuxer) + time = VNSIDemuxer->GetBufferTimeStart(); + return time; +} + +time_t GetBufferTimeEnd() +{ + time_t time = 0; + if (VNSIDemuxer) + time = VNSIDemuxer->GetBufferTimeEnd(); + return time; +} + void SetSpeed(int) {}; void PauseStream(bool bPaused) {} @@ -706,6 +731,15 @@ long long LengthRecordedStream(void) return 0; } +PVR_ERROR GetRecordingEdl(const PVR_RECORDING& recinfo, PVR_EDL_ENTRY edl[], int *size) +{ + if(!VNSIData) + return PVR_ERROR_UNKNOWN; + + return VNSIData->GetRecordingEdl(recinfo, edl, size); +} + + /*******************************************/ /** PVR Menu Hook Functions **/ @@ -735,9 +769,5 @@ const char * GetLiveStreamURL(const PVR_CHANNEL &channel) { return ""; } PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING &recording, int count) { return PVR_ERROR_NOT_IMPLEMENTED; } PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition) { return PVR_ERROR_NOT_IMPLEMENTED; } int GetRecordingLastPlayedPosition(const PVR_RECORDING &recording) { return -1; } -PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY[], int*) { return PVR_ERROR_NOT_IMPLEMENTED; }; unsigned int GetChannelSwitchDelay(void) { return 0; } -time_t GetPlayingTime() { return 0; } -time_t GetBufferTimeStart() { return 0; } -time_t GetBufferTimeEnd() { return 0; } } diff --git a/addons/pvr.vdr.vnsi/src/vnsicommand.h b/addons/pvr.vdr.vnsi/src/vnsicommand.h index f591e9958..bc4c1d787 100644 --- a/addons/pvr.vdr.vnsi/src/vnsicommand.h +++ b/addons/pvr.vdr.vnsi/src/vnsicommand.h @@ -23,7 +23,7 @@ #define VNSI_COMMAND_H /** Current VNSI Protocol Version number */ -#define VNSI_PROTOCOLVERSION 4 +#define VNSI_PROTOCOLVERSION 5 /** Packet types */ #define VNSI_CHANNEL_REQUEST_RESPONSE 1 @@ -68,6 +68,11 @@ #define VNSI_CHANNELGROUP_GETCOUNT 65 #define VNSI_CHANNELGROUP_LIST 66 #define VNSI_CHANNELGROUP_MEMBERS 67 +#define VNSI_CHANNELS_GETCAIDS 68 +#define VNSI_CHANNELS_GETWHITELIST 69 +#define VNSI_CHANNELS_GETBLACKLIST 70 +#define VNSI_CHANNELS_SETWHITELIST 71 +#define VNSI_CHANNELS_SETBLACKLIST 72 /* OPCODE 80 - 99: VNSI network functions for timer access */ #define VNSI_TIMER_GETCOUNT 80 @@ -83,6 +88,7 @@ #define VNSI_RECORDINGS_GETLIST 102 #define VNSI_RECORDINGS_RENAME 103 #define VNSI_RECORDINGS_DELETE 104 +#define VNSI_RECORDINGS_GETEDL 105 /* OPCODE 120 - 139: VNSI network functions for epg access and manipulating */ #define VNSI_EPG_GETFORCHANNEL 120 @@ -107,6 +113,7 @@ #define VNSI_STREAM_SIGNALINFO 5 #define VNSI_STREAM_CONTENTINFO 6 #define VNSI_STREAM_BUFFERSTATS 7 +#define VNSI_STREAM_REFTIME 8 /** Scan packet types (server -> client) */ #define VNSI_SCANNER_PERCENTAGE 1 diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/HISTORY b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/HISTORY index 4be1019d0..980d8ce23 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/HISTORY +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/HISTORY @@ -12,3 +12,12 @@ VDR Plugin 'vnsiserver' Revision History - proper handling of PMT changes - suffix plugin with version of protocol: vnsiserver3 - this version is compatible with XBMC 12.0 + +2013-12-04: Version 0.9.3 + +- add support for EDL (marks) +- add channel filter +- send buffer times for timeshift +- bump protocol to XBMC to 5 +- suffix plugin with version of protocol: vnsiserver5 +- this version is compatible with XBMC 13 \ No newline at end of file diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile index 8f37c9259..f15fdb9cb 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile @@ -7,7 +7,7 @@ # This name will be used in the '-P...' option of VDR to load the plugin. # By default the main source file also carries this name. -PLUGIN = vnsiserver4 +PLUGIN = vnsiserver5 ### The version number of this plugin (taken from the main source file): @@ -90,7 +90,7 @@ OBJS = vnsi.o bitstream.o vnsiclient.o config.o cxsocket.o parser.o parser_AAC.o parser_AC3.o parser_DTS.o parser_h264.o parser_MPEGAudio.o parser_MPEGVideo.o \ parser_Subtitle.o parser_Teletext.o streamer.o recplayer.o requestpacket.o responsepacket.o \ vnsiserver.o hash.o recordingscache.o setup.o vnsiosd.o demuxer.o videobuffer.o \ - videoinput.o + videoinput.o channelfilter.o ### The main target: diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.c new file mode 100644 index 000000000..d8a61ca48 --- /dev/null +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "channelfilter.h" +#include "config.h" +#include "hash.h" +#include +#include +#include +#include +#include + +cVNSIProvider::cVNSIProvider() + :m_name(""), m_caid(0) +{ + +} + +cVNSIProvider::cVNSIProvider(std::string name, int caid) + :m_name(name), m_caid(caid) +{ +}; + +bool cVNSIProvider::operator==(const cVNSIProvider &rhs) +{ + if (rhs.m_caid != m_caid) + return false; + if (rhs.m_name.compare(m_name) != 0) + return false; + return true; +} + + +bool cVNSIChannelFilter::IsRadio(const cChannel* channel) +{ + bool isRadio = false; + + // assume channels without VPID & APID are video channels + if (channel->Vpid() == 0 && channel->Apid(0) == 0) + isRadio = false; + // channels without VPID are radio channels (channels with VPID 1 are encrypted radio channels) + else if (channel->Vpid() == 0 || channel->Vpid() == 1) + isRadio = true; + + return isRadio; +} + +void cVNSIChannelFilter::Load() +{ + cMutexLock lock(&m_Mutex); + + cString filename; + std::string line; + std::ifstream rfile; + cVNSIProvider provider; + std::vector::iterator p_it; + + filename = cString::sprintf("%s/videowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory); + m_providersVideo.clear(); + rfile.open(filename); + if (rfile.is_open()) + { + while(std::getline(rfile,line)) + { + size_t pos = line.find("|"); + if(pos == line.npos) + { + provider.m_name = line; + provider.m_caid = 0; + } + else + { + provider.m_name = line.substr(0, pos); + std::string tmp = line.substr(pos+1); + char *pend; + provider.m_caid = strtol(tmp.c_str(), &pend, 10); + } + p_it = std::find(m_providersVideo.begin(), m_providersVideo.end(), provider); + if(p_it == m_providersVideo.end()) + { + m_providersVideo.push_back(provider); + } + } + rfile.close(); + } + + filename = cString::sprintf("%s/radiowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory); + rfile.open(filename); + m_providersRadio.clear(); + if (rfile.is_open()) + { + while(std::getline(rfile,line)) + { + unsigned int pos = line.find("|"); + if(pos == line.npos) + { + provider.m_name = line; + provider.m_caid = 0; + } + else + { + provider.m_name = line.substr(0, pos); + std::string tmp = line.substr(pos+1); + char *pend; + provider.m_caid = strtol(tmp.c_str(), &pend, 10); + } + p_it = std::find(m_providersRadio.begin(), m_providersRadio.end(), provider); + if(p_it == m_providersRadio.end()) + { + m_providersRadio.push_back(provider); + } + } + rfile.close(); + } + + filename = cString::sprintf("%s/videoblacklist.vnsi", *VNSIServerConfig.ConfigDirectory); + rfile.open(filename); + m_channelsVideo.clear(); + if (rfile.is_open()) + { + while(getline(rfile,line)) + { + char *pend; + int id = strtol(line.c_str(), &pend, 10); + m_channelsVideo.push_back(id); + } + rfile.close(); + } + + filename = cString::sprintf("%s/radioblacklist.vnsi", *VNSIServerConfig.ConfigDirectory); + rfile.open(filename); + m_channelsRadio.clear(); + if (rfile.is_open()) + { + while(getline(rfile,line)) + { + char *pend; + int id = strtol(line.c_str(), &pend, 10); + m_channelsRadio.push_back(id); + } + rfile.close(); + } +} + +void cVNSIChannelFilter::StoreWhitelist(bool radio) +{ + cMutexLock lock(&m_Mutex); + + cString filename; + std::ofstream wfile; + cVNSIProvider provider; + std::vector::iterator p_it; + std::vector *whitelist; + + if (radio) + { + filename = cString::sprintf("%s/radiowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory); + whitelist = &m_providersRadio; + } + else + { + filename = cString::sprintf("%s/videowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory); + whitelist = &m_providersVideo; + } + + wfile.open(filename); + if(wfile.is_open()) + { + std::string tmp; + char buf[16]; + for(p_it=whitelist->begin(); p_it!=whitelist->end(); ++p_it) + { + tmp = p_it->m_name; + tmp += "|"; + sprintf(buf, "%d\n", p_it->m_caid); + tmp += buf; + wfile << tmp; + } + wfile.close(); + } + + SortChannels(); +} + +void cVNSIChannelFilter::StoreBlacklist(bool radio) +{ + cMutexLock lock(&m_Mutex); + + cString filename; + std::ofstream wfile; + cVNSIProvider provider; + std::vector::iterator it; + std::vector *blacklist; + + if (radio) + { + filename = cString::sprintf("%s/radioblacklist.vnsi", *VNSIServerConfig.ConfigDirectory); + blacklist = &m_channelsRadio; + } + else + { + filename = cString::sprintf("%s/videoblacklist.vnsi", *VNSIServerConfig.ConfigDirectory); + blacklist = &m_channelsVideo; + } + + wfile.open(filename); + if(wfile.is_open()) + { + std::string tmp; + char buf[16]; + for(it=blacklist->begin(); it!=blacklist->end(); ++it) + { + sprintf(buf, "%d\n", *it); + tmp = buf; + wfile << tmp; + } + wfile.close(); + } + + SortChannels(); +} + +bool cVNSIChannelFilter::IsWhitelist(const cChannel &channel) +{ + cVNSIProvider provider; + std::vector::iterator p_it; + std::vector *providers; + provider.m_name = channel.Provider(); + + if (IsRadio(&channel)) + providers = &m_providersRadio; + else + providers = &m_providersVideo; + + if(providers->empty()) + return true; + + if (channel.Ca(0) == 0) + { + provider.m_caid = 0; + p_it = std::find(providers->begin(), providers->end(), provider); + if(p_it!=providers->end()) + return true; + else + return false; + } + + int caid; + int idx = 0; + while((caid = channel.Ca(idx)) != 0) + { + provider.m_caid = caid; + p_it = std::find(providers->begin(), providers->end(), provider); + if(p_it!=providers->end()) + return true; + + idx++; + } + return false; +} + +bool cVNSIChannelFilter::PassFilter(const cChannel &channel) +{ + cMutexLock lock(&m_Mutex); + + if(channel.GroupSep()) + return true; + + if (!IsWhitelist(channel)) + return false; + + std::vector::iterator it; + if (IsRadio(&channel)) + { + it = std::find(m_channelsRadio.begin(), m_channelsRadio.end(), CreateChannelUID(&channel)); + if(it!=m_channelsRadio.end()) + return false; + } + else + { + it = std::find(m_channelsVideo.begin(), m_channelsVideo.end(), CreateChannelUID(&channel)); + if(it!=m_channelsVideo.end()) + return false; + } + + return true; +} + +void cVNSIChannelFilter::SortChannels() +{ + Channels.IncBeingEdited(); + Channels.Lock(true); + + for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) + { + if(!PassFilter(*channel)) + { + for (cChannel *whitechan = Channels.Next(channel); whitechan; whitechan = Channels.Next(whitechan)) + { + if(PassFilter(*whitechan)) + { + Channels.Move(whitechan, channel); + channel = whitechan; + break; + } + } + } + } + + Channels.SetModified(true); + Channels.Unlock(); + Channels.DecBeingEdited(); +} + +cVNSIChannelFilter VNSIChannelFilter; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.h new file mode 100644 index 000000000..dc4972815 --- /dev/null +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#pragma once + +#include +#include +#include +#include + +class cVNSIProvider +{ +public: + cVNSIProvider(); + cVNSIProvider(std::string name, int caid); + bool operator==(const cVNSIProvider &rhs); + std::string m_name; + int m_caid; +}; + +class cVNSIChannelFilter +{ +public: + void Load(); + void StoreWhitelist(bool radio); + void StoreBlacklist(bool radio); + bool IsWhitelist(const cChannel &channel); + bool PassFilter(const cChannel &channel); + void SortChannels(); + static bool IsRadio(const cChannel* channel); + std::vector m_providersVideo; + std::vector m_providersRadio; + std::vector m_channelsVideo; + std::vector m_channelsRadio; + cMutex m_Mutex; +}; + +extern cVNSIChannelFilter VNSIChannelFilter; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c index 1f3c9e85b..1e249cd93 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.c @@ -50,13 +50,14 @@ void cVNSIDemuxer::Open(const cChannel &channel, cVideoBuffer *videoBuffer) else m_WaitIFrame = false; - m_FirstFrameDTS = 0; + m_FirstFramePTS = 0; m_PtsWrap.m_Wrap = false; m_PtsWrap.m_NoOfWraps = 0; m_PtsWrap.m_ConfirmCount = 0; m_MuxPacketSerial = 0; m_Error = ERROR_DEMUX_NODATA; + m_SetRefTime = true; } void cVNSIDemuxer::Close() @@ -88,7 +89,7 @@ int cVNSIDemuxer::Read(sStreamPacket *packet) packet->pmtChange = false; // read TS Packet from buffer - len = m_VideoBuffer->Read(&buf, TS_SIZE); + len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime); // eof if (len == -2) return -2; @@ -136,14 +137,21 @@ int cVNSIDemuxer::Read(sStreamPacket *packet) { if (m_WaitIFrame) { - m_FirstFrameDTS = packet->dts; + if (packet->pts != DVD_NOPTS_VALUE) + m_FirstFramePTS = packet->pts; m_WaitIFrame = false; } - if (packet->dts < m_FirstFrameDTS) + if (packet->pts < m_FirstFramePTS) return 0; packet->serial = m_MuxPacketSerial; + if (m_SetRefTime) + { + m_refTime = m_VideoBuffer->GetRefTime(); + packet->reftime = m_refTime; + m_SetRefTime = false; + } return 1; } else if (error < 0) @@ -316,9 +324,27 @@ bool cVNSIDemuxer::SeekTime(int64_t time) return true; } -void cVNSIDemuxer::BufferStatus(bool ×hift, int &start, int ¤t, int &end) +void cVNSIDemuxer::BufferStatus(bool ×hift, uint32_t &start, uint32_t &end) { timeshift = m_VideoBuffer->HasBuffer(); + + if (timeshift) + { + if (!m_wrapTime) + { + start = m_refTime; + } + else + { + start = m_endTime - (m_wrapTime - m_refTime); + } + end = m_endTime; + } + else + { + start = 0; + end = 0; + } } cTSStream *cVNSIDemuxer::GetFirstStream() @@ -600,7 +626,7 @@ bool cVNSIDemuxer::GetTimeAtPos(off_t *pos, int64_t *time) m_VideoBuffer->SetPos(*pos); ResetParsers(); - while (len = m_VideoBuffer->Read(&buf, TS_SIZE) == TS_SIZE) + while (len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime) == TS_SIZE) { ts_pid = TsPid(buf); if (stream = FindStream(ts_pid)) diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h index 019595fed..cf7198310 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/demuxer.h @@ -60,7 +60,7 @@ class cVNSIDemuxer bool SeekTime(int64_t time); uint32_t GetSerial() { return m_MuxPacketSerial; } void SetSerial(uint32_t serial) { m_MuxPacketSerial = serial; } - void BufferStatus(bool ×hift, int &start, int ¤t, int &end); + void BufferStatus(bool ×hift, uint32_t &start, uint32_t &end); uint16_t GetError(); protected: @@ -78,10 +78,12 @@ class cVNSIDemuxer cPatPmtParser m_PatPmtParser; int m_OldPmtVersion; bool m_WaitIFrame; - int64_t m_FirstFrameDTS; + int64_t m_FirstFramePTS; cVideoBuffer *m_VideoBuffer; cMutex m_Mutex; uint32_t m_MuxPacketSerial; sPtsWrap m_PtsWrap; uint16_t m_Error; + bool m_SetRefTime; + time_t m_refTime, m_endTime, m_wrapTime; }; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.c index d325fae15..93be4925f 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.c @@ -164,7 +164,7 @@ int cParser::ParsePESHeader(uint8_t *buf, size_t len) } } else - m_curDTS = m_curPTS; + m_curDTS = DVD_NOPTS_VALUE; return hdr_len; } @@ -521,10 +521,10 @@ cTSStream::~cTSStream() int cTSStream::ProcessTSPacket(uint8_t *data, sStreamPacket *pkt, bool iframe) { if (!data) - return false; + return 1; if (!m_pesParser) - return false; + return 1; int payloadSize = m_pesParser->ParsePacketHeader(data); if (payloadSize == 0) @@ -548,12 +548,11 @@ int cTSStream::ProcessTSPacket(uint8_t *data, sStreamPacket *pkt, bool iframe) int64_t dts = pkt->dts; int64_t pts = pkt->pts; - if (dts == DVD_NOPTS_VALUE) - dts = pts; - // Rescale for XBMC - pkt->dts = Rescale(dts, DVD_TIME_BASE, 90000); - pkt->pts = Rescale(pts, DVD_TIME_BASE, 90000); + if (pkt->dts != DVD_NOPTS_VALUE) + pkt->dts = Rescale(dts, DVD_TIME_BASE, 90000); + if (pkt->pts != DVD_NOPTS_VALUE) + pkt->pts = Rescale(pts, DVD_TIME_BASE, 90000); pkt->duration = Rescale(pkt->duration, DVD_TIME_BASE, 90000); return 0; } @@ -578,6 +577,7 @@ bool cTSStream::ReadTime(uint8_t *data, int64_t *dts) data += TS_SIZE-payloadSize; if (payloadSize >= 6 && m_pesParser->IsValidStartCode(data, payloadSize)) { + m_pesParser->m_curPTS = DVD_NOPTS_VALUE; m_pesParser->m_curDTS = DVD_NOPTS_VALUE; m_pesParser->ParsePESHeader(data, payloadSize); if (m_pesParser->m_curDTS != DVD_NOPTS_VALUE) @@ -585,6 +585,11 @@ bool cTSStream::ReadTime(uint8_t *data, int64_t *dts) *dts = m_pesParser->m_curDTS; return true; } + else if (m_pesParser->m_curPTS != DVD_NOPTS_VALUE) + { + *dts = m_pesParser->m_curPTS; + return true; + } } m_pesParser->m_IsPusi = false; } diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.h index f3e8db439..d0f7b648e 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser.h @@ -122,6 +122,7 @@ struct sStreamPacket bool streamChange; bool pmtChange; uint32_t serial; + uint32_t reftime; }; struct sPtsWrap diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.c index 5aa911a60..be8919d80 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.c @@ -57,6 +57,7 @@ cParserMPEG2Video::cParserMPEG2Video(int pID, cTSStream *stream, sPtsWrap *ptsWr m_Height = 0; m_Width = 0; m_Dar = 0.0; + m_FpsScale = 0; m_PesBufferInitialSize = 80000; m_IsVideo = true; Reset(); @@ -93,8 +94,14 @@ void cParserMPEG2Video::Parse(sStreamPacket *pkt) { if (!m_NeedSPS && !m_NeedIFrame) { - int fpsScale = m_Stream->Rescale(m_FrameDuration, DVD_TIME_BASE, 90000); - bool streamChange = m_Stream->SetVideoInformation(fpsScale,DVD_TIME_BASE, m_Height, m_Width, m_Dar); + if (m_FpsScale == 0) + { + if (m_FrameDuration != DVD_NOPTS_VALUE) + m_FpsScale = m_Stream->Rescale(m_FrameDuration, DVD_TIME_BASE, 90000); + else + m_FpsScale = 40000; + } + bool streamChange = m_Stream->SetVideoInformation(m_FpsScale, DVD_TIME_BASE, m_Height, m_Width, m_Dar); pkt->id = m_pID; pkt->size = m_PesNextFramePtr; @@ -148,13 +155,12 @@ int cParserMPEG2Video::Parse_MPEG2Video(uint32_t startcode, int buf_ptr, bool &c m_AuPrevDTS = m_AuDTS; if (buf_ptr - 4 >= m_PesTimePos) { - - m_AuDTS = m_curDTS; + m_AuDTS = m_curDTS != DVD_NOPTS_VALUE ? m_curDTS : m_curPTS; m_AuPTS = m_curPTS; } else { - m_AuDTS = m_prevDTS; + m_AuDTS = m_prevDTS != DVD_NOPTS_VALUE ? m_prevDTS : m_prevPTS;; m_AuPTS = m_prevPTS; } } diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.h index 18da85850..c5d2d9e74 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_MPEGVideo.h @@ -46,6 +46,7 @@ class cParserMPEG2Video : public cParser int m_TemporalReference; int m_TrLastTime; int m_PicNumber; + int m_FpsScale; int Parse_MPEG2Video(uint32_t startcode, int buf_ptr, bool &complete); bool Parse_MPEG2Video_SeqStart(uint8_t *buf); diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_h264.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_h264.c index 6d45e307c..9de43c810 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_h264.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/parser_h264.c @@ -99,19 +99,28 @@ void cParserH264::Parse(sStreamPacket *pkt) double DAR = (PAR * m_Width) / m_Height; DEBUGLOG("H.264 SPS: PAR %i:%i", m_PixelAspect.num, m_PixelAspect.den); DEBUGLOG("H.264 SPS: DAR %.2f", DAR); -// int fpsScale = DVD_TIME_BASE / m_FPS; + if (m_FpsScale == 0) { - m_FpsScale = m_Stream->Rescale(m_curDTS - m_prevDTS, DVD_TIME_BASE, 90000); + if (m_curDTS != DVD_NOPTS_VALUE && m_prevDTS != DVD_NOPTS_VALUE) + m_FpsScale = m_Stream->Rescale(m_curDTS - m_prevDTS, DVD_TIME_BASE, 90000); + else + m_FpsScale = 40000; } - bool streamChange = m_Stream->SetVideoInformation(m_FpsScale,DVD_TIME_BASE, m_Height, m_Width, DAR); + bool streamChange = m_Stream->SetVideoInformation(m_FpsScale, DVD_TIME_BASE, m_Height, m_Width, DAR); + + int duration; + if (m_curDTS != DVD_NOPTS_VALUE && m_prevDTS != DVD_NOPTS_VALUE) + duration = m_curDTS - m_prevDTS; + else + duration = m_Stream->Rescale(m_FpsScale, 90000, DVD_TIME_BASE); pkt->id = m_pID; pkt->size = m_PesNextFramePtr; pkt->data = m_PesBuffer; pkt->dts = m_DTS; pkt->pts = m_PTS; - pkt->duration = m_curDTS - m_prevDTS; + pkt->duration = duration; pkt->streamChange = streamChange; } m_StartCode = 0xffffffff; @@ -226,7 +235,7 @@ int cParserH264::Parse_H264(uint32_t startcode, int buf_ptr, bool &complete) } case NAL_AUD: - if (m_FoundFrame && (m_prevDTS != DVD_NOPTS_VALUE)) + if (m_FoundFrame && (m_prevPTS != DVD_NOPTS_VALUE)) { complete = true; m_PesNextFramePtr = buf_ptr - 4; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.c index b9b81a37d..d79b8c40d 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.c @@ -165,6 +165,7 @@ void cLiveStreamer::Action(void) { int ret; sStreamPacket pkt; + memset(&pkt, 0, sizeof(sStreamPacket)); bool requestStreamChange = false; cTimeMs last_info(1000); cTimeMs bufferStatsTimer(1000); @@ -183,6 +184,11 @@ void cLiveStreamer::Action(void) if (pkt.streamChange || requestStreamChange) sendStreamChange(); requestStreamChange = false; + if (pkt.reftime) + { + sendRefTime(&pkt); + pkt.reftime = 0; + } sendStreamPacket(&pkt); } @@ -601,13 +607,32 @@ void cLiveStreamer::sendBufferStatus() delete resp; return; } - int32_t start, current, end; + uint32_t start, end; bool timeshift; - m_Demuxer.BufferStatus(timeshift, start, current, end); + m_Demuxer.BufferStatus(timeshift, start, end); resp->add_U8(timeshift); - resp->add_S32(start); - resp->add_S32(current); - resp->add_S32(end); + resp->add_U32(start); + resp->add_U32(end); + resp->finaliseStream(); + m_Socket->write(resp->getPtr(), resp->getLen()); + delete resp; +} + +void cLiveStreamer::sendRefTime(sStreamPacket *pkt) +{ + if(pkt == NULL) + return; + + cResponsePacket *resp = new cResponsePacket(); + if (!resp->initStream(VNSI_STREAM_REFTIME, 0, 0, 0, 0, 0)) + { + ERRORLOG("stream response packet init fail"); + delete resp; + return; + } + + resp->add_U32(pkt->reftime); + resp->add_U64(pkt->pts); resp->finaliseStream(); m_Socket->write(resp->getPtr(), resp->getLen()); delete resp; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.h index 3c308e5cc..6cf54d217 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/streamer.h @@ -58,6 +58,7 @@ class cLiveStreamer : public cThread void sendSignalInfo(); void sendStreamStatus(); void sendBufferStatus(); + void sendRefTime(sStreamPacket *pkt); int m_ClientID; const cChannel *m_Channel; /*!> Channel to stream */ diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.c index 92c38f0d7..ebd9fe50a 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.c @@ -37,7 +37,7 @@ class cVideoBufferSimple : public cVideoBuffer friend class cVideoBuffer; public: virtual void Put(uint8_t *buf, unsigned int size); - virtual int ReadBlock(uint8_t **buf, unsigned int size); + virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime); protected: cVideoBufferSimple(); @@ -64,7 +64,7 @@ void cVideoBufferSimple::Put(uint8_t *buf, unsigned int size) m_Buffer->Put(buf, size); } -int cVideoBufferSimple::ReadBlock(uint8_t **buf, unsigned int size) +int cVideoBufferSimple::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime) { int readBytes; if (m_BytesConsumed) @@ -96,6 +96,8 @@ int cVideoBufferSimple::ReadBlock(uint8_t **buf, unsigned int size) } m_BytesConsumed += TS_SIZE; + endTime = 0; + wrapTime = 0; return TS_SIZE; } @@ -193,7 +195,7 @@ class cVideoBufferRAM : public cVideoBufferTimeshift friend class cVideoBuffer; public: virtual void Put(uint8_t *buf, unsigned int size); - virtual int ReadBlock(uint8_t **buf, unsigned int size); + virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime); virtual void SetPos(off_t pos); protected: @@ -263,11 +265,16 @@ void cVideoBufferRAM::Put(uint8_t *buf, unsigned int size) if (!m_BufferFull) { if ((m_WritePtr + 2*MARGIN) > m_BufferSize) + { m_BufferFull = true; + time(&m_bufferWrapTime); + } } + + time(&m_bufferEndTime); } -int cVideoBufferRAM::ReadBlock(uint8_t **buf, unsigned int size) +int cVideoBufferRAM::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime) { // move read pointer if (m_BytesConsumed) @@ -276,6 +283,9 @@ int cVideoBufferRAM::ReadBlock(uint8_t **buf, unsigned int size) m_ReadPtr += m_BytesConsumed; if (m_ReadPtr >= m_BufferSize) m_ReadPtr -= m_BufferSize; + + endTime = m_bufferEndTime; + wrapTime = m_bufferWrapTime; } m_BytesConsumed = 0; @@ -323,7 +333,7 @@ friend class cVideoBuffer; public: virtual off_t GetPosMax(); virtual void Put(uint8_t *buf, unsigned int size); - virtual int ReadBlock(uint8_t **buf, unsigned int size); + virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime); virtual void SetPos(off_t pos); protected: @@ -491,8 +501,13 @@ void cVideoBufferFile::Put(uint8_t *buf, unsigned int size) if (!m_BufferFull) { if ((m_WritePtr + 2*MARGIN) > m_BufferSize) + { m_BufferFull = true; + time(&m_bufferWrapTime); + } } + + time(&m_bufferEndTime); } int cVideoBufferFile::ReadBytes(uint8_t *buf, off_t pos, unsigned int size) @@ -509,7 +524,7 @@ int cVideoBufferFile::ReadBytes(uint8_t *buf, off_t pos, unsigned int size) } } -int cVideoBufferFile::ReadBlock(uint8_t **buf, unsigned int size) +int cVideoBufferFile::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime) { // move read pointer if (m_BytesConsumed) @@ -519,6 +534,9 @@ int cVideoBufferFile::ReadBlock(uint8_t **buf, unsigned int size) if (m_ReadPtr >= m_BufferSize) m_ReadPtr -= m_BufferSize; m_ReadCachePtr += m_BytesConsumed; + + endTime = m_bufferEndTime; + wrapTime = m_bufferWrapTime; } m_BytesConsumed = 0; @@ -607,7 +625,8 @@ friend class cVideoBuffer; public: virtual off_t GetPosMax(); virtual void Put(uint8_t *buf, unsigned int size); - virtual int ReadBlock(uint8_t **buf, unsigned int size); + virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime); + virtual time_t GetRefTime(); protected: cVideoBufferRecording(cRecording *rec); @@ -663,9 +682,15 @@ bool cVideoBufferRecording::Init() m_ReadCacheSize = 0; m_InputAttached = false; m_ScanTimer.Set(0); + return true; } +time_t cVideoBufferRecording::GetRefTime() +{ + return m_Recording->Start(); +} + off_t cVideoBufferRecording::Available() { if (m_ScanTimer.TimedOut()) @@ -677,7 +702,7 @@ off_t cVideoBufferRecording::Available() return cVideoBufferTimeshift::Available(); } -int cVideoBufferRecording::ReadBlock(uint8_t **buf, unsigned int size) +int cVideoBufferRecording::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime) { // move read pointer if (m_BytesConsumed) @@ -739,6 +764,8 @@ int cVideoBufferRecording::ReadBlock(uint8_t **buf, unsigned int size) } m_BytesConsumed += TS_SIZE; + time(&endTime); + wrapTime = 0; return TS_SIZE; } @@ -829,6 +856,8 @@ cVideoBuffer::cVideoBuffer() { m_CheckEof = false; m_InputAttached = true; + m_bufferEndTime = 0; + m_bufferWrapTime = 0; } cVideoBuffer::~cVideoBuffer() @@ -897,9 +926,9 @@ cVideoBuffer* cVideoBuffer::Create(cRecording *rec) return buffer; } -int cVideoBuffer::Read(uint8_t **buf, unsigned int size) +int cVideoBuffer::Read(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime) { - int count = ReadBlock(buf, size); + int count = ReadBlock(buf, size, endTime, wrapTime); // check for end of file if (!m_InputAttached && count != TS_SIZE) @@ -925,3 +954,10 @@ void cVideoBuffer::AttachInput(bool attach) { m_InputAttached = attach; } + +time_t cVideoBuffer::GetRefTime() +{ + time_t t; + time(&t); + return t; +} diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.h index 8ea74fca3..c61bd3c52 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/videobuffer.h @@ -34,7 +34,7 @@ class cVideoBuffer static cVideoBuffer* Create(cString filename); static cVideoBuffer* Create(cRecording *rec); virtual void Put(uint8_t *buf, unsigned int size) = 0; - virtual int ReadBlock(uint8_t **buf, unsigned int size) = 0; + virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime) = 0; virtual off_t GetPosMin() { return 0; }; virtual off_t GetPosMax() { return 0; }; virtual off_t GetPosCur() { return 0; }; @@ -42,11 +42,14 @@ class cVideoBuffer virtual void SetPos(off_t pos) {}; virtual void SetCache(bool on) {}; virtual bool HasBuffer() { return false; }; - int Read(uint8_t **buf, unsigned int size); + virtual time_t GetRefTime(); + int Read(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime); void AttachInput(bool attach); protected: cVideoBuffer(); cTimeMs m_Timer; bool m_CheckEof; bool m_InputAttached; + time_t m_bufferEndTime; + time_t m_bufferWrapTime; }; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h index eb7ed7983..e82450b09 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsi.h @@ -27,7 +27,7 @@ #include #include "vnsiserver.h" -static const char *VERSION = "0.9.2"; +static const char *VERSION = "0.9.3"; static const char *DESCRIPTION = "VDR-Network-Streaming-Interface (VNSI) Server"; extern int PmtTimeout; diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.c index f88d00b86..d2143f94e 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.c @@ -47,24 +47,11 @@ #include "requestpacket.h" #include "responsepacket.h" #include "hash.h" +#include "channelfilter.h" #include "wirbelscanservice.h" /// copied from modified wirbelscan plugin /// must be hold up to date with wirbelscan -static bool IsRadio(const cChannel* channel) -{ - bool isRadio = false; - - // assume channels without VPID & APID are video channels - if (channel->Vpid() == 0 && channel->Apid(0) == 0) - isRadio = false; - // channels without VPID are radio channels (channels with VPID 1 are encrypted radio channels) - else if (channel->Vpid() == 0 || channel->Vpid() == 1) - isRadio = true; - - return isRadio; -} - cMutex cVNSIClient::m_timerLock; cVNSIClient::cVNSIClient(int fd, unsigned int id, const char *ClientAdr) @@ -275,15 +262,24 @@ void cVNSIClient::EpgChange() if (!lastEvent) continue; + Channels.Lock(false); + const cChannel *channel = Channels.GetByChannelID(schedule->ChannelID()); + Channels.Unlock(); + + if (!channel) + continue; + + if (!VNSIChannelFilter.PassFilter(*channel)) + continue; + uint32_t channelId = CreateStringHash(schedule->ChannelID().ToString()); it = m_epgUpdate.find(channelId); - if (it == m_epgUpdate.end()) + if (it != m_epgUpdate.end() && it->second >= lastEvent->StartTime()) { continue; } - if (it->second >= lastEvent->StartTime()) - continue; + INFOLOG("Trigger EPG update for channel %s, id: %d", channel->Name(), channelId); cResponsePacket *resp = new cResponsePacket(); if (!resp->initStatus(VNSI_STATUS_EPGCHANGE)) @@ -295,10 +291,6 @@ void cVNSIClient::EpgChange() resp->finalise(); m_socket.write(resp->getPtr(), resp->getLen()); delete resp; - - const cChannel *channel = FindChannelByUID(channelId); - if (channel) - INFOLOG("Trigger EPG update for channel %s", channel->Name()); } } @@ -480,6 +472,26 @@ bool cVNSIClient::processRequest(cRequestPacket* req) result = processCHANNELS_GetGroupMembers(); break; + case VNSI_CHANNELS_GETCAIDS: + result = processCHANNELS_GetCaids(); + break; + + case VNSI_CHANNELS_GETWHITELIST: + result = processCHANNELS_GetWhitelist(); + break; + + case VNSI_CHANNELS_GETBLACKLIST: + result = processCHANNELS_GetBlacklist(); + break; + + case VNSI_CHANNELS_SETWHITELIST: + result = processCHANNELS_SetWhitelist(); + break; + + case VNSI_CHANNELS_SETBLACKLIST: + result = processCHANNELS_SetBlacklist(); + break; + /** OPCODE 80 - 99: VNSI network functions for timer access */ case VNSI_TIMER_GETCOUNT: result = processTIMER_GetCount(); @@ -527,6 +539,9 @@ bool cVNSIClient::processRequest(cRequestPacket* req) result = processRECORDINGS_Delete(); break; + case VNSI_RECORDINGS_GETEDL: + result = processRECORDINGS_GetEdl(); + break; /** OPCODE 120 - 139: VNSI network functions for epg access and manipulating */ case VNSI_EPG_GETFORCHANNEL: @@ -937,31 +952,42 @@ bool cVNSIClient::processCHANNELS_ChannelsCount() /* OPCODE 61 */ bool cVNSIClient::processCHANNELS_GetChannels() /* OPCODE 63 */ { - if (m_req->getDataLength() != 4) return false; + if (m_req->getDataLength() != 5) return false; bool radio = m_req->extract_U32(); + bool filter = m_req->extract_U8(); Channels.Lock(false); + cString caids; + int caid; + int caid_idx; for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) { - if (radio != IsRadio(channel)) + if (radio != cVNSIChannelFilter::IsRadio(channel)) continue; // skip invalid channels if (channel->Sid() == 0) continue; + // check filter + if (filter && !VNSIChannelFilter.PassFilter(*channel)) + continue; + m_resp->add_U32(channel->Number()); m_resp->add_String(m_toUTF8.Convert(channel->Name())); + m_resp->add_String(m_toUTF8.Convert(channel->Provider())); m_resp->add_U32(CreateChannelUID(channel)); - m_resp->add_U32(0); // groupindex unused - m_resp->add_U32(channel->Ca()); -#if APIVERSNUM >= 10701 - m_resp->add_U32(channel->Vtype()); -#else - m_resp->add_U32(2); -#endif + m_resp->add_U32(channel->Ca(0)); + caid_idx = 0; + caids = "caids:"; + while((caid = channel->Ca(caid_idx)) != 0) + { + caids = cString::sprintf("%s%d;", (const char*)caids, caid); + caid_idx++; + } + m_resp->add_String((const char*)caids); } Channels.Unlock(); @@ -1024,6 +1050,7 @@ bool cVNSIClient::processCHANNELS_GetGroupMembers() { char* groupname = m_req->extract_String(); uint32_t radio = m_req->extract_U8(); + bool filter = m_req->extract_U8(); int index = 0; // unknown group @@ -1057,7 +1084,11 @@ bool cVNSIClient::processCHANNELS_GetGroupMembers() if(name.empty()) continue; - if(IsRadio(channel) != radio) + if(cVNSIChannelFilter::IsRadio(channel) != radio) + continue; + + // check filter + if (filter && !VNSIChannelFilter.PassFilter(*channel)) continue; if(name == groupname) @@ -1075,13 +1106,142 @@ bool cVNSIClient::processCHANNELS_GetGroupMembers() return true; } +bool cVNSIClient::processCHANNELS_GetCaids() +{ + uint32_t uid = m_req->extract_U32(); + + Channels.Lock(false); + const cChannel *channel = NULL; + channel = FindChannelByUID(uid); + Channels.Unlock(); + + if (channel != NULL) + { + int caid; + int idx = 0; + while((caid = channel->Ca(idx)) != 0) + { + m_resp->add_U32(caid); + idx++; + } + } + + m_resp->finalise(); + m_socket.write(m_resp->getPtr(), m_resp->getLen()); + + return true; +} + +bool cVNSIClient::processCHANNELS_GetWhitelist() +{ + bool radio = m_req->extract_U8(); + std::vector *providers; + + if(radio) + providers = &VNSIChannelFilter.m_providersRadio; + else + providers = &VNSIChannelFilter.m_providersVideo; + + VNSIChannelFilter.m_Mutex.Lock(); + for(unsigned int i=0; isize(); i++) + { + m_resp->add_String((*providers)[i].m_name.c_str()); + m_resp->add_U32((*providers)[i].m_caid); + } + VNSIChannelFilter.m_Mutex.Unlock(); + + m_resp->finalise(); + m_socket.write(m_resp->getPtr(), m_resp->getLen()); + return true; +} + +bool cVNSIClient::processCHANNELS_GetBlacklist() +{ + bool radio = m_req->extract_U8(); + std::vector *channels; + + if(radio) + channels = &VNSIChannelFilter.m_channelsRadio; + else + channels = &VNSIChannelFilter.m_channelsVideo; + + VNSIChannelFilter.m_Mutex.Lock(); + for(unsigned int i=0; isize(); i++) + { + m_resp->add_U32((*channels)[i]); + } + VNSIChannelFilter.m_Mutex.Unlock(); + + m_resp->finalise(); + m_socket.write(m_resp->getPtr(), m_resp->getLen()); + return true; +} + +bool cVNSIClient::processCHANNELS_SetWhitelist() +{ + bool radio = m_req->extract_U8(); + cVNSIProvider provider; + std::vector *providers; + + if(radio) + providers = &VNSIChannelFilter.m_providersRadio; + else + providers = &VNSIChannelFilter.m_providersVideo; + + VNSIChannelFilter.m_Mutex.Lock(); + providers->clear(); + + while(!m_req->end()) + { + char *str = m_req->extract_String(); + provider.m_name = str; + provider.m_caid = m_req->extract_U32(); + delete [] str; + providers->push_back(provider); + } + VNSIChannelFilter.StoreWhitelist(radio); + VNSIChannelFilter.m_Mutex.Unlock(); + + m_resp->finalise(); + m_socket.write(m_resp->getPtr(), m_resp->getLen()); + return true; +} + +bool cVNSIClient::processCHANNELS_SetBlacklist() +{ + bool radio = m_req->extract_U8(); + cVNSIProvider provider; + std::vector *channels; + + if(radio) + channels = &VNSIChannelFilter.m_channelsRadio; + else + channels = &VNSIChannelFilter.m_channelsVideo; + + VNSIChannelFilter.m_Mutex.Lock(); + channels->clear(); + + int id; + while(!m_req->end()) + { + id = m_req->extract_U32(); + channels->push_back(id); + } + VNSIChannelFilter.StoreBlacklist(radio); + VNSIChannelFilter.m_Mutex.Unlock(); + + m_resp->finalise(); + m_socket.write(m_resp->getPtr(), m_resp->getLen()); + return true; +} + void cVNSIClient::CreateChannelGroups(bool automatic) { std::string groupname; for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) { - bool isRadio = IsRadio(channel); + bool isRadio = cVNSIChannelFilter::IsRadio(channel); if(automatic && !channel->GroupSep()) groupname = channel->Provider(); @@ -1631,6 +1791,37 @@ bool cVNSIClient::processRECORDINGS_Delete() /* OPCODE 104 */ return true; } +bool cVNSIClient::processRECORDINGS_GetEdl() /* OPCODE 105 */ +{ + cString recName; + cRecording* recording = NULL; + + uint32_t uid = m_req->extract_U32(); + recording = cRecordingsCache::GetInstance().Lookup(uid); + + if (recording) + { + cMarks marks; + if(marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording())) + { +#if VDRVERSNUM >= 10732 + cMark* mark = NULL; + double fps = recording->FramesPerSecond(); + while((mark = marks.GetNextBegin(mark)) != NULL) + { + m_resp->add_U64(mark->Position() *1000 / fps); + m_resp->add_U64(mark->Position() *1000 / fps); + m_resp->add_S32(2); + } +#endif + } + } + m_resp->finalise(); + m_socket.write(m_resp->getPtr(), m_resp->getLen()); + + return true; +} + /** OPCODE 120 - 139: VNSI network functions for epg access and manipulating */ diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.h index 948940a99..506ff1187 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.h @@ -130,6 +130,11 @@ class cVNSIClient : public cThread bool processCHANNELS_GroupList(); bool processCHANNELS_GetChannels(); bool processCHANNELS_GetGroupMembers(); + bool processCHANNELS_GetCaids(); + bool processCHANNELS_GetWhitelist(); + bool processCHANNELS_GetBlacklist(); + bool processCHANNELS_SetWhitelist(); + bool processCHANNELS_SetBlacklist(); void CreateChannelGroups(bool automatic); @@ -147,6 +152,7 @@ class cVNSIClient : public cThread bool processRECORDINGS_Rename(); bool processRECORDINGS_Delete(); bool processRECORDINGS_Move(); + bool processRECORDINGS_GetEdl(); bool processEPG_GetForChannel(); diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsicommand.h b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsicommand.h index 17d3d08a7..9877db4a0 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsicommand.h +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsicommand.h @@ -27,7 +27,7 @@ #define VNSI_COMMAND_H /** Current VNSI Protocol Version number */ -#define VNSI_PROTOCOLVERSION 4 +#define VNSI_PROTOCOLVERSION 5 /** Packet types */ #define VNSI_CHANNEL_REQUEST_RESPONSE 1 @@ -73,6 +73,11 @@ #define VNSI_CHANNELGROUP_GETCOUNT 65 #define VNSI_CHANNELGROUP_LIST 66 #define VNSI_CHANNELGROUP_MEMBERS 67 +#define VNSI_CHANNELS_GETCAIDS 68 +#define VNSI_CHANNELS_GETWHITELIST 69 +#define VNSI_CHANNELS_GETBLACKLIST 70 +#define VNSI_CHANNELS_SETWHITELIST 71 +#define VNSI_CHANNELS_SETBLACKLIST 72 /* OPCODE 80 - 99: VNSI network functions for timer access */ #define VNSI_TIMER_GETCOUNT 80 @@ -88,6 +93,7 @@ #define VNSI_RECORDINGS_GETLIST 102 #define VNSI_RECORDINGS_RENAME 103 #define VNSI_RECORDINGS_DELETE 104 +#define VNSI_RECORDINGS_GETEDL 105 /* OPCODE 120 - 139: VNSI network functions for epg access and manipulating */ #define VNSI_EPG_GETFORCHANNEL 120 @@ -112,6 +118,7 @@ #define VNSI_STREAM_SIGNALINFO 5 #define VNSI_STREAM_CONTENTINFO 6 #define VNSI_STREAM_BUFFERSTATS 7 +#define VNSI_STREAM_REFTIME 8 /** Scan packet types (server -> client) */ #define VNSI_SCANNER_PERCENTAGE 1 diff --git a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiserver.c b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiserver.c index db2e03325..4da375051 100644 --- a/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiserver.c +++ b/addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiserver.c @@ -45,6 +45,7 @@ #include "vnsi.h" #include "vnsiserver.h" #include "vnsiclient.h" +#include "channelfilter.h" unsigned int cVNSIServer::m_IdCnt = 0; @@ -84,6 +85,9 @@ cVNSIServer::cVNSIServer(int listenPort) : cThread("VDR VNSI Server") m_AllowedHostsFile = cString::sprintf("/video/" ALLOWED_HOSTS_FILE); } + VNSIChannelFilter.Load(); + VNSIChannelFilter.SortChannels(); + m_ServerFD = socket(AF_INET, SOCK_STREAM, 0); if(m_ServerFD == -1) return; @@ -184,10 +188,6 @@ void cVNSIServer::Action(void) fd_set fds; struct timeval tv; - // initial time for channels change - struct timespec channelsUpdate; - channelsUpdate.tv_sec = 0; - channelsUpdate.tv_nsec = 0; cTimeMs chanTimer(0); // get initial state of the recordings @@ -221,6 +221,9 @@ void cVNSIServer::Action(void) } int ret = system(cmd); + // set thread priority + SetPriority(1); + while (Running()) { FD_ZERO(&fds); @@ -254,17 +257,13 @@ void cVNSIServer::Action(void) // trigger clients to reload the modified channel list if(m_clients.size() > 0 && chanTimer.TimedOut()) { - struct stat s; - if(stat(Channels.FileName(), &s) != -1) + int modified = Channels.Modified(); + if (modified) { - if ((s.st_mtim.tv_sec != channelsUpdate.tv_sec) && - (s.st_mtim.tv_nsec != channelsUpdate.tv_nsec)) - { - INFOLOG("Requesting clients to reload channel list"); - for (ClientList::iterator i = m_clients.begin(); i != m_clients.end(); i++) - (*i)->ChannelChange(); - channelsUpdate = s.st_mtim; - } + Channels.SetModified((modified == CHANNELSMOD_USER) ? true : false); + INFOLOG("Requesting clients to reload channel list"); + for (ClientList::iterator i = m_clients.begin(); i != m_clients.end(); i++) + (*i)->ChannelChange(); } chanTimer.Set(5000); }