mirror of
				https://github.com/rofafor/vdr-plugin-iptv.git
				synced 2023-10-10 11:37:03 +00:00 
			
		
		
		
	Updated for vdr-1.7.38 and added a new CURL protocol for HTTP/HTTPS.
This commit is contained in:
		
							
								
								
									
										5
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								HISTORY
									
									
									
									
									
								
							@@ -188,3 +188,8 @@ VDR Plugin 'iptv' Revision History
 | 
				
			|||||||
- Added support for source-specific multicasts (SSM).
 | 
					- Added support for source-specific multicasts (SSM).
 | 
				
			||||||
- Changed default external script directory from the
 | 
					- Changed default external script directory from the
 | 
				
			||||||
  configuration to the resource.
 | 
					  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.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										103
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								Makefile
									
									
									
									
									
								
							@@ -2,24 +2,22 @@
 | 
				
			|||||||
# Makefile for IPTV plugin
 | 
					# Makefile for IPTV plugin
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Debugging on/off 
 | 
					# Debugging on/off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#IPTV_DEBUG = 1
 | 
					#IPTV_DEBUG = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Default shell for EXT protocol
 | 
					# Default shell for EXT protocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#IPTV_EXTSHELL = /bin/bash
 | 
					#IPTV_EXTSHELL = /bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Strip debug symbols?  Set eg. to /bin/true if not
 | 
					# Strip debug symbols?  Set eg. to /bin/true if not
 | 
				
			||||||
STRIP = strip
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Install command
 | 
					STRIP = strip
 | 
				
			||||||
INSTALL = cp --remove-destination
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The official name of this plugin.
 | 
					# The official name of this plugin.
 | 
				
			||||||
# This name will be used in the '-P...' option of VDR to load the 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.
 | 
					# 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
 | 
					PLUGIN = iptv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### The version number of this plugin (taken from the main source file):
 | 
					### 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')
 | 
					VERSION = $(shell grep 'const char VERSION\[\] *=' $(PLUGIN).c | awk '{ print $$5 }' | sed -e 's/[";]//g')
 | 
				
			||||||
GITTAG  = $(shell git describe --always 2>/dev/null)
 | 
					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:
 | 
					### The directory environment:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VDRDIR ?= ../../..
 | 
					# Use package data if installed...otherwise assume we're under the VDR source directory:
 | 
				
			||||||
LIBDIR ?= ../../lib
 | 
					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
 | 
					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:
 | 
					### Allow user defined options to overwrite defaults:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-include $(VDRDIR)/Make.config
 | 
					-include $(PLGCFG)
 | 
				
			||||||
 | 
					 | 
				
			||||||
### 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)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### The name of the distribution archive:
 | 
					### The name of the distribution archive:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARCHIVE = $(PLUGIN)-$(VERSION)
 | 
					ARCHIVE = $(PLUGIN)-$(VERSION)
 | 
				
			||||||
PACKAGE = vdr-$(ARCHIVE)
 | 
					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 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
 | 
					ifdef IPTV_DEBUG
 | 
				
			||||||
DEFINES += -DDEBUG
 | 
					DEFINES += -DDEBUG
 | 
				
			||||||
@@ -79,61 +84,67 @@ all-redirect: all
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### The object files (add further files here):
 | 
					### The object files (add further files here):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o \
 | 
					OBJS = $(PLUGIN).o common.o config.o device.o pidscanner.o \
 | 
				
			||||||
	protocolhttp.o protocolfile.o protocolext.o sectionfilter.o \
 | 
						protocolcurl.o protocolext.o protocolfile.o protocolhttp.o \
 | 
				
			||||||
	sidscanner.o pidscanner.o statistics.o common.o socket.o source.o
 | 
						protocoludp.o sectionfilter.o setup.o sidscanner.o socket.o \
 | 
				
			||||||
 | 
						source.o statistics.o streamer.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### The main target:
 | 
					### The main target:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all: libvdr-$(PLUGIN).so i18n
 | 
					all: $(SOFILE) i18n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Implicit rules:
 | 
					### Implicit rules:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%.o: %.c Makefile
 | 
					%.o: %.c
 | 
				
			||||||
	$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
 | 
						$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Dependencies:
 | 
					### Dependencies:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MAKEDEP = $(CXX) -MM -MG
 | 
					MAKEDEP = $(CXX) -MM -MG
 | 
				
			||||||
DEPFILE = .dependencies
 | 
					DEPFILE = .dependencies
 | 
				
			||||||
