diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 647fee9..7f3dddc 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -12,14 +12,14 @@ The Metzler Brothers as a lot of code has been taken from their libdvbmpeg package Angelus (DOm) - for providing italian language texts + for providing Italian language texts for reporting problems with the Elchi-Patch Michal for sending a patch to select the HTTP streamtype via remote Rolf Ahrenberg - for providing finnish language texts + for providing Finnish language texts for adding externremux.sh commandline parameter for silencing compiler warnings for adding PAT, PMT, PCR and EIT to HTTP TS streams @@ -35,6 +35,9 @@ Rolf Ahrenberg for improving externremux script termination for fixing PAT repacker version field for improving LIMIKUUTIO and PARENTALRATING patch detection + for suggesting to include the charset in HTTP replies + for requesting replacement of asprintf calls + for suggesting to change the URL path from EXTERN to EXT Rantanen Teemu for providing vdr-incompletesections.diff @@ -54,6 +57,7 @@ Udo Richter for speeding up cPluginStreamdevServer::Active() for adapting to VDR 1.5.0 API for adapting to VDR 1.7.1 + for proper tsplay-0.2 patch detection greenman for reporting that the log could get flooded on connection failures. @@ -88,10 +92,10 @@ tobi for pointing to unused files in the libdvbmpeg directory Diego Pierotto - for providing italian language texts + for providing Italian language texts micky979 - for providing french language texts + for providing French language texts Tiroler for reporting a problem when switching between encrypted channels @@ -100,10 +104,12 @@ Pixelpeter for an initial fix to the "switching between ecncrypted channels" problem Anssi Hannula - for the vdr-1.6.0-ignore_missing_cam.diff patch + for the vdr-1.6.0-intcamdevices patch + for fixing insecure format strings in LSTX handlers wirbel for pointing out that section filtering is optional for VDR devices + for reporting a problem with Makefile defines in VDR 1.7.4+ Jori Hamalainen for extensive testing while making stream compatible to Network Media Tank @@ -111,6 +117,7 @@ Jori Hamalainen owagner for pointing out a problem with the encrypted channel switching fix + for suggesting use of SO_KEEPALIVE socket option to detect dead sockets Joachim Knig-Baltes for fixing Min/MaxPriority parsing @@ -120,3 +127,23 @@ Artem Makhutov Alwin Esch for adding XBMC support by extending VTP capabilities + for adding VDR 1.7.11 parental rating support for VTP LSTE command + for adding the DELT FORCE option to delete running timers + +BBlack + for reporting that updating recordings list on CmdPLAY is a bad idea + +Milan Hrala + for providing Slovak language texts + +Valdemaras Pipiras + for providing Lithuanian language texts + +sk8ter + for fixing failures when switching between two encrypted channels + +lhanisch + for fixing a memory leak in cStreamdevPatFilter::GetPid + +Eric Valette + for adding support for EnhancedAC3 diff --git a/HISTORY b/HISTORY index 7752f8d..5bfe74e 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,51 @@ VDR Plugin 'streamdev' Revision History --------------------------------------- +- config option "client may suspend" hidden if not applicable +- updated and enhanced README +- separated language resources of client and server +- restructured build process +- added support for HTTP method HEAD +- rewrite of externremux.sh, including support for various URL parameters, + logging and improved shutdown +- start externremux script in a separate process group +- changed HTTP URL path for externremux from EXTERN to EXT (suggested by + Rolf Ahrenberg) +- HTTP headers now have to be emitted by externremux script +- pass channel related information and URL parameters to externremux script + through environment +- implement CGI like interface for externremux script +- dropped "Synchronize EPG" feature. Please use epgsync-plugin instead + (available from http://vdr.schmirler.de) +- proper tsplay-0.2 patch detection. tsplay-0.1 is no longer recognized + (thanks to Udo Richter) +- added compatibility with VDR 1.6 tsplay-0.1 patch +- added support for EnhancedAC3 (thanks to Eric Valette) +- fixed a memory leak in cStreamdevPatFilter::GetPid (thanks to lhanisch) +- length -1 is the correct value for streams in M3U playlists +- switching between two encrypted channels on the same transponder didn't + always work (thanks to sk8ter@vdrportal) +- added DELT FORCE option to delete running timers (thanks to Alwin Esch) +- added VDR 1.7.11 parental rating support for VTP LSTE command (thanks to + Alwin Esch) +- added Lithuanian translation (thanks to Valdemaras Pipiras) +- fixed missing virtual destructor for cTSRemux +- added defines for large file support to Makefile as required by VDR 1.7.4+ + (reported by wirbel@vdrportal) +- added Slovak translation (thanks to Milan Hrala) +- fixed regression from fix for switching between encrypted channels. It was + no longer possible to receive multiple (FTA) streams from the same + transponder +- silenced warnings concerning asprintf (requested by Rolf Ahrenberg) +- don't update recordings list on CmdPLAY (reported by BBlack) +- cleaned up common.h / common.c +- dropped cStreamdevMenuSetupPage +- report charset in HTTP replies (suggested by Rolf Ahrenberg) +- use SO_KEEPALIVE option on all sockets do detect dead sockets (thanks to + owagner) +- enable PatFilter for externremux, so VLC can be used as remuxer or client +- fixed insecure format strings in LSTX handlers (thanks to Anssi Hannula) +- updated Finish translation (thanks to Rolf Ahrenberg) - removed redefinitions in includes - caused problems in older compilers - fixed ts2ps.h defines - fixed missing virtual for cTS2PESRemux destructor diff --git a/Makefile b/Makefile index 2b6e959..25410b4 100644 --- a/Makefile +++ b/Makefile @@ -1,36 +1,57 @@ # # Makefile for a Video Disk Recorder plugin # -# $Id: Makefile,v 1.19 2009/07/01 10:46:15 schmirl Exp $ +# $Id: Makefile,v 1.21.2.1 2010/06/14 10:40:11 schmirl Exp $ -# The official name of this plugin. -# This name will be used in the '-P...' option of VDR to load the plugin. -# By default the main source file also carries this name. +# The main source file name. # PLUGIN = streamdev +### The C/C++ compiler and options: + +CC ?= gcc +CFLAGS ?= -g -O2 -Wall + +CXX ?= g++ +CXXFLAGS ?= -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses + ### The version number of this plugin (taken from the main source file): VERSION = $(shell grep 'const char \*VERSION *=' common.c | awk '{ print $$5 }' | sed -e 's/[";]//g') -### The C++ compiler and options: - -CXX ?= g++ -CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses - ### The directory environment: VDRDIR = ../../.. LIBDIR = ../../lib TMPDIR = /tmp -### Allow user defined options to overwrite defaults: - --include $(VDRDIR)/Make.config - ### The version number of VDR (taken from VDR's "config.h"): APIVERSION = $(shell grep 'define APIVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') +APIVERSNUM = $(shell grep 'define APIVERSNUM ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') +TSPLAYVERSNUM = $(shell grep 'define TSPLAY_PATCH_VERSION ' $(VDRDIR)/device.h | awk '{ print $$3 }') + +### Allow user defined options to overwrite defaults: + +ifeq ($(shell test $(APIVERSNUM) -ge 10713; echo $$?),0) +include $(VDRDIR)/Make.global +else ifeq ($(shell test $(APIVERSNUM) -ge 10704 -o -n "$(TSPLAYVERSNUM)" ; echo $$?),0) +DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE +CFLAGS += -fPIC +CXXFLAGS += -fPIC +else +CFLAGS += -fPIC +CXXFLAGS += -fPIC +endif + +-include $(VDRDIR)/Make.config + +### export all vars for sub-makes, using absolute paths + +VDRDIR := $(abspath $(VDRDIR)) +LIBDIR := $(abspath $(LIBDIR)) +export +unexport PLUGIN ### The name of the distribution archive: @@ -39,98 +60,33 @@ PACKAGE = vdr-$(ARCHIVE) ### Includes and Defines (add further entries here): -INCLUDES += -I$(VDRDIR)/include -I. +INCLUDES += -I$(VDRDIR)/include -I.. -DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -D_GNU_SOURCE -### The object files (add further files here): - -COMMONOBJS = common.o \ - \ - tools/source.o tools/select.o tools/socket.o tools/tools.o - -CLIENTOBJS = $(PLUGIN)-client.o \ - \ - client/socket.o client/device.o client/setup.o \ - client/filter.o - - -SERVEROBJS = $(PLUGIN)-server.o \ - \ - server/server.o server/component.o server/connection.o \ - server/componentVTP.o server/componentHTTP.o server/componentIGMP.o \ - server/connectionVTP.o server/connectionHTTP.o server/connectionIGMP.o \ - server/streamer.o server/livestreamer.o server/livefilter.o \ - server/suspend.o server/setup.o server/menuHTTP.o server/recplayer.o \ - remux/tsremux.o remux/ts2pes.o remux/ts2ps.o remux/ts2es.o remux/extern.o - ifdef DEBUG - DEFINES += -DDEBUG +DEFINES += -DDEBUG +endif +ifdef STREAMDEV_DEBUG +DEFINES += -DDEBUG endif ### The main target: -.PHONY: all i18n dist clean -all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so i18n - -### Implicit rules: - -%.o: %.c - $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< - -# Dependencies: - -MAKEDEP = $(CXX) -MM -MG -DEPFILE = .dependencies -ifdef GCC3 -$(DEPFILE): Makefile - @rm -f $@ - @for i in $(CLIENTOBJS:%.o=%.c) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) ; do \ - $(MAKEDEP) $(DEFINES) $(INCLUDES) -MT "`dirname $$i`/`basename $$i .c`.o" $$i >>$@ ; \ - done -else -$(DEPFILE): Makefile - @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(CLIENTOBJS:%.o=%.c) $(SERVEROBJS:%.o=%.c) \ - $(COMMONOBJS:%.o=%.c) > $@ -endif - --include $(DEPFILE) - -### Internationalization (I18N): - -PODIR = po -LOCALEDIR = $(VDRDIR)/locale -I18Npo = $(wildcard $(PODIR)/*.po) -I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) -I18Npot = $(PODIR)/$(PLUGIN).pot - -%.mo: %.po - msgfmt -c -o $@ $< - -$(I18Npot): $(CLIENTOBJS:%.o=%.c) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) - xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='' -o $@ $^ - -%.po: $(I18Npot) - msgmerge -U --no-wrap --no-location --backup=none -q $@ $< - @touch $@ - -$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo - @mkdir -p $(dir $@) - cp $< $@ - -i18n: $(I18Nmsgs) +.PHONY: all client server dist clean +all: client server ### Targets: -libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.h - $(MAKE) -C ./libdvbmpeg libdvbmpegtools.a +client: + $(MAKE) -C ./tools + $(MAKE) -C ./client -libvdr-$(PLUGIN)-client.so: $(CLIENTOBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a -libvdr-$(PLUGIN)-server.so: $(SERVEROBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a - -%.so: - $(CXX) $(CXXFLAGS) -shared $^ -o $@ - @cp $@ $(LIBDIR)/$@.$(APIVERSION) +server: + $(MAKE) -C ./tools + $(MAKE) -C ./libdvbmpeg + $(MAKE) -C ./remux + $(MAKE) -C ./server dist: clean @-rm -rf $(TMPDIR)/$(ARCHIVE) @@ -141,5 +97,8 @@ dist: clean @echo Distribution package created as $(PACKAGE).tgz clean: - @-rm -f $(COMMONOBJS) $(CLIENTOBJS) $(SERVEROBJS) $(DEPFILE) $(PODIR)/*.mo $(PODIR)/*.pot *.so *.tgz core* *~ + $(MAKE) -C ./tools clean $(MAKE) -C ./libdvbmpeg clean + $(MAKE) -C ./remux clean + $(MAKE) -C ./client clean + $(MAKE) -C ./server clean diff --git a/README b/README index cd03c58..e1597f5 100644 --- a/README +++ b/README @@ -15,9 +15,9 @@ Contents: 1. Description 2. Installation -2.1 VDR 1.4.x and older -2.2 VDR 1.6.0 and above -2.3 Updating from streamdev 0.3.x +2.1 Compatibility +2.2 Compiling +2.3 Updating 3. Usage 3.1 Usage HTTP server 3.2 Usage IGMP multicast server @@ -27,7 +27,8 @@ Contents: 4.1 Plugins for VDR-to-VDR clients 4.2 Plugins for Server 4.3 Alternatives -5. Known Problems +5. externremux.sh +6. Known Problems 1. Description: @@ -62,7 +63,7 @@ the PROTOCOL file. 2. Installation: ---------------- -Let's say streamdev's version is 0.4.0 and vdr's version is 1.X.X. If you +Let's say streamdev's version is 0.5.0 and vdr's version is 1.X.X. If you use anything else please exchange the version numbers appropriately (this way I don't have to update this section all the times;) ). @@ -79,54 +80,71 @@ If you want to drive additional Input-Devices (with different sources) on the client, you can merge the channels.conf files. VDR will detect if the local device or the network device can receive the channels. -Last, but not least you have to copy the streamdev folder into the -"plugins/streamdev" subfolder of VDR's config-directory (which is equal to your -video-directory if not specified otherwise). For example, if you didn't specify -a separate config-directory, and specified your video directory as "/video0", -the directory has to be copied to /video0/plugins/streamdev. +Last, but not least you have to copy the streamdev-server folder into the +"plugins/streamdev-server" subfolder of VDR's config-directory (which is equal +to your video-directory if not specified otherwise). For example, if you didn't +specify a separate config-directory, and set your video directory to "/video0", +the directory has to be copied to /video0/plugins/streamdev-server. The directory contains a file named streamdevhosts.conf which you must adjust to your needs. The syntax is the same as for svdrphosts.conf, so please consult VDR's documentation on how to fill that file, if you can't do it on-the-fly. There's also a sample externremux.sh script in this directory. It is used by -streamdev's external remux feature. The sample script uses mencoder. Please -check the script for further information. You can specify a different script -location with the -r parameter. The VDR commandline would then include a +streamdev's external remux feature. The sample script uses mencoder by default. +Please check the script for further information. You can specify a different +script location with the -r parameter. The VDR commandline would then include a "-P 'streamdev-server -r /usr/local/bin/remux.sh'". Note the additional quotes, as otherwise -r will be passed to VDR and not to streamdev. -2.1 VDR 1.4.x and older: ------------------------- +2.1 Compatibility: +------------------ This version is not compatible to VDR releases older than 1.5.9. Take one of the streamdev-0.4.x releases if you are running at least VDR 1.4.x. For older VDRs you will probably need one of the streamdev-0.3.x releases. -2.2 VDR 1.6.0 and above: ------------------------- +2.2 Compiling: +-------------- -cd vdr-1.X.X/PLUGINS/src -tar xvfz vdr-streamdev-0.4.0.tgz -ln -s streamdev-0.4.0 streamdev -cp -r streamdev/streamdev VDRCONFDIR/plugins/ -cd ../.. -make [options, if necessary] vdr -make [options, if necessary] plugins + cd vdr-1.X.X/PLUGINS/src + tar xvfz vdr-streamdev-0.5.0.tgz + ln -s streamdev-0.5.0 streamdev + cp -r streamdev/streamdev-server VDRCONFDIR/plugins/ + cd ../.. + make [options, if necessary] vdr + make [options, if necessary] plugins -2.3 Updating from streamdev 0.3.x ----------------------------------- +To build only the plugin, change into the streamdev source folder and issue + make -Starting with streamdev 0.4.0, all additional files are kept in a directory -called "streamdev" inside VDR's plugin config directory. It is the new default -location of externremux.sh and the new place where streamdev-server expects the -file "streamdevhosts.conf". You will have to move this file to its new location: +To build only streamdev-server or only streamdev-client, use + make server + make client -mv VDRCONFDIR/plugins/streamdevhosts.conf VDRCONFDIR/plugins/streamdev/ +2.3 Updating: +-------------- -(Directory VDRCONFDIR/plugins/streamdev already exists, as you copied the -whole folder from the sources directory as suggested above, right?) +If you are updating streamdev from an earlier release, you might have to +perform some additional steps. Check which version you've been running before, +then read below for the necessary changes. + +* Location of files: +-------------------- +(Affected: 0.3.x, 0.4.x, 0.4.0pre, 0.5.0pre) + +Starting with streamdev 0.5.0, all additional files are kept in a directory +called "streamdev-server" inside VDR's plugin config directory. It is the new +default location of externremux.sh and the new place where streamdev-server +expects the file "streamdevhosts.conf". You will have to move this file to its +new location: + +streamdev 0.3.x: + mv VDRCONFDIR/plugins/streamdevhosts.conf VDRCONFDIR/plugins/streamdev-server/ + +streamdev 0.4.x, 0.4.0pre and 0.5.0pre: + mv VDRCONFDIR/plugins/streamdev VDRCONFDIR/plugins/streamdev-server/ Now check the contents of streamdevhosts.conf. Does it contain a "0.0.0.0/0" entry? If your VDR machine is connected to the Internet, this line gives @@ -134,6 +152,21 @@ entry? If your VDR machine is connected to the Internet, this line gives prevent this (e.g. firewall). You might want to remove this line and enable HTTP authentication instead. +* Handling of externremux script: +--------------------------------- +(Affected: 0.3.x, 0.4.0pre, 0.5.0pre) + +Streamdev server's externremux script became responsible for emitting all HTTP +headers. A quick and dirty extension to your current script would be: + + echo -ne 'Content-type: video/mpeg\r\n' + echo -ne '\r\n' + +However I encourage you to try the new externremux.sh script shipped with the +streamdev source distribution. + +To emphasize the required change in externremux, the URL path for passing the +stream through externremux has changed from EXTERN to EXT. 3. Usage: --------- @@ -172,15 +205,15 @@ listen to with the parameter "HTTP Server Port". The parameter "HTTP Streamtype" allows you to specify a default stream type, which is used if no specific type has been requested in the URL (see below). The supported stream types are: -TS Transport Stream (i.e. a dump from the device) -PES Packetized Elemetary Stream (VDR's native recording format) -PS Program Stream (SVCD, DVD like stream) -ES Elementary Stream (only Video, if available, otherwise only Audio) -EXTERN Pass stream through external script (e.g. for converting with mencoder) + TS Transport Stream (i.e. a dump from the device) + PES Packetized Elemetary Stream (VDR's native recording format) + PS Program Stream (SVCD, DVD like stream) + ES Elementary Stream (only Video, if available, otherwise only Audio) + EXT Pass stream through external script (e.g. for converting with mencoder) Assuming that you leave the default port (3000), point your web browser to -http://hostname:3000/ + http://hostname:3000/ You will be presented a menu with links to various channel lists, including M3U playlist formats. @@ -188,27 +221,28 @@ playlist formats. If you don't want to use the HTML menu or the M3U playlists, you can access the streams directly like this: -http://hostname:3000/3 -http://hostname:3000/S19.2E-0-12480-898 + http://hostname:3000/3 + http://hostname:3000/S19.2E-0-12480-898 The first one will deliver a channel by number on the server, the second one will request the channel by unique channel id. In addition, you can specify the desired stream type as a path to the channel. -http://hostname:3000/TS/3 -http://hostname:3000/PES/S19.2E-0-12480-898 + http://hostname:3000/TS/3 + http://hostname:3000/PES/S19.2E-0-12480-898 The first one would deliver the stream in TS, the second one in PES format. -Possible values are 'PES', 'TS', 'PS', 'ES' and 'EXTERN'. You need to specify +Possible values are 'PES', 'TS', 'PS', 'ES' and 'EXT'. You need to specify the ES format explicitly if you want to listen to radio channels. Play them back i.e. with mpg123. -mpg123 http://hostname:3000/ES/200 + mpg123 http://hostname:3000/ES/200 -With 'EXTERN' you can also add a parameter which is passed as argument to the -externremux script. - -http://hostname:3000/EXTERN;some_parameter/3 +With 'EXT' you can also add parameters which are passed as arguments to the +externremux script (e.g. http://hostname:3000/EXT;param1=value1;param2=value2/3) +Check your externremux.sh script for the parameters it understands. For details +on how to modify or write your own externremux.sh, please see the chapter upon +externremux.sh further down. If you want to access streamdev's HTTP server from the Internet, do *not* grant access for anyone by allowing any IP in "streamdevhosts.conf". Instead, pass the @@ -216,7 +250,7 @@ access for anyone by allowing any IP in "streamdevhosts.conf". Instead, pass the as argument. Clients with an IP not accepted by "streamdevhosts.conf" will then have to login. The VDR commandline will have to look like this: -vdr ... -P 'streamdev-server -a vdr:secret' ... + vdr ... -P 'streamdev-server -a vdr:secret' ... Note the single quotes, as otherwise "-a" will be passed to VDR and not to streamdev-server. The login ("vdr" in the example above) doesn't have to exist @@ -267,11 +301,11 @@ You might want to increase this up to "number_of_channels + 1". Note that it's "number_of_channels", not "maximum_channel_number". #First 100 channels: - bash# sysctl -w sys.net.ipv4.igmp_max_memberships=101 + bash# sysctl -w net.ipv4.igmp_max_memberships=101 #All channels: bash# COUNT=$(grep -c '^[^:]' PATH_TO_YOUR/channels.conf) - bash# sysctl -w sys.net.ipv4.igmp_max_memberships=$COUNT + bash# sysctl -w net.ipv4.igmp_max_memberships=$COUNT A multicast server never knows how many clients are actually receiving a stream. If a client signals that it leaves a multicast group, the server has to query @@ -337,15 +371,6 @@ With "Filter Streaming" enabled, the client will receive meta information like EPG data and service information, just as if the client had its own DVB card. Link channels and even a client-side EPG scan have been reported to work. -The next parameter, "Synchronize EPG", will have the client synchronize it's -program table with the server every now and then, but not regularly. This -happens when starting the client, and everytime VDR does its housekeeping -tasks. The only thing that's guaranteed is, that there will be a minimum -interval of ten seconds between each EPG synchronization. With "Filter -Streaming" this option has been obsoleted. If you still need to synchronize -EPG as additional information is available from the server, you should use the -epgsync-plugin instead (http://vdr.schmirler.de). - Finally with the maximum and minimum priority, you can keep VDR from considering streamdev in certain cases. If for instance you have a streamdev client with its own DVB card, VDR would normally use streamdev for recording. If this is not @@ -356,6 +381,21 @@ which streamdev will accept to tune. Setting the minimum priority to a higher value than the maximum, you will get two ranges: "up to maximum" and "minimum and above". +Note that streamdev-client acts similar to a DVB card. It is possible to receive +multiple channels simultaneously, but only from the same transponder. Just add +additional instances of streamdev-client and you will be able to receive as many +transponders at a time. The same trick allows a client to receive channels from +different servers. To create an additional instance, copy the streamdev-client +binary to a different name (e.g. streamdev-client2): + + cd VDRPLUGINLIBDIR + cp libvdr-streamdev-client.so.1.X.X libvdr-streamdev-client2.so.1.X.X + +Now add -Pstreamdev-client2 to the VDR commandline. In the VDR plugin setup +a second streamdev-client entry should show up. Both instances have to be +configured individually. + + 4. Other useful Plugins: ------------------------ @@ -398,7 +438,58 @@ With its networking option, xineliboutput provides an alternative to streamdev. You will get the picture of the server VDR, including its OSD. However you won't get independent clients, as they all share the same output. -5. Known Problems: +5. externremux.sh: +------------------ + +When selecting streamtype "EXT", the TS stream from VDR is passed through an +external program for further processing. By default a script installed at +VDRCONFDIR/plugins/streamdev/externremux.sh is expected, however you may +specify a different location as parameter -r to the streamdev-server plugin +(see chapter upon Installation above). + +The TS stream is passed to the script on stdin, the resulting stream is expected +on stdout. The following parameters are passed to the script in the environment: + +* Information on the channel: + REMUX_CHANNEL_ID VDR channel ID + REMUX_CHANNEL_NAME Channel name + REMUX_VTYPE Video type (2 for MPEG-2) + REMUX_VPID Video PID (undefined if audio only) + REMUX_PPID PCR PID (undefined if equal to VPID) + REMUX_TPID Teletext PID (undefined if not available) + REMUX_APID Space separated list of audio pids + REMUX_ALANG Space separated list of audio languages + REMUX_DPID Space separated list of dolby pids + REMUX_DLANG Space separated list of dolby languages + REMUX_SPID Space separated list of subtitle pids + REMUX_SLANG Space separated list of subtitle languages + REMUX_PARAM_* All (user supplied) parameters (e.g. REMUX_PARAM_x) + +* Information on the connection (CGI like) + REMOTE_ADDR Client IP + SERVER_NAME Local IP + SERVER_PORT Local port + SERVER_PROTOCOL Streamdev protocol (HTTP, VTP, IGMP) + SERVER_SOFTWARE Streamdev version + All HTTP headers converted to uppercase, '-' replaced by '_' (e.g. USER_AGENT) + +The script should perform the following steps (pseudocode): + + if (SERVER_PROTOCOL == HTTP) + write headers (including Content-Type) to STDOUT + write empty line to STDOUT + if (REQUEST_METHOD == HEAD) + exit + endif + endif + while (read STDIN) + remux to STDOUT + wend + + onSIGINT/SIGKILL: cleanup and exit + + +6. Known Problems: ------------------ * In VDR-to-VDR setup, the availability of a channel is checked with a different @@ -424,15 +515,9 @@ up. So please consider the logs for the correct value. Remember to fill in hexadecimal values if you are using an editor to modify your channels.conf (number 10 becomes an "a", number 11 a "b", ...). -2. Turn encrypted channels into Free-to-Air channels on the client. Again, -either enter the channels menu or edit the client's channels.conf. You will -also have to disable automatic channel updates on the client or (if streamdev -is the only DVB source) disable streamdev's filter streaming feature. Otherwise -VDR will revert the channel into an encrypted one. - -3. Apply either patch "patches/vdr-1.6.0-intcamdevices.patch" or patch +2. Apply either patch "patches/vdr-1.6.0-intcamdevices.patch" or patch "patches/vdr-1.6.0-ignore_missing_cam.diff" to your client VDR. Intcamdevices -is the clean solution. But as it modifies the VDR API, so you will need to +is the clean solution, but it modifies the VDR API. So you will need to recompile all of your plugins. The ignore_missing_cam patch is trivial, no need to recompile other plugins. However it is not suitable for clients with a DVB card of their own. diff --git a/client/Makefile b/client/Makefile new file mode 100644 index 0000000..8c3e565 --- /dev/null +++ b/client/Makefile @@ -0,0 +1,84 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.1.2.1 2010/06/14 10:40:11 schmirl Exp $ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = streamdev-client + +### Includes and Defines (add further entries here): + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +COMMONOBJS = ../common.o + +CLIENTOBJS = $(PLUGIN).o \ + device.o filter.o setup.o socket.o + +### The main target: + +.PHONY: all i18n dist clean +all: libvdr-$(PLUGIN).so i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies + +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(CLIENTOBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(CLIENTOBJS:%.o=%.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='' -o $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +i18n: $(I18Nmsgs) + +### Targets: + +libvdr-$(PLUGIN).so: $(CLIENTOBJS) $(COMMONOBJS) ../tools/sockettools.a + +%.so: + $(CXX) $(CXXFLAGS) -shared $^ -o $@ + @cp $@ $(LIBDIR)/$@.$(APIVERSION) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz --exclude CVS -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(COMMONOBJS) $(CLIENTOBJS) $(DEPFILE) $(PODIR)/*.mo $(PODIR)/*.pot *.so *.tgz core* *~ diff --git a/client/device.c b/client/device.c index 4b6c3c5..d53bde1 100644 --- a/client/device.c +++ b/client/device.c @@ -1,5 +1,5 @@ /* - * $Id: device.c,v 1.23 2009/04/06 06:48:59 schmirl Exp $ + * $Id: device.c,v 1.26 2010/06/08 05:55:17 schmirl Exp $ */ #include "client/device.h" @@ -33,9 +33,6 @@ cStreamdevDevice::cStreamdevDevice(void) { m_Device = this; m_Pids = 0; m_DvrClosed = true; - - if (StreamdevClientSetup.SyncEPG) - ClientSocket.SynchronizeEPG(); } cStreamdevDevice::~cStreamdevDevice() { @@ -72,7 +69,9 @@ bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel) { bool res = false; if (ClientSocket.DataSocket(siLive) != NULL - && TRANSPONDER(Channel, m_Channel)) + && TRANSPONDER(Channel, m_Channel) + && Channel->Ca() == CA_FTA + && m_Channel->Ca() == CA_FTA) res = true; return res; } @@ -123,12 +122,11 @@ bool cStreamdevDevice::SetChannelDevice(const cChannel *Channel, if (LiveView) return false; -#if 0 if (ClientSocket.DataSocket(siLive) != NULL && TRANSPONDER(Channel, m_Channel) - && Channel->Ca() < CA_ENCRYPTED_MIN) + && Channel->Ca() == CA_FTA + && m_Channel->Ca() == CA_FTA) return true; -#endif DetachAllReceivers(); m_Channel = Channel; diff --git a/client/po/de_DE.po b/client/po/de_DE.po new file mode 100644 index 0000000..1e481a2 --- /dev/null +++ b/client/po/de_DE.po @@ -0,0 +1,50 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Frank Schmirler , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:05+0200\n" +"PO-Revision-Date: 2008-03-30 02:11+0200\n" +"Last-Translator: Frank Schmirler \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP Streaming Client" + +msgid "Suspend Server" +msgstr "Server pausieren" + +msgid "Server is suspended" +msgstr "Server ist pausiert" + +msgid "Couldn't suspend Server!" +msgstr "Konnte Server nicht pausieren!" + +msgid "Hide Mainmenu Entry" +msgstr "Hauptmeneintrag verstecken" + +msgid "Start Client" +msgstr "Client starten" + +msgid "Remote IP" +msgstr "IP der Gegenseite" + +msgid "Remote Port" +msgstr "Port der Gegenseite" + +msgid "Filter Streaming" +msgstr "Filter-Daten streamen" + +msgid "Minimum Priority" +msgstr "Minimale Prioritt" + +msgid "Maximum Priority" +msgstr "Maximale Prioritt" + diff --git a/client/po/fi_FI.po b/client/po/fi_FI.po new file mode 100644 index 0000000..2091680 --- /dev/null +++ b/client/po/fi_FI.po @@ -0,0 +1,50 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Rolf Ahrenberg , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:05+0200\n" +"PO-Revision-Date: 2008-03-30 02:11+0200\n" +"Last-Translator: Rolf Ahrenberg \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP-suoratoistoasiakas" + +msgid "Suspend Server" +msgstr "Pysyt palvelin" + +msgid "Server is suspended" +msgstr "Palvelin on pysytetty" + +msgid "Couldn't suspend Server!" +msgstr "Palvelinta ei onnistuttu pysyttmn!" + +msgid "Hide Mainmenu Entry" +msgstr "Piilota valinta pvalikosta" + +msgid "Start Client" +msgstr "Kynnist VDR-asiakas" + +msgid "Remote IP" +msgstr "Etkoneen IP-osoite" + +msgid "Remote Port" +msgstr "Etkoneen portti" + +msgid "Filter Streaming" +msgstr "Suodatetun tiedon suoratoisto" + +msgid "Minimum Priority" +msgstr "Pienin prioriteetti" + +msgid "Maximum Priority" +msgstr "Suurin prioriteetti" + diff --git a/client/po/fr_FR.po b/client/po/fr_FR.po new file mode 100644 index 0000000..5c3e756 --- /dev/null +++ b/client/po/fr_FR.po @@ -0,0 +1,50 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Frank Schmirler , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:05+0200\n" +"PO-Revision-Date: 2008-03-30 02:11+0200\n" +"Last-Translator: micky979 \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "Client de streaming VTP" + +msgid "Suspend Server" +msgstr "Suspendre le serveur" + +msgid "Server is suspended" +msgstr "Le serveur est suspendu" + +msgid "Couldn't suspend Server!" +msgstr "Impossible de suspendre le serveur!" + +msgid "Hide Mainmenu Entry" +msgstr "Masquer dans le menu principal" + +msgid "Start Client" +msgstr "Dmarrage du client" + +msgid "Remote IP" +msgstr "Adresse IP du serveur" + +msgid "Remote Port" +msgstr "Port du serveur" + +msgid "Filter Streaming" +msgstr "Filtre streaming" + +msgid "Minimum Priority" +msgstr "" + +msgid "Maximum Priority" +msgstr "" + diff --git a/client/po/it_IT.po b/client/po/it_IT.po new file mode 100644 index 0000000..068be7c --- /dev/null +++ b/client/po/it_IT.po @@ -0,0 +1,52 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Alberto Carraro , 2001 +# Antonio Ospite , 2003 +# Sean Carlos , 2005 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:05+0200\n" +"PO-Revision-Date: 2008-04-13 23:42+0100\n" +"Last-Translator: Diego Pierotto \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "Client trasmissione VTP" + +msgid "Suspend Server" +msgstr "Sospendi Server" + +msgid "Server is suspended" +msgstr "Server sospeso" + +msgid "Couldn't suspend Server!" +msgstr "Impossibile sospendere il server!" + +msgid "Hide Mainmenu Entry" +msgstr "Nascondi voce menu principale" + +msgid "Start Client" +msgstr "Avvia Client" + +msgid "Remote IP" +msgstr "Indirizzo IP del Server" + +msgid "Remote Port" +msgstr "Porta Server Remoto" + +msgid "Filter Streaming" +msgstr "Filtra trasmissione" + +msgid "Minimum Priority" +msgstr "" + +msgid "Maximum Priority" +msgstr "" + diff --git a/client/po/lt_LT.po b/client/po/lt_LT.po new file mode 100644 index 0000000..f6a7d5c --- /dev/null +++ b/client/po/lt_LT.po @@ -0,0 +1,50 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Frank Schmirler , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:05+0200\n" +"PO-Revision-Date: 2009-11-26 21:57+0200\n" +"Last-Translator: Valdemaras Pipiras \n" +"Language-Team: Lietuvių\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP transliavimo standartas" + +msgid "Suspend Server" +msgstr "Sustabdyti serverį" + +msgid "Server is suspended" +msgstr "Serveris sustabdytas" + +msgid "Couldn't suspend Server!" +msgstr "Negali sustabdyti serverio!" + +msgid "Hide Mainmenu Entry" +msgstr "Paslėpti pagrindinio meniu įrašą" + +msgid "Start Client" +msgstr "Paleisti klientą" + +msgid "Remote IP" +msgstr "Nuotolinis IP adresas" + +msgid "Remote Port" +msgstr "Nuotolinis portas" + +msgid "Filter Streaming" +msgstr "Filtruoti transliavimą" + +msgid "Minimum Priority" +msgstr "Minimalus prioritetas" + +msgid "Maximum Priority" +msgstr "Maksimalus prioritetas" + diff --git a/client/po/ru_RU.po b/client/po/ru_RU.po new file mode 100644 index 0000000..c09d3f1 --- /dev/null +++ b/client/po/ru_RU.po @@ -0,0 +1,50 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Frank Schmirler , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:05+0200\n" +"PO-Revision-Date: 2008-06-26 15:36+0100\n" +"Last-Translator: Oleg Roitburd \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-5\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP Streaming " + +msgid "Suspend Server" +msgstr " " + +msgid "Server is suspended" +msgstr " " + +msgid "Couldn't suspend Server!" +msgstr " " + +msgid "Hide Mainmenu Entry" +msgstr " " + +msgid "Start Client" +msgstr " " + +msgid "Remote IP" +msgstr " IP" + +msgid "Remote Port" +msgstr " " + +msgid "Filter Streaming" +msgstr " " + +msgid "Minimum Priority" +msgstr "" + +msgid "Maximum Priority" +msgstr "" + diff --git a/client/po/sk_SK.po b/client/po/sk_SK.po new file mode 100644 index 0000000..e3dbf6b --- /dev/null +++ b/client/po/sk_SK.po @@ -0,0 +1,52 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2009 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Milan Hrala , 2009 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev_SK\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:05+0200\n" +"PO-Revision-Date: \n" +"Last-Translator: Milan Hrala \n" +"Language-Team: Slovak \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-2\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Slovak\n" +"X-Poedit-Country: SLOVAKIA\n" + +msgid "VTP Streaming Client" +msgstr "VTP prdov klient" + +msgid "Suspend Server" +msgstr "Server pozastaven" + +msgid "Server is suspended" +msgstr "Server je doasne preruen" + +msgid "Couldn't suspend Server!" +msgstr "Nepodarilo sa pozastavi Server!" + +msgid "Hide Mainmenu Entry" +msgstr "Schova poloku v hlavnom menu" + +msgid "Start Client" +msgstr "Spusti Klienta" + +msgid "Remote IP" +msgstr "Vzdialen IP" + +msgid "Remote Port" +msgstr "Vzdialen port" + +msgid "Filter Streaming" +msgstr "filtrova prdy" + +msgid "Minimum Priority" +msgstr "minimlna priorita" + +msgid "Maximum Priority" +msgstr "maximlna priorita" + diff --git a/client/setup.c b/client/setup.c index bf050b3..dd337c8 100644 --- a/client/setup.c +++ b/client/setup.c @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.8 2009/02/03 10:26:21 schmirl Exp $ + * $Id: setup.c,v 1.10 2010/06/08 05:55:17 schmirl Exp $ */ #include @@ -13,7 +13,6 @@ cStreamdevClientSetup::cStreamdevClientSetup(void) { StartClient = false; RemotePort = 2004; StreamFilters = false; - SyncEPG = false; HideMenuEntry = false; MinPriority = -1; MaxPriority = MAXPRIORITY; @@ -30,7 +29,6 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) { } else if (strcmp(Name, "RemotePort") == 0) RemotePort = atoi(Value); else if (strcmp(Name, "StreamFilters") == 0) StreamFilters = atoi(Value); - else if (strcmp(Name, "SyncEPG") == 0) SyncEPG = atoi(Value); else if (strcmp(Name, "HideMenuEntry") == 0) HideMenuEntry = atoi(Value); else if (strcmp(Name, "MinPriority") == 0) MinPriority = atoi(Value); else if (strcmp(Name, "MaxPriority") == 0) MaxPriority = atoi(Value); @@ -41,14 +39,13 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) { cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(void) { m_NewSetup = StreamdevClientSetup; - AddBoolEdit (tr("Hide Mainmenu Entry"),m_NewSetup.HideMenuEntry); - AddBoolEdit (tr("Start Client"), m_NewSetup.StartClient); - AddIpEdit (tr("Remote IP"), m_NewSetup.RemoteIp); - AddShortEdit(tr("Remote Port"), m_NewSetup.RemotePort); - AddBoolEdit (tr("Filter Streaming"), m_NewSetup.StreamFilters); - AddBoolEdit (tr("Synchronize EPG"), m_NewSetup.SyncEPG); - AddRangeEdit (tr("Minimum Priority"), m_NewSetup.MinPriority, -1, MAXPRIORITY); - AddRangeEdit (tr("Maximum Priority"), m_NewSetup.MaxPriority, -1, MAXPRIORITY); + Add(new cMenuEditBoolItem(tr("Hide Mainmenu Entry"), &m_NewSetup.HideMenuEntry)); + Add(new cMenuEditBoolItem(tr("Start Client"), &m_NewSetup.StartClient)); + Add(new cMenuEditIpItem (tr("Remote IP"), m_NewSetup.RemoteIp)); + Add(new cMenuEditIntItem (tr("Remote Port"), &m_NewSetup.RemotePort, 0, 65535)); + Add(new cMenuEditBoolItem(tr("Filter Streaming"), &m_NewSetup.StreamFilters)); + Add(new cMenuEditIntItem (tr("Minimum Priority"), &m_NewSetup.MinPriority, -1, MAXPRIORITY)); + Add(new cMenuEditIntItem (tr("Maximum Priority"), &m_NewSetup.MaxPriority, -1, MAXPRIORITY)); SetCurrent(Get(0)); } @@ -68,7 +65,6 @@ void cStreamdevClientMenuSetupPage::Store(void) { SetupStore("RemoteIp", m_NewSetup.RemoteIp); SetupStore("RemotePort", m_NewSetup.RemotePort); SetupStore("StreamFilters", m_NewSetup.StreamFilters); - SetupStore("SyncEPG", m_NewSetup.SyncEPG); SetupStore("HideMenuEntry", m_NewSetup.HideMenuEntry); SetupStore("MinPriority", m_NewSetup.MinPriority); SetupStore("MaxPriority", m_NewSetup.MaxPriority); diff --git a/client/setup.h b/client/setup.h index 9f4d11b..6049967 100644 --- a/client/setup.h +++ b/client/setup.h @@ -1,5 +1,5 @@ /* - * $Id: setup.h,v 1.5 2009/01/29 07:48:59 schmirl Exp $ + * $Id: setup.h,v 1.7 2010/06/08 05:55:17 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SETUPCLIENT_H @@ -16,7 +16,6 @@ struct cStreamdevClientSetup { char RemoteIp[20]; int RemotePort; int StreamFilters; - int SyncEPG; int HideMenuEntry; int MinPriority; int MaxPriority; @@ -24,7 +23,7 @@ struct cStreamdevClientSetup { extern cStreamdevClientSetup StreamdevClientSetup; -class cStreamdevClientMenuSetupPage: public cStreamdevMenuSetupPage { +class cStreamdevClientMenuSetupPage: public cMenuSetupPage { private: cStreamdevClientSetup m_NewSetup; diff --git a/client/socket.c b/client/socket.c index 02f501d..bd2f9ba 100644 --- a/client/socket.c +++ b/client/socket.c @@ -1,5 +1,5 @@ /* - * $Id: socket.c,v 1.12 2008/04/08 14:18:16 schmirl Exp $ + * $Id: socket.c,v 1.13 2010/06/08 05:55:17 schmirl Exp $ */ #include @@ -300,52 +300,6 @@ bool cClientSocket::CloseDvr(void) { return true; } -bool cClientSocket::SynchronizeEPG(void) { - std::string buffer; - bool result; - FILE *epgfd; - - if (!CheckConnection()) return false; - - isyslog("Streamdev: Synchronizing EPG from server\n"); - - CMD_LOCK; - - if (!Command("LSTE")) - return false; - - if ((epgfd = tmpfile()) == NULL) { - esyslog("ERROR: Streamdev: Error while processing EPG data: %s", - strerror(errno)); - return false; - } - - while ((result = Expect(215, &buffer))) { - if (buffer[3] == ' ') break; - fputs(buffer.c_str() + 4, epgfd); - fputc('\n', epgfd); - } - - if (!result) { - if (errno == 0) - esyslog("ERROR: Streamdev: Couldn't fetch EPG data from %s:%d", - RemoteIp().c_str(), RemotePort()); - fclose(epgfd); - return false; - } - - rewind(epgfd); - if (cSchedules::Read(epgfd)) - cSchedules::Cleanup(true); - else { - esyslog("ERROR: Streamdev: Parsing EPG data failed"); - fclose(epgfd); - return false; - } - fclose(epgfd); - return true; -} - bool cClientSocket::Quit(void) { bool res; diff --git a/client/socket.h b/client/socket.h index a0400e6..7ad9a80 100644 --- a/client/socket.h +++ b/client/socket.h @@ -1,5 +1,5 @@ /* - * $Id: socket.h,v 1.6 2008/04/07 14:40:40 schmirl Exp $ + * $Id: socket.h,v 1.7 2010/06/08 05:55:17 schmirl Exp $ */ #ifndef VDR_STREAMDEV_CLIENT_CONNECTION_H @@ -48,7 +48,6 @@ public: bool SetPid(int Pid, bool On); bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On); bool CloseDvr(void); - bool SynchronizeEPG(void); bool SuspendServer(void); bool Quit(void); diff --git a/streamdev-client.c b/client/streamdev-client.c similarity index 86% rename from streamdev-client.c rename to client/streamdev-client.c index bc9403c..79c3d74 100644 --- a/streamdev-client.c +++ b/client/streamdev-client.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: streamdev-client.c,v 1.6 2008/04/08 14:18:15 schmirl Exp $ + * $Id: streamdev-client.c,v 1.1.2.1 2010/06/14 10:40:11 schmirl Exp $ */ #include "streamdev-client.h" @@ -32,11 +32,6 @@ bool cPluginStreamdevClient::Start(void) { return true; } -void cPluginStreamdevClient::Housekeeping(void) { - if (StreamdevClientSetup.StartClient && StreamdevClientSetup.SyncEPG) - ClientSocket.SynchronizeEPG(); -} - const char *cPluginStreamdevClient::MainMenuEntry(void) { return StreamdevClientSetup.StartClient && !StreamdevClientSetup.HideMenuEntry ? tr("Suspend Server") : NULL; } diff --git a/streamdev-client.h b/client/streamdev-client.h similarity index 85% rename from streamdev-client.h rename to client/streamdev-client.h index b01e0d7..07befe3 100644 --- a/streamdev-client.h +++ b/client/streamdev-client.h @@ -1,5 +1,5 @@ /* - * $Id: streamdev-client.h,v 1.1.1.1 2004/12/30 22:43:59 lordjaxom Exp $ + * $Id: streamdev-client.h,v 1.1.2.1 2010/06/14 10:40:11 schmirl Exp $ */ #ifndef VDR_STREAMDEVCLIENT_H @@ -19,7 +19,6 @@ public: virtual const char *Version(void) { return VERSION; } virtual const char *Description(void); virtual bool Start(void); - virtual void Housekeeping(void); virtual const char *MainMenuEntry(void); virtual cOsdObject *MainMenuAction(void); virtual cMenuSetupPage *SetupMenu(void); diff --git a/common.c b/common.c index 021583a..47834fd 100644 --- a/common.c +++ b/common.c @@ -1,5 +1,5 @@ /* - * $Id: common.c,v 1.10 2009/06/19 06:32:38 schmirl Exp $ + * $Id: common.c,v 1.11.2.1 2010/06/08 07:47:45 schmirl Exp $ */ #include @@ -10,142 +10,9 @@ using namespace std; -const char *VERSION = "0.5.0-pre-20090706"; +const char *VERSION = "0.5.0-rc1"; -const char *StreamTypes[st_Count] = { - "TS", - "PES", - "PS", - "ES", - "Extern", - "", // used internally only -}; - -const char *SuspendModes[sm_Count] = { - trNOOP("Offer suspend mode"), - trNOOP("Always suspended"), - trNOOP("Never suspended") -}; - -const char IpCharacters[] = "0123456789."; - -char *GetNextLine(char *String, uint Length, uint &Offset) { - char *last, *first; - - first = String + Offset; - for (last = first; last < String + Length; ++last) { - if (*last == '\012') { - if (*(last - 1) == '\015') - *(last - 1) = '\0'; - - *last++ = '\0'; - Dprintf("IN: |%s|\n", first); - Offset = last - String; - return first; - } - } - return NULL; -} - -const cChannel *ChannelFromString(const char *String, int *Apid) { - const cChannel *channel = NULL; - char *string = strdup(String); - char *ptr, *end; - int apididx = 0; - - if ((ptr = strrchr(string, '+')) != NULL) { - *(ptr++) = '\0'; - apididx = strtoul(ptr, &end, 10); - Dprintf("found apididx: %d\n", apididx); - } - - if (isnumber(string)) { - int temp = strtol(String, NULL, 10); - if (temp >= 1 && temp <= Channels.MaxNumber()) - channel = Channels.GetByNumber(temp); - } else { - channel = Channels.GetByChannelID(tChannelID::FromString(string)); - - if (channel == NULL) { - int i = 1; - while ((channel = Channels.GetByNumber(i, 1)) != NULL) { - if (String == channel->Name()) - break; - - i = channel->Number() + 1; - } - } - } - - if (channel != NULL && apididx > 0) { - int apid = 0, index = 1; - - for (int i = 0; channel->Apid(i) != 0; ++i, ++index) { - if (index == apididx) { - apid = channel->Apid(i); - break; - } - } - - if (apid == 0) { - for (int i = 0; channel->Dpid(i) != 0; ++i, ++index) { - if (index == apididx) { - apid = channel->Dpid(i); - break; - } - } - } - - if (Apid != NULL) - *Apid = apid; - } - - free(string); - return channel; -} - -void cStreamdevMenuSetupPage::AddCategory(const char *Title) { - char *buffer = NULL; - - asprintf(&buffer, "--- %s -------------------------------------------------" - "---------------", Title ); - - cOsdItem *item = new cOsdItem(buffer); - free(buffer); - item->SetSelectable(false); - Add(item); -} - -void cStreamdevMenuSetupPage::AddBoolEdit(const char *Title, int &Value) { - Add(new cMenuEditBoolItem(Title, &Value)); -} - -void cStreamdevMenuSetupPage::AddIpEdit(const char *Title, char *Value) { - Add(new cMenuEditIpItem(Title, Value)); -} - -void cStreamdevMenuSetupPage::AddShortEdit(const char *Title, int &Value) { - AddRangeEdit(Title, Value, 0, 65535); -} - -void cStreamdevMenuSetupPage::AddRangeEdit(const char *Title, int &Value, - int Min, int Max) { - Add(new cMenuEditIntItem(Title, &Value, Min, Max)); -} - -void cStreamdevMenuSetupPage::AddSuspEdit(const char *Title, int &Value) { - static const char *SuspendModesTR[sm_Count] = { NULL }; - - if (SuspendModesTR[0] == NULL) { - for (int i = 0; i < sm_Count; ++i) - SuspendModesTR[i] = tr(SuspendModes[i]); - } - - Add(new cMenuEditStraItem(Title, &Value, sm_Count, SuspendModesTR)); -} -void cStreamdevMenuSetupPage::AddTypeEdit(const char *Title, int &Value) { - Add(new cMenuEditStraItem(Title, &Value, st_CountSetup, StreamTypes)); -} +const char cMenuEditIpItem::IpCharacters[] = "0123456789."; cMenuEditIpItem::cMenuEditIpItem(const char *Name, char *Value): cMenuEditItem(Name) { diff --git a/common.h b/common.h index f7b894a..a8830bd 100644 --- a/common.h +++ b/common.h @@ -1,5 +1,5 @@ /* - * $Id: common.h,v 1.14 2009/07/01 10:46:16 schmirl Exp $ + * $Id: common.h,v 1.15.2.1 2010/06/11 06:06:01 schmirl Exp $ */ #ifndef VDR_STREAMDEV_COMMON_H @@ -23,42 +23,23 @@ # define Dprintf(x...) #endif -# define TRANSPONDER(c1, c2) (c1->Transponder() == c2->Transponder()) +#define TRANSPONDER(c1, c2) (c1->Transponder() == c2->Transponder()) -# define MAXPARSEBUFFER KILOBYTE(16) +#define MAXPARSEBUFFER KILOBYTE(16) /* Check if a channel is a radio station. */ #define ISRADIO(x) ((x)->Vpid()==0||(x)->Vpid()==1||(x)->Vpid()==0x1fff) class cChannel; -char *GetNextLine(char *String, uint Length, uint &Offset); - -const cChannel *ChannelFromString(const char *String, int *Apid = NULL); - -/* Disable logging if BUFCOUNT buffer overflows occur within BUFOVERTIME - milliseconds. Enable logging again if there is no error within BUFOVERTIME - milliseconds. */ -#define BUFOVERTIME 5000 -#define BUFOVERCOUNT 100 - -#define POLLFAIL esyslog("Streamdev: Polling failed: %s", strerror(errno)) -#define WRITEFAIL esyslog("Streamdev: Writing failed: %s", strerror(errno)) -#define READFAIL esyslog("Streamdev: Reading failed: %s", strerror(errno)) -#define CHECKPOLL(x) if ((x)<0){POLLFAIL; return false;} -#define CHECKWRITE(x) if ((x)<0) { WRITEFAIL; return false; } -#define CHECKREAD(x) if ((x)<0) { READFAIL; return false; } - enum eStreamType { stTS, stPES, stPS, stES, - stExtern, + stEXT, stTSPIDS, - -#define st_CountSetup (stExtern+1) -#define st_Count (stTSPIDS+1) + st_Count }; enum eSuspendMode { @@ -77,25 +58,10 @@ enum eSocketId { }; extern const char *VERSION; -extern const char *StreamTypes[st_Count]; -extern const char *SuspendModes[sm_Count]; -extern const char IpCharacters[]; - -class cStreamdevMenuSetupPage: public cMenuSetupPage { -protected: - void AddCategory(const char *Title); - virtual void Store(void) = 0; - - void AddBoolEdit(const char *Title, int &Value); - void AddIpEdit(const char *Title, char *Value); - void AddShortEdit(const char *Title, int &Value); - void AddRangeEdit(const char *Title, int &Value, int Min, int Max); - void AddSuspEdit(const char *Title, int &Value); - void AddTypeEdit(const char *Title, int &Value); -}; class cMenuEditIpItem: public cMenuEditItem { private: + static const char IpCharacters[]; char *value; int curNum; int pos; diff --git a/libdvbmpeg/Makefile b/libdvbmpeg/Makefile index a586182..481d9c9 100644 --- a/libdvbmpeg/Makefile +++ b/libdvbmpeg/Makefile @@ -1,25 +1,34 @@ -INCS = -I. -CFLAGS = -g -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fPIC -MFLAG = -M -OBJS = ctools.o ringbuffy.o remux.o transform.o -SRC = $(wildcard *.c) +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.3.4.1 2010/06/14 10:40:13 schmirl Exp $ -DESTDIR = /usr/local +### The object files (add further files here): + +OBJS = ctools.o remux.o ringbuffy.o transform.o + +### The main target: .PHONY: clean - -clean: - - rm -f *.o *~ *.a .depend - libdvbmpegtools.a: $(OBJS) ar -rcs libdvbmpegtools.a $(OBJS) -%.o: %.c - $(CC) -c $(CFLAGS) $(INCS) $(DEFINES) $< +### Implicit rules: -.depend: - $(CXX) $(DEFINES) $(MFLAG) $(SRC) $(INCS)> .depend +%.o: %.c + $(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< +### Dependencies: +MAKEDEP = $(CC) -MM -MG +DEPFILE = .dependencies --include .depend +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.a core* *~ diff --git a/po/fi_FI.po.bak b/po/fi_FI.po.bak deleted file mode 100644 index f96a406..0000000 --- a/po/fi_FI.po.bak +++ /dev/null @@ -1,106 +0,0 @@ -# VDR streamdev plugin language source file. -# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org -# This file is distributed under the same license as the VDR streamdev package. -# Rolf Ahrenberg , 2008 -# -msgid "" -msgstr "" -"Project-Id-Version: streamdev 0.5.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-01-31 13:34+0200\n" -"PO-Revision-Date: 2008-03-30 02:11+0200\n" -"Last-Translator: Rolf Ahrenberg \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "VTP Streaming Client" -msgstr "VTP-suoratoistoasiakas" - -msgid "Suspend Server" -msgstr "Pysäytä palvelin" - -msgid "Server is suspended" -msgstr "Palvelin on pysäytetty" - -msgid "Couldn't suspend Server!" -msgstr "Palvelinta ei onnistuttu pysäyttämään!" - -msgid "Hide Mainmenu Entry" -msgstr "Piilota valinta päävalikosta" - -msgid "Start Client" -msgstr "Käynnistä VDR-asiakas" - -msgid "Remote IP" -msgstr "Etäkoneen IP-osoite" - -msgid "Remote Port" -msgstr "Etäkoneen portti" - -msgid "Filter Streaming" -msgstr "Suodatetun tiedon suoratoisto" - -msgid "Synchronize EPG" -msgstr "Päivitä ohjelmaopas" - -msgid "Minimum Priority" -msgstr "Pienin prioriteetti" - -msgid "Maximum Priority" -msgstr "Suurin prioriteetti" - -msgid "VDR Streaming Server" -msgstr "VDR-suoratoistopalvelin" - -msgid "Streaming active" -msgstr "Suoratoistopalvelin aktiivinen" - -msgid "Suspend Live TV" -msgstr "Pysäytä suora TV-lähetys" - -msgid "Common Settings" -msgstr "Yleiset asetukset" - -msgid "Maximum Number of Clients" -msgstr "Suurin sallittu asiakkaiden määrä" - -msgid "Suspend behaviour" -msgstr "Pysäytystoiminto" - -msgid "Client may suspend" -msgstr "Asiakas saa pysäyttää palvelimen" - -msgid "VDR-to-VDR Server" -msgstr "VDR-palvelin" - -msgid "Start VDR-to-VDR Server" -msgstr "Käynnistä VDR-palvelin" - -msgid "VDR-to-VDR Server Port" -msgstr "VDR-palvelimen portti" - -msgid "Bind to IP" -msgstr "Sido osoitteeseen" - -msgid "HTTP Server" -msgstr "HTTP-palvelin" - -msgid "Start HTTP Server" -msgstr "Käynnistä HTTP-palvelin" - -msgid "HTTP Server Port" -msgstr "HTTP-palvelimen portti" - -msgid "HTTP Streamtype" -msgstr "HTTP-lähetysmuoto" - -msgid "Offer suspend mode" -msgstr "tyrkytä" - -msgid "Always suspended" -msgstr "aina" - -msgid "Never suspended" -msgstr "ei koskaan" diff --git a/remux/Makefile b/remux/Makefile new file mode 100644 index 0000000..8adfb89 --- /dev/null +++ b/remux/Makefile @@ -0,0 +1,34 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.1.2.1 2010/06/14 10:40:18 schmirl Exp $ + +### The object files (add further files here): + +OBJS = tsremux.o ts2es.o ts2pes.o ts2ps.o extern.o + +### The main target: + +.PHONY: clean +remux.a: $(OBJS) + ar -rcs remux.a $^ + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies + +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.a core* *~ diff --git a/remux/extern.c b/remux/extern.c index 3791d10..ce76883 100644 --- a/remux/extern.c +++ b/remux/extern.c @@ -1,14 +1,19 @@ #include "remux/extern.h" #include "server/server.h" +#include "server/connection.h" #include "server/streamer.h" +#include #include #include #include #include #include +#include namespace Streamdev { +#define MAXENV 63 + class cTSExt: public cThread { private: cRingBufferLinear *m_ResultBuffer; @@ -20,7 +25,7 @@ protected: virtual void Action(void); public: - cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter); + cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connection, const cChannel *Channel, const int *Apids, const int *Dpids); virtual ~cTSExt(); void Put(const uchar *Data, int Count); @@ -29,7 +34,7 @@ public: } // namespace Streamdev using namespace Streamdev; -cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter): +cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connection, const cChannel *Channel, const int *Apids, const int *Dpids): m_ResultBuffer(ResultBuffer), m_Active(false), m_Process(-1), @@ -62,6 +67,115 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter): if (m_Process == 0) { // child process + char *env[MAXENV + 1]; + int i = 0; + +#define ADDENV(x...) if (asprintf(&env[i++], x) < 0) i-- + + // add channel ID, name and pids to environment + ADDENV("REMUX_CHANNEL_ID=%s", *Channel->GetChannelID().ToString()); + ADDENV("REMUX_CHANNEL_NAME=%s", Channel->Name()); +#if APIVERSNUM >= 10701 + ADDENV("REMUX_VTYPE=%d", Channel->Vtype()); +#endif + if (Channel->Vpid()) + ADDENV("REMUX_VPID=%d", Channel->Vpid()); + if (Channel->Ppid() != Channel->Vpid()) + ADDENV("REMUX_PPID=%d", Channel->Ppid()); + if (Channel->Tpid()) + ADDENV("REMUX_TPID=%d", Channel->Tpid()); + + std::string buffer; + if (Apids && *Apids) { + for (const int *pid = Apids; *pid; pid++) + (buffer += (const char *) itoa(*pid)) += (*(pid + 1) ? " " : ""); + ADDENV("REMUX_APID=%s", buffer.c_str()); + + buffer.clear(); + for (const int *pid = Apids; *pid; pid++) { + int j; + for (j = 0; Channel->Apid(j) && Channel->Apid(j) != *pid; j++) + ; + (buffer += Channel->Alang(j)) += (*(pid + 1) ? " " : ""); + } + ADDENV("REMUX_ALANG=%s", buffer.c_str()); + } + + if (Dpids && *Dpids) { + buffer.clear(); + for (const int *pid = Dpids; *pid; pid++) + (buffer += (const char *) itoa(*pid)) += (*(pid + 1) ? " " : ""); + ADDENV("REMUX_DPID=%s", buffer.c_str()); + + buffer.clear(); + for (const int *pid = Dpids; *pid; pid++) { + int j; + for (j = 0; Channel->Dpid(j) && Channel->Dpid(j) != *pid; j++) + ; + (buffer += Channel->Dlang(j)) += (*(pid + 1) ? " " : ""); + } + ADDENV("REMUX_DLANG=%s", buffer.c_str()); + } + + if (Channel->Spid(0)) { + buffer.clear(); + for (const int *pid = Channel->Spids(); *pid; pid++) + (buffer += (const char *) itoa(*pid)) += (*(pid + 1) ? " " : ""); + ADDENV("REMUX_SPID=%s", buffer.c_str()); + + buffer.clear(); + for (int j = 0; Channel->Spid(j); j++) + (buffer += Channel->Slang(j)) += (Channel->Spid(j + 1) ? " " : ""); + ADDENV("REMUX_SLANG=%s", buffer.c_str()); + } + + if (Connection) { + // add vars for a CGI like interface + // the following vars are not implemented: + // REMOTE_HOST, REMOTE_IDENT, REMOTE_USER + // CONTENT_TYPE, CONTENT_LENGTH, + // SCRIPT_NAME, PATH_TRANSLATED, GATEWAY_INTERFACE + ADDENV("REMOTE_ADDR=%s", Connection->RemoteIp().c_str()); + ADDENV("SERVER_NAME=%s", Connection->LocalIp().c_str()); + ADDENV("SERVER_PORT=%d", Connection->LocalPort()); + ADDENV("SERVER_PROTOCOL=%s", Connection->Protocol()); + ADDENV("SERVER_SOFTWARE=%s", VERSION); + + for (tStrStrMap::const_iterator it = Connection->Headers().begin(); it != Connection->Headers().end(); it++) { + if (i >= MAXENV) { + esyslog("streamdev-server: Too many headers for externremux.sh"); + break; + } + ADDENV("%s=%s", it->first.c_str(), it->second.c_str()); + } + + // look for section parameters: /path;param1=value1;param2=value2/ + std::string::size_type begin, end; + std::string path = Connection->Headers().at("PATH_INFO"); + begin = path.find(';', 0); + begin = path.find_first_not_of(';', begin); + end = path.find_first_of(";/", begin); + while (begin != std::string::npos && path[begin] != '/') { + std::string param = path.substr(begin, end - begin); + std::string::size_type e = param.find('='); + + if (i >= MAXENV) { + esyslog("streamdev-server: Too many parameters for externremux.sh"); + break; + } + else if (e > 0 && e != std::string::npos) { + ADDENV("REMUX_PARAM_%s", param.c_str()); + } + else + esyslog("streamdev-server: Invalid externremux.sh parameter %s", param.c_str()); + + begin = path.find_first_not_of(';', end); + end = path.find_first_of(";/", begin); + } + } + + env[i] = NULL; + dup2(inpipe[0], STDIN_FILENO); close(inpipe[1]); dup2(outpipe[1], STDOUT_FILENO); @@ -71,9 +185,11 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter): for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++) close(i); //close all dup'ed filedescriptors - std::string cmd = std::string(opt_remux) + " " + Parameter; - if (execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL) == -1) { - esyslog("streamdev-server: externremux script '%s' execution failed: %m", cmd.c_str()); + if (setpgid(0, 0) == -1) + esyslog("streamdev-server: externremux setpgid failed: %m"); + + if (execle("/bin/sh", "sh", "-c", opt_remux, NULL, env) == -1) { + esyslog("streamdev-server: externremux script '%s' execution failed: %m", opt_remux); _exit(-1); } // should never be reached @@ -172,9 +288,9 @@ void cTSExt::Put(const uchar *Data, int Count) } } -cExternRemux::cExternRemux(int VPid, const int *APids, const int *Dpids, const int *SPids, std::string Parameter): +cExternRemux::cExternRemux(const cServerConnection *Connection, const cChannel *Channel, const int *Apids, const int *Dpids): m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, TS_SIZE * 2)), - m_Remux(new cTSExt(m_ResultBuffer, Parameter)) + m_Remux(new cTSExt(m_ResultBuffer, Connection, Channel, Apids, Dpids)) { m_ResultBuffer->SetTimeouts(500, 100); } diff --git a/remux/extern.h b/remux/extern.h index ff4ddec..070e4f6 100644 --- a/remux/extern.h +++ b/remux/extern.h @@ -5,6 +5,9 @@ #include #include +class cChannel; +class cServerConnection; + namespace Streamdev { class cTSExt; @@ -15,7 +18,7 @@ private: cTSExt *m_Remux; public: - cExternRemux(int VPid, const int *APids, const int *Dpids, const int *SPids, std::string Parameter); + cExternRemux(const cServerConnection *Connection, const cChannel *Channel, const int *APids, const int *Dpids); virtual ~cExternRemux(); int Put(const uchar *Data, int Count); diff --git a/remux/tsremux.h b/remux/tsremux.h index dbcd5de..8f22b1d 100644 --- a/remux/tsremux.h +++ b/remux/tsremux.h @@ -11,6 +11,8 @@ namespace Streamdev { class cTSRemux { public: + virtual ~cTSRemux() {}; + virtual int Put(const uchar *Data, int Count) = 0; virtual uchar *Get(int &Count) = 0; virtual void Del(int Count) = 0; diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..91c2a93 --- /dev/null +++ b/server/Makefile @@ -0,0 +1,82 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.1.2.1 2010/06/14 10:40:20 schmirl Exp $ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = streamdev-server + +### Includes and Defines (add further entries here): + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +COMMONOBJS = ../common.o + +SERVEROBJS = $(PLUGIN).o \ + server.o component.o connection.o \ + componentVTP.o connectionVTP.o \ + componentHTTP.o connectionHTTP.o menuHTTP.o \ + componentIGMP.o connectionIGMP.o \ + streamer.o livestreamer.o livefilter.o recplayer.o \ + suspend.o setup.o + +### The main target: + +.PHONY: all i18n clean +all: libvdr-$(PLUGIN).so i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies + +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(SERVEROBJS:%.o=%.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='' -o $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +i18n: $(I18Nmsgs) + +### Targets: + +libvdr-$(PLUGIN).so: $(SERVEROBJS) $(COMMONOBJS) \ + ../tools/sockettools.a ../remux/remux.a ../libdvbmpeg/libdvbmpegtools.a + +%.so: + $(CXX) $(CXXFLAGS) -shared $^ -o $@ + @cp $@ $(LIBDIR)/$@.$(APIVERSION) + +clean: + @-rm -f $(COMMONOBJS) $(SERVEROBJS) $(DEPFILE) $(PODIR)/*.mo $(PODIR)/*.pot *.so *.tgz core* *~ diff --git a/server/connection.c b/server/connection.c index 74b2783..6121b7a 100644 --- a/server/connection.c +++ b/server/connection.c @@ -1,5 +1,5 @@ /* - * $Id: connection.c,v 1.12 2009/02/13 10:39:22 schmirl Exp $ + * $Id: connection.c,v 1.13.2.1 2010/06/11 06:06:02 schmirl Exp $ */ #include "server/connection.h" @@ -27,6 +27,66 @@ cServerConnection::~cServerConnection() { } +const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid, int *Dpid) { + const cChannel *channel = NULL; + char *string = strdup(String); + char *ptr, *end; + int apididx = 0; + + if ((ptr = strrchr(string, '+')) != NULL) { + *(ptr++) = '\0'; + apididx = strtoul(ptr, &end, 10); + Dprintf("found apididx: %d\n", apididx); + } + + if (isnumber(string)) { + int temp = strtol(String, NULL, 10); + if (temp >= 1 && temp <= Channels.MaxNumber()) + channel = Channels.GetByNumber(temp); + } else { + channel = Channels.GetByChannelID(tChannelID::FromString(string)); + + if (channel == NULL) { + int i = 1; + while ((channel = Channels.GetByNumber(i, 1)) != NULL) { + if (String == channel->Name()) + break; + + i = channel->Number() + 1; + } + } + } + + if (channel != NULL && apididx > 0) { + int apid = 0, dpid = 0; + int index = 1; + + for (int i = 0; channel->Apid(i) != 0; ++i, ++index) { + if (index == apididx) { + apid = channel->Apid(i); + break; + } + } + + if (apid == 0) { + for (int i = 0; channel->Dpid(i) != 0; ++i, ++index) { + if (index == apididx) { + dpid = channel->Dpid(i); + break; + } + } + } + + if (Apid != NULL) + *Apid = apid; + if (Dpid != NULL) + *Dpid = dpid; + } + + free(string); + return channel; +} + bool cServerConnection::Read(void) { int b; diff --git a/server/connection.h b/server/connection.h index 2c28a09..dfaff91 100644 --- a/server/connection.h +++ b/server/connection.h @@ -1,5 +1,5 @@ /* - * $Id: connection.h,v 1.7 2009/02/13 10:39:22 schmirl Exp $ + * $Id: connection.h,v 1.8.2.1 2010/06/11 06:06:02 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVER_CONNECTION_H @@ -8,6 +8,11 @@ #include "tools/socket.h" #include "common.h" +#include + +typedef std::map tStrStrMap; +typedef std::pair tStrStr; + class cChannel; class cDevice; @@ -28,6 +33,8 @@ private: uint m_WriteBytes; uint m_WriteIndex; + tStrStrMap m_Headers; + protected: /* Will be called when a command terminated by a newline has been received */ @@ -41,6 +48,11 @@ protected: virtual bool Respond(const char *Message, bool Last = true, ...); //__attribute__ ((format (printf, 2, 4))); + /* Add a request header */ + void SetHeader(const char *Name, const char *Value, const char *Prefix = "") { m_Headers.insert(tStrStr(std::string(Prefix) + Name, Value)); } + + static const cChannel *ChannelFromString(const char *String, int *Apid = NULL, int *Dpid = NULL); + public: /* If you derive, specify a short string such as HTTP for Protocol, which will be displayed in error messages */ @@ -87,6 +99,12 @@ public: virtual void Detach(void) = 0; virtual void Attach(void) = 0; + + /* This connections protocol name */ + virtual const char* Protocol(void) const { return m_Protocol; } + + /* std::map with additional information */ + const tStrStrMap& Headers(void) const { return m_Headers; } }; inline bool cServerConnection::HasData(void) const diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c index 83e568d..b963d64 100644 --- a/server/connectionHTTP.c +++ b/server/connectionHTTP.c @@ -1,5 +1,5 @@ /* - * $Id: connectionHTTP.c,v 1.17 2009/06/19 06:32:45 schmirl Exp $ + * $Id: connectionHTTP.c,v 1.17.2.1 2010/06/11 06:06:02 schmirl Exp $ */ #include @@ -13,13 +13,13 @@ cConnectionHTTP::cConnectionHTTP(void): cServerConnection("HTTP"), m_Status(hsRequest), m_LiveStreamer(NULL), - m_StreamerParameter(""), m_Channel(NULL), - m_Apid(0), m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType), m_ChannelList(NULL) { Dprintf("constructor hsRequest\n"); + m_Apid[0] = m_Apid[1] = 0; + m_Dpid[0] = m_Dpid[1] = 0; } cConnectionHTTP::~cConnectionHTTP() @@ -37,30 +37,64 @@ bool cConnectionHTTP::Command(char *Cmd) Dprintf("command %s\n", Cmd); switch (m_Status) { case hsRequest: - Dprintf("Request\n"); - m_Request = Cmd; - m_Status = hsHeaders; - return true; + // parse METHOD PATH[?QUERY] VERSION + { + char *p, *q, *v; + p = strchr(Cmd, ' '); + if (p) { + *p = 0; + v = strchr(++p, ' '); + if (v) { + *v = 0; + SetHeader("REQUEST_METHOD", Cmd); + q = strchr(p, '?'); + if (q) + *q = 0; + SetHeader("QUERY_STRING", q ? ++q : ""); + SetHeader("PATH_INFO", p); + m_Status = hsHeaders; + return true; + } + } + } + return false; case hsHeaders: if (*Cmd == '\0') { m_Status = hsBody; return ProcessRequest(); } - if (strncasecmp(Cmd, "Host:", 5) == 0) { - Dprintf("Host-Header\n"); - m_Host = (std::string) skipspace(Cmd + 5); - return true; + else if (isspace(*Cmd)) { + ; //TODO: multi-line header } - else if (strncasecmp(Cmd, "Authorization:", 14) == 0) { - Cmd = skipspace(Cmd + 14); - if (strncasecmp(Cmd, "Basic", 5) == 0) { - Dprintf("'Authorization Basic'-Header\n"); - m_Authorization = (std::string) skipspace(Cmd + 5); - return true; + else { + // convert header name to CGI conventions: + // uppercase, '-' replaced with '_', prefix "HTTP_" + char *p; + for (p = Cmd; *p != 0 && *p != ':'; p++) { + if (*p == '-') + *p = '_'; + else + *p = toupper(*p); + } + if (*p == ':') { + *p = 0; + p = skipspace(++p); + // don't disclose Authorization header + if (strcmp(Cmd, "AUTHORIZATION") == 0) { + char *q; + for (q = p; *q != 0 && *q != ' '; q++) + *q = toupper(*q); + if (p != q) { + *q = 0; + SetHeader("AUTH_TYPE", p); + m_Authorization = (std::string) skipspace(++q); + } + } + else + SetHeader(Cmd, p, "HTTP_"); } } - Dprintf("header\n"); return true; default: // skip additional blank lines @@ -73,10 +107,31 @@ bool cConnectionHTTP::Command(char *Cmd) bool cConnectionHTTP::ProcessRequest(void) { + // keys for Headers() hash + const static std::string AUTH_TYPE("AUTH_TYPE"); + const static std::string REQUEST_METHOD("REQUEST_METHOD"); + const static std::string PATH_INFO("PATH_INFO"); + Dprintf("process\n"); - if (!StreamdevHosts.Acceptable(RemoteIpAddr())) - { - if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) { + if (!StreamdevHosts.Acceptable(RemoteIpAddr())) { + bool authOk = opt_auth && !m_Authorization.empty(); + if (authOk) { + tStrStrMap::const_iterator it = Headers().find(AUTH_TYPE); + + if (it == Headers().end()) { + // no authorization header present + authOk = false; + } + else if (it->second.compare("BASIC") == 0) { + // basic auth + authOk &= m_Authorization.compare(opt_auth) == 0; + } + else { + // unsupported auth type + authOk = false; + } + } + if (!authOk) { isyslog("streamdev-server: HTTP authorization required"); DeferClose(); return Respond("HTTP/1.0 401 Authorization Required") @@ -84,28 +139,22 @@ bool cConnectionHTTP::ProcessRequest(void) && Respond(""); } } - if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) { - switch (m_Job) { - case hjListing: - if (m_ChannelList) - return Respond("%s", true, m_ChannelList->HttpHeader().c_str()); - break; - case hjTransfer: - if (m_Channel == NULL) { - DeferClose(); - return Respond("HTTP/1.0 404 not found"); - } - - m_LiveStreamer = new cStreamdevLiveStreamer(0, m_StreamerParameter); + if (Headers().at(REQUEST_METHOD).compare("GET") == 0 && ProcessURI(Headers().at(PATH_INFO))) { + if (m_ChannelList) + return Respond("%s", true, m_ChannelList->HttpHeader().c_str()); + else if (m_Channel != NULL) { cDevice *device = GetDevice(m_Channel, 0); if (device != NULL) { device->SwitchChannel(m_Channel, false); - if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) { + m_LiveStreamer = new cStreamdevLiveStreamer(0, this); + if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) { m_LiveStreamer->SetDevice(device); if (!SetDSCP()) LOG_ERROR_STR("unable to set DSCP sockopt"); - if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) { + if (m_StreamType == stEXT) { + return Respond("HTTP/1.0 200 OK"); + } else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) { return Respond("HTTP/1.0 200 OK") && Respond("Content-Type: audio/mpeg") && Respond("icy-name: %s", true, m_Channel->Name()) @@ -116,12 +165,46 @@ bool cConnectionHTTP::ProcessRequest(void) && Respond(""); } } + DELETENULL(m_LiveStreamer); } - DELETENULL(m_LiveStreamer); DeferClose(); return Respond("HTTP/1.0 409 Channel not available") && Respond(""); } + else { + DeferClose(); + return Respond("HTTP/1.0 404 not found") + && Respond(""); + } + } else if (Headers().at(REQUEST_METHOD).compare("HEAD") == 0 && ProcessURI(Headers().at(PATH_INFO))) { + DeferClose(); + if (m_ChannelList) + return Respond("%s", true, m_ChannelList->HttpHeader().c_str()); + else if (m_Channel != NULL) { + cDevice *device = GetDevice(m_Channel, 0); + if (device != NULL) { + if (m_StreamType == stEXT) { + // TODO + return Respond("HTTP/1.0 200 OK") + && Respond(""); + } else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) { + return Respond("HTTP/1.0 200 OK") + && Respond("Content-Type: audio/mpeg") + && Respond("icy-name: %s", true, m_Channel->Name()) + && Respond(""); + } else { + return Respond("HTTP/1.0 200 OK") + && Respond("Content-Type: video/mpeg") + && Respond(""); + } + } + return Respond("HTTP/1.0 409 Channel not available") + && Respond(""); + } + else { + return Respond("HTTP/1.0 404 not found") + && Respond(""); + } } DeferClose(); @@ -136,78 +219,108 @@ void cConnectionHTTP::Flushed(void) if (m_Status != hsBody) return; - switch (m_Job) { - case hjListing: - if (m_ChannelList) { - if (m_ChannelList->HasNext()) { - if (!Respond("%s", true, m_ChannelList->Next().c_str())) - DeferClose(); - } - else { - DELETENULL(m_ChannelList); - m_Status = hsFinished; + if (m_ChannelList) { + if (m_ChannelList->HasNext()) { + if (!Respond("%s", true, m_ChannelList->Next().c_str())) DeferClose(); - } - return; } - // should never be reached - esyslog("streamdev-server cConnectionHTTP::Flushed(): no channel list"); - m_Status = hsFinished; - break; - - case hjTransfer: + else { + DELETENULL(m_ChannelList); + m_Status = hsFinished; + DeferClose(); + } + return; + } + else if (m_Channel != NULL) { Dprintf("streamer start\n"); m_LiveStreamer->Start(this); m_Status = hsFinished; - break; + } + else { + // should never be reached + esyslog("streamdev-server cConnectionHTTP::Flushed(): no job to do"); + m_Status = hsFinished; } } -bool cConnectionHTTP::CmdGET(const std::string &Opts) +cChannelList* cConnectionHTTP::ChannelListFromString(const std::string& Path, const std::string& Filebase, const std::string& Fileext) const { - const char *ptr, *sp, *pp, *fp, *xp, *qp, *ep; - const cChannel *chan; - int apid = 0; + // keys for Headers() hash + const static std::string QUERY_STRING("QUERY_STRING"); + const static std::string HOST("HTTP_HOST"); - ptr = Opts.c_str(); + const std::string query = Headers().at(QUERY_STRING); - // find begin of URL - sp = skipspace(ptr); - // find end of URL (\0 or first space character) - for (ep = sp; *ep && !isspace(*ep); ep++) - ; - // find begin of query string (first ?) - for (qp = sp; qp < ep && *qp != '?'; qp++) - ; - // find begin of filename (last /) - for (fp = qp; fp > sp && *fp != '/'; --fp) - ; - // find begin of section params (first ;) - for (pp = sp; pp < fp && *pp != ';'; pp++) - ; - // find filename extension (first .) - for (xp = fp; xp < qp && *xp != '.'; xp++) - ; - if (qp - xp > 5) // too long for a filename extension - xp = qp; + std::string groupTarget; + cChannelIterator *iterator = NULL; + + if (Filebase.compare("tree") == 0) { + const cChannel* c = NULL; + size_t groupIndex = query.find("group="); + if (groupIndex != std::string::npos) + c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); + iterator = new cListTree(c); + groupTarget = Filebase + Fileext; + } else if (Filebase.compare("groups") == 0) { + iterator = new cListGroups(); + groupTarget = (std::string) "group" + Fileext; + } else if (Filebase.compare("group") == 0) { + const cChannel* c = NULL; + size_t groupIndex = query.find("group="); + if (groupIndex != std::string::npos) + c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); + iterator = new cListGroup(c); + } else if (Filebase.compare("channels") == 0) { + iterator = new cListChannels(); + } else if (Filebase.compare("all") == 0 || + (Filebase.empty() && Fileext.empty())) { + iterator = new cListAll(); + } + + if (iterator) { + if (Filebase.empty() || Fileext.compare(".htm") == 0 || Fileext.compare(".html") == 0) { + std::string self = Filebase + Fileext; + if (!query.empty()) + self += '?' + query; + return new cHtmlChannelList(iterator, m_StreamType, self.c_str(), groupTarget.c_str()); + } else if (Fileext.compare(".m3u") == 0) { + std::string base; + tStrStrMap::const_iterator it = Headers().find(HOST); + if (it != Headers().end()) + base = "http://" + it->second + "/"; + else + base = (std::string) "http://" + LocalIp() + ":" + + (const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/"; + base += Path; + return new cM3uChannelList(iterator, base.c_str()); + } else { + delete iterator; + } + } + return NULL; +} + +bool cConnectionHTTP::ProcessURI(const std::string& PathInfo) +{ + std::string filespec, fileext; + size_t file_pos = PathInfo.rfind('/'); + + if (file_pos != std::string::npos) { + size_t ext_pos = PathInfo.rfind('.'); + // file basename with leading / stripped off + filespec = PathInfo.substr(file_pos + 1, ext_pos - file_pos - 1); + if (ext_pos != std::string::npos) + // file extension including leading . + fileext = PathInfo.substr(ext_pos); + } + if (fileext.length() > 5) { + //probably not an extension + filespec += fileext; + fileext.clear(); + } - std::string type, filespec, fileext, query; // Streamtype with leading / stripped off - if (pp > sp) - type = Opts.substr(sp - ptr + 1, pp - sp - 1); - // Section parameters with leading ; stripped off - if (fp > pp) - m_StreamerParameter = Opts.substr(pp - ptr + 1, fp - pp - 1); - // file basename with leading / stripped off - if (xp > fp) - filespec = Opts.substr(fp - ptr + 1, xp - fp - 1); - // file extension including leading . - fileext = Opts.substr(xp - ptr, qp - xp); - // query string including leading ? - query = Opts.substr(qp - ptr, ep - qp); - - Dprintf("before channelfromstring: type(%s) param(%s) filespec(%s) fileext(%s) query(%s)\n", type.c_str(), m_StreamerParameter.c_str(), filespec.c_str(), fileext.c_str(), query.c_str()); - + std::string type = PathInfo.substr(1, PathInfo.find_first_of("/;", 1) - 1); const char* pType = type.c_str(); if (strcasecmp(pType, "PS") == 0) { m_StreamType = stPS; @@ -217,80 +330,19 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts) m_StreamType = stTS; } else if (strcasecmp(pType, "ES") == 0) { m_StreamType = stES; - } else if (strcasecmp(pType, "Extern") == 0) { - m_StreamType = stExtern; + } else if (strcasecmp(pType, "EXT") == 0) { + m_StreamType = stEXT; } - std::string groupTarget; - cChannelIterator *iterator = NULL; + Dprintf("before channelfromstring: type(%s) filespec(%s) fileext(%s)\n", type.c_str(), filespec.c_str(), fileext.c_str()); - if (filespec.compare("tree") == 0) { - const cChannel* c = NULL; - size_t groupIndex = query.find("group="); - if (groupIndex != std::string::npos) - c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); - iterator = new cListTree(c); - groupTarget = filespec + fileext; - } else if (filespec.compare("groups") == 0) { - iterator = new cListGroups(); - groupTarget = (std::string) "group" + fileext; - } else if (filespec.compare("group") == 0) { - const cChannel* c = NULL; - size_t groupIndex = query.find("group="); - if (groupIndex != std::string::npos) - c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6)); - iterator = new cListGroup(c); - } else if (filespec.compare("channels") == 0) { - iterator = new cListChannels(); - } else if (filespec.compare("all") == 0 || - (filespec.empty() && fileext.empty())) { - iterator = new cListAll(); - } - - if (iterator) { - if (filespec.empty() || fileext.compare(".htm") == 0 || fileext.compare(".html") == 0) { - m_ChannelList = new cHtmlChannelList(iterator, m_StreamType, (filespec + fileext + query).c_str(), groupTarget.c_str()); - m_Job = hjListing; - } else if (fileext.compare(".m3u") == 0) { - std::string base; - if (*(m_Host.c_str())) - base = "http://" + m_Host + "/"; - else - base = (std::string) "http://" + LocalIp() + ":" + - (const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/"; - if (type.empty()) - { - switch (m_StreamType) - { - case stTS: base += "TS/"; break; - case stPS: base += "PS/"; break; - case stPES: base += "PES/"; break; - case stES: base += "ES/"; break; - case stExtern: base += "Extern/"; break; - default: break; - - } - } else { - base += type; - if (!m_StreamerParameter.empty()) - base += ";" + m_StreamerParameter; - base += "/"; - } - m_ChannelList = new cM3uChannelList(iterator, base.c_str()); - m_Job = hjListing; - } else { - delete iterator; - return false; - } - } else if ((chan = ChannelFromString(filespec.c_str(), &apid)) != NULL) { - m_Channel = chan; - m_Apid = apid; - Dprintf("Apid is %d\n", apid); - m_Job = hjTransfer; + if ((m_ChannelList = ChannelListFromString(PathInfo.substr(0, file_pos), filespec.c_str(), fileext.c_str())) != NULL) { + Dprintf("Channel list requested\n"); + return true; + } else if ((m_Channel = ChannelFromString(filespec.c_str(), &m_Apid[0], &m_Dpid[0])) != NULL) { + Dprintf("Channel found. Apid/Dpid is %d/%d\n", m_Apid[0], m_Dpid[0]); + return true; } else return false; - - Dprintf("after channelfromstring\n"); - return true; } diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h index 0548959..1ea6ed2 100644 --- a/server/connectionHTTP.h +++ b/server/connectionHTTP.h @@ -1,5 +1,5 @@ /* - * $Id: connectionHTTP.h,v 1.6 2008/10/14 11:05:48 schmirl Exp $ + * $Id: connectionHTTP.h,v 1.6.2.1 2010/06/11 06:06:02 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H @@ -8,6 +8,7 @@ #include "connection.h" #include "server/livestreamer.h" +#include #include class cChannel; @@ -23,26 +24,19 @@ private: hsFinished, }; - enum eHTTPJob { - hjTransfer, - hjListing, - }; - - std::string m_Request; - std::string m_Host; std::string m_Authorization; - //std::map m_Headers; TODO: later? eHTTPStatus m_Status; - eHTTPJob m_Job; // job: transfer cStreamdevLiveStreamer *m_LiveStreamer; - std::string m_StreamerParameter; const cChannel *m_Channel; - int m_Apid; + int m_Apid[2]; + int m_Dpid[2]; eStreamType m_StreamType; // job: listing cChannelList *m_ChannelList; + cChannelList* ChannelListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const; + bool ProcessURI(const std::string &PathInfo); protected: bool ProcessRequest(void); @@ -56,7 +50,6 @@ public: virtual bool CanAuthenticate(void); virtual bool Command(char *Cmd); - bool CmdGET(const std::string &Opts); virtual bool Abort(void) const; virtual void Flushed(void); diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c index dc08798..7ea7e11 100644 --- a/server/connectionIGMP.c +++ b/server/connectionIGMP.c @@ -1,5 +1,5 @@ /* - * $Id: connectionIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $ + * $Id: connectionIGMP.c,v 1.1.4.1 2010/06/11 06:06:02 schmirl Exp $ */ #include @@ -31,7 +31,7 @@ bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst) struct in_addr ip; ip.s_addr = Dst; if (Connect(inet_ntoa(ip), m_ClientPort)) { - m_LiveStreamer = new cStreamdevLiveStreamer(0); + m_LiveStreamer = new cStreamdevLiveStreamer(0, this); if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) { m_LiveStreamer->SetDevice(device); if (!SetDSCP()) diff --git a/server/connectionVTP.c b/server/connectionVTP.c index 6037ecc..ca73cfb 100644 --- a/server/connectionVTP.c +++ b/server/connectionVTP.c @@ -1,5 +1,5 @@ /* - * $Id: connectionVTP.c,v 1.22 2009/07/02 06:03:51 schmirl Exp $ + * $Id: connectionVTP.c,v 1.27.2.1 2010/06/11 06:06:03 schmirl Exp $ */ #include "server/connectionVTP.h" @@ -40,6 +40,9 @@ private: #if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM) enum eStates { Channel, Event, Title, Subtitle, Description, Vps, Content, EndEvent, EndChannel, EndEPG }; +#elif APIVERSNUM >= 10711 + enum eStates { Channel, Event, Title, Subtitle, Description, Vps, Content, Rating, + EndEvent, EndChannel, EndEPG }; #else enum eStates { Channel, Event, Title, Subtitle, Description, Vps, EndEvent, EndChannel, EndEPG }; @@ -50,7 +53,7 @@ private: const cSchedule *m_Schedule; const cEvent *m_Event; int m_Errno; - char *m_Error; + cString m_Error; eStates m_State; bool m_Traverse; time_t m_ToTime; @@ -67,7 +70,6 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): m_Schedule(NULL), m_Event(NULL), m_Errno(0), - m_Error(NULL), m_State(Channel), m_Traverse(false), m_ToTime(0) @@ -94,12 +96,12 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): attime = strtol(p, NULL, 10); else { m_Errno = 501; - m_Error = strdup("Invalid time"); + m_Error = "Invalid time"; break; } } else { m_Errno = 501; - m_Error = strdup("Missing time"); + m_Error = "Missing time"; break; } } @@ -110,7 +112,7 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): fromtime = strtol(p, NULL, 10); else { m_Errno = 501; - m_Error = strdup("Invalid time"); + m_Error = "Invalid time"; break; } if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) { @@ -120,19 +122,19 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): m_ToTime = strtol(p, NULL, 10); else { m_Errno = 501; - m_Error = strdup("Invalid time"); + m_Error = "Invalid time"; break; } } else { m_Errno = 501; - m_Error = strdup("Missing time"); + m_Error = "Missing time"; break; } } } } else { m_Errno = 501; - m_Error = strdup("Missing time"); + m_Error = "Missing time"; break; } } else if (!m_Schedule) { @@ -146,27 +148,27 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): m_Schedule = m_Schedules->GetSchedule(Channel->GetChannelID()); if (!m_Schedule) { m_Errno = 550; - m_Error = strdup("No schedule found"); + m_Error = "No schedule found"; break; } } else { m_Errno = 550; - asprintf(&m_Error, "Channel \"%s\" not defined", p); + m_Error = cString::sprintf("Channel \"%s\" not defined", p); break; } } else { m_Errno = 501; - asprintf(&m_Error, "Unknown option: \"%s\"", p); + m_Error = cString::sprintf("Unknown option: \"%s\"", p); break; } p = strtok_r(NULL, delim, &strtok_next); } } else if (m_Schedules == NULL) { m_Errno = 451; - m_Error = strdup("EPG data is being modified, try again"); + m_Error = "EPG data is being modified, try again"; } - if (m_Error == NULL) { + if (*m_Error == NULL) { if (m_Schedule != NULL) m_Schedules = NULL; else if (m_Schedules != NULL) @@ -205,17 +207,15 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): cLSTEHandler::~cLSTEHandler() { delete m_SchedulesLock; - if (m_Error != NULL) - free(m_Error); } bool cLSTEHandler::Next(bool &Last) { - if (m_Error != NULL) { + if (*m_Error != NULL) { Last = true; - cString str(m_Error, true); + cString str(m_Error); m_Error = NULL; - return m_Client->Respond(m_Errno, *str); + return m_Client->Respond(m_Errno, "%s", *str); } Last = false; @@ -285,7 +285,7 @@ bool cLSTEHandler::Next(bool &Last) break; case Vps: -#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM) +#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM) || APIVERSNUM >= 10711 m_State = Content; #else m_State = EndEvent; @@ -311,6 +311,25 @@ bool cLSTEHandler::Next(bool &Last) } else return Next(Last); break; +#elif APIVERSNUM >= 10711 + case Content: + m_State = Rating; + if (!isempty(m_Event->ContentToString(m_Event->Contents()))) { + char *copy = strdup(m_Event->ContentToString(m_Event->Contents())); + cString cpy(copy, true); + strreplace(copy, '\n', '|'); + return m_Client->Respond(-215, "G %i %i %s", m_Event->Contents() & 0xF0, m_Event->Contents() & 0x0F, copy); + } else + return Next(Last); + break; + + case Rating: + m_State = EndEvent; + if (m_Event->ParentalRating()) + return m_Client->Respond(-215, "R %d", m_Event->ParentalRating()); + else + return Next(Last); + break; #endif case EndEvent: @@ -361,7 +380,7 @@ private: const cChannel *m_Channel; char *m_Option; int m_Errno; - char *m_Error; + cString m_Error; bool m_Traverse; public: cLSTCHandler(cConnectionVTP *Client, const char *Option); @@ -374,18 +393,17 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option): m_Channel(NULL), m_Option(NULL), m_Errno(0), - m_Error(NULL), m_Traverse(false) { if (!Channels.Lock(false, 500)) { m_Errno = 451; - m_Error = strdup("Channels are being modified - try again"); + m_Error = "Channels are being modified - try again"; } else if (*Option) { if (isnumber(Option)) { m_Channel = Channels.GetByNumber(strtol(Option, NULL, 10)); if (m_Channel == NULL) { m_Errno = 501; - asprintf(&m_Error, "Channel \"%s\" not defined", Option); + m_Error = cString::sprintf("Channel \"%s\" not defined", Option); return; } } else { @@ -401,7 +419,7 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option): if (i > Channels.MaxNumber()) { m_Errno = 501; - asprintf(&m_Error, "Channel \"%s\" not defined", Option); + m_Error = cString::sprintf("Channel \"%s\" not defined", Option); return; } } @@ -410,26 +428,24 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option): m_Traverse = true; } else { m_Errno = 550; - m_Error = strdup("No channels defined"); + m_Error = "No channels defined"; } } cLSTCHandler::~cLSTCHandler() { Channels.Unlock(); - if (m_Error != NULL) - free(m_Error); if (m_Option != NULL) free(m_Option); } bool cLSTCHandler::Next(bool &Last) { - if (m_Error != NULL) { + if (*m_Error != NULL) { Last = true; - cString str(m_Error, true); + cString str(m_Error); m_Error = NULL; - return m_Client->Respond(m_Errno, *str); + return m_Client->Respond(m_Errno, "%s", *str); } int number; @@ -452,7 +468,7 @@ bool cLSTCHandler::Next(bool &Last) i = m_Channel->Number() + 1; } else { m_Errno = 501; - asprintf(&m_Error, "Channel \"%d\" not found", i); + m_Error = cString::sprintf("Channel \"%d\" not found", i); } } @@ -472,7 +488,7 @@ private: cTimer *m_Timer; int m_Index; int m_Errno; - char *m_Error; + cString m_Error; bool m_Traverse; public: cLSTTHandler(cConnectionVTP *Client, const char *Option); @@ -485,7 +501,6 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option): m_Timer(NULL), m_Index(0), m_Errno(0), - m_Error(NULL), m_Traverse(false) { if (*Option) { @@ -493,11 +508,11 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option): m_Timer = Timers.Get(strtol(Option, NULL, 10) - 1); if (m_Timer == NULL) { m_Errno = 501; - asprintf(&m_Error, "Timer \"%s\" not defined", Option); + m_Error = cString::sprintf("Timer \"%s\" not defined", Option); } } else { m_Errno = 501; - asprintf(&m_Error, "Error in timer number \"%s\"", Option); + m_Error = cString::sprintf("Error in timer number \"%s\"", Option); } } else if (Timers.Count()) { m_Traverse = true; @@ -505,27 +520,25 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option): m_Timer = Timers.Get(m_Index); if (m_Timer == NULL) { m_Errno = 501; - asprintf(&m_Error, "Timer \"%d\" not found", m_Index + 1); + m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1); } } else { m_Errno = 550; - m_Error = strdup("No timers defined"); + m_Error = "No timers defined"; } } cLSTTHandler::~cLSTTHandler() { - if (m_Error != NULL) - free(m_Error); } bool cLSTTHandler::Next(bool &Last) { - if (m_Error != NULL) { + if (*m_Error != NULL) { Last = true; - cString str(m_Error, true); + cString str(m_Error); m_Error = NULL; - return m_Client->Respond(m_Errno, *str); + return m_Client->Respond(m_Errno, "%s", *str); } bool result; @@ -541,7 +554,7 @@ bool cLSTTHandler::Next(bool &Last) m_Timer = Timers.Get(++m_Index); if (m_Timer == NULL) { m_Errno = 501; - asprintf(&m_Error, "Timer \"%d\" not found", m_Index + 1); + m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1); } } return result; @@ -559,7 +572,7 @@ private: const cEvent *m_Event; int m_Index; int m_Errno; - char *m_Error; + cString m_Error; bool m_Traverse; bool m_Info; eStates m_State; @@ -576,7 +589,6 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option): m_Event(NULL), m_Index(0), m_Errno(0), - m_Error(NULL), m_Traverse(false), m_Info(false), m_State(Recording), @@ -591,12 +603,12 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option): m_Info = true; if (m_Recording == NULL) { m_Errno = 501; - asprintf(&m_Error, "Recording \"%s\" not found", Option); + m_Error = cString::sprintf("Recording \"%s\" not found", Option); } } else { m_Errno = 501; - asprintf(&m_Error, "Error in Recording number \"%s\"", Option); + m_Error = cString::sprintf("Error in Recording number \"%s\"", Option); } } else if (Recordings.Count()) { @@ -605,28 +617,26 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option): m_Recording = Recordings.Get(m_Index); if (m_Recording == NULL) { m_Errno = 501; - asprintf(&m_Error, "Recording \"%d\" not found", m_Index + 1); + m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1); } } else { m_Errno = 550; - m_Error = strdup("No recordings available"); + m_Error = "No recordings available"; } } cLSTRHandler::~cLSTRHandler() { - if (m_Error != NULL) - free(m_Error); } bool cLSTRHandler::Next(bool &Last) { - if (m_Error != NULL) { + if (*m_Error != NULL) { Last = true; - cString str(m_Error, true); + cString str(m_Error); m_Error = NULL; - return m_Client->Respond(m_Errno, *str); + return m_Client->Respond(m_Errno, "%s", *str); } if (m_Info) { @@ -714,7 +724,7 @@ bool cLSTRHandler::Next(bool &Last) m_Recording = Recordings.Get(++m_Index); if (m_Recording == NULL) { m_Errno = 501; - asprintf(&m_Error, "Recording \"%d\" not found", m_Index + 1); + m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1); } } return result; @@ -871,8 +881,8 @@ bool cConnectionVTP::CmdCAPS(char *Opts) return Respond(220, "Capability \"%s\" accepted", Opts); } - if (strcasecmp(Opts, "EXTERN") == 0) { - m_StreamType = stExtern; + if (strcasecmp(Opts, "EXT") == 0) { + m_StreamType = stEXT; return Respond(220, "Capability \"%s\" accepted", Opts); } @@ -1068,7 +1078,7 @@ bool cConnectionVTP::CmdTUNE(char *Opts) return Respond(560, "Channel not available"); delete m_LiveStreamer; - m_LiveStreamer = new cStreamdevLiveStreamer(1); + m_LiveStreamer = new cStreamdevLiveStreamer(1, this); m_LiveStreamer->SetChannel(chan, m_StreamType); m_LiveStreamer->SetDevice(dev); if(m_LiveSocket) @@ -1086,7 +1096,6 @@ bool cConnectionVTP::CmdTUNE(char *Opts) bool cConnectionVTP::CmdPLAY(char *Opts) { - Recordings.Update(true); if (*Opts) { if (isnumber(Opts)) { cRecording *recording = Recordings.Get(strtol(Opts, NULL, 10) - 1); @@ -1397,22 +1406,52 @@ bool cConnectionVTP::CmdDELT(const char *Option) { INIT_WRAPPER(); if (*Option) { - if (isnumber(Option)) { - cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1); + int number = 0; + bool force = false; + char buf[strlen(Option) + 1]; + strcpy(buf, Option); + const char *delim = " \t"; + char *strtok_next; + char *p = strtok_r(buf, delim, &strtok_next); + + if (isnumber(p)) { + number = strtol(p, NULL, 10) - 1; + } + else if (strcasecmp(p, "FORCE") == 0) { + force = true; + } + if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) { + if (isnumber(p)) { + number = strtol(p, NULL, 10) - 1; + } + else if (strcasecmp(p, "FORCE") == 0) { + force = true; + } + else { + Reply(501, "Timer not found or wrong syntax"); + } + } + + cTimer *timer = Timers.Get(number); if (timer) { - if (!timer->Recording()) { + if (timer->Recording()) { + if (force) { + timer->Skip(); + cRecordControls::Process(time(NULL)); + } + else { + Reply(550, "Timer \"%i\" is recording", number); + EXIT_WRAPPER(); + } + } isyslog("deleting timer %s", *timer->ToDescr()); Timers.Del(timer); Timers.SetModified(); - Reply(250, "Timer \"%s\" deleted", Option); + Reply(250, "Timer \"%i\" deleted", number); } else - Reply(550, "Timer \"%s\" is recording", Option); + Reply(501, "Timer \"%i\" not defined", number); } else - Reply(501, "Timer \"%s\" not defined", Option); - } else - Reply(501, "Error in timer number \"%s\"", Option); - } else - Reply(501, "Missing timer number"); + Reply(501, "Missing timer option"); EXIT_WRAPPER(); } @@ -1706,12 +1745,17 @@ bool cConnectionVTP::CmdRENR(const char *Option) bool cConnectionVTP::Respond(int Code, const char *Message, ...) { - char *buffer; va_list ap; va_start(ap, Message); - vasprintf(&buffer, Message, ap); - va_end(ap); +#if APIVERSNUM < 10515 + char *buffer; + if (vasprintf(&buffer, Message, ap) < 0) + buffer = strdup("???"); cString str(buffer, true); +#else + cString str = cString::sprintf(Message, ap); +#endif + va_end(ap); if (Code >= 0 && m_LastCommand != NULL) { free(m_LastCommand); @@ -1719,6 +1763,6 @@ bool cConnectionVTP::Respond(int Code, const char *Message, ...) } return cServerConnection::Respond("%03d%c%s", Code >= 0, - Code < 0 ? -Code : Code, - Code < 0 ? '-' : ' ', buffer); + Code < 0 ? -Code : Code, + Code < 0 ? '-' : ' ', *str); } diff --git a/server/livestreamer.c b/server/livestreamer.c index 71a3565..2b0065c 100644 --- a/server/livestreamer.c +++ b/server/livestreamer.c @@ -172,16 +172,20 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream) for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { switch (d->getDescriptorTag()) { case SI::AC3DescriptorTag: + case SI::EnhancedAC3DescriptorTag: Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3"); + delete d; return stream.getPid(); case SI::TeletextDescriptorTag: Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext"); + delete d; return stream.getPid(); case SI::SubtitlingDescriptorTag: Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB"); + delete d; return stream.getPid(); default: Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n", @@ -214,6 +218,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream) stream.getPid(), stream.getStreamType(), d->getLength(), rawdata[2], rawdata[3], rawdata[4], rawdata[5]); + delete d; return stream.getPid(); } } @@ -330,10 +335,9 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i // --- cStreamdevLiveStreamer ------------------------------------------------- -cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Parameter): - cStreamdevStreamer("streamdev-livestreaming"), +cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection): + cStreamdevStreamer("streamdev-livestreaming", Connection), m_Priority(Priority), - m_Parameter(Parameter), m_NumPids(0), m_StreamType(stTSPIDS), m_Channel(NULL), @@ -443,37 +447,39 @@ void cStreamdevLiveStreamer::StartReceiver(void) } } -bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid) +bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid, const int *Dpid) { Dprintf("Initializing Remuxer for full channel transfer\n"); //printf("ca pid: %d\n", Channel->Ca()); m_Channel = Channel; m_StreamType = StreamType; - int apid[2] = { Apid, 0 }; - const int *Apids = Apid ? apid : m_Channel->Apids(); - const int *Dpids = Apid ? NULL : m_Channel->Dpids(); + const int *Apids = Apid ? Apid : m_Channel->Apids(); + const int *Dpids = Dpid ? Dpid : m_Channel->Dpids(); switch (m_StreamType) { case stES: { int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid(); - if (Apid != 0) - pid = Apid; + if (Apid && Apid[0]) + pid = Apid[0]; + else if (Dpid && Dpid[0]) + pid = Dpid[0]; m_Remux = new cTS2ESRemux(pid); return SetPids(pid); } case stPES: - m_Remux = new cTS2PESRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), - m_Channel->Spids()); + m_Remux = new cTS2PESRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); case stPS: - m_Remux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), - m_Channel->Spids()); + m_Remux = new cTS2PSRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); + case stEXT: + m_Remux = new cExternRemux(Connection(), m_Channel, Apids, Dpids); + // fall through case stTS: // This should never happen, but ... if (m_PatFilter) { @@ -488,16 +494,12 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str m_PatFilter = new cStreamdevPatFilter(this, m_Channel); return true; - case stExtern: - m_Remux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), - m_Channel->Spids(), m_Parameter); - return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); - case stTSPIDS: Dprintf("pid streaming mode\n"); return true; + default: + return false; } - return false; } int cStreamdevLiveStreamer::Put(const uchar *Data, int Count) diff --git a/server/livestreamer.h b/server/livestreamer.h index 92448bb..283a395 100644 --- a/server/livestreamer.h +++ b/server/livestreamer.h @@ -18,7 +18,6 @@ class cStreamdevLiveReceiver; class cStreamdevLiveStreamer: public cStreamdevStreamer { private: int m_Priority; - std::string m_Parameter; int m_Pids[MAXRECEIVEPIDS + 1]; int m_NumPids; eStreamType m_StreamType; @@ -32,13 +31,13 @@ private: bool HasPid(int Pid); public: - cStreamdevLiveStreamer(int Priority, std::string Parameter = ""); + cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection); virtual ~cStreamdevLiveStreamer(); void SetDevice(cDevice *Device) { m_Device = Device; } bool SetPid(int Pid, bool On); bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL); - bool SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid = 0); + bool SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL); virtual int Put(const uchar *Data, int Count); virtual uchar *Get(int &Count); diff --git a/server/menuHTTP.c b/server/menuHTTP.c index 8d3e404..5fb5010 100644 --- a/server/menuHTTP.c +++ b/server/menuHTTP.c @@ -205,8 +205,8 @@ std::string cHtmlChannelList::StreamTypeMenu() (std::string) "[PES] "); typeMenu += (streamType == stES ? (std::string) "[ES] " : (std::string) "[ES] "); - typeMenu += (streamType == stExtern ? (std::string) "[Extern] " : - (std::string) "[Extern] "); + typeMenu += (streamType == stEXT ? (std::string) "[EXT] " : + (std::string) "[EXT] "); return typeMenu; } @@ -415,13 +415,13 @@ std::string cM3uChannelList::Next() if (channel->GroupSep()) { - return (std::string) "#EXTINF:0," + name + "\r\n" + + return (std::string) "#EXTINF:-1," + name + "\r\n" + base + "group.m3u?group=" + (const char*) itoa(cChannelList::GetGroupIndex(channel)); } else { - return (std::string) "#EXTINF:0," + + return (std::string) "#EXTINF:-1," + (const char*) itoa(channel->Number()) + " " + name + "\r\n" + base + (std::string) channel->GetChannelID().ToString(); } diff --git a/server/menuHTTP.h b/server/menuHTTP.h index fa699b9..cbd7b59 100644 --- a/server/menuHTTP.h +++ b/server/menuHTTP.h @@ -113,7 +113,12 @@ class cHtmlChannelList: public cChannelList std::string ItemText(); std::string PageBottom(); public: - virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: text/html\r\n\r\n"; } + virtual std::string HttpHeader() { + return cChannelList::HttpHeader() + + "Content-type: text/html; charset=" + + (cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8") + + "\r\n"; + } virtual bool HasNext(); virtual std::string Next(); cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget); @@ -128,7 +133,7 @@ class cM3uChannelList: public cChannelList eM3uState m3uState; cCharSetConv m_IConv; public: - virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl\r\n"; }; + virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl; charset=UTF-8\r\n"; }; virtual bool HasNext(); virtual std::string Next(); cM3uChannelList(cChannelIterator *Iterator, const char* Base); diff --git a/po/de_DE.po b/server/po/de_DE.po similarity index 72% rename from po/de_DE.po rename to server/po/de_DE.po index 82fa808..5fb611d 100644 --- a/po/de_DE.po +++ b/server/po/de_DE.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: streamdev 0.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"POT-Creation-Date: 2010-06-14 13:06+0200\n" "PO-Revision-Date: 2008-03-30 02:11+0200\n" "Last-Translator: Frank Schmirler \n" "Language-Team: \n" @@ -15,42 +15,6 @@ msgstr "" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" -msgid "VTP Streaming Client" -msgstr "VTP Streaming Client" - -msgid "Suspend Server" -msgstr "Server pausieren" - -msgid "Server is suspended" -msgstr "Server ist pausiert" - -msgid "Couldn't suspend Server!" -msgstr "Konnte Server nicht pausieren!" - -msgid "Hide Mainmenu Entry" -msgstr "Hauptmeneintrag verstecken" - -msgid "Start Client" -msgstr "Client starten" - -msgid "Remote IP" -msgstr "IP der Gegenseite" - -msgid "Remote Port" -msgstr "Port der Gegenseite" - -msgid "Filter Streaming" -msgstr "Filter-Daten streamen" - -msgid "Synchronize EPG" -msgstr "EPG synchronisieren" - -msgid "Minimum Priority" -msgstr "Minimale Prioritt" - -msgid "Maximum Priority" -msgstr "Maximale Prioritt" - msgid "VDR Streaming Server" msgstr "VDR Streaming Server" @@ -60,6 +24,15 @@ msgstr "Streamen im Gange" msgid "Suspend Live TV" msgstr "Live-TV pausieren" +msgid "Offer suspend mode" +msgstr "Pausieren anbieten" + +msgid "Always suspended" +msgstr "Immer pausiert" + +msgid "Never suspended" +msgstr "Nie pausiert" + msgid "Common Settings" msgstr "Allgemeines" @@ -108,11 +81,3 @@ msgstr "Port des Multicast Clients" msgid "Multicast Streamtype" msgstr "Multicast Streamtyp" -msgid "Offer suspend mode" -msgstr "Pausieren anbieten" - -msgid "Always suspended" -msgstr "Immer pausiert" - -msgid "Never suspended" -msgstr "Nie pausiert" diff --git a/po/fi_FI.po b/server/po/fi_FI.po similarity index 69% rename from po/fi_FI.po rename to server/po/fi_FI.po index 259ef05..99c6ee5 100644 --- a/po/fi_FI.po +++ b/server/po/fi_FI.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: streamdev 0.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"POT-Creation-Date: 2010-06-14 13:06+0200\n" "PO-Revision-Date: 2008-03-30 02:11+0200\n" "Last-Translator: Rolf Ahrenberg \n" "Language-Team: \n" @@ -15,42 +15,6 @@ msgstr "" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" -msgid "VTP Streaming Client" -msgstr "VTP-suoratoistoasiakas" - -msgid "Suspend Server" -msgstr "Pysyt palvelin" - -msgid "Server is suspended" -msgstr "Palvelin on pysytetty" - -msgid "Couldn't suspend Server!" -msgstr "Palvelinta ei onnistuttu pysyttmn!" - -msgid "Hide Mainmenu Entry" -msgstr "Piilota valinta pvalikosta" - -msgid "Start Client" -msgstr "Kynnist VDR-asiakas" - -msgid "Remote IP" -msgstr "Etkoneen IP-osoite" - -msgid "Remote Port" -msgstr "Etkoneen portti" - -msgid "Filter Streaming" -msgstr "Suodatetun tiedon suoratoisto" - -msgid "Synchronize EPG" -msgstr "Pivit ohjelmaopas" - -msgid "Minimum Priority" -msgstr "Pienin prioriteetti" - -msgid "Maximum Priority" -msgstr "Suurin prioriteetti" - msgid "VDR Streaming Server" msgstr "VDR-suoratoistopalvelin" @@ -60,6 +24,15 @@ msgstr "Suoratoistopalvelin aktiivinen" msgid "Suspend Live TV" msgstr "Pysyt suora TV-lhetys" +msgid "Offer suspend mode" +msgstr "tyrkyt" + +msgid "Always suspended" +msgstr "aina" + +msgid "Never suspended" +msgstr "ei koskaan" + msgid "Common Settings" msgstr "Yleiset asetukset" @@ -97,22 +70,14 @@ msgid "HTTP Streamtype" msgstr "HTTP-lhetysmuoto" msgid "Multicast Streaming Server" -msgstr "" +msgstr "Multicast-suoratoistopalvelin" msgid "Start IGMP Server" -msgstr "" +msgstr "Kynnist IGMP-palvelin" msgid "Multicast Client Port" -msgstr "" +msgstr "Multicast-portti" msgid "Multicast Streamtype" -msgstr "" +msgstr "Multicast-lhetysmuoto" -msgid "Offer suspend mode" -msgstr "tyrkyt" - -msgid "Always suspended" -msgstr "aina" - -msgid "Never suspended" -msgstr "ei koskaan" diff --git a/po/fr_FR.po b/server/po/fr_FR.po similarity index 72% rename from po/fr_FR.po rename to server/po/fr_FR.po index 3ba78c0..c4b458e 100644 --- a/po/fr_FR.po +++ b/server/po/fr_FR.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: streamdev 0.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"POT-Creation-Date: 2010-06-14 13:06+0200\n" "PO-Revision-Date: 2008-03-30 02:11+0200\n" "Last-Translator: micky979 \n" "Language-Team: \n" @@ -15,42 +15,6 @@ msgstr "" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" -msgid "VTP Streaming Client" -msgstr "Client de streaming VTP" - -msgid "Suspend Server" -msgstr "Suspendre le serveur" - -msgid "Server is suspended" -msgstr "Le serveur est suspendu" - -msgid "Couldn't suspend Server!" -msgstr "Impossible de suspendre le serveur!" - -msgid "Hide Mainmenu Entry" -msgstr "Masquer dans le menu principal" - -msgid "Start Client" -msgstr "Dmarrage du client" - -msgid "Remote IP" -msgstr "Adresse IP du serveur" - -msgid "Remote Port" -msgstr "Port du serveur" - -msgid "Filter Streaming" -msgstr "Filtre streaming" - -msgid "Synchronize EPG" -msgstr "Synchroniser l'EPG" - -msgid "Minimum Priority" -msgstr "" - -msgid "Maximum Priority" -msgstr "" - msgid "VDR Streaming Server" msgstr "Serveur de streaming VDR" @@ -60,6 +24,15 @@ msgstr "Streaming actif" msgid "Suspend Live TV" msgstr "Suspendre Live TV" +msgid "Offer suspend mode" +msgstr "Offrir le mode suspendre" + +msgid "Always suspended" +msgstr "Toujours suspendre" + +msgid "Never suspended" +msgstr "Jamais suspendre" + msgid "Common Settings" msgstr "Paramtres communs" @@ -108,11 +81,3 @@ msgstr "" msgid "Multicast Streamtype" msgstr "" -msgid "Offer suspend mode" -msgstr "Offrir le mode suspendre" - -msgid "Always suspended" -msgstr "Toujours suspendre" - -msgid "Never suspended" -msgstr "Jamais suspendre" diff --git a/po/it_IT.po b/server/po/it_IT.po old mode 100755 new mode 100644 similarity index 73% rename from po/it_IT.po rename to server/po/it_IT.po index 4db80ed..d51f62a --- a/po/it_IT.po +++ b/server/po/it_IT.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: streamdev 0.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"POT-Creation-Date: 2010-06-14 13:06+0200\n" "PO-Revision-Date: 2008-04-13 23:42+0100\n" "Last-Translator: Diego Pierotto \n" "Language-Team: \n" @@ -17,42 +17,6 @@ msgstr "" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" -msgid "VTP Streaming Client" -msgstr "Client trasmissione VTP" - -msgid "Suspend Server" -msgstr "Sospendi Server" - -msgid "Server is suspended" -msgstr "Server sospeso" - -msgid "Couldn't suspend Server!" -msgstr "Impossibile sospendere il server!" - -msgid "Hide Mainmenu Entry" -msgstr "Nascondi voce menu principale" - -msgid "Start Client" -msgstr "Avvia Client" - -msgid "Remote IP" -msgstr "Indirizzo IP del Server" - -msgid "Remote Port" -msgstr "Porta Server Remoto" - -msgid "Filter Streaming" -msgstr "Filtra trasmissione" - -msgid "Synchronize EPG" -msgstr "Sincronizza EPG" - -msgid "Minimum Priority" -msgstr "" - -msgid "Maximum Priority" -msgstr "" - msgid "VDR Streaming Server" msgstr "Server trasmissione VDR" @@ -62,6 +26,15 @@ msgstr "Trasmissione attiva" msgid "Suspend Live TV" msgstr "Sospendi TV dal vivo" +msgid "Offer suspend mode" +msgstr "Offri mod. sospensione" + +msgid "Always suspended" +msgstr "Sempre sospeso" + +msgid "Never suspended" +msgstr "Mai sospeso" + msgid "Common Settings" msgstr "Impostazioni comuni" @@ -110,11 +83,3 @@ msgstr "" msgid "Multicast Streamtype" msgstr "" -msgid "Offer suspend mode" -msgstr "Offri mod. sospensione" - -msgid "Always suspended" -msgstr "Sempre sospeso" - -msgid "Never suspended" -msgstr "Mai sospeso" diff --git a/server/po/lt_LT.po b/server/po/lt_LT.po new file mode 100644 index 0000000..f12de4d --- /dev/null +++ b/server/po/lt_LT.po @@ -0,0 +1,83 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Frank Schmirler , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:06+0200\n" +"PO-Revision-Date: 2009-11-26 21:57+0200\n" +"Last-Translator: Valdemaras Pipiras \n" +"Language-Team: Lietuvių\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VDR Streaming Server" +msgstr "VDR transliavimo serveris" + +msgid "Streaming active" +msgstr "Transliavimas vyksta" + +msgid "Suspend Live TV" +msgstr "Pristabdyti Live TV" + +msgid "Offer suspend mode" +msgstr "Klausti dėl sustabdymo" + +msgid "Always suspended" +msgstr "Visada stabdyti" + +msgid "Never suspended" +msgstr "Niekada nestabdyti" + +msgid "Common Settings" +msgstr "Bendri nustatymai" + +msgid "Maximum Number of Clients" +msgstr "Maksimalus klientų skaičius" + +msgid "Suspend behaviour" +msgstr "Pristabdyti veikimą" + +msgid "Client may suspend" +msgstr "Klientas gali pristabdyti" + +msgid "VDR-to-VDR Server" +msgstr "VDR-su-VDR Serveris" + +msgid "Start VDR-to-VDR Server" +msgstr "Paleisti VDR-su-VDR serverį" + +msgid "VDR-to-VDR Server Port" +msgstr "VDR-su-VDR Serverio portas" + +msgid "Bind to IP" +msgstr "Pririšti IP" + +msgid "HTTP Server" +msgstr "HTTP Serveris" + +msgid "Start HTTP Server" +msgstr "Paleisti HTTP serverį" + +msgid "HTTP Server Port" +msgstr "HTTP serverio portas" + +msgid "HTTP Streamtype" +msgstr "HTTP transliavimo tipas" + +msgid "Multicast Streaming Server" +msgstr "Multicast transliavimo serveris" + +msgid "Start IGMP Server" +msgstr "Paleisti IGMP serverį" + +msgid "Multicast Client Port" +msgstr "Multicast kliento portas" + +msgid "Multicast Streamtype" +msgstr "Multicast transliavimo tipas" + diff --git a/po/ru_RU.po b/server/po/ru_RU.po similarity index 73% rename from po/ru_RU.po rename to server/po/ru_RU.po index b80fcd3..21abeaf 100644 --- a/po/ru_RU.po +++ b/server/po/ru_RU.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: streamdev 0.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"POT-Creation-Date: 2010-06-14 13:06+0200\n" "PO-Revision-Date: 2008-06-26 15:36+0100\n" "Last-Translator: Oleg Roitburd \n" "Language-Team: \n" @@ -15,42 +15,6 @@ msgstr "" "Content-Type: text/plain; charset=ISO-8859-5\n" "Content-Transfer-Encoding: 8bit\n" -msgid "VTP Streaming Client" -msgstr "VTP Streaming " - -msgid "Suspend Server" -msgstr " " - -msgid "Server is suspended" -msgstr " " - -msgid "Couldn't suspend Server!" -msgstr " " - -msgid "Hide Mainmenu Entry" -msgstr " " - -msgid "Start Client" -msgstr " " - -msgid "Remote IP" -msgstr " IP" - -msgid "Remote Port" -msgstr " " - -msgid "Filter Streaming" -msgstr " " - -msgid "Synchronize EPG" -msgstr " EPG" - -msgid "Minimum Priority" -msgstr "" - -msgid "Maximum Priority" -msgstr "" - msgid "VDR Streaming Server" msgstr "VDR Streaming " @@ -60,6 +24,15 @@ msgstr " msgid "Suspend Live TV" msgstr " Live TV" +msgid "Offer suspend mode" +msgstr " " + +msgid "Always suspended" +msgstr " " + +msgid "Never suspended" +msgstr " " + msgid "Common Settings" msgstr "" @@ -108,11 +81,3 @@ msgstr "" msgid "Multicast Streamtype" msgstr "" -msgid "Offer suspend mode" -msgstr " " - -msgid "Always suspended" -msgstr " " - -msgid "Never suspended" -msgstr " " diff --git a/server/po/sk_SK.po b/server/po/sk_SK.po new file mode 100644 index 0000000..78d98c9 --- /dev/null +++ b/server/po/sk_SK.po @@ -0,0 +1,85 @@ +# VDR streamdev plugin language source file. +# Copyright (C) 2009 streamdev development team. See http://streamdev.vdr-developer.org +# This file is distributed under the same license as the VDR streamdev package. +# Milan Hrala , 2009 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev_SK\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-06-14 13:06+0200\n" +"PO-Revision-Date: \n" +"Last-Translator: Milan Hrala \n" +"Language-Team: Slovak \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-2\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Slovak\n" +"X-Poedit-Country: SLOVAKIA\n" + +msgid "VDR Streaming Server" +msgstr "VDR prdov server" + +msgid "Streaming active" +msgstr "streamovanie aktivne" + +msgid "Suspend Live TV" +msgstr "Pozastavenie ivho vysielania" + +msgid "Offer suspend mode" +msgstr "Vber remu pozastavenia" + +msgid "Always suspended" +msgstr "Vdy pozastavi" + +msgid "Never suspended" +msgstr "Nikdy nepozastavi" + +msgid "Common Settings" +msgstr "Veobecn nastavenia" + +msgid "Maximum Number of Clients" +msgstr "Maximly poet klientov" + +msgid "Suspend behaviour" +msgstr "Sprvanie preruenia" + +msgid "Client may suspend" +msgstr "Klient me pozastavi" + +msgid "VDR-to-VDR Server" +msgstr "VDR-do-VDR server" + +msgid "Start VDR-to-VDR Server" +msgstr "Spusti VDR-do-VDR Server" + +msgid "VDR-to-VDR Server Port" +msgstr "Port serveru pre VDR-do-VDR" + +msgid "Bind to IP" +msgstr "viaza na IP" + +msgid "HTTP Server" +msgstr "server HTTP" + +msgid "Start HTTP Server" +msgstr "Spusti HTTP Server" + +msgid "HTTP Server Port" +msgstr "Port serveru HTTP" + +msgid "HTTP Streamtype" +msgstr "typ prdu HTTP" + +msgid "Multicast Streaming Server" +msgstr "Multicast prdov server" + +msgid "Start IGMP Server" +msgstr "Spusti IGMP Server" + +msgid "Multicast Client Port" +msgstr "Port klienta Multicast" + +msgid "Multicast Streamtype" +msgstr "Multicast typ streamu" + diff --git a/server/recplayer.c b/server/recplayer.c index f45d8c3..384ac13 100644 --- a/server/recplayer.c +++ b/server/recplayer.c @@ -21,6 +21,9 @@ #include "recplayer.h" +// for TSPLAY patch detection +#include "vdr/device.h" + #define _XOPEN_SOURCE 600 #include @@ -34,7 +37,7 @@ RecPlayer::RecPlayer(cRecording* rec) // FIXME find out max file path / name lengths -#if VDRVERSNUM >= 10703 +#if VDRVERSNUM >= 10703 || defined(TSPLAY_PATCH_VERSION) indexFile = new cIndexFile(recording->FileName(), false, rec->IsPesRecording()); #else indexFile = new cIndexFile(recording->FileName(), false); @@ -58,7 +61,7 @@ void RecPlayer::scan() for(i = 1; i < 1000; i++) { -#if APIVERSNUM < 10703 +#if APIVERSNUM < 10703 || !defined(TSPLAY_PATCH_VERSION) snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i); //log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName); file = fopen(fileName, "r"); @@ -99,7 +102,7 @@ int RecPlayer::openFile(int index) char fileName[2048]; -#if APIVERSNUM >= 10703 +#if APIVERSNUM >= 10703 || defined(TSPLAY_PATCH_VERSION) snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), index); isyslog("openFile called for index %i string:%s", index, fileName); @@ -222,7 +225,7 @@ uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber) { if (!indexFile) return 0; -#if VDRVERSNUM >= 10703 +#if VDRVERSNUM >= 10703 || defined(TSPLAY_PATCH_VERSION) uint16_t retFileNumber; off_t retFileOffset; #else diff --git a/server/setup.c b/server/setup.c index 710b1fa..986f876 100644 --- a/server/setup.c +++ b/server/setup.c @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.6 2009/02/13 10:39:22 schmirl Exp $ + * $Id: setup.c,v 1.9.2.2 2010/06/18 19:07:32 schmirl Exp $ */ #include @@ -45,35 +45,72 @@ bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) { return true; } +const char* cStreamdevServerMenuSetupPage::StreamTypes[st_Count - 1] = { + "TS", + "PES", + "PS", + "ES", + "EXT" +}; + +const char* cStreamdevServerMenuSetupPage::SuspendModes[sm_Count] = { + trNOOP("Offer suspend mode"), + trNOOP("Always suspended"), + trNOOP("Never suspended") +}; + cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) { m_NewSetup = StreamdevServerSetup; - AddCategory (tr("Common Settings")); - AddRangeEdit(tr("Maximum Number of Clients"), m_NewSetup.MaxClients, 0, 100); - AddSuspEdit (tr("Suspend behaviour"), m_NewSetup.SuspendMode); - AddBoolEdit (tr("Client may suspend"), m_NewSetup.AllowSuspend); - - AddCategory (tr("VDR-to-VDR Server")); - AddBoolEdit (tr("Start VDR-to-VDR Server"), m_NewSetup.StartVTPServer); - AddShortEdit(tr("VDR-to-VDR Server Port"), m_NewSetup.VTPServerPort); - AddIpEdit (tr("Bind to IP"), m_NewSetup.VTPBindIP); - - AddCategory (tr("HTTP Server")); - AddBoolEdit (tr("Start HTTP Server"), m_NewSetup.StartHTTPServer); - AddShortEdit(tr("HTTP Server Port"), m_NewSetup.HTTPServerPort); - AddTypeEdit (tr("HTTP Streamtype"), m_NewSetup.HTTPStreamType); - AddIpEdit (tr("Bind to IP"), m_NewSetup.HTTPBindIP); - AddCategory (tr("Multicast Streaming Server")); - AddBoolEdit (tr("Start IGMP Server"), m_NewSetup.StartIGMPServer); - AddShortEdit(tr("Multicast Client Port"), m_NewSetup.IGMPClientPort); - AddTypeEdit (tr("Multicast Streamtype"), m_NewSetup.IGMPStreamType); - AddIpEdit (tr("Bind to IP"), m_NewSetup.IGMPBindIP); - SetCurrent(Get(1)); + Set(); } cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() { } +void cStreamdevServerMenuSetupPage::Set(void) { + static const char* modes[sm_Count]; + for (int i = 0; i < sm_Count; i++) + modes[i] = tr(SuspendModes[i]); + + int current = Current(); + Clear(); + AddCategory (tr("Common Settings")); + Add(new cMenuEditIntItem (tr("Maximum Number of Clients"), &m_NewSetup.MaxClients, 0, 100)); + + Add(new cMenuEditStraItem(tr("Suspend behaviour"), &m_NewSetup.SuspendMode, sm_Count, modes)); + if (m_NewSetup.SuspendMode == smOffer) + Add(new cMenuEditBoolItem(tr("Client may suspend"), &m_NewSetup.AllowSuspend)); + + AddCategory (tr("VDR-to-VDR Server")); + Add(new cMenuEditBoolItem(tr("Start VDR-to-VDR Server"), &m_NewSetup.StartVTPServer)); + Add(new cMenuEditIntItem (tr("VDR-to-VDR Server Port"), &m_NewSetup.VTPServerPort, 0, 65535)); + Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.VTPBindIP)); + + AddCategory (tr("HTTP Server")); + Add(new cMenuEditBoolItem(tr("Start HTTP Server"), &m_NewSetup.StartHTTPServer)); + Add(new cMenuEditIntItem (tr("HTTP Server Port"), &m_NewSetup.HTTPServerPort, 0, 65535)); + Add(new cMenuEditStraItem(tr("HTTP Streamtype"), &m_NewSetup.HTTPStreamType, st_Count - 1, StreamTypes)); + Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.HTTPBindIP)); + AddCategory (tr("Multicast Streaming Server")); + Add(new cMenuEditBoolItem(tr("Start IGMP Server"), &m_NewSetup.StartIGMPServer)); + Add(new cMenuEditIntItem (tr("Multicast Client Port"), &m_NewSetup.IGMPClientPort, 0, 65535)); + Add(new cMenuEditStraItem(tr("Multicast Streamtype"), &m_NewSetup.IGMPStreamType, st_Count - 1, StreamTypes)); + Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.IGMPBindIP)); + SetCurrent(Get(current)); + Display(); +} + +void cStreamdevServerMenuSetupPage::AddCategory(const char *Title) { + + cString str = cString::sprintf("--- %s -------------------------------------------------" + "---------------", Title ); + + cOsdItem *item = new cOsdItem(*str); + item->SetSelectable(false); + Add(item); +} + void cStreamdevServerMenuSetupPage::Store(void) { bool restart = false; if (m_NewSetup.StartVTPServer != StreamdevServerSetup.StartVTPServer @@ -110,3 +147,10 @@ void cStreamdevServerMenuSetupPage::Store(void) { cStreamdevServer::Initialize(); } +eOSState cStreamdevServerMenuSetupPage::ProcessKey(eKeys Key) { + int oldMode = m_NewSetup.SuspendMode; + eOSState state = cMenuSetupPage::ProcessKey(Key); + if (oldMode != m_NewSetup.SuspendMode) + Set(); + return state; +} diff --git a/server/setup.h b/server/setup.h index d2b1592..f71162f 100644 --- a/server/setup.h +++ b/server/setup.h @@ -1,5 +1,5 @@ /* - * $Id: setup.h,v 1.2 2009/02/13 10:39:22 schmirl Exp $ + * $Id: setup.h,v 1.3.2.1 2010/06/18 19:07:32 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SETUPSERVER_H @@ -30,12 +30,17 @@ struct cStreamdevServerSetup { extern cStreamdevServerSetup StreamdevServerSetup; -class cStreamdevServerMenuSetupPage: public cStreamdevMenuSetupPage { +class cStreamdevServerMenuSetupPage: public cMenuSetupPage { private: + static const char* StreamTypes[]; + static const char* SuspendModes[]; cStreamdevServerSetup m_NewSetup; + void AddCategory(const char *Title); + void Set(); protected: virtual void Store(void); + virtual eOSState ProcessKey(eKeys Key); public: cStreamdevServerMenuSetupPage(void); diff --git a/streamdev-server.c b/server/streamdev-server.c similarity index 98% rename from streamdev-server.c rename to server/streamdev-server.c index 3593d9f..8e9f979 100644 --- a/streamdev-server.c +++ b/server/streamdev-server.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: streamdev-server.c,v 1.12 2009/06/19 06:32:38 schmirl Exp $ + * $Id: streamdev-server.c,v 1.1.2.1 2010/06/14 10:40:20 schmirl Exp $ */ #include diff --git a/streamdev-server.h b/server/streamdev-server.h similarity index 91% rename from streamdev-server.h rename to server/streamdev-server.h index 8149e4b..1224ecf 100644 --- a/streamdev-server.h +++ b/server/streamdev-server.h @@ -1,5 +1,5 @@ /* - * $Id: streamdev-server.h,v 1.4 2007/02/19 12:08:16 schmirl Exp $ + * $Id: streamdev-server.h,v 1.1.2.1 2010/06/14 10:40:20 schmirl Exp $ */ #ifndef VDR_STREAMDEVSERVER_H diff --git a/server/streamer.c b/server/streamer.c index 42e7efa..b545b21 100644 --- a/server/streamer.c +++ b/server/streamer.c @@ -1,5 +1,5 @@ /* - * $Id: streamer.c,v 1.19 2009/06/19 06:32:45 schmirl Exp $ + * $Id: streamer.c,v 1.19.2.1 2010/06/11 06:06:03 schmirl Exp $ */ #include @@ -100,8 +100,9 @@ void cStreamdevWriter::Action(void) // --- cStreamdevStreamer ----------------------------------------------------- -cStreamdevStreamer::cStreamdevStreamer(const char *Name): +cStreamdevStreamer::cStreamdevStreamer(const char *Name, const cServerConnection *Connection): cThread(Name), + m_Connection(Connection), m_Writer(NULL), m_RingBuffer(new cStreamdevBuffer(STREAMERBUFSIZE, TS_SIZE * 2, true, "streamdev-streamer")), diff --git a/server/streamer.h b/server/streamer.h index 6561bc2..d3ddd23 100644 --- a/server/streamer.h +++ b/server/streamer.h @@ -1,5 +1,5 @@ /* - * $Id: streamer.h,v 1.11 2009/06/19 06:32:45 schmirl Exp $ + * $Id: streamer.h,v 1.11.2.1 2010/06/11 06:06:03 schmirl Exp $ */ #ifndef VDR_STREAMDEV_STREAMER_H @@ -11,6 +11,7 @@ class cTBSocket; class cStreamdevStreamer; +class cServerConnection; #ifndef TS_SIZE #define TS_SIZE 188 @@ -64,6 +65,7 @@ public: class cStreamdevStreamer: public cThread { private: + const cServerConnection *m_Connection; cStreamdevWriter *m_Writer; cStreamdevBuffer *m_RingBuffer; cStreamdevBuffer *m_SendBuffer; @@ -74,9 +76,11 @@ protected: bool IsRunning(void) const { return m_Writer; } public: - cStreamdevStreamer(const char *Name); + cStreamdevStreamer(const char *Name, const cServerConnection *Connection = NULL); virtual ~cStreamdevStreamer(); + const cServerConnection* Connection(void) const { return m_Connection; } + virtual void Start(cTBSocket *Socket); virtual void Stop(void); bool Abort(void); diff --git a/streamdev-server/externremux.sh b/streamdev-server/externremux.sh new file mode 100755 index 0000000..553abf9 --- /dev/null +++ b/streamdev-server/externremux.sh @@ -0,0 +1,268 @@ +#!/bin/bash +# +# externremux.sh - sample remux script using mencoder for remuxing. +# +# Install this script as VDRCONFDIR/plugins/streamdev-server/externremux.sh +# +# The parameter QUALITY selects the default remux parameters. Adjust +# to your needs and point your web browser to http://servername:3000/ext/ +# To select different remux parameters on the fly, insert a semicolon +# followed by the name and value of the requested parameter, e.g: +# e.g. http://servername:3000/ext;QUALITY=WLAN11;VBR=512/ +# The following parameters are recognized: +# +# PROG actual remux program +# VC video codec +# VBR video bitrate (kbit) +# VOPTS custom video options +# WIDTH scale video to width +# AC audio codec +# ABR audio bitrate (kbit) +# AOPTS custom audio options +# + +########################################################################## + +### GENERAL CONFIG START +### +# Pick one of DSL1000/DSL2000/DSL3000/DSL6000/DSL16000/LAN10/WLAN11/WLAN54 +QUALITY='DSL1000' +# Program used for logging (logging disabled if empty) +LOGGER=logger +# Path and name of FIFO +FIFO=/tmp/externremux-${RANDOM:-$$} +# Default remux program (cat/mencoder/ogg) +PROG=mencoder +# Use mono if $ABR is lower than this value +ABR_MONO=64 +### +### GENERAL CONFIG END + +### MENCODER CONFIG START +### +# mencoder binary +MENCODER=mencoder +# Default video codec (e.g. lavc/x264/copy) +MENCODER_VC=lavc +# Default audio codec (e.g. lavc/mp3lame/faac/copy) +MENCODER_AC=mp3lame +# Default video codec if lavc is used (-ovc lavc -lavcopts vcodec=) +MENCODER_LAVC_VC=mpeg4 +# Default audio codec if lavc is used (-oac lavc -lavcopts acodec=) +MENCODER_LAVC_AC=mp2 +### +### MENCODER CONFIG END + +### OGG CONFIG START +### +# ffmpeg2theora binary +OGG=ffmpeg2theora +# speedlevel - lower value gives better quality but is slower (0..2) +OGG_SPEED=1 +# videoquality - higher value gives better quality but is slower (0..10) +OGG_VQUALITY=0 +# audioquality - higher value gives better quality but is slower (0..10) +OGG_AQUALITY=0 +### +### OGG CONFIG END + +########################################################################## + +function hasOpt { echo "$1" | grep -q "\b${2}\b"; } + +function isNumeric() { echo "$@" | grep -q '^[0-9]\{1,\}$'; } + +function remux_cat +{ + startReply + exec 3<&0 + cat 0<&3 >"$FIFO" & +} + +function remux_mencoder +{ + # lavc may be used for video and audio + LAVCOPTS=() + + # Assemble video options + VC=${REMUX_PARAM_VC:-$MENCODER_VC} + VOPTS=${REMUX_PARAM_VOPTS} + WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH} + case "$VC" in + lavc) + LAVCOPTS=( + ${VOPTS} + $(hasOpt "$VOPTS" vcodec || echo "vcodec=$MENCODER_LAVC_VC") + ${VBR:+vbitrate=$VBR} + ) + [ ${#LAVCOPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -lavcopts "${LAVCOPTS[*]}") + ;; + x264) + X264OPTS=( + ${VOPTS} + $(hasOpt "$VOPTS" threads || echo "threads=auto") + ${VBR:+bitrate=$ABR} + ) + [ ${#X264OPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -x264encopts "${X264OPTS[*]}") + ;; + copy) + VOPTS= + ;; + *) + error "Unknown video codec '$VC'" + ;; + esac + + # Assemble audio options + AC=${REMUX_PARAM_AC:-$MENCODER_AC} + AOPTS=${REMUX_PARAM_AOPTS} + case "$AC" in + lavc) + LAVCOPTS=( + ${LAVCOPTS[*]} + ${AOPTS} + $(hasOpt "$AOPTS" acodec || echo "acodec=$MENCODER_LAVC_AC") + ${ABR:+abitrate=$ABR} + ) + + [ ${#LAVCOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -lavcopts "${LAVCOPTS[*]}") + # lavc used for video and audio decoding - wipe out VOPTS as video options became part of AOPTS + [ "$VC" = lavc ] && VOPTS= + ;; + mp3lame) + LAMEOPTS=( + ${AOPTS} + $(isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" mode ] && echo 'mode=3') + ${ABR:+preset=$ABR} + ) + [ ${#LAMEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -lameopts "${LAMEOPTS[*]}") + ;; + faac) + FAACOPTS=( + ${AOPTS} + ${ABR:+br=$ABR} + ) + [ ${#FAACOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -faacopts "${FAACOPTS[*]}") + ;; + copy) + AOPTS= + ;; + *) + error "Unknown audio codec '$AC'" + ;; + esac + + + startReply + exec 3<&0 + echo "$MENCODER" \ + -ovc $VC $VOPTS \ + -oac $AC $AOPTS \ + ${WIDTH:+-vf scale -zoom -xy $WIDTH} \ + -o "$FIFO" -- - >&2 + "$MENCODER" \ + -ovc $VC $VOPTS \ + -oac $AC $AOPTS \ + ${WIDTH:+-vf scale -zoom -xy $WIDTH} \ + -o "$FIFO" -- - 0<&3 >/dev/null & +} + +function remux_ogg +{ + VOPTS=${REMUX_PARAM_VOPTS//[:=]/ } + AOPTS=${REMUX_PARAM_AOPTS//[:=]/ } + WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH} + + OGGOPTS=( + ${VOPTS} + ${VBR:+--videobitrate $VBR} + $(hasOpt "${VOPTS}" videoquality || echo "--videoquality $OGG_VQUALITY") + $(hasOpt "${VOPTS}" speedlevel || echo "--speedlevel $OGG_SPEED") + ${AOPTS} + ${ABR:+--audiobitrate $ABR} + $(isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" channels ] && echo '--channels 1') + $(hasOpt "${AOPTS}" audioquality || echo "--audioquality $OGG_AQUALITY") + $(hasOpt "${AOPTS}" audiostream || echo '--audiostream 1') + ) + + startReply + exec 3<&0 + echo "$OGG" --format ts \ + ${OGGOPTS[*]} \ + ${WIDTH:+--width $WIDTH --height $(($WIDTH * 3 / 4 / 8 * 8))} \ + --title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \ + --output "$FIFO" -- - 0<&3 >&2 + "$OGG" --format ts \ + ${OGGOPTS[*]} \ + ${WIDTH:+--width $WIDTH --height $(($WIDTH * 3 / 4 / 8 * 8))} \ + --title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \ + --output "$FIFO" -- - 0<&3 >/dev/null & +} + +function error +{ + if [ "$SERVER_PROTOCOL" = HTTP ]; then + echo -ne "Content-type: text/plain\r\n" + echo -ne '\r\n' + echo "$*" + fi + + echo "$*" >&2 + exit 1 +} + +function startReply +{ + if [ "$SERVER_PROTOCOL" = HTTP ]; then + # send content-type and custom headers + echo -ne "Content-type: ${CONTENTTYPE}\r\n" + for header in "${HEADER[@]}"; do echo -ne "$header\r\n"; done + echo -ne '\r\n' + + # abort after headers + [ "$REQUEST_METHOD" = HEAD ] && exit 0 + fi + + # create FIFO and read from it in the background + mkfifo "$FIFO" + trap "kill 0; sleep 1; rm '$FIFO'; trap - EXIT HUP INT TERM ABRT PIPE CHLD" EXIT HUP INT TERM ABRT PIPE CHLD + cat "$FIFO" <&- & +} + +HEADER=() + +set > /tmp/env +[ "$LOGGER" ] && exec 2> >($LOGGER -t "vdr: [$$] streamdev EXT" 2>&-) + +# set default content-types +case "$REMUX_VPID" in + ''|0|1) CONTENTTYPE='audio/mpeg';; + *) CONTENTTYPE='video/mpeg';; +esac + +QUALITY=${REMUX_PARAM_QUALITY:-$QUALITY} +case "$QUALITY" in + DSL1000) VBR=96; ABR=16; WIDTH=160;; + DSL2000) VBR=128; ABR=16; WIDTH=160;; + DSL3000) VBR=256; ABR=16; WIDTH=320;; + DSL6000) VBR=378; ABR=32; WIDTH=320;; + DSL16000) VBR=512; ABR=32; WIDTH=480;; + WLAN11) VBR=768; ABR=64; WIDTH=640;; + WLAN45) VBR=2048; ABR=128; WIDTH=;; + LAN10) VBR=4096; ABR=; WIDTH=;; + *) error "Unknown quality '$QUALITY'";; +esac +ABR=${REMUX_PARAM_ABR:-$ABR} +VBR=${REMUX_PARAM_VBR:-$VBR} +WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH} +PROG=${REMUX_PARAM_PROG:-$PROG} + +case "$PROG" in + cat) remux_cat;; + mencoder) remux_mencoder;; + ogg) remux_ogg;; + *) error "Unknown remuxer '$PROG'";; +esac + +set -o monitor +wait diff --git a/streamdev/streamdevhosts.conf b/streamdev-server/streamdevhosts.conf similarity index 85% rename from streamdev/streamdevhosts.conf rename to streamdev-server/streamdevhosts.conf index 49882a2..7243eeb 100644 --- a/streamdev/streamdevhosts.conf +++ b/streamdev-server/streamdevhosts.conf @@ -11,4 +11,4 @@ #192.168.100.0/24 # any host on the local net #204.152.189.113 # a specific host #239.255.0.0/16 # uncomment for IGMP multicast streaming -#0.0.0.0/0 # any host on any net (USE THIS WITH CARE!) +#0.0.0.0/0 # any host on any net (DON'T DO THAT! USE AUTHENTICATION) diff --git a/streamdev/externremux.sh b/streamdev/externremux.sh deleted file mode 100755 index e2b4156..0000000 --- a/streamdev/externremux.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# -# externremux.sh - sample remux script using mencoder for remuxing. -# -# Install this script as VDRCONFDIR/plugins/streamdev/externremux.sh -# -# The parameter STREAMQUALITY selects the default remux parameters. Adjust -# to your needs and point your web browser to http://servername:3000/extern/ -# To select different remux parameters on the fly, insert a semicolon and -# the name of the requested quality: http://servername:3000/extern;WLAN11/ - -# CONFIG START - STREAMQUALITY="DSL6000" # DSL{1,2,3,6}000, LAN10, WLAN{11,54}, IPAQ - TMP=/tmp/externremux-${RANDOM:-$$} - MENCODER=mencoder -# CONFIG END - -mkdir -p $TMP -mkfifo $TMP/out.avi -(trap "rm -rf $TMP" EXIT HUP INT TERM ABRT; cat $TMP/out.avi) & - -case ${1:-$STREAMQUALITY} in - DSL1000) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=100 \ - -oac mp3lame -lameopts preset=15:mode=3 -vf scale=160:104 \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - DSL2000) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=128 \ - -oac mp3lame -lameopts preset=15:mode=3 -vf scale=160:104 \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - DSL3000) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=250 \ - -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:208 \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - DSL6000) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=350 \ - -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:208 \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - LAN10) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=4096 \ - -oac mp3lame -lameopts preset=standard \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - WLAN11) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=768 \ - -oac mp3lame -lameopts preset=standard -vf scale=640:408 \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - WLAN54) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2048 \ - -oac mp3lame -lameopts preset=standard \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - IPAQ) exec $MENCODER -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=350 \ - -oac mp3lame -lameopts preset=15:mode=3 -vf scale=320:208 \ - -o $TMP/out.avi -- - &>$TMP/out.log ;; - *) touch $TMP/out.avi ;; -esac diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..f5673db --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,34 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.1.2.1 2010/06/14 10:40:31 schmirl Exp $ + +### The object files (add further files here): + +OBJS = select.o socket.o source.o tools.o + +### The main target: + +.PHONY: clean +sockettools.a: $(OBJS) + ar -rcs sockettools.a $(OBJS) + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies + +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.a core* *~ diff --git a/tools/socket.c b/tools/socket.c index 3523c29..5dde45a 100644 --- a/tools/socket.c +++ b/tools/socket.c @@ -124,6 +124,10 @@ bool cTBSocket::Accept(const cTBSocket &Listener) { if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &addrlen) == -1) return false; + int sol=1; + // Ignore possible errors here, proceed as usual + ::setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &sol, sizeof(sol)); + if (!cTBSource::Open(socket)) return false;