From 94461d6c08d8767170c5331a4758facc631d0298 Mon Sep 17 00:00:00 2001 From: Rolf Ahrenberg Date: Sat, 23 Feb 2013 02:03:27 +0200 Subject: [PATCH] Updated for vdr-1.7.38 and added a new CURL protocol for HTTP/HTTPS. --- HISTORY | 5 + Makefile | 103 +++++----- README | 32 +++- common.c | 16 +- common.h | 2 + device.c | 59 +++--- device.h | 7 +- iptv.c | 13 +- po/de_DE.po | 5 +- po/fi_FI.po | 5 +- po/fr_FR.po | 5 +- po/it_IT.po | 5 +- po/nl_NL.po | 5 +- po/ru_RU.po | 5 +- protocolcurl.c | 512 +++++++++++++++++++++++++++++++++++++++++++++++++ protocolcurl.h | 72 +++++++ setup.c | 1 + setup.h | 2 +- socket.c | 3 +- socket.h | 2 +- source.c | 8 + source.h | 3 +- statistics.c | 32 ++-- streamer.c | 2 +- 24 files changed, 786 insertions(+), 118 deletions(-) create mode 100644 protocolcurl.c create mode 100644 protocolcurl.h diff --git a/HISTORY b/HISTORY index f027b34..0ec442f 100644 --- a/HISTORY +++ b/HISTORY @@ -188,3 +188,8 @@ VDR Plugin 'iptv' Revision History - Added support for source-specific multicasts (SSM). - Changed default external script directory from the configuration to the resource. + +2013-02-24: Version 1.2.0 + +- Updated for vdr-1.7.38. +- Added a new CURL protocol for HTTP/HTTPS. diff --git a/Makefile b/Makefile index c7b78bf..b282cfd 100644 --- a/Makefile +++ b/Makefile @@ -2,24 +2,22 @@ # Makefile for IPTV plugin # -# Debugging on/off +# Debugging on/off + #IPTV_DEBUG = 1 # Default shell for EXT protocol + #IPTV_EXTSHELL = /bin/bash # Strip debug symbols? Set eg. to /bin/true if not -STRIP = strip -# Install command -INSTALL = cp --remove-destination +STRIP = strip # The official name of this plugin. # 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. -# IMPORTANT: the presence of this macro is important for the Make.config -# file. So it must be defined, even if it is not used here! -# + PLUGIN = iptv ### The version number of this plugin (taken from the main source file): @@ -27,40 +25,47 @@ PLUGIN = iptv VERSION = $(shell grep 'const char VERSION\[\] *=' $(PLUGIN).c | awk '{ print $$5 }' | sed -e 's/[";]//g') GITTAG = $(shell git describe --always 2>/dev/null) -### The C++ compiler and options: - -CXX ?= g++ -CXXFLAGS ?= -fPIC -g -O3 -Wall -Wextra -Wswitch-default -Wfloat-equal -Wundef -Wpointer-arith -Wconversion -Wcast-align -Wredundant-decls -Wno-unused-parameter -Werror=overloaded-virtual -Wno-parentheses -LDFLAGS ?= -Wl,--as-needed - ### The directory environment: -VDRDIR ?= ../../.. -LIBDIR ?= ../../lib +# Use package data if installed...otherwise assume we're under the VDR source directory: +PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc)) +LIBDIR = $(call PKGCFG,libdir) +LOCDIR = $(call PKGCFG,locdir) +PLGCFG = $(call PKGCFG,plgcfg) +# TMPDIR ?= /tmp -### Make sure that necessary options are included: +### The compiler options: --include $(VDRDIR)/Make.global +export CFLAGS = $(call PKGCFG,cflags) +export CXXFLAGS = $(call PKGCFG,cxxflags) + +### The version number of VDR's plugin API: + +APIVERSION = $(call PKGCFG,apiversion) ### Allow user defined options to overwrite defaults: --include $(VDRDIR)/Make.config - -### The version number of VDR's plugin API (taken from VDR's "config.h"): - -APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) +-include $(PLGCFG) ### The name of the distribution archive: ARCHIVE = $(PLUGIN)-$(VERSION) PACKAGE = vdr-$(ARCHIVE) +### The name of the shared object file: + +SOFILE = libvdr-$(PLUGIN).so + +### Libraries + +LIBS = $(shell curl-config --libs) + ### Includes and Defines (add further entries here): -INCLUDES += -I$(VDRDIR)/include +INCLUDES += -DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ifdef IPTV_DEBUG DEFINES += -DDEBUG @@ -79,61 +84,67 @@ all-redirect: all ### The object files (add further files here): -OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o \ - protocolhttp.o protocolfile.o protocolext.o sectionfilter.o \ - sidscanner.o pidscanner.o statistics.o common.o socket.o source.o +OBJS = $(PLUGIN).o common.o config.o device.o pidscanner.o \ + protocolcurl.o protocolext.o protocolfile.o protocolhttp.o \ + protocoludp.o sectionfilter.o setup.o sidscanner.o socket.o \ + source.o statistics.o streamer.o ### The main target: -all: libvdr-$(PLUGIN).so i18n +all: $(SOFILE) i18n ### Implicit rules: -%.o: %.c Makefile - $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< ### Dependencies: MAKEDEP = $(CXX) -MM -MG DEPFILE = .dependencies $(DEPFILE): Makefile - @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + @$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ -include $(DEPFILE) ### Internationalization (I18N): PODIR = po -LOCALEDIR = $(VDRDIR)/locale I18Npo = $(wildcard $(PODIR)/*.po) -I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file)))) +I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) I18Npot = $(PODIR)/$(PLUGIN).pot %.mo: %.po msgfmt -c -o $@ $< $(I18Npot): $(wildcard *.c) - xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name='vdr-$(PLUGIN)' --package-version='$(VERSION)' --msgid-bugs-address='' -o $@ `ls $^` + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='' -o $@ `ls $^` %.po: $(I18Npot) - msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $< @touch $@ -$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo - @mkdir -p $(dir $@) - cp $< $@ +$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + install -D -m644 $< $@ .PHONY: i18n -i18n: $(I18Nmsgs) $(I18Npot) +i18n: $(I18Nmo) $(I18Npot) + +install-i18n: $(I18Nmsgs) ### Targets: -libvdr-$(PLUGIN).so: $(OBJS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@ +$(SOFILE): $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@ ifndef IPTV_DEBUG @$(STRIP) $@ endif - @$(INSTALL) $@ $(LIBDIR)/$@.$(APIVERSION) + +install-lib: $(SOFILE) + install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) + +install: install-lib install-i18n dist: $(I18Npo) clean @-rm -rf $(TMPDIR)/$(ARCHIVE) @@ -144,7 +155,9 @@ dist: $(I18Npo) clean @echo Distribution package created as $(PACKAGE).tgz clean: - @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot + @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ -cppcheck: $(OBJS) - @cppcheck --enable=information,style,unusedFunction -v -f $(OBJS:%.o=%.c) +.PHONY: cppcheck +cppcheck: + @cppcheck --language=c++ --enable=all -v -f $(OBJS:%.o=%.c) diff --git a/README b/README index 9145e5d..89f03ea 100644 --- a/README +++ b/README @@ -17,7 +17,8 @@ See the file COPYING for more information. Requirements: -DVB compatible MPEG1/2 or H.264 network video streams. +- Libcurl - the multiprotocol file transfer library + http://curl.haxx.se/libcurl/ Description: @@ -91,16 +92,24 @@ Configuration: TV4;IPTV:40:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:4:0:0:0 TV3;IPTV:30:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:3:0:0:0 TV2;IPTV:20:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:2:0:0:0 + TV1;IPTV:10:S=1|P=0|F=CURL|U=http%3A//foo%3Abar@127.0.0.1%3A3000/TS/2|A=0:I:0:512:650:2321:0:1:0:0:0 TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1@127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0 TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0 - ^ ^ ^ ^ ^ ^ ^ - | | | | | | Source type ("I") - | | | | | Stream parameter (multicast port - | | | | | number, HTTP port number, file delay - | | | | | (ms), script parameter) - | | | | Stream address (multicast source@group address, - | | | | URL, file location, script location) - | | | Stream protocol ("UDP", "HTTP", "FILE", "EXT") + ^ ^ ^ ^ ^ ^ ^ + | | | | | | Source type ("I") + | | | | | Stream parameter + | | | | | UDP: multicast port + | | | | | CURL: <> + | | | | | HTTP: HTTP port number + | | | | | FILE: file delay (ms) + | | | | | EXT: script parameter + | | | | Stream address + | | | | UDP: multicast [source@]group address + | | | | CURL: HTTP/HTTPS URL; colons (%3A) and pipes (%7C) shall be URL encoded + | | | | HTTP: URL; missing the scheme name part and possible port declaration + | | | | FILE: file location + | | | | EXT: script location + | | | Stream protocol ("UDP", "CURL", "HTTP", "FILE", "EXT") | | Pid scanner ("0" disable, "1" enable) | Section id (Sid/Nid/Tid) scanner ("0" disable, "1" enable) Unique enumeration @@ -173,6 +182,11 @@ Notes: IGMP v3 protocol: "U=@" +- The CURL implementation supports only HTTP/HTTPS protocols and an optional + netrc configuration file for authentication: + $(CONFDIR)/iptv/netrc + +- CURL implementation Acknowledgements: - The IPTV section filtering code is derived from Linux kernel. diff --git a/common.c b/common.c index afe9f4c..f528b1f 100644 --- a/common.c +++ b/common.c @@ -44,14 +44,18 @@ int select_single_desc(int descriptor, const int usecs, const bool selectWrite) tv.tv_sec = 0; tv.tv_usec = usecs; // Use select - fd_set fds; - FD_ZERO(&fds); - FD_SET(descriptor, &fds); - int retval = 0; + fd_set infd; + fd_set outfd; + fd_set errfd; + FD_ZERO(&infd); + FD_ZERO(&outfd); + FD_ZERO(&errfd); + FD_SET(descriptor, &errfd); if (selectWrite) - retval = select(descriptor + 1, NULL, &fds, NULL, &tv); + FD_SET(descriptor, &outfd); else - retval = select(descriptor + 1, &fds, NULL, NULL, &tv); + FD_SET(descriptor, &infd); + int retval = select(descriptor + 1, &infd, &outfd, &errfd, &tv); // Check if error ERROR_IF_RET(retval < 0, "select()", return retval); return retval; diff --git a/common.h b/common.h index b6dad7e..b0a2dc7 100644 --- a/common.h +++ b/common.h @@ -14,9 +14,11 @@ #ifdef DEBUG #define debug(x...) dsyslog("IPTV: " x); +#define info(x...) isyslog("IPTV: " x); #define error(x...) esyslog("ERROR: " x); #else #define debug(x...) ; +#define info(x...) isyslog("IPTV: " x); #define error(x...) esyslog("ERROR: " x); #endif diff --git a/device.c b/device.c index 8757189..b469672 100644 --- a/device.c +++ b/device.c @@ -20,6 +20,7 @@ cIptvDevice::cIptvDevice(unsigned int Index) dvrFd(-1), isPacketDelivered(false), isOpenDvr(false), + isBuffering(true), sidScanEnabled(false), pidScanEnabled(false), channelId(tChannelID::InvalidID) @@ -32,6 +33,7 @@ cIptvDevice::cIptvDevice(unsigned int Index) tsBuffer->SetTimeouts(10, 10); ResetBuffering(); pUdpProtocol = new cIptvProtocolUdp(); + pCurlProtocol = new cIptvProtocolCurl(); pHttpProtocol = new cIptvProtocolHttp(); pFileProtocol = new cIptvProtocolFile(); pExtProtocol = new cIptvProtocolExt(); @@ -63,6 +65,7 @@ cIptvDevice::~cIptvDevice() StopSectionHandler(); DELETE_POINTER(pIptvStreamer); DELETE_POINTER(pUdpProtocol); + DELETE_POINTER(pCurlProtocol); DELETE_POINTER(pHttpProtocol); DELETE_POINTER(pFileProtocol); DELETE_POINTER(pExtProtocol); @@ -141,48 +144,48 @@ cString cIptvDevice::GetFiltersInformation(void) { //debug("cIptvDevice::GetFiltersInformation(%d)\n", deviceIndex); unsigned int count = 0; - cString info("Active section filters:\n"); + cString s("Active section filters:\n"); // loop through active section filters for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { if (secfilters[i]) { - info = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *info, i, - *secfilters[i]->GetSectionStatistic(), secfilters[i]->GetPid(), - id_pid(secfilters[i]->GetPid())); + s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i, + *secfilters[i]->GetSectionStatistic(), secfilters[i]->GetPid(), + id_pid(secfilters[i]->GetPid())); if (++count > IPTV_STATS_ACTIVE_FILTERS_COUNT) break; } } - return info; + return s; } cString cIptvDevice::GetInformation(unsigned int Page) { // generate information string - cString info; + cString s; switch (Page) { case IPTV_DEVICE_INFO_GENERAL: - info = GetGeneralInformation(); + s = GetGeneralInformation(); break; case IPTV_DEVICE_INFO_PIDS: - info = GetPidsInformation(); + s = GetPidsInformation(); break; case IPTV_DEVICE_INFO_FILTERS: - info = GetFiltersInformation(); + s = GetFiltersInformation(); break; case IPTV_DEVICE_INFO_PROTOCOL: - info = pIptvStreamer ? *pIptvStreamer->GetInformation() : ""; + s = pIptvStreamer ? *pIptvStreamer->GetInformation() : ""; break; case IPTV_DEVICE_INFO_BITRATE: - info = pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : ""; + s = pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : ""; break; default: - info = cString::sprintf("%s%s%s", - *GetGeneralInformation(), - *GetPidsInformation(), - *GetFiltersInformation()); + s = cString::sprintf("%s%s%s", + *GetGeneralInformation(), + *GetPidsInformation(), + *GetFiltersInformation()); break; } - return info; + return s; } cString cIptvDevice::DeviceType(void) const @@ -268,6 +271,9 @@ bool cIptvDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) case cIptvTransponderParameters::eProtocolUDP: protocol = pUdpProtocol; break; + case cIptvTransponderParameters::eProtocolCURL: + protocol = pCurlProtocol; + break; case cIptvTransponderParameters::eProtocolHTTP: protocol = pHttpProtocol; break; @@ -400,10 +406,10 @@ void cIptvDevice::CloseDvr(void) isOpenDvr = false; } -bool cIptvDevice::HasLock(int TimeoutMs) +bool cIptvDevice::HasLock(int TimeoutMs) const { //debug("cIptvDevice::HasLock(%d): %d\n", deviceIndex, TimeoutMs); - return (!IsBuffering()); + return (!isBuffering); } bool cIptvDevice::HasInternalCam(void) @@ -415,26 +421,29 @@ bool cIptvDevice::HasInternalCam(void) void cIptvDevice::ResetBuffering(void) { debug("cIptvDevice::ResetBuffering(%d)\n", deviceIndex); + isBuffering = true; // pad prefill to multiple of TS_SIZE tsBufferPrefill = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize()) * IptvConfig.GetTsBufferPrefillRatio() / 100; tsBufferPrefill -= (tsBufferPrefill % TS_SIZE); } -bool cIptvDevice::IsBuffering(void) +void cIptvDevice::CheckBuffering(void) { - //debug("cIptvDevice::IsBuffering(%d): %d\n", deviceIndex); - if (tsBufferPrefill && tsBuffer->Available() < tsBufferPrefill) - return true; - else + //debug("cIptvDevice::CheckBuffering(%d): %d\n", deviceIndex); + if (tsBufferPrefill && tsBuffer && tsBuffer->Available() < tsBufferPrefill) + isBuffering = true; + else { + isBuffering = false; tsBufferPrefill = 0; - return false; + } } bool cIptvDevice::GetTSPacket(uchar *&Data) { //debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex); - if (tsBuffer && !IsBuffering()) { + CheckBuffering(); + if (tsBuffer && !isBuffering) { if (isPacketDelivered) { tsBuffer->Del(TS_SIZE); isPacketDelivered = false; diff --git a/device.h b/device.h index 1899727..14fb3c4 100644 --- a/device.h +++ b/device.h @@ -11,6 +11,7 @@ #include #include "common.h" #include "protocoludp.h" +#include "protocolcurl.h" #include "protocolhttp.h" #include "protocolfile.h" #include "protocolext.h" @@ -37,12 +38,14 @@ private: int dvrFd; bool isPacketDelivered; bool isOpenDvr; + bool isBuffering; bool sidScanEnabled; bool pidScanEnabled; cRingBufferLinear *tsBuffer; int tsBufferPrefill; tChannelID channelId; cIptvProtocolUdp *pUdpProtocol; + cIptvProtocolCurl *pCurlProtocol; cIptvProtocolHttp *pHttpProtocol; cIptvProtocolFile *pFileProtocol; cIptvProtocolExt *pExtProtocol; @@ -71,7 +74,7 @@ private: // for channel parsing & buffering private: void ResetBuffering(void); - bool IsBuffering(void); + void CheckBuffering(void); bool DeleteFilter(unsigned int Index); bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const; @@ -107,7 +110,7 @@ public: // for transponder lock public: - virtual bool HasLock(int); + virtual bool HasLock(int) const; // for common interface public: diff --git a/iptv.c b/iptv.c index acb6e3a..9a04370 100644 --- a/iptv.c +++ b/iptv.c @@ -13,15 +13,15 @@ #include "device.h" #include "iptvservice.h" -#if defined(APIVERSNUM) && APIVERSNUM < 10730 -#error "VDR-1.7.30 API version or greater is required!" +#if defined(APIVERSNUM) && APIVERSNUM < 10738 +#error "VDR-1.7.38 API version or greater is required!" #endif #ifndef GITVERSION #define GITVERSION "" #endif - const char VERSION[] = "1.1.0" GITVERSION; + const char VERSION[] = "1.2.0" GITVERSION; static const char DESCRIPTION[] = trNOOP("Experience the IPTV"); class cPluginIptv : public cPlugin { @@ -107,6 +107,10 @@ bool cPluginIptv::Start(void) { debug("cPluginIptv::Start()\n"); // Start any background activities the plugin shall perform. + if (curl_global_init(CURL_GLOBAL_ALL) == CURLE_OK) { + curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); + info("Using CURL %s", data->version); + } return true; } @@ -114,6 +118,7 @@ void cPluginIptv::Stop(void) { debug("cPluginIptv::Stop()\n"); // Stop any background activities the plugin is performing. + curl_global_cleanup(); } void cPluginIptv::Housekeeping(void) @@ -204,7 +209,7 @@ bool cPluginIptv::Service(const char *Id, void *Data) debug("cPluginIptv::Service()\n"); if (strcmp(Id,"IptvService-v1.0") == 0) { if (Data) { - IptvService_v1_0 *data = (IptvService_v1_0*)Data; + IptvService_v1_0 *data = reinterpret_cast(Data); cIptvDevice *dev = cIptvDevice::GetIptvDevice(data->cardIndex); if (!dev) return false; diff --git a/po/de_DE.po b/po/de_DE.po index 69c3116..b5c7aa5 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: vdr-iptv 1.0.0\n" +"Project-Id-Version: vdr-iptv 1.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2012-06-03 06:03+0300\n" @@ -118,6 +118,9 @@ msgstr "Hilfe" msgid "UDP" msgstr "UDP" +msgid "CURL" +msgstr "CURL" + msgid "HTTP" msgstr "HTTP" diff --git a/po/fi_FI.po b/po/fi_FI.po index ee4846f..55ff2cd 100644 --- a/po/fi_FI.po +++ b/po/fi_FI.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: vdr-iptv 1.0.0\n" +"Project-Id-Version: vdr-iptv 1.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2012-06-03 06:03+0300\n" @@ -133,6 +133,9 @@ msgstr "Opaste" msgid "UDP" msgstr "UDP" +msgid "CURL" +msgstr "CURL" + msgid "HTTP" msgstr "HTTP" diff --git a/po/fr_FR.po b/po/fr_FR.po index 1bb525b..bb89666 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -6,7 +6,7 @@ # msgid "" msgstr "" -"Project-Id-Version: vdr-iptv 1.0.0\n" +"Project-Id-Version: vdr-iptv 1.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2012-06-03 06:03+0300\n" @@ -135,6 +135,9 @@ msgstr "Aide" msgid "UDP" msgstr "UDP" +msgid "CURL" +msgstr "CURL" + msgid "HTTP" msgstr "HTTP" diff --git a/po/it_IT.po b/po/it_IT.po index 341d640..8c091b8 100644 --- a/po/it_IT.po +++ b/po/it_IT.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: vdr-iptv 1.0.0\n" +"Project-Id-Version: vdr-iptv 1.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2012-06-03 06:03+0300\n" @@ -134,6 +134,9 @@ msgstr "Aiuto" msgid "UDP" msgstr "UDP" +msgid "CURL" +msgstr "CURL" + msgid "HTTP" msgstr "HTTP" diff --git a/po/nl_NL.po b/po/nl_NL.po index 76a3f64..31b0134 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: vdr-iptv 1.0.0\n" +"Project-Id-Version: vdr-iptv 1.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2012-06-03 06:03+0300\n" @@ -133,6 +133,9 @@ msgstr "Help" msgid "UDP" msgstr "UDP" +msgid "CURL" +msgstr "CURL" + msgid "HTTP" msgstr "HTTP" diff --git a/po/ru_RU.po b/po/ru_RU.po index 9eba377..e7759ac 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: vdr-iptv 1.0.0\n" +"Project-Id-Version: vdr-iptv 1.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-03 06:03+0300\n" "PO-Revision-Date: 2012-06-03 06:03+0300\n" @@ -119,6 +119,9 @@ msgstr "Справка" msgid "UDP" msgstr "UDP" +msgid "CURL" +msgstr "CURL" + msgid "HTTP" msgstr "HTTP" diff --git a/protocolcurl.c b/protocolcurl.c new file mode 100644 index 0000000..933ac29 --- /dev/null +++ b/protocolcurl.c @@ -0,0 +1,512 @@ +/* + * protocolcurl.c: IPTV plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "common.h" +#include "config.h" +#include "protocolcurl.h" + +#define iptv_curl_easy_setopt(X, Y, Z) \ + if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { error("curl_easy_setopt(%s, %s, %s) failed: %d\n", #X, #Y, #Z, res); } + +#define iptv_curl_easy_perform(X) \ + if ((res = curl_easy_perform((X))) != CURLE_OK) { error("curl_easy_perform(%s) failed: %d\n", #X, res); } + +cIptvProtocolCurl::cIptvProtocolCurl() +: streamUrlM(""), + streamParamM(0), + mutexM(), + handleM(NULL), + multiM(NULL), + headerListM(NULL), + ringBufferM(new cRingBufferLinear(MEGABYTE(IptvConfig.GetTsBufferSize()), 7 * TS_SIZE)), + rtspControlM(), + modeM(eModeUnknown), + connectedM(false), + pausedM(false) +{ + debug("cIptvProtocolCurl::cIptvProtocolCurl()\n"); + if (ringBufferM) + ringBufferM->SetTimeouts(100, 0); + Connect(); +} + +cIptvProtocolCurl::~cIptvProtocolCurl() +{ + debug("cIptvProtocolCurl::~cIptvProtocolCurl()\n"); + Disconnect(); + // Free allocated memory + DELETE_POINTER(ringBufferM); +} + +size_t cIptvProtocolCurl::WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) +{ + cIptvProtocolCurl *obj = reinterpret_cast(dataP); + size_t len = sizeP * nmembP; + //debug("cIptvProtocolCurl::WriteCallback(%zu)\n", len); + + if (obj && !obj->PutData((unsigned char *)ptrP, (int)len)) + return CURL_WRITEFUNC_PAUSE; + + return len; +} + +size_t cIptvProtocolCurl::WriteRtspCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) +{ + cIptvProtocolCurl *obj = reinterpret_cast(dataP); + size_t len = sizeP * nmembP; + unsigned char *p = (unsigned char *)ptrP; + //debug("cIptvProtocolCurl::WriteRtspCallback(%zu)\n", len); + + // validate packet header ('$') and channel (0) + if (obj && (p[0] == 0x24 ) && (p[1] == 0)) { + int length = (p[2] << 8) | p[3]; + if (length > 3) { + // skip interleave header + p += 4; + // http://tools.ietf.org/html/rfc3550 + // http://tools.ietf.org/html/rfc2250 + // version + unsigned int v = (p[0] >> 6) & 0x03; + // extension bit + unsigned int x = (p[0] >> 4) & 0x01; + // cscr count + unsigned int cc = p[0] & 0x0F; + // payload type: MPEG2 TS = 33 + //unsigned int pt = p[1] & 0x7F; + // header lenght + unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t); + // check if extension + if (x) { + // extension header length + unsigned int ehl = (((p[headerlen + 2] & 0xFF) << 8) |(p[headerlen + 3] & 0xFF)); + // update header length + headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t); + } + // Check that rtp is version 2 and payload contains multiple of TS packet data + if ((v == 2) && (((length - headerlen) % TS_SIZE) == 0) && (p[headerlen] == TS_SYNC_BYTE)) { + // Set argument point to payload in read buffer + obj->PutData(&p[headerlen], (length - headerlen)); + } + } + } + + return len; +} + +size_t cIptvProtocolCurl::DescribeCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) +{ + cIptvProtocolCurl *obj = reinterpret_cast(dataP); + size_t len = sizeP * nmembP; + //debug("cIptvProtocolCurl::DescribeCallback(%zu)\n", len); + + cString control = ""; + char *p = (char *)ptrP; + char *r = strtok(p, "\r\n"); + + while (r) { + //debug("cIptvProtocolCurl::DescribeCallback(%zu): %s\n", len, r); + if (strstr(r, "a=control")) { + char *s = NULL; + if (sscanf(r, "a=control:%64ms", &s) == 1) + control = compactspace(s); + free(s); + } + r = strtok(NULL, "\r\n"); + } + + if (!isempty(*control) && obj) + obj->SetRtspControl(*control); + + return len; +} + +size_t cIptvProtocolCurl::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) +{ + //cIptvProtocolCurl *obj = reinterpret_cast(dataP); + size_t len = sizeP * nmembP; + //debug("cIptvProtocolCurl::HeaderCallback(%zu)\n", len); + + char *p = (char *)ptrP; + char *r = strtok(p, "\r\n"); + + while (r) { + //debug("cIptvProtocolCurl::HeaderCallback(%zu): %s\n", len, r); + r = strtok(NULL, "\r\n"); + } + + return len; +} + +void cIptvProtocolCurl::SetRtspControl(const char *controlP) +{ + cMutexLock MutexLock(&mutexM); + debug("cIptvProtocolCurl::SetRtspControl('%s')\n", controlP); + rtspControlM = controlP; +} + +bool cIptvProtocolCurl::PutData(unsigned char *dataP, int lenP) +{ + cMutexLock MutexLock(&mutexM); + //debug("cIptvProtocolCurl::PutData(%d)\n", lenP); + if (pausedM) + return false; + if (ringBufferM && (lenP >= 0)) { + // should be pause the transfer? + if (ringBufferM->Free() < (2 * CURL_MAX_WRITE_SIZE)) { + debug("cIptvProtocolCurl::PutData(pause): free=%d available=%d len=%d", ringBufferM->Free(), ringBufferM->Available(), lenP); + pausedM = true; + return false; + } + int p = ringBufferM->Put(dataP, lenP); + if (p != lenP) + ringBufferM->ReportOverflow(lenP - p); + } + + return true; +} + +void cIptvProtocolCurl::DelData(int lenP) +{ + cMutexLock MutexLock(&mutexM); + //debug("cIptvProtocolCurl::DelData()\n"); + if (ringBufferM && (lenP >= 0)) + ringBufferM->Del(lenP); +} + +void cIptvProtocolCurl::ClearData() +{ + //debug("cIptvProtocolCurl::ClearData()\n"); + if (ringBufferM) + ringBufferM->Clear(); +} + +unsigned char *cIptvProtocolCurl::GetData(unsigned int *lenP) +{ + cMutexLock MutexLock(&mutexM); + //debug("cIptvProtocolCurl::GetData()\n"); + unsigned char *p = NULL; + *lenP = 0; + if (ringBufferM) { + int count = 0; + p = ringBufferM->Get(count); +#if 0 + if (p && count >= TS_SIZE) { + if (*p != TS_SYNC_BYTE) { + for (int i = 1; i < count; ++i) { + if (p[i] == TS_SYNC_BYTE) { + count = i; + break; + } + } + error("IPTV skipped %d bytes to sync on TS packet\n", count); + ringBufferM->Del(count); + *lenP = 0; + return NULL; + } + } +#endif + count -= (count % TS_SIZE); + *lenP = count; + } + + return p; +} + +bool cIptvProtocolCurl::Connect() +{ + cMutexLock MutexLock(&mutexM); + debug("cIptvProtocolCurl::Connect()\n"); + if (connectedM) + return true; + + // initialize the curl session + if (!handleM) + handleM = curl_easy_init(); + if (!multiM) + multiM = curl_multi_init(); + + if (handleM && multiM && !isempty(*streamUrlM)) { + CURLcode res = CURLE_OK; + cString netrc = cString::sprintf("%s/netrc", IptvConfig.GetConfigDirectory()); + +#ifdef DEBUG + // verbose output + iptv_curl_easy_setopt(handleM, CURLOPT_VERBOSE, 1L); +#endif + + // set callbacks + iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::WriteCallback); + iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this); + iptv_curl_easy_setopt(handleM, CURLOPT_HEADERFUNCTION, cIptvProtocolCurl::HeaderCallback); + iptv_curl_easy_setopt(handleM, CURLOPT_WRITEHEADER, this); + + // no progress meter and no signaling + iptv_curl_easy_setopt(handleM, CURLOPT_NOPROGRESS, 1L); + iptv_curl_easy_setopt(handleM, CURLOPT_NOSIGNAL, 1L); + + // support netrc + iptv_curl_easy_setopt(handleM, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL); + iptv_curl_easy_setopt(handleM, CURLOPT_NETRC_FILE, *netrc); + + // set timeout + iptv_curl_easy_setopt(handleM, CURLOPT_CONNECTTIMEOUT, (long)eConnectTimeoutS); + + // set user-agent + iptv_curl_easy_setopt(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION)); + + // set url + //char *p = curl_easy_unescape(handleM, *streamUrlM, 0, NULL); + //streamUrlM = p; + //curl_free(p); + iptv_curl_easy_setopt(handleM, CURLOPT_URL, *streamUrlM); + + // protocol specific initializations + switch (modeM) { + case eModeRtsp: + { + cString uri, control, transport, range; + + // request server options + uri = cString::sprintf("%s", *streamUrlM); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS); + iptv_curl_easy_perform(handleM); + + // request session description - SDP is delivered in message body and not in the header! + iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::DescribeCallback); + iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this); + uri = cString::sprintf("%s", *streamUrlM); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_DESCRIBE); + iptv_curl_easy_perform(handleM); + iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, NULL); + iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, NULL); + + // setup media stream + uri = cString::sprintf("%s/%s", *streamUrlM, *rtspControlM); + transport = "RTP/AVP/TCP;unicast;interleaved=0-1"; + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_TRANSPORT, *transport); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP); + iptv_curl_easy_perform(handleM); + + // start playing + uri = cString::sprintf("%s/", *streamUrlM); + range = "0.000-"; + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); + iptv_curl_easy_setopt(handleM, CURLOPT_RANGE, *range); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_PLAY); + iptv_curl_easy_perform(handleM); + + // start receiving + iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEFUNCTION, cIptvProtocolCurl::WriteRtspCallback); + iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEDATA, this); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_RECEIVE); + iptv_curl_easy_perform(handleM); + } + break; + + case eModeHttp: + case eModeHttps: + { + // limit download speed (bytes/s) + iptv_curl_easy_setopt(handleM, CURLOPT_MAX_RECV_SPEED_LARGE, eMaxDownloadSpeedMBits * 131072L); + + // follow location + iptv_curl_easy_setopt(handleM, CURLOPT_FOLLOWLOCATION, 1L); + + // fail if HTTP return code is >= 400 + iptv_curl_easy_setopt(handleM, CURLOPT_FAILONERROR, 1L); + + // set additional headers to prevent caching + headerListM = curl_slist_append(headerListM, "Cache-Control: no-store, no-cache, must-revalidate"); + headerListM = curl_slist_append(headerListM, "Cache-Control: post-check=0, pre-check=0"); + headerListM = curl_slist_append(headerListM, "Pragma: no-cache"); + headerListM = curl_slist_append(headerListM, "Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + iptv_curl_easy_setopt(handleM, CURLOPT_HTTPHEADER, headerListM); + } + break; + + case eModeFile: + case eModeUnknown: + default: + break; + } + + // add handle into multi set + curl_multi_add_handle(multiM, handleM); + + connectedM = true; + return true; + } + + return false; +} + +bool cIptvProtocolCurl::Disconnect() +{ + cMutexLock MutexLock(&mutexM); + debug("cIptvProtocolCurl::Disconnect()\n"); + if (handleM) { + // mode specific tricks + switch (modeM) { + case eModeRtsp: + { + CURLcode res = CURLE_OK; + // teardown rtsp session + cString uri = cString::sprintf("%s/", *streamUrlM); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); + iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN); + iptv_curl_easy_perform(handleM); + rtspControlM = ""; + } + break; + + case eModeHttp: + case eModeHttps: + case eModeFile: + case eModeUnknown: + default: + break; + } + + // cleanup curl stuff + if (headerListM) { + curl_slist_free_all(headerListM); + headerListM = NULL; + } + curl_multi_remove_handle(multiM, handleM); + curl_multi_cleanup(multiM); + multiM = NULL; + curl_easy_cleanup(handleM); + handleM = NULL; + } + + ClearData(); + connectedM = false; + return true; +} + +bool cIptvProtocolCurl::Open(void) +{ + debug("cIptvProtocolCurl::Open()\n"); + return Connect(); +} + +bool cIptvProtocolCurl::Close(void) +{ + debug("cIptvProtocolCurl::Close()\n"); + Disconnect(); + return true; +} + +int cIptvProtocolCurl::Read(unsigned char* BufferAddr, unsigned int BufferLen) +{ + //debug("cIptvProtocolCurl::Read()\n"); + int len = 0; + if (ringBufferM) { + // fill up the buffer + if (handleM && multiM) { + switch (modeM) { + case eModeRtsp: + { + //CURLcode res = CURLE_OK; + //iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_RECEIVE); + //iptv_curl_easy_perform(handleM); + // @todo - how to detect eof? + } + break; + + case eModeFile: + break; + + case eModeHttp: + case eModeHttps: + { + CURLMcode res; + int running_handles; + + do { + res = curl_multi_perform(multiM, &running_handles); + } while (res == CURLM_CALL_MULTI_PERFORM); + + // shall be continue filling up the buffer? + mutexM.Lock(); + if (pausedM && (ringBufferM->Free() > ringBufferM->Available())) { + debug("cIptvProtocolCurl::Read(continue): free=%d available=%d\n", ringBufferM->Free(), ringBufferM->Available()); + pausedM = false; + curl_easy_pause(handleM, CURLPAUSE_CONT); + } + mutexM.Unlock(); + + // check end of file + if (running_handles == 0) { + int msgcount; + CURLMsg *msg = curl_multi_info_read(multiM, &msgcount); + if (msg && (msg->msg == CURLMSG_DONE)) { + debug("cIptvProtocolCurl::Read(done): %s (%d)\n", curl_easy_strerror(msg->data.result), msg->data.result); + Disconnect(); + Connect(); + } + } + } + break; + + default: + break; + } + } + + // ... and try to empty it + unsigned char *p = GetData(&BufferLen); + if (p && (BufferLen > 0)) { + memcpy(BufferAddr, p, BufferLen); + DelData(BufferLen); + len = BufferLen; + //debug("cIptvProtocolCurl::Read(): get %d bytes\n", len); + } + } + + return len; +} + +bool cIptvProtocolCurl::Set(const char* Location, const int Parameter, const int Index) +{ + debug("cIptvProtocolCurl::Set(): Location=%s Parameter=%d Index=%d\n", Location, Parameter, Index); + if (!isempty(Location)) { + // Disconnect + Disconnect(); + // Update stream URL: colons (%3A) and pipes (%7C) shall be decoded + char *s = strdup(Location); + strreplace(s, "%3A", ":"); + strreplace(s, "%7C", "|"); + streamUrlM = s; + free(s); + if (startswith(*streamUrlM, "rtsp") || startswith(*streamUrlM, "RTSP")) + modeM = eModeRtsp; + else if (startswith(*streamUrlM, "https") || startswith(*streamUrlM, "HTTPS")) + modeM = eModeHttp; + else if (startswith(*streamUrlM, "http") || startswith(*streamUrlM, "HTTP")) + modeM = eModeHttps; + else if (startswith(*streamUrlM, "file") || startswith(*streamUrlM, "FILE")) + modeM = eModeFile; + else + modeM = eModeUnknown; + // Update stream parameter + streamParamM = Parameter; + //debug("%s [%d]\n", *streamUrlM, streamParamM); + // Reconnect + Connect(); + } + return true; +} + +cString cIptvProtocolCurl::GetInformation(void) +{ + //debug("cIptvProtocolCurl::GetInformation()"); + return cString::sprintf("%s [%d]", *streamUrlM, streamParamM); +} diff --git a/protocolcurl.h b/protocolcurl.h new file mode 100644 index 0000000..03d56b5 --- /dev/null +++ b/protocolcurl.h @@ -0,0 +1,72 @@ +/* + * protocolcurl.h: IPTV plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __IPTV_PROTOCOLCURL_H +#define __IPTV_PROTOCOLCURL_H + +#include +#include + +#include +#include +#include + +#include "protocolif.h" + +class cIptvProtocolCurl : public cIptvProtocolIf { +private: + enum eModeType { + eModeUnknown = 0, + eModeHttp, + eModeHttps, + eModeRtsp, + eModeFile, + eModeCount + }; + enum { + eConnectTimeoutS = 5, // in seconds + eSelectTimeoutMs = 10, // in milliseconds + eMaxDownloadSpeedMBits = 20 // in megabits per second + }; + + static size_t WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP); + static size_t WriteRtspCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP); + static size_t DescribeCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP); + static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP); + + cString streamUrlM; + int streamParamM; + cMutex mutexM; + CURL *handleM; + CURLM *multiM; + struct curl_slist *headerListM; + cRingBufferLinear *ringBufferM; + cString rtspControlM; + eModeType modeM; + bool connectedM; + bool pausedM; + + bool Connect(void); + bool Disconnect(void); + bool PutData(unsigned char *dataP, int lenP); + void DelData(int lenP); + void ClearData(void); + unsigned char *GetData(unsigned int *lenP); + +public: + cIptvProtocolCurl(); + virtual ~cIptvProtocolCurl(); + int Read(unsigned char* BufferAddr, unsigned int BufferLen); + bool Set(const char* Location, const int Parameter, const int Index); + bool Open(void); + bool Close(void); + cString GetInformation(void); + void SetRtspControl(const char *controlP); +}; + +#endif // __IPTV_PROTOCOLCURL_H + diff --git a/setup.c b/setup.c index 5e24dea..0f2a899 100644 --- a/setup.c +++ b/setup.c @@ -36,6 +36,7 @@ public: cIptvMenuInfo::cIptvMenuInfo() :cOsdMenu(tr("IPTV Information")), text(""), timeout(), page(IPTV_DEVICE_INFO_GENERAL) { + SetMenuCategory(mcText); timeout.Set(INFO_TIMEOUT_MS); UpdateInfo(); SetHelp(tr("General"), tr("Pids"), tr("Filters"), tr("Bits/bytes")); diff --git a/setup.h b/setup.h index f1e6420..d9749a4 100644 --- a/setup.h +++ b/setup.h @@ -19,7 +19,7 @@ private: int sidscan; int pidscan; int protocol; - char address[MaxFileName]; + char address[NAME_MAX]; int parameter; public: cIptvTransponderParameters(const char *Parameters = NULL); diff --git a/socket.c b/socket.c index ecdf1f8..4b2d62e 100644 --- a/socket.c +++ b/socket.c @@ -265,7 +265,8 @@ int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) if (BufferAddr[0] == TS_SYNC_BYTE) return len; else if (len > 3) { - // http://www.networksorcery.com/enp/rfc/rfc2250.txt + // http://tools.ietf.org/html/rfc3550 + // http://tools.ietf.org/html/rfc2250 // version unsigned int v = (BufferAddr[0] >> 6) & 0x03; // extension bit diff --git a/socket.h b/socket.h index 0d3fe58..8753d89 100644 --- a/socket.h +++ b/socket.h @@ -1,5 +1,5 @@ /* - * protocoludp.h: IPTV plugin for the Video Disk Recorder + * socket.h: IPTV plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * diff --git a/source.c b/source.c index 8445dc0..c247709 100644 --- a/source.c +++ b/source.c @@ -32,6 +32,9 @@ cString cIptvTransponderParameters::ToString(char Type) const case eProtocolEXT: protocolstr = "EXT"; break; + case eProtocolCURL: + protocolstr = "CURL"; + break; case eProtocolHTTP: protocolstr = "HTTP"; break; @@ -81,6 +84,10 @@ bool cIptvTransponderParameters::Parse(const char *s) protocol = eProtocolUDP; found_f = true; } + else if (strstr(data, "CURL")) { + protocol = eProtocolCURL; + found_f = true; + } else if (strstr(data, "HTTP")) { protocol = eProtocolHTTP; found_f = true; @@ -134,6 +141,7 @@ cIptvSourceParam::cIptvSourceParam(char Source, const char *Description) debug("cIptvSourceParam::cIptvSourceParam(): Source=%c Description=%s\n", Source, Description); protocols[cIptvTransponderParameters::eProtocolUDP] = tr("UDP"); + protocols[cIptvTransponderParameters::eProtocolCURL] = tr("CURL"); protocols[cIptvTransponderParameters::eProtocolHTTP] = tr("HTTP"); protocols[cIptvTransponderParameters::eProtocolFILE] = tr("FILE"); protocols[cIptvTransponderParameters::eProtocolEXT] = tr("EXT"); diff --git a/source.h b/source.h index 4d46fd4..88805a5 100644 --- a/source.h +++ b/source.h @@ -20,12 +20,13 @@ private: int sidscan; int pidscan; int protocol; - char address[MaxFileName]; + char address[NAME_MAX]; int parameter; public: enum { eProtocolUDP, + eProtocolCURL, eProtocolHTTP, eProtocolFILE, eProtocolEXT, diff --git a/statistics.c b/statistics.c index 6c24b15..c9e76f0 100644 --- a/statistics.c +++ b/statistics.c @@ -36,10 +36,10 @@ cString cIptvSectionStatistics::GetSectionStatistic() if (!IptvConfig.GetUseBytes()) bitrate *= 8; // no trailing linefeed here! - cString info = cString::sprintf("%4ld (%4ld k%s/s)", numberOfCalls, bitrate, - IptvConfig.GetUseBytes() ? "B" : "bit"); + cString s = cString::sprintf("%4ld (%4ld k%s/s)", numberOfCalls, bitrate, + IptvConfig.GetUseBytes() ? "B" : "bit"); filteredData = numberOfCalls = 0; - return info; + return s; } void cIptvSectionStatistics::AddSectionStatistic(long Bytes, long Calls) @@ -72,26 +72,26 @@ cString cIptvPidStatistics::GetPidStatistic() cMutexLock MutexLock(&mutex); uint64_t elapsed = timer.Elapsed(); /* in milliseconds */ timer.Set(); - cString info("Active pids:\n"); + cString s("Active pids:\n"); for (unsigned int i = 0; i < IPTV_STATS_ACTIVE_PIDS_COUNT; ++i) { if (mostActivePids[i].pid) { long bitrate = elapsed ? (long)(1000.0L * mostActivePids[i].DataAmount / KILOBYTE(1) / elapsed) : 0L; if (!IptvConfig.GetUseBytes()) bitrate *= 8; - info = cString::sprintf("%sPid %d: %4d (%4ld k%s/s)\n", *info, i, - mostActivePids[i].pid, bitrate, - IptvConfig.GetUseBytes() ? "B" : "bit"); + s = cString::sprintf("%sPid %d: %4d (%4ld k%s/s)\n", *s, i, + mostActivePids[i].pid, bitrate, + IptvConfig.GetUseBytes() ? "B" : "bit"); } } memset(mostActivePids, '\0', sizeof(mostActivePids)); - return info; + return s; } int cIptvPidStatistics::SortPids(const void* data1, const void* data2) { //debug("cIptvPidStatistics::SortPids()\n"); - pidStruct *comp1 = (pidStruct*)data1; - pidStruct *comp2 = (pidStruct*)data2; + const pidStruct *comp1 = reinterpret_cast(data1); + const pidStruct *comp2 = reinterpret_cast(data2); if (comp1->DataAmount > comp2->DataAmount) return -1; if (comp1->DataAmount < comp2->DataAmount) @@ -148,9 +148,9 @@ cString cIptvStreamerStatistics::GetStreamerStatistic() long bitrate = elapsed ? (long)(1000.0L * dataBytes / KILOBYTE(1) / elapsed) : 0L; if (!IptvConfig.GetUseBytes()) bitrate *= 8; - cString info = cString::sprintf("%ld k%s/s", bitrate, IptvConfig.GetUseBytes() ? "B" : "bit"); + cString s = cString::sprintf("%ld k%s/s", bitrate, IptvConfig.GetUseBytes() ? "B" : "bit"); dataBytes = 0; - return info; + return s; } void cIptvStreamerStatistics::AddStreamerStatistic(long Bytes) @@ -193,12 +193,12 @@ cString cIptvBufferStatistics::GetBufferStatistic() totalKilos *= 8; usedKilos *= 8; } - cString info = cString::sprintf("Buffer bitrate: %ld k%s/s\nBuffer usage: %ld/%ld k%s (%2.1f%%)\n", bitrate, - IptvConfig.GetUseBytes() ? "B" : "bit", usedKilos, totalKilos, - IptvConfig.GetUseBytes() ? "B" : "bit", percentage); + cString s = cString::sprintf("Buffer bitrate: %ld k%s/s\nBuffer usage: %ld/%ld k%s (%2.1f%%)\n", bitrate, + IptvConfig.GetUseBytes() ? "B" : "bit", usedKilos, totalKilos, + IptvConfig.GetUseBytes() ? "B" : "bit", percentage); dataBytes = 0; usedSpace = 0; - return info; + return s; } void cIptvBufferStatistics::AddBufferStatistic(long Bytes, long Used) diff --git a/streamer.c b/streamer.c index 6c811a8..e03ad6e 100644 --- a/streamer.c +++ b/streamer.c @@ -46,7 +46,7 @@ void cIptvStreamer::Action(void) while (packetBuffer && Running()) { int length = -1; if (protocol) - length = protocol->Read(packetBuffer, packetBufferLen); + length = protocol->Read(packetBuffer, min((unsigned int)ringBuffer->Free(), packetBufferLen)); if (length > 0) { AddStreamerStatistic(length); if (ringBuffer) {