$(DEPFILE): Makefile
 | 
					$(DEPFILE): Makefile
 | 
				
			||||||
	@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
 | 
						@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-include $(DEPFILE)
 | 
					-include $(DEPFILE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Internationalization (I18N):
 | 
					### Internationalization (I18N):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PODIR     = po
 | 
					PODIR     = po
 | 
				
			||||||
LOCALEDIR = $(VDRDIR)/locale
 | 
					 | 
				
			||||||
I18Npo    = $(wildcard $(PODIR)/*.po)
 | 
					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
 | 
					I18Npot   = $(PODIR)/$(PLUGIN).pot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%.mo: %.po
 | 
					%.mo: %.po
 | 
				
			||||||
	msgfmt -c -o $@ $<
 | 
						msgfmt -c -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(I18Npot): $(wildcard *.c)
 | 
					$(I18Npot): $(wildcard *.c)
 | 
				
			||||||
	xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name='vdr-$(PLUGIN)' --package-version='$(VERSION)' --msgid-bugs-address='<see README>' -o $@ `ls $^`
 | 
						xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%.po: $(I18Npot)
 | 
					%.po: $(I18Npot)
 | 
				
			||||||
	msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
 | 
						msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
 | 
				
			||||||
	@touch $@
 | 
						@touch $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
 | 
					$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
 | 
				
			||||||
	@mkdir -p $(dir $@)
 | 
						install -D -m644 $< $@
 | 
				
			||||||
	cp $< $@
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: i18n
 | 
					.PHONY: i18n
 | 
				
			||||||
i18n: $(I18Nmsgs) $(I18Npot)
 | 
					i18n: $(I18Nmo) $(I18Npot)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install-i18n: $(I18Nmsgs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Targets:
 | 
					### Targets:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libvdr-$(PLUGIN).so: $(OBJS)
 | 
					$(SOFILE): $(OBJS)
 | 
				
			||||||
	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
 | 
						$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
 | 
				
			||||||
ifndef IPTV_DEBUG
 | 
					ifndef IPTV_DEBUG
 | 
				
			||||||
	@$(STRIP) $@
 | 
						@$(STRIP) $@
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
	@$(INSTALL) $@ $(LIBDIR)/$@.$(APIVERSION)
 | 
					
 | 
				
			||||||
 | 
					install-lib: $(SOFILE)
 | 
				
			||||||
 | 
						install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install: install-lib install-i18n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dist: $(I18Npo) clean
 | 
					dist: $(I18Npo) clean
 | 
				
			||||||
	@-rm -rf $(TMPDIR)/$(ARCHIVE)
 | 
						@-rm -rf $(TMPDIR)/$(ARCHIVE)
 | 
				
			||||||
@@ -144,7 +155,9 @@ dist: $(I18Npo) clean
 | 
				
			|||||||
	@echo Distribution package created as $(PACKAGE).tgz
 | 
						@echo Distribution package created as $(PACKAGE).tgz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					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)
 | 
					.PHONY: cppcheck
 | 
				
			||||||
	@cppcheck --enable=information,style,unusedFunction -v -f $(OBJS:%.o=%.c)
 | 
					cppcheck:
 | 
				
			||||||
 | 
						@cppcheck --language=c++ --enable=all -v -f $(OBJS:%.o=%.c)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								README
									
									
									
									
									
								
							@@ -17,7 +17,8 @@ See the file COPYING for more information.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Requirements:
 | 
					Requirements:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DVB compatible MPEG1/2 or H.264 network video streams.
 | 
					- Libcurl - the multiprotocol file transfer library
 | 
				
			||||||
 | 
					  http://curl.haxx.se/libcurl/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Description:
 | 
					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
 | 
					  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
 | 
					  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
 | 
					  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@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
 | 
					  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")
 | 
					           |  |   |   |     |           |      Source type ("I")
 | 
				
			||||||
           |  |   |   |     |           Stream parameter (multicast port
 | 
					           |  |   |   |     |           Stream parameter
 | 
				
			||||||
           |  |   |   |     |           number, HTTP port number, file delay
 | 
					           |  |   |   |     |            UDP:  multicast port
 | 
				
			||||||
           |  |   |   |     |           (ms), script parameter)
 | 
					           |  |   |   |     |            CURL: <<to be defined>>
 | 
				
			||||||
           |  |   |   |     Stream address (multicast source@group address,
 | 
					           |  |   |   |     |            HTTP: HTTP port number
 | 
				
			||||||
           |  |   |   |     URL, file location, script location)
 | 
					           |  |   |   |     |            FILE: file delay (ms)
 | 
				
			||||||
           |  |   |   Stream protocol ("UDP", "HTTP", "FILE", "EXT")
 | 
					           |  |   |   |     |            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)
 | 
					           |  |   Pid scanner ("0" disable, "1" enable)
 | 
				
			||||||
           |  Section id (Sid/Nid/Tid) scanner ("0" disable, "1" enable)
 | 
					           |  Section id (Sid/Nid/Tid) scanner ("0" disable, "1" enable)
 | 
				
			||||||
           Unique enumeration
 | 
					           Unique enumeration
 | 
				
			||||||
@@ -173,6 +182,11 @@ Notes:
 | 
				
			|||||||
  IGMP v3 protocol:
 | 
					  IGMP v3 protocol:
 | 
				
			||||||
  "U=<source address>@<group address>"
 | 
					  "U=<source address>@<group address>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The CURL implementation supports only HTTP/HTTPS protocols and an optional
 | 
				
			||||||
 | 
					  netrc configuration file for authentication:
 | 
				
			||||||
 | 
					  $(CONFDIR)/iptv/netrc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- CURL implementation
 | 
				
			||||||
Acknowledgements:
 | 
					Acknowledgements:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- The IPTV section filtering code is derived from Linux kernel.
 | 
					- The IPTV section filtering code is derived from Linux kernel.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								common.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								common.c
									
									
									
									
									
								
							@@ -44,14 +44,18 @@ int select_single_desc(int descriptor, const int usecs, const bool selectWrite)
 | 
				
			|||||||
  tv.tv_sec = 0;
 | 
					  tv.tv_sec = 0;
 | 
				
			||||||
  tv.tv_usec = usecs;
 | 
					  tv.tv_usec = usecs;
 | 
				
			||||||
  // Use select
 | 
					  // Use select
 | 
				
			||||||
  fd_set fds;
 | 
					  fd_set infd;
 | 
				
			||||||
  FD_ZERO(&fds);
 | 
					  fd_set outfd;
 | 
				
			||||||
  FD_SET(descriptor, &fds);
 | 
					  fd_set errfd;
 | 
				
			||||||
  int retval = 0;
 | 
					  FD_ZERO(&infd);
 | 
				
			||||||
 | 
					  FD_ZERO(&outfd);
 | 
				
			||||||
 | 
					  FD_ZERO(&errfd);
 | 
				
			||||||
 | 
					  FD_SET(descriptor, &errfd);
 | 
				
			||||||
  if (selectWrite)
 | 
					  if (selectWrite)
 | 
				
			||||||
     retval = select(descriptor + 1, NULL, &fds, NULL, &tv);
 | 
					     FD_SET(descriptor, &outfd);
 | 
				
			||||||
  else
 | 
					  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
 | 
					  // Check if error
 | 
				
			||||||
  ERROR_IF_RET(retval < 0, "select()", return retval);
 | 
					  ERROR_IF_RET(retval < 0, "select()", return retval);
 | 
				
			||||||
  return retval;
 | 
					  return retval;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								common.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								common.h
									
									
									
									
									
								
							@@ -14,9 +14,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG
 | 
					#ifdef DEBUG
 | 
				
			||||||
#define debug(x...) dsyslog("IPTV: " x);
 | 
					#define debug(x...) dsyslog("IPTV: " x);
 | 
				
			||||||
 | 
					#define info(x...)  isyslog("IPTV: " x);
 | 
				
			||||||
#define error(x...) esyslog("ERROR: " x);
 | 
					#define error(x...) esyslog("ERROR: " x);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define debug(x...) ;
 | 
					#define debug(x...) ;
 | 
				
			||||||
 | 
					#define info(x...)  isyslog("IPTV: " x);
 | 
				
			||||||
#define error(x...) esyslog("ERROR: " x);
 | 
					#define error(x...) esyslog("ERROR: " x);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										59
									
								
								device.c
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								device.c
									
									
									
									
									
								
							@@ -20,6 +20,7 @@ cIptvDevice::cIptvDevice(unsigned int Index)
 | 
				
			|||||||
  dvrFd(-1),
 | 
					  dvrFd(-1),
 | 
				
			||||||
  isPacketDelivered(false),
 | 
					  isPacketDelivered(false),
 | 
				
			||||||
  isOpenDvr(false),
 | 
					  isOpenDvr(false),
 | 
				
			||||||
 | 
					  isBuffering(true),
 | 
				
			||||||
  sidScanEnabled(false),
 | 
					  sidScanEnabled(false),
 | 
				
			||||||
  pidScanEnabled(false),
 | 
					  pidScanEnabled(false),
 | 
				
			||||||
  channelId(tChannelID::InvalidID)
 | 
					  channelId(tChannelID::InvalidID)
 | 
				
			||||||
@@ -32,6 +33,7 @@ cIptvDevice::cIptvDevice(unsigned int Index)
 | 
				
			|||||||
  tsBuffer->SetTimeouts(10, 10);
 | 
					  tsBuffer->SetTimeouts(10, 10);
 | 
				
			||||||
  ResetBuffering();
 | 
					  ResetBuffering();
 | 
				
			||||||
  pUdpProtocol = new cIptvProtocolUdp();
 | 
					  pUdpProtocol = new cIptvProtocolUdp();
 | 
				
			||||||
 | 
					  pCurlProtocol = new cIptvProtocolCurl();
 | 
				
			||||||
  pHttpProtocol = new cIptvProtocolHttp();
 | 
					  pHttpProtocol = new cIptvProtocolHttp();
 | 
				
			||||||
  pFileProtocol = new cIptvProtocolFile();
 | 
					  pFileProtocol = new cIptvProtocolFile();
 | 
				
			||||||
  pExtProtocol = new cIptvProtocolExt();
 | 
					  pExtProtocol = new cIptvProtocolExt();
 | 
				
			||||||
@@ -63,6 +65,7 @@ cIptvDevice::~cIptvDevice()
 | 
				
			|||||||
  StopSectionHandler();
 | 
					  StopSectionHandler();
 | 
				
			||||||
  DELETE_POINTER(pIptvStreamer);
 | 
					  DELETE_POINTER(pIptvStreamer);
 | 
				
			||||||
  DELETE_POINTER(pUdpProtocol);
 | 
					  DELETE_POINTER(pUdpProtocol);
 | 
				
			||||||
 | 
					  DELETE_POINTER(pCurlProtocol);
 | 
				
			||||||
  DELETE_POINTER(pHttpProtocol);
 | 
					  DELETE_POINTER(pHttpProtocol);
 | 
				
			||||||
  DELETE_POINTER(pFileProtocol);
 | 
					  DELETE_POINTER(pFileProtocol);
 | 
				
			||||||
  DELETE_POINTER(pExtProtocol);
 | 
					  DELETE_POINTER(pExtProtocol);
 | 
				
			||||||
@@ -141,48 +144,48 @@ cString cIptvDevice::GetFiltersInformation(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  //debug("cIptvDevice::GetFiltersInformation(%d)\n", deviceIndex);
 | 
					  //debug("cIptvDevice::GetFiltersInformation(%d)\n", deviceIndex);
 | 
				
			||||||
  unsigned int count = 0;
 | 
					  unsigned int count = 0;
 | 
				
			||||||
  cString info("Active section filters:\n");
 | 
					  cString s("Active section filters:\n");
 | 
				
			||||||
  // loop through active section filters
 | 
					  // loop through active section filters
 | 
				
			||||||
  for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
 | 
					  for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
 | 
				
			||||||
      if (secfilters[i]) {
 | 
					      if (secfilters[i]) {
 | 
				
			||||||
         info = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *info, i,
 | 
					         s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i,
 | 
				
			||||||
                                 *secfilters[i]->GetSectionStatistic(), secfilters[i]->GetPid(),
 | 
					                              *secfilters[i]->GetSectionStatistic(), secfilters[i]->GetPid(),
 | 
				
			||||||
                                 id_pid(secfilters[i]->GetPid()));
 | 
					                              id_pid(secfilters[i]->GetPid()));
 | 
				
			||||||
         if (++count > IPTV_STATS_ACTIVE_FILTERS_COUNT)
 | 
					         if (++count > IPTV_STATS_ACTIVE_FILTERS_COUNT)
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
         }
 | 
					         }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
  return info;
 | 
					  return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cString cIptvDevice::GetInformation(unsigned int Page)
 | 
					cString cIptvDevice::GetInformation(unsigned int Page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // generate information string
 | 
					  // generate information string
 | 
				
			||||||
  cString info;
 | 
					  cString s;
 | 
				
			||||||
  switch (Page) {
 | 
					  switch (Page) {
 | 
				
			||||||
    case IPTV_DEVICE_INFO_GENERAL:
 | 
					    case IPTV_DEVICE_INFO_GENERAL:
 | 
				
			||||||
         info = GetGeneralInformation();
 | 
					         s = GetGeneralInformation();
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
    case IPTV_DEVICE_INFO_PIDS:
 | 
					    case IPTV_DEVICE_INFO_PIDS:
 | 
				
			||||||
         info = GetPidsInformation();
 | 
					         s = GetPidsInformation();
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
    case IPTV_DEVICE_INFO_FILTERS:
 | 
					    case IPTV_DEVICE_INFO_FILTERS:
 | 
				
			||||||
         info = GetFiltersInformation();
 | 
					         s = GetFiltersInformation();
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
    case IPTV_DEVICE_INFO_PROTOCOL:
 | 
					    case IPTV_DEVICE_INFO_PROTOCOL:
 | 
				
			||||||
         info = pIptvStreamer ? *pIptvStreamer->GetInformation() : "";
 | 
					         s = pIptvStreamer ? *pIptvStreamer->GetInformation() : "";
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
    case IPTV_DEVICE_INFO_BITRATE:
 | 
					    case IPTV_DEVICE_INFO_BITRATE:
 | 
				
			||||||
         info = pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "";
 | 
					         s = pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "";
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
         info = cString::sprintf("%s%s%s",
 | 
					         s = cString::sprintf("%s%s%s",
 | 
				
			||||||
                                 *GetGeneralInformation(),
 | 
					                              *GetGeneralInformation(),
 | 
				
			||||||
                                 *GetPidsInformation(),
 | 
					                              *GetPidsInformation(),
 | 
				
			||||||
                                 *GetFiltersInformation());
 | 
					                              *GetFiltersInformation());
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  return info;
 | 
					  return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cString cIptvDevice::DeviceType(void) const
 | 
					cString cIptvDevice::DeviceType(void) const
 | 
				
			||||||
@@ -268,6 +271,9 @@ bool cIptvDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 | 
				
			|||||||
    case cIptvTransponderParameters::eProtocolUDP:
 | 
					    case cIptvTransponderParameters::eProtocolUDP:
 | 
				
			||||||
         protocol = pUdpProtocol;
 | 
					         protocol = pUdpProtocol;
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
 | 
					    case cIptvTransponderParameters::eProtocolCURL:
 | 
				
			||||||
 | 
					         protocol = pCurlProtocol;
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
    case cIptvTransponderParameters::eProtocolHTTP:
 | 
					    case cIptvTransponderParameters::eProtocolHTTP:
 | 
				
			||||||
         protocol = pHttpProtocol;
 | 
					         protocol = pHttpProtocol;
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
@@ -400,10 +406,10 @@ void cIptvDevice::CloseDvr(void)
 | 
				
			|||||||
  isOpenDvr = false;
 | 
					  isOpenDvr = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool cIptvDevice::HasLock(int TimeoutMs)
 | 
					bool cIptvDevice::HasLock(int TimeoutMs) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  //debug("cIptvDevice::HasLock(%d): %d\n", deviceIndex, TimeoutMs);
 | 
					  //debug("cIptvDevice::HasLock(%d): %d\n", deviceIndex, TimeoutMs);
 | 
				
			||||||
  return (!IsBuffering());
 | 
					  return (!isBuffering);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool cIptvDevice::HasInternalCam(void)
 | 
					bool cIptvDevice::HasInternalCam(void)
 | 
				
			||||||
@@ -415,26 +421,29 @@ bool cIptvDevice::HasInternalCam(void)
 | 
				
			|||||||
void cIptvDevice::ResetBuffering(void)
 | 
					void cIptvDevice::ResetBuffering(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  debug("cIptvDevice::ResetBuffering(%d)\n", deviceIndex);
 | 
					  debug("cIptvDevice::ResetBuffering(%d)\n", deviceIndex);
 | 
				
			||||||
 | 
					  isBuffering = true;
 | 
				
			||||||
  // pad prefill to multiple of TS_SIZE
 | 
					  // pad prefill to multiple of TS_SIZE
 | 
				
			||||||
  tsBufferPrefill = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize()) *
 | 
					  tsBufferPrefill = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize()) *
 | 
				
			||||||
                    IptvConfig.GetTsBufferPrefillRatio() / 100;
 | 
					                    IptvConfig.GetTsBufferPrefillRatio() / 100;
 | 
				
			||||||
  tsBufferPrefill -= (tsBufferPrefill % TS_SIZE);
 | 
					  tsBufferPrefill -= (tsBufferPrefill % TS_SIZE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool cIptvDevice::IsBuffering(void)
 | 
					void cIptvDevice::CheckBuffering(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  //debug("cIptvDevice::IsBuffering(%d): %d\n", deviceIndex);
 | 
					  //debug("cIptvDevice::CheckBuffering(%d): %d\n", deviceIndex);
 | 
				
			||||||
  if (tsBufferPrefill && tsBuffer->Available() < tsBufferPrefill)
 | 
					  if (tsBufferPrefill && tsBuffer && tsBuffer->Available() < tsBufferPrefill)
 | 
				
			||||||
     return true;
 | 
					     isBuffering = true;
 | 
				
			||||||
  else
 | 
					  else {
 | 
				
			||||||
 | 
					     isBuffering = false;
 | 
				
			||||||
     tsBufferPrefill = 0;
 | 
					     tsBufferPrefill = 0;
 | 
				
			||||||
  return false;
 | 
					     }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool cIptvDevice::GetTSPacket(uchar *&Data)
 | 
					bool cIptvDevice::GetTSPacket(uchar *&Data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  //debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
 | 
					  //debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
 | 
				
			||||||
  if (tsBuffer && !IsBuffering()) {
 | 
					  CheckBuffering();
 | 
				
			||||||
 | 
					  if (tsBuffer && !isBuffering) {
 | 
				
			||||||
     if (isPacketDelivered) {
 | 
					     if (isPacketDelivered) {
 | 
				
			||||||
        tsBuffer->Del(TS_SIZE);
 | 
					        tsBuffer->Del(TS_SIZE);
 | 
				
			||||||
        isPacketDelivered = false;
 | 
					        isPacketDelivered = false;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								device.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								device.h
									
									
									
									
									
								
							@@ -11,6 +11,7 @@
 | 
				
			|||||||
#include <vdr/device.h>
 | 
					#include <vdr/device.h>
 | 
				
			||||||
#include "common.h"
 | 
					#include "common.h"
 | 
				
			||||||
#include "protocoludp.h"
 | 
					#include "protocoludp.h"
 | 
				
			||||||
 | 
					#include "protocolcurl.h"
 | 
				
			||||||
#include "protocolhttp.h"
 | 
					#include "protocolhttp.h"
 | 
				
			||||||
#include "protocolfile.h"
 | 
					#include "protocolfile.h"
 | 
				
			||||||
#include "protocolext.h"
 | 
					#include "protocolext.h"
 | 
				
			||||||
@@ -37,12 +38,14 @@ private:
 | 
				
			|||||||
  int dvrFd;
 | 
					  int dvrFd;
 | 
				
			||||||
  bool isPacketDelivered;
 | 
					  bool isPacketDelivered;
 | 
				
			||||||
  bool isOpenDvr;
 | 
					  bool isOpenDvr;
 | 
				
			||||||
 | 
					  bool isBuffering;
 | 
				
			||||||
  bool sidScanEnabled;
 | 
					  bool sidScanEnabled;
 | 
				
			||||||
  bool pidScanEnabled;
 | 
					  bool pidScanEnabled;
 | 
				
			||||||
  cRingBufferLinear *tsBuffer;
 | 
					  cRingBufferLinear *tsBuffer;
 | 
				
			||||||
  int tsBufferPrefill;
 | 
					  int tsBufferPrefill;
 | 
				
			||||||
  tChannelID channelId;
 | 
					  tChannelID channelId;
 | 
				
			||||||
  cIptvProtocolUdp *pUdpProtocol;
 | 
					  cIptvProtocolUdp *pUdpProtocol;
 | 
				
			||||||
 | 
					  cIptvProtocolCurl *pCurlProtocol;
 | 
				
			||||||
  cIptvProtocolHttp *pHttpProtocol;
 | 
					  cIptvProtocolHttp *pHttpProtocol;
 | 
				
			||||||
  cIptvProtocolFile *pFileProtocol;
 | 
					  cIptvProtocolFile *pFileProtocol;
 | 
				
			||||||
  cIptvProtocolExt *pExtProtocol;
 | 
					  cIptvProtocolExt *pExtProtocol;
 | 
				
			||||||
@@ -71,7 +74,7 @@ private:
 | 
				
			|||||||
  // for channel parsing & buffering
 | 
					  // for channel parsing & buffering
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  void ResetBuffering(void);
 | 
					  void ResetBuffering(void);
 | 
				
			||||||
  bool IsBuffering(void);
 | 
					  void CheckBuffering(void);
 | 
				
			||||||
  bool DeleteFilter(unsigned int Index);
 | 
					  bool DeleteFilter(unsigned int Index);
 | 
				
			||||||
  bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const;
 | 
					  bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,7 +110,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // for transponder lock
 | 
					  // for transponder lock
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  virtual bool HasLock(int);
 | 
					  virtual bool HasLock(int) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // for common interface
 | 
					  // for common interface
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								iptv.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								iptv.c
									
									
									
									
									
								
							@@ -13,15 +13,15 @@
 | 
				
			|||||||
#include "device.h"
 | 
					#include "device.h"
 | 
				
			||||||
#include "iptvservice.h"
 | 
					#include "iptvservice.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(APIVERSNUM) && APIVERSNUM < 10730
 | 
					#if defined(APIVERSNUM) && APIVERSNUM < 10738
 | 
				
			||||||
#error "VDR-1.7.30 API version or greater is required!"
 | 
					#error "VDR-1.7.38 API version or greater is required!"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef GITVERSION
 | 
					#ifndef GITVERSION
 | 
				
			||||||
#define GITVERSION ""
 | 
					#define GITVERSION ""
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       const char VERSION[]     = "1.1.0" GITVERSION;
 | 
					       const char VERSION[]     = "1.2.0" GITVERSION;
 | 
				
			||||||
static const char DESCRIPTION[] = trNOOP("Experience the IPTV");
 | 
					static const char DESCRIPTION[] = trNOOP("Experience the IPTV");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class cPluginIptv : public cPlugin {
 | 
					class cPluginIptv : public cPlugin {
 | 
				
			||||||
@@ -107,6 +107,10 @@ bool cPluginIptv::Start(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  debug("cPluginIptv::Start()\n");
 | 
					  debug("cPluginIptv::Start()\n");
 | 
				
			||||||
  // Start any background activities the plugin shall perform.
 | 
					  // 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;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -114,6 +118,7 @@ void cPluginIptv::Stop(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  debug("cPluginIptv::Stop()\n");
 | 
					  debug("cPluginIptv::Stop()\n");
 | 
				
			||||||
  // Stop any background activities the plugin is performing.
 | 
					  // Stop any background activities the plugin is performing.
 | 
				
			||||||
 | 
					  curl_global_cleanup();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cPluginIptv::Housekeeping(void)
 | 
					void cPluginIptv::Housekeeping(void)
 | 
				
			||||||
@@ -204,7 +209,7 @@ bool cPluginIptv::Service(const char *Id, void *Data)
 | 
				
			|||||||
  debug("cPluginIptv::Service()\n");
 | 
					  debug("cPluginIptv::Service()\n");
 | 
				
			||||||
  if (strcmp(Id,"IptvService-v1.0") == 0) {
 | 
					  if (strcmp(Id,"IptvService-v1.0") == 0) {
 | 
				
			||||||
     if (Data) {
 | 
					     if (Data) {
 | 
				
			||||||
        IptvService_v1_0 *data = (IptvService_v1_0*)Data;
 | 
					        IptvService_v1_0 *data = reinterpret_cast<IptvService_v1_0*>(Data);
 | 
				
			||||||
        cIptvDevice *dev = cIptvDevice::GetIptvDevice(data->cardIndex);
 | 
					        cIptvDevice *dev = cIptvDevice::GetIptvDevice(data->cardIndex);
 | 
				
			||||||
        if (!dev)
 | 
					        if (!dev)
 | 
				
			||||||
           return false;
 | 
					           return false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: vdr-iptv 1.0.0\n"
 | 
					"Project-Id-Version: vdr-iptv 1.2.0\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: <see README>\n"
 | 
					"Report-Msgid-Bugs-To: <see README>\n"
 | 
				
			||||||
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
					"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
				
			||||||
"PO-Revision-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"
 | 
					msgid "UDP"
 | 
				
			||||||
msgstr "UDP"
 | 
					msgstr "UDP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "CURL"
 | 
				
			||||||
 | 
					msgstr "CURL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "HTTP"
 | 
					msgid "HTTP"
 | 
				
			||||||
msgstr "HTTP"
 | 
					msgstr "HTTP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: vdr-iptv 1.0.0\n"
 | 
					"Project-Id-Version: vdr-iptv 1.2.0\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: <see README>\n"
 | 
					"Report-Msgid-Bugs-To: <see README>\n"
 | 
				
			||||||
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
					"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
				
			||||||
"PO-Revision-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"
 | 
					msgid "UDP"
 | 
				
			||||||
msgstr "UDP"
 | 
					msgstr "UDP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "CURL"
 | 
				
			||||||
 | 
					msgstr "CURL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "HTTP"
 | 
					msgid "HTTP"
 | 
				
			||||||
msgstr "HTTP"
 | 
					msgstr "HTTP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: vdr-iptv 1.0.0\n"
 | 
					"Project-Id-Version: vdr-iptv 1.2.0\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: <see README>\n"
 | 
					"Report-Msgid-Bugs-To: <see README>\n"
 | 
				
			||||||
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
					"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
				
			||||||
"PO-Revision-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"
 | 
					msgid "UDP"
 | 
				
			||||||
msgstr "UDP"
 | 
					msgstr "UDP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "CURL"
 | 
				
			||||||
 | 
					msgstr "CURL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "HTTP"
 | 
					msgid "HTTP"
 | 
				
			||||||
msgstr "HTTP"
 | 
					msgstr "HTTP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: vdr-iptv 1.0.0\n"
 | 
					"Project-Id-Version: vdr-iptv 1.2.0\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: <see README>\n"
 | 
					"Report-Msgid-Bugs-To: <see README>\n"
 | 
				
			||||||
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
					"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
				
			||||||
"PO-Revision-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"
 | 
					msgid "UDP"
 | 
				
			||||||
msgstr "UDP"
 | 
					msgstr "UDP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "CURL"
 | 
				
			||||||
 | 
					msgstr "CURL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "HTTP"
 | 
					msgid "HTTP"
 | 
				
			||||||
msgstr "HTTP"
 | 
					msgstr "HTTP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: vdr-iptv 1.0.0\n"
 | 
					"Project-Id-Version: vdr-iptv 1.2.0\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: <see README>\n"
 | 
					"Report-Msgid-Bugs-To: <see README>\n"
 | 
				
			||||||
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
					"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
				
			||||||
"PO-Revision-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"
 | 
					msgid "UDP"
 | 
				
			||||||
msgstr "UDP"
 | 
					msgstr "UDP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "CURL"
 | 
				
			||||||
 | 
					msgstr "CURL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "HTTP"
 | 
					msgid "HTTP"
 | 
				
			||||||
msgstr "HTTP"
 | 
					msgstr "HTTP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: vdr-iptv 1.0.0\n"
 | 
					"Project-Id-Version: vdr-iptv 1.2.0\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: <see README>\n"
 | 
					"Report-Msgid-Bugs-To: <see README>\n"
 | 
				
			||||||
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
					"POT-Creation-Date: 2012-06-03 06:03+0300\n"
 | 
				
			||||||
"PO-Revision-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"
 | 
					msgid "UDP"
 | 
				
			||||||
msgstr "UDP"
 | 
					msgstr "UDP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "CURL"
 | 
				
			||||||
 | 
					msgstr "CURL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "HTTP"
 | 
					msgid "HTTP"
 | 
				
			||||||
msgstr "HTTP"
 | 
					msgstr "HTTP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										512
									
								
								protocolcurl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										512
									
								
								protocolcurl.c
									
									
									
									
									
										Normal file
									
								
							@@ -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<cIptvProtocolCurl *>(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<cIptvProtocolCurl *>(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<cIptvProtocolCurl *>(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<cIptvProtocolCurl *>(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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										72
									
								
								protocolcurl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								protocolcurl.h
									
									
									
									
									
										Normal file
									
								
							@@ -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 <curl/curl.h>
 | 
				
			||||||
 | 
					#include <curl/easy.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vdr/ringbuffer.h>
 | 
				
			||||||
 | 
					#include <vdr/thread.h>
 | 
				
			||||||
 | 
					#include <vdr/tools.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								setup.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.c
									
									
									
									
									
								
							@@ -36,6 +36,7 @@ public:
 | 
				
			|||||||
cIptvMenuInfo::cIptvMenuInfo()
 | 
					cIptvMenuInfo::cIptvMenuInfo()
 | 
				
			||||||
:cOsdMenu(tr("IPTV Information")), text(""), timeout(), page(IPTV_DEVICE_INFO_GENERAL)
 | 
					:cOsdMenu(tr("IPTV Information")), text(""), timeout(), page(IPTV_DEVICE_INFO_GENERAL)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  SetMenuCategory(mcText);
 | 
				
			||||||
  timeout.Set(INFO_TIMEOUT_MS);
 | 
					  timeout.Set(INFO_TIMEOUT_MS);
 | 
				
			||||||
  UpdateInfo();
 | 
					  UpdateInfo();
 | 
				
			||||||
  SetHelp(tr("General"), tr("Pids"), tr("Filters"), tr("Bits/bytes"));
 | 
					  SetHelp(tr("General"), tr("Pids"), tr("Filters"), tr("Bits/bytes"));
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								setup.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.h
									
									
									
									
									
								
							@@ -19,7 +19,7 @@ private:
 | 
				
			|||||||
  int sidscan;
 | 
					  int sidscan;
 | 
				
			||||||
  int pidscan;
 | 
					  int pidscan;
 | 
				
			||||||
  int protocol;
 | 
					  int protocol;
 | 
				
			||||||
  char address[MaxFileName];
 | 
					  char address[NAME_MAX];
 | 
				
			||||||
  int parameter;
 | 
					  int parameter;
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  cIptvTransponderParameters(const char *Parameters = NULL);
 | 
					  cIptvTransponderParameters(const char *Parameters = NULL);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								socket.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								socket.c
									
									
									
									
									
								
							@@ -265,7 +265,8 @@ int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
 | 
				
			|||||||
                 if (BufferAddr[0] == TS_SYNC_BYTE)
 | 
					                 if (BufferAddr[0] == TS_SYNC_BYTE)
 | 
				
			||||||
                    return len;
 | 
					                    return len;
 | 
				
			||||||
                 else if (len > 3) {
 | 
					                 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
 | 
					                    // version
 | 
				
			||||||
                    unsigned int v = (BufferAddr[0] >> 6) & 0x03;
 | 
					                    unsigned int v = (BufferAddr[0] >> 6) & 0x03;
 | 
				
			||||||
                    // extension bit
 | 
					                    // extension bit
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								socket.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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.
 | 
					 * See the README file for copyright information and how to reach the author.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								source.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								source.c
									
									
									
									
									
								
							@@ -32,6 +32,9 @@ cString cIptvTransponderParameters::ToString(char Type) const
 | 
				
			|||||||
    case eProtocolEXT:
 | 
					    case eProtocolEXT:
 | 
				
			||||||
         protocolstr = "EXT";
 | 
					         protocolstr = "EXT";
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
 | 
					    case eProtocolCURL:
 | 
				
			||||||
 | 
					         protocolstr = "CURL";
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
    case eProtocolHTTP:
 | 
					    case eProtocolHTTP:
 | 
				
			||||||
         protocolstr = "HTTP";
 | 
					         protocolstr = "HTTP";
 | 
				
			||||||
         break;
 | 
					         break;
 | 
				
			||||||
@@ -81,6 +84,10 @@ bool cIptvTransponderParameters::Parse(const char *s)
 | 
				
			|||||||
                    protocol = eProtocolUDP;
 | 
					                    protocol = eProtocolUDP;
 | 
				
			||||||
                    found_f = true;
 | 
					                    found_f = true;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                 else if (strstr(data, "CURL")) {
 | 
				
			||||||
 | 
					                    protocol = eProtocolCURL;
 | 
				
			||||||
 | 
					                    found_f = true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                 else if (strstr(data, "HTTP")) {
 | 
					                 else if (strstr(data, "HTTP")) {
 | 
				
			||||||
                    protocol = eProtocolHTTP;
 | 
					                    protocol = eProtocolHTTP;
 | 
				
			||||||
                    found_f = true;
 | 
					                    found_f = true;
 | 
				
			||||||
@@ -134,6 +141,7 @@ cIptvSourceParam::cIptvSourceParam(char Source, const char *Description)
 | 
				
			|||||||
  debug("cIptvSourceParam::cIptvSourceParam(): Source=%c Description=%s\n", Source, Description);
 | 
					  debug("cIptvSourceParam::cIptvSourceParam(): Source=%c Description=%s\n", Source, Description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  protocols[cIptvTransponderParameters::eProtocolUDP]  = tr("UDP");
 | 
					  protocols[cIptvTransponderParameters::eProtocolUDP]  = tr("UDP");
 | 
				
			||||||
 | 
					  protocols[cIptvTransponderParameters::eProtocolCURL] = tr("CURL");
 | 
				
			||||||
  protocols[cIptvTransponderParameters::eProtocolHTTP] = tr("HTTP");
 | 
					  protocols[cIptvTransponderParameters::eProtocolHTTP] = tr("HTTP");
 | 
				
			||||||
  protocols[cIptvTransponderParameters::eProtocolFILE] = tr("FILE");
 | 
					  protocols[cIptvTransponderParameters::eProtocolFILE] = tr("FILE");
 | 
				
			||||||
  protocols[cIptvTransponderParameters::eProtocolEXT]  = tr("EXT");
 | 
					  protocols[cIptvTransponderParameters::eProtocolEXT]  = tr("EXT");
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								source.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								source.h
									
									
									
									
									
								
							@@ -20,12 +20,13 @@ private:
 | 
				
			|||||||
  int sidscan;
 | 
					  int sidscan;
 | 
				
			||||||
  int pidscan;
 | 
					  int pidscan;
 | 
				
			||||||
  int protocol;
 | 
					  int protocol;
 | 
				
			||||||
  char address[MaxFileName];
 | 
					  char address[NAME_MAX];
 | 
				
			||||||
  int parameter;
 | 
					  int parameter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  enum {
 | 
					  enum {
 | 
				
			||||||
    eProtocolUDP,
 | 
					    eProtocolUDP,
 | 
				
			||||||
 | 
					    eProtocolCURL,
 | 
				
			||||||
    eProtocolHTTP,
 | 
					    eProtocolHTTP,
 | 
				
			||||||
    eProtocolFILE,
 | 
					    eProtocolFILE,
 | 
				
			||||||
    eProtocolEXT,
 | 
					    eProtocolEXT,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								statistics.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								statistics.c
									
									
									
									
									
								
							@@ -36,10 +36,10 @@ cString cIptvSectionStatistics::GetSectionStatistic()
 | 
				
			|||||||
  if (!IptvConfig.GetUseBytes())
 | 
					  if (!IptvConfig.GetUseBytes())
 | 
				
			||||||
     bitrate *= 8;
 | 
					     bitrate *= 8;
 | 
				
			||||||
  // no trailing linefeed here!
 | 
					  // no trailing linefeed here!
 | 
				
			||||||
  cString info = cString::sprintf("%4ld (%4ld k%s/s)", numberOfCalls, bitrate,
 | 
					  cString s = cString::sprintf("%4ld (%4ld k%s/s)", numberOfCalls, bitrate,
 | 
				
			||||||
                                  IptvConfig.GetUseBytes() ? "B" : "bit");
 | 
					                               IptvConfig.GetUseBytes() ? "B" : "bit");
 | 
				
			||||||
  filteredData = numberOfCalls = 0;
 | 
					  filteredData = numberOfCalls = 0;
 | 
				
			||||||
  return info;
 | 
					  return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cIptvSectionStatistics::AddSectionStatistic(long Bytes, long Calls)
 | 
					void cIptvSectionStatistics::AddSectionStatistic(long Bytes, long Calls)
 | 
				
			||||||
@@ -72,26 +72,26 @@ cString cIptvPidStatistics::GetPidStatistic()
 | 
				
			|||||||
  cMutexLock MutexLock(&mutex);
 | 
					  cMutexLock MutexLock(&mutex);
 | 
				
			||||||
  uint64_t elapsed = timer.Elapsed(); /* in milliseconds */
 | 
					  uint64_t elapsed = timer.Elapsed(); /* in milliseconds */
 | 
				
			||||||
  timer.Set();
 | 
					  timer.Set();
 | 
				
			||||||
  cString info("Active pids:\n");
 | 
					  cString s("Active pids:\n");
 | 
				
			||||||
  for (unsigned int i = 0; i < IPTV_STATS_ACTIVE_PIDS_COUNT; ++i) {
 | 
					  for (unsigned int i = 0; i < IPTV_STATS_ACTIVE_PIDS_COUNT; ++i) {
 | 
				
			||||||
      if (mostActivePids[i].pid) {
 | 
					      if (mostActivePids[i].pid) {
 | 
				
			||||||
         long bitrate = elapsed ? (long)(1000.0L * mostActivePids[i].DataAmount / KILOBYTE(1) / elapsed) : 0L;
 | 
					         long bitrate = elapsed ? (long)(1000.0L * mostActivePids[i].DataAmount / KILOBYTE(1) / elapsed) : 0L;
 | 
				
			||||||
         if (!IptvConfig.GetUseBytes())
 | 
					         if (!IptvConfig.GetUseBytes())
 | 
				
			||||||
            bitrate *= 8;
 | 
					            bitrate *= 8;
 | 
				
			||||||
         info = cString::sprintf("%sPid %d: %4d (%4ld k%s/s)\n", *info, i,
 | 
					         s = cString::sprintf("%sPid %d: %4d (%4ld k%s/s)\n", *s, i,
 | 
				
			||||||
                                 mostActivePids[i].pid, bitrate,
 | 
					                              mostActivePids[i].pid, bitrate,
 | 
				
			||||||
                                 IptvConfig.GetUseBytes() ? "B" : "bit");
 | 
					                              IptvConfig.GetUseBytes() ? "B" : "bit");
 | 
				
			||||||
         }
 | 
					         }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
  memset(mostActivePids, '\0', sizeof(mostActivePids));
 | 
					  memset(mostActivePids, '\0', sizeof(mostActivePids));
 | 
				
			||||||
  return info;
 | 
					  return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int cIptvPidStatistics::SortPids(const void* data1, const void* data2)
 | 
					int cIptvPidStatistics::SortPids(const void* data1, const void* data2)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  //debug("cIptvPidStatistics::SortPids()\n");
 | 
					  //debug("cIptvPidStatistics::SortPids()\n");
 | 
				
			||||||
  pidStruct *comp1 = (pidStruct*)data1;
 | 
					  const pidStruct *comp1 = reinterpret_cast<const pidStruct*>(data1);
 | 
				
			||||||
  pidStruct *comp2 = (pidStruct*)data2;
 | 
					  const pidStruct *comp2 = reinterpret_cast<const pidStruct*>(data2);
 | 
				
			||||||
  if (comp1->DataAmount > comp2->DataAmount)
 | 
					  if (comp1->DataAmount > comp2->DataAmount)
 | 
				
			||||||
     return -1;
 | 
					     return -1;
 | 
				
			||||||
  if (comp1->DataAmount < comp2->DataAmount)
 | 
					  if (comp1->DataAmount < comp2->DataAmount)
 | 
				
			||||||
@@ -148,9 +148,9 @@ cString cIptvStreamerStatistics::GetStreamerStatistic()
 | 
				
			|||||||
  long bitrate = elapsed ? (long)(1000.0L * dataBytes / KILOBYTE(1) / elapsed) : 0L;
 | 
					  long bitrate = elapsed ? (long)(1000.0L * dataBytes / KILOBYTE(1) / elapsed) : 0L;
 | 
				
			||||||
  if (!IptvConfig.GetUseBytes())
 | 
					  if (!IptvConfig.GetUseBytes())
 | 
				
			||||||
     bitrate *= 8;
 | 
					     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;
 | 
					  dataBytes = 0;
 | 
				
			||||||
  return info;
 | 
					  return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cIptvStreamerStatistics::AddStreamerStatistic(long Bytes)
 | 
					void cIptvStreamerStatistics::AddStreamerStatistic(long Bytes)
 | 
				
			||||||
@@ -193,12 +193,12 @@ cString cIptvBufferStatistics::GetBufferStatistic()
 | 
				
			|||||||
     totalKilos *= 8;
 | 
					     totalKilos *= 8;
 | 
				
			||||||
     usedKilos *= 8;
 | 
					     usedKilos *= 8;
 | 
				
			||||||
     }
 | 
					     }
 | 
				
			||||||
  cString info = cString::sprintf("Buffer bitrate: %ld k%s/s\nBuffer usage: %ld/%ld k%s (%2.1f%%)\n", bitrate,
 | 
					  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", usedKilos, totalKilos,
 | 
				
			||||||
                                  IptvConfig.GetUseBytes() ? "B" : "bit", percentage);
 | 
					                               IptvConfig.GetUseBytes() ? "B" : "bit", percentage);
 | 
				
			||||||
  dataBytes = 0;
 | 
					  dataBytes = 0;
 | 
				
			||||||
  usedSpace = 0;
 | 
					  usedSpace = 0;
 | 
				
			||||||
  return info;
 | 
					  return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cIptvBufferStatistics::AddBufferStatistic(long Bytes, long Used)
 | 
					void cIptvBufferStatistics::AddBufferStatistic(long Bytes, long Used)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ void cIptvStreamer::Action(void)
 | 
				
			|||||||
  while (packetBuffer && Running()) {
 | 
					  while (packetBuffer && Running()) {
 | 
				
			||||||
        int length = -1;
 | 
					        int length = -1;
 | 
				
			||||||
        if (protocol)
 | 
					        if (protocol)
 | 
				
			||||||
           length = protocol->Read(packetBuffer, packetBufferLen);
 | 
					           length = protocol->Read(packetBuffer, min((unsigned int)ringBuffer->Free(), packetBufferLen));
 | 
				
			||||||
        if (length > 0) {
 | 
					        if (length > 0) {
 | 
				
			||||||
           AddStreamerStatistic(length);
 | 
					           AddStreamerStatistic(length);
 | 
				
			||||||
           if (ringBuffer) {
 | 
					           if (ringBuffer) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user