mirror of
https://projects.vdr-developer.org/git/vdr-plugin-streamdev.git
synced 2023-10-10 19:16:51 +02:00
Snapshot 2009-06-11
This commit is contained in:
parent
31df0eaf8e
commit
7254a67528
41
CONTRIBUTORS
41
CONTRIBUTORS
@ -24,6 +24,12 @@ Rolf Ahrenberg
|
|||||||
for suggesting a fix of the Makefile's default target
|
for suggesting a fix of the Makefile's default target
|
||||||
for a TS PAT repacker based on Petri Laine's VDR TS recording patch
|
for a TS PAT repacker based on Petri Laine's VDR TS recording patch
|
||||||
for making it possible to pass parameters to externremux.sh
|
for making it possible to pass parameters to externremux.sh
|
||||||
|
for removing pre VDR 1.4 legacy code
|
||||||
|
for adding gettext support
|
||||||
|
for fixing output format of some debug messages
|
||||||
|
for replacing private members by cThread::Running()/Active()
|
||||||
|
for improving externremux script termination
|
||||||
|
for fixing PAT repacker version field
|
||||||
|
|
||||||
Rantanen Teemu
|
Rantanen Teemu
|
||||||
for providing vdr-incompletesections.diff
|
for providing vdr-incompletesections.diff
|
||||||
@ -42,6 +48,7 @@ Udo Richter
|
|||||||
for fixing streamdev-server shutdown
|
for fixing streamdev-server shutdown
|
||||||
for speeding up cPluginStreamdevServer::Active()
|
for speeding up cPluginStreamdevServer::Active()
|
||||||
for adapting to VDR 1.5.0 API
|
for adapting to VDR 1.5.0 API
|
||||||
|
for adapting to VDR 1.7.1
|
||||||
|
|
||||||
greenman
|
greenman
|
||||||
for reporting that the log could get flooded on connection failures.
|
for reporting that the log could get flooded on connection failures.
|
||||||
@ -70,3 +77,37 @@ Olli Lammi
|
|||||||
|
|
||||||
Joerg Pulz
|
Joerg Pulz
|
||||||
for his FreeBSD compatibility patch
|
for his FreeBSD compatibility patch
|
||||||
|
|
||||||
|
tobi
|
||||||
|
for pointing to unused files in the libdvbmpeg directory
|
||||||
|
|
||||||
|
Diego Pierotto
|
||||||
|
for providing italian language texts
|
||||||
|
|
||||||
|
micky979
|
||||||
|
for providing french language texts
|
||||||
|
|
||||||
|
Tiroler
|
||||||
|
for reporting a problem when switching between encrypted channels
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
wirbel
|
||||||
|
for pointing out that section filtering is optional for VDR devices
|
||||||
|
|
||||||
|
Jori Hamalainen
|
||||||
|
for extensive testing while making stream compatible to Network Media Tank
|
||||||
|
for adding Network Media Tank browser support to HTML pages
|
||||||
|
|
||||||
|
owagner
|
||||||
|
for pointing out a problem with the encrypted channel switching fix
|
||||||
|
|
||||||
|
Joachim König-Baltes
|
||||||
|
for fixing Min/MaxPriority parsing
|
||||||
|
|
||||||
|
Artem Makhutov
|
||||||
|
for suggesting and heavy testing IGMP based multicast streaming
|
||||||
|
53
HISTORY
53
HISTORY
@ -1,6 +1,59 @@
|
|||||||
VDR Plugin 'streamdev' Revision History
|
VDR Plugin 'streamdev' Revision History
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
- added missing call to StopSectionHandler which could cause crashes when
|
||||||
|
shutting down VDR
|
||||||
|
- added IGMP based multicast streaming
|
||||||
|
- ignore trailing blank lines in HTTP requests
|
||||||
|
- fixed parsing Min/MaxPriority from config (thanks to Joachim König-Baltes)
|
||||||
|
- updated Finnish translation (thanks to Rolf Ahrenberg)
|
||||||
|
- added Min/MaxPriority parameters. Can be used to keep client VDR from
|
||||||
|
using streamdev e.g. when recording
|
||||||
|
- disabled PES for VDR 1.7.3+
|
||||||
|
- added Network Media Tank browser support to HTML pages (thanks to Jori
|
||||||
|
Hamalainen)
|
||||||
|
- minor fixes of PAT repacker
|
||||||
|
- repack and send every PAT packet we receive
|
||||||
|
- fixed null pointer in server.c when cConnection::Accept() failes
|
||||||
|
- consider Pids from channels.conf when HTTP TS streaming. Section filtering
|
||||||
|
is an optional feature for VDR devices, so we must not rely on the PMT
|
||||||
|
alone (pointed out by wirbel@vdrportal)
|
||||||
|
- improved externremux script termination (thanks to Rolf Ahrenberg)
|
||||||
|
- use cThread::Running()/Active() instead of private members (thanks to
|
||||||
|
Rolf Ahrenberg)
|
||||||
|
- fixed output format of some debug messages (thanks to Rolf Ahrenberg)
|
||||||
|
- added HTTP authentication
|
||||||
|
- compatibility for VDR 1.7.1 (thanks to Udo Richter)
|
||||||
|
- added vdr-1.6.0-intcamdevices.patch (thanks to Anssi Hannula)
|
||||||
|
- fixed problem when switching from one encrypted channel to an other
|
||||||
|
(reported by Tiroler@vdrportal, initial bugfix by pixelpeter@vdrportal,
|
||||||
|
another fix by owagner@vdrportal)
|
||||||
|
- added preprocessor directive for ancient gcc
|
||||||
|
- added Russian translation (thanks to Oleg Roitburd)
|
||||||
|
- fixed assignment of externremux.sh's default location (reported by plautze)
|
||||||
|
- added French translation (thanks to micky979)
|
||||||
|
- added Italian translation (thanks to Diego Pierotto)
|
||||||
|
- added gettext support (thanks to Rolf Ahrenberg)
|
||||||
|
- added vdr-1.6.0-ignore_missing_cam patch
|
||||||
|
- dropped obsolete respect_ca patch
|
||||||
|
- removed legacy code for < VDR 1.5.9 (thanks to Rolf Ahrenberg)
|
||||||
|
|
||||||
|
2008-04-07: Branched v0_4
|
||||||
|
|
||||||
|
- changed location of streamdevhosts.conf to VDRCONFDIR/plugins/streamdev
|
||||||
|
- changed externremux.sh's default location to VDRCONFDIR/plugins/streamdev
|
||||||
|
- added sample externremux.sh from http://www.vdr-wiki.de/
|
||||||
|
- stop providing channels after client has been disabled at runtime
|
||||||
|
- added logging of the client device's card index
|
||||||
|
- changed default suspend mode to "Always suspended"
|
||||||
|
- added "Hide Mainmenu Entry" setup option on client
|
||||||
|
- resurrected clients "Suspend Server" menu item as its mainmenu entry
|
||||||
|
- dropped unused code for remote timers/recordings on client side
|
||||||
|
- dropped unused files client/{assembler,menu,remote}.[hc]
|
||||||
|
- dropped unused files in libdvbmpeg (reported by tobi)
|
||||||
|
- dropped patches for pre VDR 1.4
|
||||||
|
- removed legacy code for pre VDR 1.4 (thanks to Rolf Ahrenberg)
|
||||||
|
|
||||||
2008-03-31: Version 0.3.4
|
2008-03-31: Version 0.3.4
|
||||||
|
|
||||||
- added possibility to pass parameter to externremux.sh (thanks to Rolf
|
- added possibility to pass parameter to externremux.sh (thanks to Rolf
|
||||||
|
74
Makefile
74
Makefile
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Makefile for a Video Disk Recorder plugin
|
# Makefile for a Video Disk Recorder plugin
|
||||||
#
|
#
|
||||||
# $Id: Makefile,v 1.12 2008/03/31 10:34:26 schmirl Exp $
|
# $Id: Makefile,v 1.17 2009/02/13 10:39:20 schmirl Exp $
|
||||||
|
|
||||||
# The official name of this plugin.
|
# The official name of this plugin.
|
||||||
# This name will be used in the '-P...' option of VDR to load the plugin.
|
# This name will be used in the '-P...' option of VDR to load the plugin.
|
||||||
@ -16,11 +16,10 @@ VERSION = $(shell grep 'const char \*VERSION *=' common.c | awk '{ print $$5 }'
|
|||||||
### The C++ compiler and options:
|
### The C++ compiler and options:
|
||||||
|
|
||||||
CXX ?= g++
|
CXX ?= g++
|
||||||
CXXFLAGS ?= -fPIC -Wall -Woverloaded-virtual
|
CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
|
||||||
|
|
||||||
### The directory environment:
|
### The directory environment:
|
||||||
|
|
||||||
DVBDIR = ../../../../DVB
|
|
||||||
VDRDIR = ../../..
|
VDRDIR = ../../..
|
||||||
LIBDIR = ../../lib
|
LIBDIR = ../../lib
|
||||||
TMPDIR = /tmp
|
TMPDIR = /tmp
|
||||||
@ -40,55 +39,39 @@ PACKAGE = vdr-$(ARCHIVE)
|
|||||||
|
|
||||||
### Includes and Defines (add further entries here):
|
### Includes and Defines (add further entries here):
|
||||||
|
|
||||||
INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -I.
|
INCLUDES += -I$(VDRDIR)/include -I.
|
||||||
|
|
||||||
DEFINES += -D_GNU_SOURCE
|
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
|
||||||
|
|
||||||
### The object files (add further files here):
|
### The object files (add further files here):
|
||||||
|
|
||||||
COMMONOBJS = common.o i18n.o \
|
COMMONOBJS = common.o \
|
||||||
\
|
\
|
||||||
tools/source.o tools/select.o tools/socket.o tools/tools.o
|
tools/source.o tools/select.o tools/socket.o tools/tools.o
|
||||||
|
|
||||||
CLIENTOBJS = $(PLUGIN)-client.o \
|
CLIENTOBJS = $(PLUGIN)-client.o \
|
||||||
\
|
\
|
||||||
client/socket.o client/device.o client/setup.o \
|
client/socket.o client/device.o client/setup.o \
|
||||||
client/remote.o client/assembler.o client/filter.o
|
client/filter.o
|
||||||
|
|
||||||
|
|
||||||
SERVEROBJS = $(PLUGIN)-server.o \
|
SERVEROBJS = $(PLUGIN)-server.o \
|
||||||
\
|
\
|
||||||
server/server.o server/connectionVTP.o server/connectionHTTP.o \
|
server/server.o server/component.o server/connection.o \
|
||||||
server/componentHTTP.o server/componentVTP.o server/connection.o \
|
server/componentVTP.o server/componentHTTP.o server/componentIGMP.o \
|
||||||
server/component.o server/suspend.o server/setup.o server/streamer.o \
|
server/connectionVTP.o server/connectionHTTP.o server/connectionIGMP.o \
|
||||||
server/livestreamer.o server/livefilter.o server/menuHTTP.o \
|
server/streamer.o server/livestreamer.o server/livefilter.o \
|
||||||
\
|
server/suspend.o server/setup.o server/menuHTTP.o \
|
||||||
remux/tsremux.o remux/ts2ps.o remux/ts2es.o remux/extern.o
|
remux/tsremux.o remux/ts2ps.o remux/ts2es.o remux/extern.o
|
||||||
|
|
||||||
ifdef DEBUG
|
ifdef DEBUG
|
||||||
DEFINES += -DDEBUG
|
DEFINES += -DDEBUG
|
||||||
CXXFLAGS += -g
|
|
||||||
else
|
|
||||||
CXXFLAGS += -O2
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(shell test -f $(VDRDIR)/fontsym.h ; echo $$?),0)
|
|
||||||
DEFINES += -DHAVE_BEAUTYPATCH
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(shell test -f $(VDRDIR)/fontsym.c ; echo $$?),0)
|
|
||||||
DEFINES += -DHAVE_BEAUTYPATCH
|
|
||||||
endif
|
|
||||||
|
|
||||||
# HAVE_AUTOPID only applies if VDRVERSNUM < 10300
|
|
||||||
ifeq ($(shell test -f $(VDRDIR)/sections.c ; echo $$?),0)
|
|
||||||
DEFINES += -DHAVE_AUTOPID
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
### The main target:
|
### The main target:
|
||||||
|
|
||||||
.PHONY: all dist clean
|
.PHONY: all i18n dist clean
|
||||||
all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so
|
all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so i18n
|
||||||
|
|
||||||
### Implicit rules:
|
### Implicit rules:
|
||||||
|
|
||||||
@ -97,7 +80,7 @@ all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so
|
|||||||
|
|
||||||
# Dependencies:
|
# Dependencies:
|
||||||
|
|
||||||
MAKEDEP = g++ -MM -MG
|
MAKEDEP = $(CXX) -MM -MG
|
||||||
DEPFILE = .dependencies
|
DEPFILE = .dependencies
|
||||||
ifdef GCC3
|
ifdef GCC3
|
||||||
$(DEPFILE): Makefile
|
$(DEPFILE): Makefile
|
||||||
@ -113,12 +96,35 @@ endif
|
|||||||
|
|
||||||
-include $(DEPFILE)
|
-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='<http://www.vdr-developer.org/mantisbt/>' -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:
|
### Targets:
|
||||||
|
|
||||||
libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.cc libdvbmpeg/*.h libdvbmpeg/*.hh
|
libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.h
|
||||||
$(MAKE) -C ./libdvbmpeg libdvbmpegtools.a
|
$(MAKE) -C ./libdvbmpeg libdvbmpegtools.a
|
||||||
|
|
||||||
|
|
||||||
libvdr-$(PLUGIN)-client.so: $(CLIENTOBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a
|
libvdr-$(PLUGIN)-client.so: $(CLIENTOBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a
|
||||||
libvdr-$(PLUGIN)-server.so: $(SERVEROBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a
|
libvdr-$(PLUGIN)-server.so: $(SERVEROBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a
|
||||||
|
|
||||||
@ -135,5 +141,5 @@ dist: clean
|
|||||||
@echo Distribution package created as $(PACKAGE).tgz
|
@echo Distribution package created as $(PACKAGE).tgz
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@-rm -f $(COMMONOBJS) $(CLIENTOBJS) $(SERVEROBJS) $(DEPFILE) *.so *.tgz core* *~
|
@-rm -f $(COMMONOBJS) $(CLIENTOBJS) $(SERVEROBJS) $(DEPFILE) $(PODIR)/*.mo $(PODIR)/*.pot *.so *.tgz core* *~
|
||||||
$(MAKE) -C ./libdvbmpeg clean
|
$(MAKE) -C ./libdvbmpeg clean
|
||||||
|
225
README
225
README
@ -15,13 +15,18 @@ Contents:
|
|||||||
|
|
||||||
1. Description
|
1. Description
|
||||||
2. Installation
|
2. Installation
|
||||||
2.1 VDR 1.2.X
|
2.1 VDR 1.4.x and older
|
||||||
2.2 VDR 1.3.X and above
|
2.2 VDR 1.6.0 and above
|
||||||
|
2.3 Updating from streamdev 0.3.x
|
||||||
3. Usage
|
3. Usage
|
||||||
3.1 Usage HTTP server
|
3.1 Usage HTTP server
|
||||||
3.2 Usage VDR-to-VDR server
|
3.2 Usage IGMP multicast server
|
||||||
3.3 Usage VDR-to-VDR client
|
3.3 Usage VDR-to-VDR server
|
||||||
|
3.4 Usage VDR-to-VDR client
|
||||||
4. Other useful Plugins
|
4. Other useful Plugins
|
||||||
|
4.1 Plugins for VDR-to-VDR clients
|
||||||
|
4.2 Plugins for Server
|
||||||
|
4.3 Alternatives
|
||||||
5. Known Problems
|
5. Known Problems
|
||||||
|
|
||||||
|
|
||||||
@ -57,7 +62,7 @@ the PROTOCOL file.
|
|||||||
2. Installation:
|
2. Installation:
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
Let's say streamdev's version is 0.3.1 and vdr's version is 1.X.X. If you
|
Let's say streamdev's version is 0.4.0 and vdr's version is 1.X.X. If you
|
||||||
use anything else please exchange the version numbers appropriately (this
|
use anything else please exchange the version numbers appropriately (this
|
||||||
way I don't have to update this section all the times;) ).
|
way I don't have to update this section all the times;) ).
|
||||||
|
|
||||||
@ -68,48 +73,67 @@ command line.
|
|||||||
What's important is that the client requests a channel using its Unique Channel
|
What's important is that the client requests a channel using its Unique Channel
|
||||||
ID. So, in order to find the channel at the server, it must have the same ID
|
ID. So, in order to find the channel at the server, it must have the same ID
|
||||||
that is used on the client. You can achieve this by putting the server's
|
that is used on the client. You can achieve this by putting the server's
|
||||||
channels.conf on the client, preferably after scanning (in case you use 1.2.X
|
channels.conf on the client, preferably after scanning.
|
||||||
with AutoPID or 1.3.X).
|
|
||||||
|
|
||||||
If you want to drive additional Input-Devices (with different sources) on the
|
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
|
client, you can merge the channels.conf files. VDR will detect if the local
|
||||||
device or the network device can receive the channels.
|
device or the network device can receive the channels.
|
||||||
|
|
||||||
Last, but not least you have to put the provided streamdevhosts.conf.example
|
Last, but not least you have to copy the streamdev folder into the
|
||||||
into the "plugins" subfolder of your config-directory (which is equal to your
|
"plugins/streamdev" subfolder of VDR's config-directory (which is equal to your
|
||||||
video-directory if not specified otherwise), rename it to streamdevhosts.conf
|
video-directory if not specified otherwise). For example, if you didn't specify
|
||||||
and adjust it to your needs. The syntax is the same as for svdrphosts.conf, so
|
a separate config-directory, and specified your video directory as "/video0",
|
||||||
please consult VDR's documentation on how to fill that file, if you can't do
|
the directory has to be copied to /video0/plugins/streamdev.
|
||||||
it on-the-fly. For example, if you didn't specify a separate config-directory,
|
|
||||||
and specified your video directory as "/video0", the file has to be put to
|
The directory contains a file named streamdevhosts.conf which you must adjust
|
||||||
/video0/plugins/streamdevhosts.conf.
|
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
|
||||||
|
"-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.2.X:
|
2.1 VDR 1.4.x and older:
|
||||||
--------------
|
------------------------
|
||||||
|
|
||||||
It is recommended that you apply a patch to VDR that improves thread
|
This version is not compatible to VDR releases older than 1.5.9. Take one of
|
||||||
cancellation. You can work without it, but you _might_ have delays in switching
|
the streamdev-0.4.x releases if you are running at least VDR 1.4.x. For older
|
||||||
(especially when using VDR-to-VDR streaming) that are around three seconds.
|
VDRs you will probably need one of the streamdev-0.3.x releases.
|
||||||
|
|
||||||
cd vdr-1.X.X/PLUGINS/src
|
2.2 VDR 1.6.0 and above:
|
||||||
tar xvfz vdr-streamdev-0.3.1.tgz
|
|
||||||
ln -s streamdev-0.3.1 streamdev
|
|
||||||
cd ../..
|
|
||||||
patch -p1 <PLUGINS/src/streamdev/patches/thread.c.diff
|
|
||||||
make [options, if necessary] vdr
|
|
||||||
make [options, if necessary] plugins
|
|
||||||
|
|
||||||
2.2 VDR 1.3.X and above:
|
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
cd vdr-1.X.X/PLUGINS/src
|
cd vdr-1.X.X/PLUGINS/src
|
||||||
tar xvfz vdr-streamdev-0.3.1.tgz
|
tar xvfz vdr-streamdev-0.4.0.tgz
|
||||||
ln -s streamdev-0.3.1 streamdev
|
ln -s streamdev-0.4.0 streamdev
|
||||||
|
cp -r streamdev/streamdev VDRCONFDIR/plugins/
|
||||||
cd ../..
|
cd ../..
|
||||||
make [options, if necessary] vdr
|
make [options, if necessary] vdr
|
||||||
make [options, if necessary] plugins
|
make [options, if necessary] plugins
|
||||||
|
|
||||||
|
2.3 Updating from streamdev 0.3.x
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
mv VDRCONFDIR/plugins/streamdevhosts.conf VDRCONFDIR/plugins/streamdev/
|
||||||
|
|
||||||
|
(Directory VDRCONFDIR/plugins/streamdev already exists, as you copied the
|
||||||
|
whole folder from the sources directory as suggested above, right?)
|
||||||
|
|
||||||
|
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
|
||||||
|
*anyone* full access to streamdev, unless you took some other measures to
|
||||||
|
prevent this (e.g. firewall). You might want to remove this line and enable
|
||||||
|
HTTP authentication instead.
|
||||||
|
|
||||||
|
|
||||||
3. Usage:
|
3. Usage:
|
||||||
---------
|
---------
|
||||||
@ -120,12 +144,12 @@ can run in one VDR instance, if necessary.
|
|||||||
|
|
||||||
The parameter "Suspend behaviour" allows you to specify how the server should
|
The parameter "Suspend behaviour" allows you to specify how the server should
|
||||||
react in case the client requests a channel that would require switching the
|
react in case the client requests a channel that would require switching the
|
||||||
primary device (i.e. disrupt live-tv). If set to "Offer suspend mode" (the
|
primary device (i.e. disrupt live-tv). If set to "Offer suspend mode", you will
|
||||||
default), you will have a new entry in the main menu. Activating that will put
|
have a new entry in the main menu. Activating that will put the server into
|
||||||
the server into "Suspend Mode" (a picture is displayed on TV). Then, a client
|
"Suspend Mode" (a picture is displayed on TV). Then, a client may switch the
|
||||||
may switch the primary card to wherever it likes to. While watching TV (Suspend
|
primary card to wherever it likes to. While watching TV (Suspend deactivated),
|
||||||
deactivated), the client may not switch the transponder on the primary device.
|
the client may not switch the transponder on the primary device. If you set
|
||||||
If you set the behaviour to "Always suspended", there will be normal live-tv
|
the behaviour to "Always suspended" (the default), there will be normal live-tv
|
||||||
on the server, but whenever a client decides to switch the transponder, the
|
on the server, but whenever a client decides to switch the transponder, the
|
||||||
server will lose it's live-tv. Set to "Never suspended", the server always
|
server will lose it's live-tv. Set to "Never suspended", the server always
|
||||||
prevents the client from switching transponders. If you set "Client may
|
prevents the client from switching transponders. If you set "Client may
|
||||||
@ -186,7 +210,78 @@ externremux script.
|
|||||||
|
|
||||||
http://hostname:3000/EXTERN;some_parameter/3
|
http://hostname:3000/EXTERN;some_parameter/3
|
||||||
|
|
||||||
3.2 Usage VDR-to-VDR server:
|
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
|
||||||
|
"-a" commandline option to streamdev-server. It takes a username and a password
|
||||||
|
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' ...
|
||||||
|
|
||||||
|
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
|
||||||
|
as a system account.
|
||||||
|
|
||||||
|
3.2 Usage IGMP multicast server:
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
IGMP based multicast streaming is often used by settop boxes to receive IP TV.
|
||||||
|
Streamdev's multicast server allows you to feed live TV from VDR to such a
|
||||||
|
settop box. VLC is known to work well if you look for a software client.
|
||||||
|
|
||||||
|
The advantage of multicasting is that the actual stream is sent out only once,
|
||||||
|
regardless of how many clients want to receive it. The downside is, that you
|
||||||
|
cannot simply multicast across network boundaries. You need multicast routers.
|
||||||
|
For multicast streaming over the public Internet you would even need to register
|
||||||
|
for your own IP range. So don't even think of multicasting via Internet with
|
||||||
|
streamdev! Streamdev will send the stream only to one local ethernet segment and
|
||||||
|
all clients must be connected to this same segment. There must not be a router
|
||||||
|
inbetween. Also note that the client must not run on the streamdev-server
|
||||||
|
machine.
|
||||||
|
|
||||||
|
Each channel is offered on a different multicast IP. Channel 1 is available from
|
||||||
|
multicast IP 239.255.0.1, channel 2 from 239.255.0.2 and so on. The upper limit
|
||||||
|
is 239.255.254.255 which corresponds to channel 65279 (239.255.255.0/24 is
|
||||||
|
reserved according to RFC-2365).
|
||||||
|
|
||||||
|
Before you can use streamdev's multicast server, you might need to patch VDR.
|
||||||
|
Binding an IGMP socket is a privileged operation, so you must start VDR as root.
|
||||||
|
If you pass the -u option to VDR, it will drop almost all priviledges before
|
||||||
|
streamdev is even loaded. Apply vdr-cap_net_raw.diff to keep VDR from dropping
|
||||||
|
the CAP_NET_RAW capability required to bind the IGMP socket. The patch is part
|
||||||
|
of streamdev's source distribution. Check the patches subdirectory. There's no
|
||||||
|
need to patch VDR if it is kept running as root (not recommended).
|
||||||
|
|
||||||
|
The multicast server is disabled by default. Enter the streamdev-server setup
|
||||||
|
menu to enable it and - IMPORTANT - bind the multicast server to the IP of your
|
||||||
|
VDR server's LAN ethernet card. The multicast server will refuse to start with
|
||||||
|
the default bind adresse "0.0.0.0".
|
||||||
|
|
||||||
|
Now edit your streamdevhosts.conf. To allow streaming of all channels, it must
|
||||||
|
contain "239.255.0.0/16". Note that you cannot limit connections by client IP
|
||||||
|
here. You can however restrict which channels are allowed to be multicasted.
|
||||||
|
Enter individual multicast IPs instead of "239.255.0.0/16".
|
||||||
|
|
||||||
|
By default, the linux kernel will refuse to join more than 20 multicast groups.
|
||||||
|
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
|
||||||
|
|
||||||
|
#All channels:
|
||||||
|
bash# COUNT=$(grep -c '^[^:]' PATH_TO_YOUR/channels.conf)
|
||||||
|
bash# sysctl -w sys.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
|
||||||
|
for other listeners before it can stop the stream. This may delay zapping from
|
||||||
|
one transponder to an other. The client will probably requests the new channel
|
||||||
|
before the previous stream has been stopped. If there's no free DVB card, VDR
|
||||||
|
won't be able to fulfill the request until a DVB card becomes available and the
|
||||||
|
client resends the request.
|
||||||
|
|
||||||
|
3.3 Usage VDR-to-VDR server:
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
You can activate the VDR-to-VDR server part in the PlugIn's Setup Menu. It is
|
You can activate the VDR-to-VDR server part in the PlugIn's Setup Menu. It is
|
||||||
@ -195,9 +290,14 @@ port where you want the server to listen for incoming connections. The server
|
|||||||
will be activated when you push the OK button inside the setup menu, so there's
|
will be activated when you push the OK button inside the setup menu, so there's
|
||||||
no need to restart VDR.
|
no need to restart VDR.
|
||||||
|
|
||||||
3.3 Usage VDR-to-VDR client:
|
3.4 Usage VDR-to-VDR client:
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
Streamdev-client adds a "Suspend Server" item to VDR's mainmenu. With the
|
||||||
|
setup parameter "Hide Mainmenu Entry" you can hide this menu item if you don't
|
||||||
|
need it. "Suspend Server" is only useful if the server runs in "Offer suspend
|
||||||
|
mode" with "Client may suspend" enabled.
|
||||||
|
|
||||||
The parameter "Remote IP" uses an IP-Adress-Editor, where you can just enter
|
The parameter "Remote IP" uses an IP-Adress-Editor, where you can just enter
|
||||||
the IP number with the number keys on your remote. After three digits (or if
|
the IP number with the number keys on your remote. After three digits (or if
|
||||||
the next digit would result in an invalid IP adress, or if the first digit is
|
the next digit would result in an invalid IP adress, or if the first digit is
|
||||||
@ -214,8 +314,9 @@ setting "Start Client" to yes. It is disabled by default, because it wouldn't
|
|||||||
make much sense to start the client without specifying a server anyway. The
|
make much sense to start the client without specifying a server anyway. The
|
||||||
client is activated after you push the OK button, so there's no need to restart
|
client is activated after you push the OK button, so there's no need to restart
|
||||||
VDR. Deactivation on-the-fly is not possible, so in order to deactivate the
|
VDR. Deactivation on-the-fly is not possible, so in order to deactivate the
|
||||||
client, you will have to restart VDR. All other settings can be changed without
|
client, you will have to restart VDR. However requests to switch channels will
|
||||||
restarting VDR.
|
be refused by streamdev-client once it has been deactivated. All other settings
|
||||||
|
can be changed without restarting VDR.
|
||||||
|
|
||||||
The client will try to connect to the server (in case it isn't yet) whenever
|
The client will try to connect to the server (in case it isn't yet) whenever
|
||||||
a remote channel is requested. Just activate the client and switch to a
|
a remote channel is requested. Just activate the client and switch to a
|
||||||
@ -236,7 +337,7 @@ 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.
|
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.
|
Link channels and even a client-side EPG scan have been reported to work.
|
||||||
|
|
||||||
The last parameter, "Synchronize EPG", will have the client synchronize it's
|
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
|
program table with the server every now and then, but not regularly. This
|
||||||
happens when starting the client, and everytime VDR does its housekeeping
|
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
|
tasks. The only thing that's guaranteed is, that there will be a minimum
|
||||||
@ -245,6 +346,16 @@ 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
|
EPG as additional information is available from the server, you should use the
|
||||||
epgsync-plugin instead (http://vdr.schmirler.de).
|
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
|
||||||
|
what you want, you could set the maximum priority to 0. As recordings usually
|
||||||
|
have a much higher priority (default 50), streamdev is now no longer used for
|
||||||
|
recordings. The two parameters define the inclusive range of priorities for
|
||||||
|
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".
|
||||||
|
|
||||||
4. Other useful Plugins:
|
4. Other useful Plugins:
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@ -295,3 +406,33 @@ priority than the actual channel switch. The later always uses priority 0.
|
|||||||
Usually a channel switch for live TV has priority 0 anyway, so it is not a
|
Usually a channel switch for live TV has priority 0 anyway, so it is not a
|
||||||
problem here. However timers usually have a higher priority. Either avoid
|
problem here. However timers usually have a higher priority. Either avoid
|
||||||
client side recordings or set the priority of client side timers to 0.
|
client side recordings or set the priority of client side timers to 0.
|
||||||
|
|
||||||
|
* There have been reports that channel switching with VDR 1.5.x/1.6.x clients
|
||||||
|
sometimes fails. Current version includes a workaround which seems to work, but
|
||||||
|
YMMV ;)
|
||||||
|
|
||||||
|
* Viewing encrypted channels became an issue with VDR's new CAM handling code.
|
||||||
|
Streamdev doesn't provide a (dummy) CAM, so out of the box, VDR won't ever try
|
||||||
|
to receive encrypted channels from streamdev. Pick one of the following
|
||||||
|
solutions to work around the problem:
|
||||||
|
|
||||||
|
1. Force VDR to use streamdev. Open the channels menu on the client (or edit its
|
||||||
|
channels.conf if you know how to do this) and set the CA field of all channels
|
||||||
|
that only the server can decrypt to streamdev's device index. Usually streamdev
|
||||||
|
will get number 9 or 10. Streamdev logs the actual device number when starting
|
||||||
|
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
|
||||||
|
"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
|
||||||
|
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.
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: assembler.c,v 1.2 2005/01/25 14:14:43 lordjaxom Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "client/assembler.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include "tools/socket.h"
|
|
||||||
#include "tools/select.h"
|
|
||||||
|
|
||||||
#include <vdr/tools.h>
|
|
||||||
#include <vdr/device.h>
|
|
||||||
#include <vdr/ringbuffer.h>
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
cStreamdevAssembler::cStreamdevAssembler(cTBSocket *Socket)
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
:cThread("Streamdev: UDP-TS Assembler")
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
m_Socket = Socket;
|
|
||||||
if (pipe(m_Pipe) != 0) {
|
|
||||||
esyslog("streamdev-client: Couldn't open assembler pipe: %m");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fcntl(m_Pipe[0], F_SETFL, O_NONBLOCK);
|
|
||||||
fcntl(m_Pipe[1], F_SETFL, O_NONBLOCK);
|
|
||||||
m_Mutex.Lock();
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
cStreamdevAssembler::~cStreamdevAssembler() {
|
|
||||||
if (m_Active) {
|
|
||||||
m_Active = false;
|
|
||||||
/* WakeUp();*/
|
|
||||||
Cancel(3);
|
|
||||||
}
|
|
||||||
close(m_Pipe[0]);
|
|
||||||
close(m_Pipe[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cStreamdevAssembler::Action(void) {
|
|
||||||
cTBSelect sel;
|
|
||||||
uchar buffer[2048];
|
|
||||||
bool fillup = true;
|
|
||||||
|
|
||||||
const int rbsize = TS_SIZE * 5600;
|
|
||||||
const int rbmargin = TS_SIZE * 2;
|
|
||||||
const int rbminfill = rbmargin * 50;
|
|
||||||
cRingBufferLinear ringbuf(rbsize, rbmargin, true);
|
|
||||||
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
isyslog("streamdev-client: UDP-TS Assembler thread started (pid=%d)",
|
|
||||||
getpid());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_Mutex.Lock();
|
|
||||||
|
|
||||||
m_Active = true;
|
|
||||||
while (m_Active) {
|
|
||||||
sel.Clear();
|
|
||||||
|
|
||||||
if (ringbuf.Available() < rbsize * 80 / 100)
|
|
||||||
sel.Add(*m_Socket, false);
|
|
||||||
if (ringbuf.Available() > rbminfill) {
|
|
||||||
if (fillup) {
|
|
||||||
Dprintf("giving signal\n");
|
|
||||||
m_WaitFill.Broadcast();
|
|
||||||
m_Mutex.Unlock();
|
|
||||||
fillup = false;
|
|
||||||
}
|
|
||||||
sel.Add(m_Pipe[1], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sel.Select(1500) < 0) {
|
|
||||||
if (!m_Active) // Exit was requested
|
|
||||||
break;
|
|
||||||
esyslog("streamdev-client: Fatal error: %m");
|
|
||||||
Dprintf("streamdev-client: select failed (%m)\n");
|
|
||||||
m_Active = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sel.CanRead(*m_Socket)) {
|
|
||||||
int b;
|
|
||||||
if ((b = m_Socket->Read(buffer, sizeof(buffer))) < 0) {
|
|
||||||
esyslog("streamdev-client: Couldn't read from server: %m");
|
|
||||||
Dprintf("streamdev-client: read failed (%m)\n");
|
|
||||||
m_Active = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (b == 0)
|
|
||||||
m_Active = false;
|
|
||||||
else
|
|
||||||
ringbuf.Put(buffer, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sel.CanWrite(m_Pipe[1])) {
|
|
||||||
int recvd;
|
|
||||||
const uchar *block = ringbuf.Get(recvd);
|
|
||||||
if (block && recvd > 0) {
|
|
||||||
int result;
|
|
||||||
if (recvd > ringbuf.Available() - rbminfill)
|
|
||||||
recvd = ringbuf.Available() - rbminfill;
|
|
||||||
if ((result = write(m_Pipe[1], block, recvd)) == -1) {
|
|
||||||
esyslog("streamdev-client: Couldn't write to VDR: %m"); // TODO
|
|
||||||
Dprintf("streamdev-client: write failed (%m)\n");
|
|
||||||
m_Active = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ringbuf.Del(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
isyslog("streamdev-client: UDP-TS Assembler thread stopped", getpid());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void cStreamdevAssembler::WaitForFill(void) {
|
|
||||||
m_WaitFill.Wait(m_Mutex);
|
|
||||||
m_Mutex.Unlock();
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: assembler.h,v 1.1.1.1 2004/12/30 22:44:04 lordjaxom Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_ASSEMBLER_H
|
|
||||||
#define VDR_STREAMDEV_ASSEMBLER_H
|
|
||||||
|
|
||||||
#include <vdr/config.h>
|
|
||||||
#include <vdr/thread.h>
|
|
||||||
|
|
||||||
class cTBSocket;
|
|
||||||
|
|
||||||
class cStreamdevAssembler: public cThread {
|
|
||||||
private:
|
|
||||||
cTBSocket *m_Socket;
|
|
||||||
cMutex m_Mutex;
|
|
||||||
cCondVar m_WaitFill;
|
|
||||||
int m_Pipe[2];
|
|
||||||
bool m_Active;
|
|
||||||
protected:
|
|
||||||
virtual void Action(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
cStreamdevAssembler(cTBSocket *Socket);
|
|
||||||
virtual ~cStreamdevAssembler();
|
|
||||||
|
|
||||||
int ReadPipe(void) const { return m_Pipe[0]; }
|
|
||||||
void WaitForFill(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // VDR_STREAMDEV_ASSEMBLER_H
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: device.c,v 1.15 2007/12/12 12:22:45 schmirl Exp $
|
* $Id: device.c,v 1.23 2009/04/06 06:48:59 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "client/device.h"
|
#include "client/device.h"
|
||||||
#include "client/setup.h"
|
#include "client/setup.h"
|
||||||
#include "client/assembler.h"
|
|
||||||
#include "client/filter.h"
|
#include "client/filter.h"
|
||||||
|
|
||||||
#include "tools/select.h"
|
#include "tools/select.h"
|
||||||
@ -26,20 +25,10 @@ cStreamdevDevice *cStreamdevDevice::m_Device = NULL;
|
|||||||
cStreamdevDevice::cStreamdevDevice(void) {
|
cStreamdevDevice::cStreamdevDevice(void) {
|
||||||
m_Channel = NULL;
|
m_Channel = NULL;
|
||||||
m_TSBuffer = NULL;
|
m_TSBuffer = NULL;
|
||||||
m_Assembler = NULL;
|
|
||||||
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
# if defined(HAVE_AUTOPID)
|
|
||||||
(void)new cSIProcessor(new cSectionsScanner(""));
|
|
||||||
# else
|
|
||||||
(void)new cSIProcessor("");
|
|
||||||
# endif
|
|
||||||
cSIProcessor::Read();
|
|
||||||
#else
|
|
||||||
m_Filters = new cStreamdevFilters;
|
m_Filters = new cStreamdevFilters;
|
||||||
StartSectionHandler();
|
StartSectionHandler();
|
||||||
cSchedules::Read();
|
isyslog("streamdev-client: got device number %d", CardIndex() + 1);
|
||||||
#endif
|
|
||||||
|
|
||||||
m_Device = this;
|
m_Device = this;
|
||||||
m_Pids = 0;
|
m_Pids = 0;
|
||||||
@ -61,11 +50,11 @@ cStreamdevDevice::~cStreamdevDevice() {
|
|||||||
|
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
#if APIVERSNUM >= 10515
|
||||||
DELETENULL(m_Filters);
|
StopSectionHandler();
|
||||||
#endif
|
#endif
|
||||||
|
DELETENULL(m_Filters);
|
||||||
DELETENULL(m_TSBuffer);
|
DELETENULL(m_TSBuffer);
|
||||||
delete m_Assembler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cStreamdevDevice::ProvidesSource(int Source) const {
|
bool cStreamdevDevice::ProvidesSource(int Source) const {
|
||||||
@ -93,8 +82,25 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
|
|||||||
bool res = false;
|
bool res = false;
|
||||||
bool prio = Priority < 0 || Priority > this->Priority();
|
bool prio = Priority < 0 || Priority > this->Priority();
|
||||||
bool ndr = false;
|
bool ndr = false;
|
||||||
|
|
||||||
|
if (!StreamdevClientSetup.StartClient)
|
||||||
|
return false;
|
||||||
|
|
||||||
Dprintf("ProvidesChannel, Channel=%s, Prio=%d\n", Channel->Name(), Priority);
|
Dprintf("ProvidesChannel, Channel=%s, Prio=%d\n", Channel->Name(), Priority);
|
||||||
|
|
||||||
|
if (StreamdevClientSetup.MinPriority <= StreamdevClientSetup.MaxPriority)
|
||||||
|
{
|
||||||
|
if (Priority < StreamdevClientSetup.MinPriority ||
|
||||||
|
Priority > StreamdevClientSetup.MaxPriority)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Priority < StreamdevClientSetup.MinPriority &&
|
||||||
|
Priority > StreamdevClientSetup.MaxPriority)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (ClientSocket.DataSocket(siLive) != NULL
|
if (ClientSocket.DataSocket(siLive) != NULL
|
||||||
&& TRANSPONDER(Channel, m_Channel))
|
&& TRANSPONDER(Channel, m_Channel))
|
||||||
res = true;
|
res = true;
|
||||||
@ -117,23 +123,14 @@ bool cStreamdevDevice::SetChannelDevice(const cChannel *Channel,
|
|||||||
if (LiveView)
|
if (LiveView)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (ClientSocket.DataSocket(siLive) != NULL
|
if (ClientSocket.DataSocket(siLive) != NULL
|
||||||
&& TRANSPONDER(Channel, m_Channel))
|
&& TRANSPONDER(Channel, m_Channel)
|
||||||
|
&& Channel->Ca() < CA_ENCRYPTED_MIN)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#if VDRVERSNUM < 10338
|
|
||||||
DetachAll(pidHandles[ptAudio].pid);
|
|
||||||
DetachAll(pidHandles[ptVideo].pid);
|
|
||||||
DetachAll(pidHandles[ptPcr].pid);
|
|
||||||
DetachAll(pidHandles[ptTeletext].pid);
|
|
||||||
DelPid(pidHandles[ptAudio].pid);
|
|
||||||
DelPid(pidHandles[ptVideo].pid);
|
|
||||||
DelPid(pidHandles[ptPcr].pid, ptPcr);
|
|
||||||
DelPid(pidHandles[ptTeletext].pid);
|
|
||||||
DelPid(pidHandles[ptDolby].pid);
|
|
||||||
#else
|
|
||||||
DetachAllReceivers();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DetachAllReceivers();
|
||||||
m_Channel = Channel;
|
m_Channel = Channel;
|
||||||
bool r = ClientSocket.SetChannelDevice(m_Channel);
|
bool r = ClientSocket.SetChannelDevice(m_Channel);
|
||||||
Dprintf("setchanneldevice r=%d\n", r);
|
Dprintf("setchanneldevice r=%d\n", r);
|
||||||
@ -212,16 +209,11 @@ void cStreamdevDevice::CloseDvrInt(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dprintf("cStreamdevDevice::CloseDvrInt(): Closing DVR connection\n");
|
Dprintf("cStreamdevDevice::CloseDvrInt(): Closing DVR connection\n");
|
||||||
#if VDRVERSNUM < 10500
|
|
||||||
DELETENULL(m_TSBuffer);
|
|
||||||
ClientSocket.CloseDvr();
|
|
||||||
#else
|
|
||||||
// Hack for VDR 1.5.x clients (sometimes sending ABRT after TUNE)
|
// Hack for VDR 1.5.x clients (sometimes sending ABRT after TUNE)
|
||||||
// TODO: Find a clean solution to fix this
|
// TODO: Find a clean solution to fix this
|
||||||
ClientSocket.SetChannelDevice(m_Channel);
|
ClientSocket.SetChannelDevice(m_Channel);
|
||||||
ClientSocket.CloseDvr();
|
ClientSocket.CloseDvr();
|
||||||
DELETENULL(m_TSBuffer);
|
DELETENULL(m_TSBuffer);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cStreamdevDevice::CloseDvr(void) {
|
void cStreamdevDevice::CloseDvr(void) {
|
||||||
@ -268,7 +260,6 @@ esyslog("cStreamDevice::GetTSPacket: GetChecked: NOTHING (%d)", m_TSFails);
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
|
int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
|
||||||
Dprintf("OpenFilter\n");
|
Dprintf("OpenFilter\n");
|
||||||
|
|
||||||
@ -290,7 +281,6 @@ int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
|
|||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool cStreamdevDevice::Init(void) {
|
bool cStreamdevDevice::Init(void) {
|
||||||
if (m_Device == NULL && StreamdevClientSetup.StartClient)
|
if (m_Device == NULL && StreamdevClientSetup.StartClient)
|
||||||
@ -308,7 +298,6 @@ bool cStreamdevDevice::ReInit(void) {
|
|||||||
ClientSocket.Reset();
|
ClientSocket.Reset();
|
||||||
if (m_Device != NULL) {
|
if (m_Device != NULL) {
|
||||||
//DELETENULL(m_Device->m_TSBuffer);
|
//DELETENULL(m_Device->m_TSBuffer);
|
||||||
DELETENULL(m_Device->m_Assembler);
|
|
||||||
m_Device->Unlock();
|
m_Device->Unlock();
|
||||||
}
|
}
|
||||||
return StreamdevClientSetup.StartClient ? Init() : true;
|
return StreamdevClientSetup.StartClient ? Init() : true;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: device.h,v 1.5 2007/04/24 10:43:40 schmirl Exp $
|
* $Id: device.h,v 1.8 2008/10/02 07:14:47 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_DEVICE_H
|
#ifndef VDR_STREAMDEV_DEVICE_H
|
||||||
@ -8,7 +8,6 @@
|
|||||||
#include <vdr/device.h>
|
#include <vdr/device.h>
|
||||||
|
|
||||||
#include "client/socket.h"
|
#include "client/socket.h"
|
||||||
#include "client/assembler.h"
|
|
||||||
#include "client/filter.h"
|
#include "client/filter.h"
|
||||||
|
|
||||||
class cTBString;
|
class cTBString;
|
||||||
@ -21,10 +20,7 @@ class cStreamdevDevice: public cDevice {
|
|||||||
private:
|
private:
|
||||||
const cChannel *m_Channel;
|
const cChannel *m_Channel;
|
||||||
cTSBuffer *m_TSBuffer;
|
cTSBuffer *m_TSBuffer;
|
||||||
cStreamdevAssembler *m_Assembler;
|
|
||||||
#if VDRVERSNUM >= 10307
|
|
||||||
cStreamdevFilters *m_Filters;
|
cStreamdevFilters *m_Filters;
|
||||||
#endif
|
|
||||||
int m_Pids;
|
int m_Pids;
|
||||||
bool m_DvrClosed;
|
bool m_DvrClosed;
|
||||||
|
|
||||||
@ -47,14 +43,13 @@ protected:
|
|||||||
virtual void CloseDvr(void);
|
virtual void CloseDvr(void);
|
||||||
virtual bool GetTSPacket(uchar *&Data);
|
virtual bool GetTSPacket(uchar *&Data);
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cStreamdevDevice(void);
|
cStreamdevDevice(void);
|
||||||
virtual ~cStreamdevDevice();
|
virtual ~cStreamdevDevice();
|
||||||
|
|
||||||
|
virtual bool HasInternalCam(void) { return true; }
|
||||||
virtual bool ProvidesSource(int Source) const;
|
virtual bool ProvidesSource(int Source) const;
|
||||||
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1,
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: filter.c,v 1.11 2007/04/24 11:23:16 schmirl Exp $
|
* $Id: filter.c,v 1.14 2009/02/13 13:02:39 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "client/filter.h"
|
#include "client/filter.h"
|
||||||
@ -9,8 +9,7 @@
|
|||||||
|
|
||||||
#include <vdr/device.h>
|
#include <vdr/device.h>
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
#define PID_MASK_HI 0x1F
|
||||||
|
|
||||||
// --- cStreamdevFilter ------------------------------------------------------
|
// --- cStreamdevFilter ------------------------------------------------------
|
||||||
|
|
||||||
class cStreamdevFilter: public cListObject {
|
class cStreamdevFilter: public cListObject {
|
||||||
@ -228,6 +227,7 @@ void cStreamdevFilters::Action(void) {
|
|||||||
u_short pid = (((u_short)block[1] & PID_MASK_HI) << 8) | block[2];
|
u_short pid = (((u_short)block[1] & PID_MASK_HI) << 8) | block[2];
|
||||||
u_char tid = block[3];
|
u_char tid = block[3];
|
||||||
bool Pusi = block[1] & 0x40;
|
bool Pusi = block[1] & 0x40;
|
||||||
|
// proprietary extension
|
||||||
int len = block[4];
|
int len = block[4];
|
||||||
#if 0
|
#if 0
|
||||||
if (block[1] == 0xff &&
|
if (block[1] == 0xff &&
|
||||||
@ -290,5 +290,3 @@ void cStreamdevFilters::Action(void) {
|
|||||||
DELETENULL(m_TSBuffer);
|
DELETENULL(m_TSBuffer);
|
||||||
dsyslog("StreamdevFilters::Action() ended");
|
dsyslog("StreamdevFilters::Action() ended");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // VDRVERSNUM >= 10300
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: filter.h,v 1.4 2007/04/24 11:23:16 schmirl Exp $
|
* $Id: filter.h,v 1.5 2008/04/07 14:27:28 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_FILTER_H
|
#ifndef VDR_STREAMDEV_FILTER_H
|
||||||
#define VDR_STREAMDEV_FILTER_H
|
#define VDR_STREAMDEV_FILTER_H
|
||||||
|
|
||||||
#include <vdr/config.h>
|
#include <vdr/config.h>
|
||||||
|
|
||||||
# if VDRVERSNUM >= 10300
|
|
||||||
|
|
||||||
#include <vdr/tools.h>
|
#include <vdr/tools.h>
|
||||||
#include <vdr/thread.h>
|
#include <vdr/thread.h>
|
||||||
|
|
||||||
@ -33,5 +30,4 @@ public:
|
|||||||
int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
||||||
};
|
};
|
||||||
|
|
||||||
# endif // VDRVERSNUM >= 10300
|
|
||||||
#endif // VDR_STREAMDEV_FILTER_H
|
#endif // VDR_STREAMDEV_FILTER_H
|
||||||
|
1045
client/menu.c
1045
client/menu.c
File diff suppressed because it is too large
Load Diff
144
client/menu.h
144
client/menu.h
@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: menu.h,v 1.1.1.1 2004/12/30 22:44:02 lordjaxom Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_MENU_H
|
|
||||||
#define VDR_STREAMDEV_MENU_H
|
|
||||||
|
|
||||||
#include <vdr/osd.h>
|
|
||||||
|
|
||||||
#include "client/remote.h"
|
|
||||||
|
|
||||||
class cStreamdevMenuRecordingItem;
|
|
||||||
|
|
||||||
// --- cStreamdevMenu --------------------------------------------------------
|
|
||||||
|
|
||||||
class cStreamdevMenu: public cOsdMenu {
|
|
||||||
private:
|
|
||||||
enum eSubmenus {
|
|
||||||
sub_Start = os_User,
|
|
||||||
subSchedule,
|
|
||||||
subTimers,
|
|
||||||
subRecordings,
|
|
||||||
subSuspend,
|
|
||||||
subSyncEPG
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void SuspendServer(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
cStreamdevMenu(void);
|
|
||||||
virtual ~cStreamdevMenu(void);
|
|
||||||
|
|
||||||
virtual eOSState ProcessKey(eKeys Key);
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- cStreamdevMenuSchedule ------------------------------------------------
|
|
||||||
|
|
||||||
class cStreamdevMenuSchedule: public cOsdMenu {
|
|
||||||
private:
|
|
||||||
bool m_Now;
|
|
||||||
bool m_Next;
|
|
||||||
int m_OtherChannel;
|
|
||||||
const cSchedules *m_Schedules;
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
cMutexLock m_Lock;
|
|
||||||
#else
|
|
||||||
cSchedulesLock m_Lock;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void PrepareSchedule(cChannel *Channel);
|
|
||||||
|
|
||||||
eOSState Switch(void);
|
|
||||||
eOSState Record(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
cStreamdevMenuSchedule(void);
|
|
||||||
virtual ~cStreamdevMenuSchedule(void);
|
|
||||||
|
|
||||||
virtual eOSState ProcessKey(eKeys Key);
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- cStreamdevMenuWhatsOn -------------------------------------------------
|
|
||||||
|
|
||||||
class cStreamdevMenuWhatsOn: public cOsdMenu {
|
|
||||||
private:
|
|
||||||
static int m_CurrentChannel;
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
static const cEventInfo *m_ScheduleEventInfo;
|
|
||||||
#else
|
|
||||||
static const cEvent *m_ScheduleEventInfo;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
eOSState Switch(void);
|
|
||||||
eOSState Record(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
cStreamdevMenuWhatsOn(const cSchedules *Schedules, bool Now,
|
|
||||||
int CurrentChannel);
|
|
||||||
|
|
||||||
static int CurrentChannel(void) { return m_CurrentChannel; }
|
|
||||||
static void SetCurrentChannel(int Channel) { m_CurrentChannel = Channel; }
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
static const cEventInfo *ScheduleEventInfo(void);
|
|
||||||
#else
|
|
||||||
static const cEvent *ScheduleEventInfo(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual eOSState ProcessKey(eKeys Key);
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- cStreamdevMenuRecordings ----------------------------------------------
|
|
||||||
|
|
||||||
class cStreamdevMenuRecordings: public cOsdMenu {
|
|
||||||
private:
|
|
||||||
char *m_Base;
|
|
||||||
int m_Level;
|
|
||||||
|
|
||||||
static int HelpKeys;
|
|
||||||
static cRemoteRecordings Recordings;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool Open(bool OpenSubMenus = false);
|
|
||||||
void SetHelpKeys();
|
|
||||||
cRemoteRecording *cStreamdevMenuRecordings::GetRecording(
|
|
||||||
cStreamdevMenuRecordingItem *Item);
|
|
||||||
|
|
||||||
eOSState Select(void);
|
|
||||||
eOSState Delete(void);
|
|
||||||
eOSState Summary(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
cStreamdevMenuRecordings(const char *Base = NULL, int Level = 0,
|
|
||||||
bool OpenSubMenus = false);
|
|
||||||
virtual ~cStreamdevMenuRecordings();
|
|
||||||
|
|
||||||
virtual eOSState ProcessKey(eKeys Key);
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- cStreamdevMenuTimers --------------------------------------------------
|
|
||||||
|
|
||||||
class cStreamdevMenuTimers: public cOsdMenu {
|
|
||||||
protected:
|
|
||||||
eOSState Edit(void);
|
|
||||||
eOSState New(void);
|
|
||||||
eOSState Delete(void);
|
|
||||||
eOSState OnOff(void);
|
|
||||||
eOSState Summary(void);
|
|
||||||
|
|
||||||
cRemoteTimer *CurrentTimer(void);
|
|
||||||
|
|
||||||
void Refresh(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
cStreamdevMenuTimers(void);
|
|
||||||
virtual ~cStreamdevMenuTimers();
|
|
||||||
|
|
||||||
virtual eOSState ProcessKey(eKeys Key);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // VDR_STREAMDEV_MENU_H
|
|
||||||
|
|
476
client/remote.c
476
client/remote.c
@ -1,476 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: remote.c,v 1.4 2005/04/24 16:26:14 lordjaxom Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "client/remote.h"
|
|
||||||
#include "client/device.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
cRemoteTimers RemoteTimers;
|
|
||||||
|
|
||||||
// --- cRemoteRecording ------------------------------------------------------
|
|
||||||
|
|
||||||
cRemoteRecording::cRemoteRecording(const char *Text) {
|
|
||||||
m_IsValid = false;
|
|
||||||
m_Index = -1;
|
|
||||||
m_IsNew = false;
|
|
||||||
m_TitleBuffer = NULL;
|
|
||||||
|
|
||||||
char *ptr;
|
|
||||||
char *timestr;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
Dprintf("text: %s\n", Text);
|
|
||||||
|
|
||||||
m_Index = strtoul(Text, &ptr, 10);
|
|
||||||
Dprintf("index: %d\n", m_Index);
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0' ) return;
|
|
||||||
timestr = ptr;
|
|
||||||
while (*ptr != '\0' && !isspace(*ptr)) ++ptr;
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0') return;
|
|
||||||
while (*ptr != '\0' && *ptr != '*' && !isspace(*ptr)) ++ptr;
|
|
||||||
if (*ptr == '*') m_IsNew = true;
|
|
||||||
Dprintf("new: %d\n", m_IsNew);
|
|
||||||
*(ptr++) = '\0';
|
|
||||||
m_StartTime = timestr;
|
|
||||||
idx = -1;
|
|
||||||
while ((idx = m_StartTime.find(' ', idx + 1)) != -1) m_StartTime[idx] = '\t';
|
|
||||||
Dprintf("m_Start: %s\n", m_StartTime.c_str());
|
|
||||||
if (*ptr == 0) return;
|
|
||||||
if (isspace(*ptr)) ++ptr;
|
|
||||||
if (*ptr == 0) return;
|
|
||||||
m_Name = ptr;
|
|
||||||
Dprintf("file: %s\n", m_Name.c_str());
|
|
||||||
m_IsValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cRemoteRecording::~cRemoteRecording(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRemoteRecording::operator==(const cRemoteRecording &Recording) {
|
|
||||||
return m_IsValid == Recording.m_IsValid
|
|
||||||
&& m_Index == Recording.m_Index
|
|
||||||
&& m_StartTime == Recording.m_StartTime
|
|
||||||
&& m_Name == Recording.m_Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cRemoteRecording::ParseInfo(const char *Text) {
|
|
||||||
m_Summary = strreplace(strdup(Text), '|', '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cRemoteRecording::Title(char Delimiter, bool NewIndicator,
|
|
||||||
int Level) {
|
|
||||||
char New = NewIndicator && IsNew() ? '*' : ' ';
|
|
||||||
|
|
||||||
if (m_TitleBuffer != NULL) {
|
|
||||||
free(m_TitleBuffer);
|
|
||||||
m_TitleBuffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Level < 0 || Level == HierarchyLevels()) {
|
|
||||||
char *s;
|
|
||||||
const char *t;
|
|
||||||
if (Level > 0 && (t = strrchr(m_Name.c_str(), '~')) != NULL)
|
|
||||||
t++;
|
|
||||||
else
|
|
||||||
t = m_Name.c_str();
|
|
||||||
|
|
||||||
asprintf(&m_TitleBuffer, "%s%c%c%s", m_StartTime.c_str(), New, Delimiter, t);
|
|
||||||
// let's not display a trailing '~':
|
|
||||||
stripspace(m_TitleBuffer);
|
|
||||||
s = &m_TitleBuffer[strlen(m_TitleBuffer) - 1];
|
|
||||||
if (*s == '~')
|
|
||||||
*s = 0;
|
|
||||||
} else if (Level < HierarchyLevels()) {
|
|
||||||
const char *s = m_Name.c_str();
|
|
||||||
const char *p = s;
|
|
||||||
while (*++s) {
|
|
||||||
if (*s == '~') {
|
|
||||||
if (Level--)
|
|
||||||
p = s + 1;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_TitleBuffer = MALLOC(char, s - p + 3);
|
|
||||||
*m_TitleBuffer = Delimiter;
|
|
||||||
*(m_TitleBuffer + 1) = Delimiter;
|
|
||||||
strn0cpy(m_TitleBuffer + 2, p, s - p + 1);
|
|
||||||
} else
|
|
||||||
return "";
|
|
||||||
return m_TitleBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cRemoteRecording::HierarchyLevels(void)
|
|
||||||
{
|
|
||||||
const char *s = m_Name.c_str();
|
|
||||||
int level = 0;
|
|
||||||
while (*++s) {
|
|
||||||
if (*s == '~') ++level;
|
|
||||||
}
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cRemoteRecordings -----------------------------------------------------
|
|
||||||
|
|
||||||
bool cRemoteRecordings::Load(void) {
|
|
||||||
Clear();
|
|
||||||
return ClientSocket.LoadRecordings(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
cRemoteRecording *cRemoteRecordings::GetByName(const char *Name) {
|
|
||||||
for (cRemoteRecording *r = First(); r; r = Next(r))
|
|
||||||
if (strcmp(r->Name(), Name) == 0)
|
|
||||||
return r;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cRemoteTimer ----------------------------------------------------------
|
|
||||||
|
|
||||||
cRemoteTimer::cRemoteTimer(const char *Text) {
|
|
||||||
m_IsValid = false;
|
|
||||||
m_Index = -1;
|
|
||||||
m_Active = -1;
|
|
||||||
m_Day = -1;
|
|
||||||
m_Start = -1;
|
|
||||||
m_Stop = -1;
|
|
||||||
m_StartTime = 0;
|
|
||||||
m_StopTime = 0;
|
|
||||||
m_Priority = -1;
|
|
||||||
m_Lifetime = -1;
|
|
||||||
m_File[0] = '\0';
|
|
||||||
m_FirstDay = 0;
|
|
||||||
m_Buffer = NULL;
|
|
||||||
m_Channel = NULL;
|
|
||||||
|
|
||||||
char *tmpbuf;
|
|
||||||
char *ptr;
|
|
||||||
|
|
||||||
Dprintf("text: %s\n", Text);
|
|
||||||
|
|
||||||
m_Index = strtoul(Text, &ptr, 10);
|
|
||||||
Dprintf("index: %d\n", m_Index);
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0') return;
|
|
||||||
m_Active = strtoul(ptr, &ptr, 10);
|
|
||||||
Dprintf("m_Active: %d\n", m_Active);
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0') return;
|
|
||||||
|
|
||||||
tmpbuf = ptr;
|
|
||||||
while (*ptr != '\0' && *ptr != ':') ++ptr;
|
|
||||||
if (*ptr == '\0') return;
|
|
||||||
*(ptr++)= '\0';
|
|
||||||
if (isnumber(tmpbuf))
|
|
||||||
m_Channel = Channels.GetByNumber(strtoul(tmpbuf, NULL, 10));
|
|
||||||
else
|
|
||||||
m_Channel = Channels.GetByChannelID(tChannelID::FromString(tmpbuf));
|
|
||||||
Dprintf("channel no.: %d\n", m_Channel->Number());
|
|
||||||
|
|
||||||
tmpbuf = ptr;
|
|
||||||
while (*ptr != '\0' && *ptr != ':') ++ptr;
|
|
||||||
if (*ptr == '\0') return;
|
|
||||||
*(ptr++) = '\0';
|
|
||||||
m_Day = ParseDay(tmpbuf, &m_FirstDay);
|
|
||||||
Dprintf("Day: %d\n", m_Day);
|
|
||||||
m_Start = strtoul(ptr, &ptr, 10);
|
|
||||||
Dprintf("Start: %d\n", m_Start);
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0') return;
|
|
||||||
m_Stop = strtoul(ptr, &ptr, 10);
|
|
||||||
Dprintf("Stop: %d\n", m_Stop);
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0') return;
|
|
||||||
m_Priority = strtoul(ptr, &ptr, 10);
|
|
||||||
Dprintf("Prio: %d\n", m_Priority);
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0') return;
|
|
||||||
m_Lifetime = strtoul(ptr, &ptr, 10);
|
|
||||||
Dprintf("Lifetime: %d\n", m_Lifetime);
|
|
||||||
if (*ptr == '\0' || *++ptr == '\0') return;
|
|
||||||
tmpbuf = ptr;
|
|
||||||
while (*ptr != '\0' && *ptr != ':') ++ptr;
|
|
||||||
if (*ptr == '\0') return;
|
|
||||||
*(ptr++) = '\0';
|
|
||||||
strncpy(m_File, tmpbuf, MaxFileName);
|
|
||||||
Dprintf("file: %s\n", m_File);
|
|
||||||
if (*ptr != '\0') m_Summary = ptr;
|
|
||||||
Dprintf("summary: %s\n", m_Summary.c_str());
|
|
||||||
m_IsValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
cRemoteTimer::cRemoteTimer(const cEventInfo *EventInfo) {
|
|
||||||
time_t tstart = EventInfo->GetTime();
|
|
||||||
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
|
|
||||||
tstart -= Setup.MarginStart * 60;
|
|
||||||
struct tm tm_r;
|
|
||||||
struct tm *time = localtime_r(&tstart, &tm_r);
|
|
||||||
const char *title = EventInfo->GetTitle();
|
|
||||||
cChannel *channel = Channels.GetByChannelID(EventInfo->GetChannelID(), true);
|
|
||||||
#else
|
|
||||||
cRemoteTimer::cRemoteTimer(const cEvent *Event) {
|
|
||||||
time_t tstart = Event->StartTime();
|
|
||||||
time_t tstop = tstart + Event->Duration() + Setup.MarginStop * 60;
|
|
||||||
tstart -= Setup.MarginStart * 60;
|
|
||||||
struct tm tm_r;
|
|
||||||
struct tm *time = localtime_r(&tstart, &tm_r);
|
|
||||||
const char *title = Event->Title();
|
|
||||||
cChannel *channel = Channels.GetByChannelID(Event->ChannelID(), true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_IsValid = true;
|
|
||||||
m_Index = -1;
|
|
||||||
m_Active = true;
|
|
||||||
m_Day = time->tm_mday;
|
|
||||||
m_Start = time->tm_hour * 100 + time->tm_min;
|
|
||||||
time = localtime_r(&tstop, &tm_r);
|
|
||||||
m_Stop = time->tm_hour * 100 + time->tm_min;
|
|
||||||
m_StartTime = 0;
|
|
||||||
m_StopTime = 0;
|
|
||||||
if (m_Stop >= 2400) m_Stop -= 2400;
|
|
||||||
m_Priority = Setup.DefaultPriority;
|
|
||||||
m_Lifetime = Setup.DefaultLifetime;
|
|
||||||
m_File[0] = '\0';
|
|
||||||
if (!isempty(title))
|
|
||||||
strn0cpy(m_File, title, sizeof(m_File));
|
|
||||||
m_FirstDay = 0;
|
|
||||||
m_Channel = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
cRemoteTimer::cRemoteTimer(void) {
|
|
||||||
time_t t = time(NULL);
|
|
||||||
struct tm tm_r;
|
|
||||||
struct tm *now = localtime_r(&t, &tm_r);
|
|
||||||
|
|
||||||
m_IsValid = true;
|
|
||||||
m_Index = -1;
|
|
||||||
m_Active = -1;
|
|
||||||
m_Day = now->tm_mday;
|
|
||||||
m_Start = now->tm_hour * 100 + now->tm_min;
|
|
||||||
m_Stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime;
|
|
||||||
m_Stop = (m_Stop / 60) * 100 + (m_Stop % 60);
|
|
||||||
if (m_Stop >= 2400) m_Stop -= 2400;
|
|
||||||
m_StartTime = 0;
|
|
||||||
m_StopTime = 0;
|
|
||||||
m_Priority = Setup.DefaultPriority;
|
|
||||||
m_Lifetime = Setup.DefaultLifetime;
|
|
||||||
m_File[0] = '\0';
|
|
||||||
m_FirstDay = 0;
|
|
||||||
m_Buffer = NULL;
|
|
||||||
m_Channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
|
||||||
}
|
|
||||||
|
|
||||||
cRemoteTimer::~cRemoteTimer() {
|
|
||||||
if (m_Buffer != NULL) free(m_Buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
cRemoteTimer &cRemoteTimer::operator=(const cRemoteTimer &Timer) {
|
|
||||||
Dprintf("\n\n\n\nOPÜERATHVBDÖLJVG\n\n\n");
|
|
||||||
m_IsValid = Timer.m_IsValid;
|
|
||||||
m_Index = Timer.m_Index;
|
|
||||||
m_Active = Timer.m_Active;
|
|
||||||
m_Day = Timer.m_Day;
|
|
||||||
m_Start = Timer.m_Start;
|
|
||||||
m_Stop = Timer.m_Stop;
|
|
||||||
m_Priority = Timer.m_Priority;
|
|
||||||
m_Lifetime = Timer.m_Lifetime;
|
|
||||||
m_FirstDay = Timer.m_FirstDay;
|
|
||||||
m_Channel = Timer.m_Channel;
|
|
||||||
m_Summary = Timer.m_Summary;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRemoteTimer::operator==(const cRemoteTimer &Timer) {
|
|
||||||
return m_IsValid == Timer.m_IsValid
|
|
||||||
&& m_Index == Timer.m_Index
|
|
||||||
&& m_Active == Timer.m_Active
|
|
||||||
&& m_Day == Timer.m_Day
|
|
||||||
&& m_Start == Timer.m_Start
|
|
||||||
&& m_Stop == Timer.m_Stop
|
|
||||||
&& m_Priority == Timer.m_Priority
|
|
||||||
&& m_Lifetime == Timer.m_Lifetime
|
|
||||||
&& m_FirstDay == Timer.m_FirstDay
|
|
||||||
&& m_Channel == Timer.m_Channel
|
|
||||||
&& strcmp(m_File, Timer.m_File) == 0
|
|
||||||
&& m_Summary == Timer.m_Summary;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cRemoteTimer::ParseDay(const char *s, time_t *FirstDay) {
|
|
||||||
char *tail;
|
|
||||||
int d = strtol(s, &tail, 10);
|
|
||||||
if (FirstDay)
|
|
||||||
*FirstDay = 0;
|
|
||||||
if (tail && *tail) {
|
|
||||||
d = 0;
|
|
||||||
if (tail == s) {
|
|
||||||
const char *first = strchr(s, '@');
|
|
||||||
int l = first ? first - s : strlen(s);
|
|
||||||
if (l == 7) {
|
|
||||||
for (const char *p = s + 6; p >= s; p--) {
|
|
||||||
d <<= 1;
|
|
||||||
d |= (*p != '-');
|
|
||||||
}
|
|
||||||
d |= 0x80000000;
|
|
||||||
}
|
|
||||||
if (FirstDay && first) {
|
|
||||||
++first;
|
|
||||||
if (strlen(first) == 10) {
|
|
||||||
struct tm tm_r;
|
|
||||||
if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
|
|
||||||
tm_r.tm_year -= 1900;
|
|
||||||
tm_r.tm_mon--;
|
|
||||||
tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
|
|
||||||
tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
|
||||||
*FirstDay = mktime(&tm_r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (d < 1 || d > 31)
|
|
||||||
d = 0;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cRemoteTimer::PrintDay(int d, time_t FirstDay) {
|
|
||||||
#define DAYBUFFERSIZE 32
|
|
||||||
static char buffer[DAYBUFFERSIZE];
|
|
||||||
if ((d & 0x80000000) != 0) {
|
|
||||||
char *b = buffer;
|
|
||||||
const char *w = tr("MTWTFSS");
|
|
||||||
while (*w) {
|
|
||||||
*b++ = (d & 1) ? *w : '-';
|
|
||||||
d >>= 1;
|
|
||||||
w++;
|
|
||||||
}
|
|
||||||
if (FirstDay) {
|
|
||||||
struct tm tm_r;
|
|
||||||
localtime_r(&FirstDay, &tm_r);
|
|
||||||
b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r);
|
|
||||||
}
|
|
||||||
*b = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sprintf(buffer, "%d", d);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cRemoteTimer::PrintFirstDay(void) const {
|
|
||||||
if (m_FirstDay) {
|
|
||||||
const char *s = PrintDay(m_Day, m_FirstDay);
|
|
||||||
if (strlen(s) == 18)
|
|
||||||
return s + 8;
|
|
||||||
}
|
|
||||||
return ""; // not NULL, so the caller can always use the result
|
|
||||||
}
|
|
||||||
|
|
||||||
void cRemoteTimer::OnOff(void) {
|
|
||||||
if (IsSingleEvent())
|
|
||||||
m_Active = !m_Active;
|
|
||||||
else if (m_FirstDay) {
|
|
||||||
m_FirstDay = 0;
|
|
||||||
m_Active = false;
|
|
||||||
}
|
|
||||||
else if (m_Active)
|
|
||||||
Skip();
|
|
||||||
else
|
|
||||||
m_Active = true;
|
|
||||||
Matches(); // refresh m_Start and end time
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t cRemoteTimer::SetTime(time_t t, int SecondsFromMidnight) {
|
|
||||||
struct tm tm_r;
|
|
||||||
tm tm = *localtime_r(&t, &tm_r);
|
|
||||||
tm.tm_hour = SecondsFromMidnight / 3600;
|
|
||||||
tm.tm_min = (SecondsFromMidnight % 3600) / 60;
|
|
||||||
tm.tm_sec = SecondsFromMidnight % 60;
|
|
||||||
tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
|
||||||
return mktime(&tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRemoteTimer::Matches(time_t t) {
|
|
||||||
m_StartTime = m_StopTime = 0;
|
|
||||||
if (t == 0)
|
|
||||||
t = time(NULL);
|
|
||||||
|
|
||||||
int begin = TimeToInt(m_Start); // seconds from midnight
|
|
||||||
int length = TimeToInt(m_Stop) - begin;
|
|
||||||
if (length < 0)
|
|
||||||
length += SECSINDAY;
|
|
||||||
|
|
||||||
int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31
|
|
||||||
for (int i = -1; i <= DaysToCheck; i++) {
|
|
||||||
time_t t0 = IncDay(t, i);
|
|
||||||
if (DayMatches(t0)) {
|
|
||||||
time_t a = SetTime(t0, begin);
|
|
||||||
time_t b = a + length;
|
|
||||||
if ((!m_FirstDay || a >= m_FirstDay) && t <= b) {
|
|
||||||
m_StartTime = a;
|
|
||||||
m_StopTime = b;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!m_StartTime)
|
|
||||||
m_StartTime = m_FirstDay; // just to have something that's more than a week in the future
|
|
||||||
else if (t > m_StartTime || t > m_FirstDay + SECSINDAY + 3600) // +3600 in case of DST change
|
|
||||||
m_FirstDay = 0;
|
|
||||||
return m_Active && m_StartTime <= t && t < m_StopTime; // must m_Stop *before* m_StopTime to allow adjacent timers
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRemoteTimer::DayMatches(time_t t) {
|
|
||||||
return IsSingleEvent()
|
|
||||||
? GetMDay(t) == m_Day
|
|
||||||
: (m_Day & (1 << GetWDay(t))) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cRemoteTimer::GetMDay(time_t t)
|
|
||||||
{
|
|
||||||
struct tm tm_r;
|
|
||||||
return localtime_r(&t, &tm_r)->tm_mday;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cRemoteTimer::GetWDay(time_t t)
|
|
||||||
{
|
|
||||||
struct tm tm_r;
|
|
||||||
int weekday = localtime_r(&t, &tm_r)->tm_wday;
|
|
||||||
return weekday == 0 ? 6 : weekday - 1; // we start with monday==0!
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t cRemoteTimer::IncDay(time_t t, int Days) {
|
|
||||||
struct tm tm_r;
|
|
||||||
tm tm = *localtime_r(&t, &tm_r);
|
|
||||||
tm.tm_mday += Days; // now tm_mday may be out of its valid range
|
|
||||||
int h = tm.tm_hour; // save original hour to compensate for DST change
|
|
||||||
tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
|
||||||
t = mktime(&tm); // normalize all values
|
|
||||||
tm.tm_hour = h; // compensate for DST change
|
|
||||||
return mktime(&tm); // calculate final result
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cRemoteTimer::ToText(void) {
|
|
||||||
char *summary = NULL;
|
|
||||||
|
|
||||||
if (m_Buffer != NULL) free(m_Buffer);
|
|
||||||
|
|
||||||
strreplace(m_File, ':', '|');
|
|
||||||
if (m_Summary != "")
|
|
||||||
summary = strreplace(strdup(m_Summary.c_str()), ':', '|');
|
|
||||||
|
|
||||||
asprintf(&m_Buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s", m_Active,
|
|
||||||
(const char*)Channel()->GetChannelID().ToString(), PrintDay(m_Day, m_FirstDay),
|
|
||||||
m_Start, m_Stop, m_Priority, m_Lifetime, m_File, summary ? summary : "");
|
|
||||||
|
|
||||||
if (summary != NULL)
|
|
||||||
free(summary);
|
|
||||||
strreplace(m_File, '|', ':');
|
|
||||||
return m_Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cRemoteTimers ---------------------------------------------------------
|
|
||||||
|
|
||||||
bool cRemoteTimers::Load(void) {
|
|
||||||
Clear();
|
|
||||||
return ClientSocket.LoadTimers(*this);
|
|
||||||
}
|
|
||||||
|
|
131
client/remote.h
131
client/remote.h
@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: remote.h,v 1.2 2005/02/08 17:22:35 lordjaxom Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_REMOTE_H
|
|
||||||
#define VDR_STREAMDEV_REMOTE_H
|
|
||||||
|
|
||||||
#include <vdr/config.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
class cEventInfo;
|
|
||||||
#else
|
|
||||||
class cEvent;
|
|
||||||
#endif
|
|
||||||
class cChannel;
|
|
||||||
|
|
||||||
class cRemoteRecording: public cListObject {
|
|
||||||
private:
|
|
||||||
bool m_IsValid;
|
|
||||||
int m_Index;
|
|
||||||
bool m_IsNew;
|
|
||||||
char *m_TitleBuffer;
|
|
||||||
std::string m_StartTime;
|
|
||||||
std::string m_Name;
|
|
||||||
std::string m_Summary;
|
|
||||||
|
|
||||||
public:
|
|
||||||
cRemoteRecording(const char *Text);
|
|
||||||
~cRemoteRecording();
|
|
||||||
|
|
||||||
bool operator==(const cRemoteRecording &Recording);
|
|
||||||
bool operator!=(const cRemoteRecording &Recording);
|
|
||||||
|
|
||||||
void ParseInfo(const char *Text);
|
|
||||||
|
|
||||||
bool IsValid(void) const { return m_IsValid; }
|
|
||||||
int Index(void) const { return m_Index; }
|
|
||||||
const char *StartTime(void) const { return m_StartTime.c_str(); }
|
|
||||||
bool IsNew(void) const { return m_IsNew; }
|
|
||||||
const char *Name(void) const { return m_Name.c_str(); }
|
|
||||||
const char *Summary(void) const { return m_Summary.c_str(); }
|
|
||||||
const char *Title(char Delimiter, bool NewIndicator, int Level);
|
|
||||||
int HierarchyLevels(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool cRemoteRecording::operator!=(const cRemoteRecording &Recording) {
|
|
||||||
return !operator==(Recording);
|
|
||||||
}
|
|
||||||
|
|
||||||
class cRemoteRecordings: public cList<cRemoteRecording> {
|
|
||||||
public:
|
|
||||||
bool Load(void);
|
|
||||||
cRemoteRecording *GetByName(const char *Name);
|
|
||||||
};
|
|
||||||
|
|
||||||
class cRemoteTimer: public cListObject {
|
|
||||||
friend class cStreamdevMenuEditTimer;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_IsValid;
|
|
||||||
int m_Index;
|
|
||||||
int m_Active;
|
|
||||||
int m_Day;
|
|
||||||
int m_Start;
|
|
||||||
int m_Stop;
|
|
||||||
time_t m_StartTime;
|
|
||||||
time_t m_StopTime;
|
|
||||||
int m_Priority;
|
|
||||||
int m_Lifetime;
|
|
||||||
char m_File[MaxFileName];
|
|
||||||
time_t m_FirstDay;
|
|
||||||
std::string m_Summary;
|
|
||||||
char *m_Buffer;
|
|
||||||
const cChannel *m_Channel;
|
|
||||||
|
|
||||||
public:
|
|
||||||
cRemoteTimer(const char *Text);
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
cRemoteTimer(const cEventInfo *EventInfo);
|
|
||||||
#else
|
|
||||||
cRemoteTimer(const cEvent *Event);
|
|
||||||
#endif
|
|
||||||
cRemoteTimer(void);
|
|
||||||
~cRemoteTimer();
|
|
||||||
|
|
||||||
cRemoteTimer &operator=(const cRemoteTimer &Timer);
|
|
||||||
bool operator==(const cRemoteTimer &Timer);
|
|
||||||
bool operator!=(const cRemoteTimer &Timer) { return !operator==(Timer); }
|
|
||||||
|
|
||||||
static int ParseDay(const char *s, time_t *FirstDay);
|
|
||||||
static const char *PrintDay(int d, time_t FirstDay = 0);
|
|
||||||
static time_t SetTime(time_t t, int SecondsFromMidnight);
|
|
||||||
static time_t IncDay(time_t t, int Days);
|
|
||||||
static int TimeToInt(int t) { return (t / 100 * 60 + t % 100) * 60; }
|
|
||||||
|
|
||||||
const char *PrintFirstDay(void) const;
|
|
||||||
void OnOff(void);
|
|
||||||
bool IsSingleEvent(void) const { return (m_Day & 0x80000000) == 0; }
|
|
||||||
void Skip(void) { m_FirstDay = IncDay(SetTime(StartTime(), 0), 1); }
|
|
||||||
bool Matches(time_t t = 0);
|
|
||||||
bool DayMatches(time_t t = 0);
|
|
||||||
int GetMDay(time_t t);
|
|
||||||
int GetWDay(time_t t);
|
|
||||||
|
|
||||||
bool IsValid(void) const { return m_IsValid; }
|
|
||||||
int Index(void) const { return m_Index; }
|
|
||||||
int Active(void) const { return m_Active; }
|
|
||||||
int Day(void) const { return m_Day; }
|
|
||||||
int Start(void) const { return m_Start; }
|
|
||||||
int Stop(void) const { return m_Stop; }
|
|
||||||
time_t StartTime(void) { if (!m_StartTime) Matches(); return m_StartTime; }
|
|
||||||
time_t StopTime(void) { if (!m_StopTime) Matches(); return m_StopTime; }
|
|
||||||
int Priority(void) const { return m_Priority; }
|
|
||||||
int Lifetime(void) const { return m_Lifetime; }
|
|
||||||
const char *File(void) const { return m_File; }
|
|
||||||
time_t FirstDay(void) const { return m_FirstDay; }
|
|
||||||
const std::string &Summary(void) const { return m_Summary; }
|
|
||||||
const cChannel *Channel(void) const { return m_Channel; }
|
|
||||||
|
|
||||||
const char *ToText(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
class cRemoteTimers: public cList<cRemoteTimer> {
|
|
||||||
public:
|
|
||||||
bool Load(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern cRemoteTimers RemoteTimers;
|
|
||||||
|
|
||||||
#endif // VDR_STREAMDEV_REMOTE_H
|
|
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: setup.c,v 1.2 2005/02/08 15:34:38 lordjaxom Exp $
|
* $Id: setup.c,v 1.8 2009/02/03 10:26:21 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vdr/menuitems.h>
|
#include <vdr/menuitems.h>
|
||||||
|
|
||||||
#include "client/setup.h"
|
#include "client/setup.h"
|
||||||
#include "client/device.h"
|
#include "client/device.h"
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
cStreamdevClientSetup StreamdevClientSetup;
|
cStreamdevClientSetup StreamdevClientSetup;
|
||||||
|
|
||||||
cStreamdevClientSetup::cStreamdevClientSetup(void) {
|
cStreamdevClientSetup::cStreamdevClientSetup(void) {
|
||||||
StartClient = false;
|
StartClient = false;
|
||||||
RemotePort = 2004;
|
RemotePort = 2004;
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
StreamFilters = false;
|
StreamFilters = false;
|
||||||
#endif
|
|
||||||
SyncEPG = false;
|
SyncEPG = false;
|
||||||
|
HideMenuEntry = false;
|
||||||
|
MinPriority = -1;
|
||||||
|
MaxPriority = MAXPRIORITY;
|
||||||
strcpy(RemoteIp, "");
|
strcpy(RemoteIp, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,10 +29,11 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
|
|||||||
strcpy(RemoteIp, Value);
|
strcpy(RemoteIp, Value);
|
||||||
}
|
}
|
||||||
else if (strcmp(Name, "RemotePort") == 0) RemotePort = atoi(Value);
|
else if (strcmp(Name, "RemotePort") == 0) RemotePort = atoi(Value);
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
else if (strcmp(Name, "StreamFilters") == 0) StreamFilters = atoi(Value);
|
else if (strcmp(Name, "StreamFilters") == 0) StreamFilters = atoi(Value);
|
||||||
#endif
|
|
||||||
else if (strcmp(Name, "SyncEPG") == 0) SyncEPG = 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);
|
||||||
else return false;
|
else return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -40,13 +41,14 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
|
|||||||
cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(void) {
|
cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(void) {
|
||||||
m_NewSetup = StreamdevClientSetup;
|
m_NewSetup = StreamdevClientSetup;
|
||||||
|
|
||||||
|
AddBoolEdit (tr("Hide Mainmenu Entry"),m_NewSetup.HideMenuEntry);
|
||||||
AddBoolEdit (tr("Start Client"), m_NewSetup.StartClient);
|
AddBoolEdit (tr("Start Client"), m_NewSetup.StartClient);
|
||||||
AddIpEdit (tr("Remote IP"), m_NewSetup.RemoteIp);
|
AddIpEdit (tr("Remote IP"), m_NewSetup.RemoteIp);
|
||||||
AddShortEdit(tr("Remote Port"), m_NewSetup.RemotePort);
|
AddShortEdit(tr("Remote Port"), m_NewSetup.RemotePort);
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
AddBoolEdit (tr("Filter Streaming"), m_NewSetup.StreamFilters);
|
AddBoolEdit (tr("Filter Streaming"), m_NewSetup.StreamFilters);
|
||||||
#endif
|
|
||||||
AddBoolEdit (tr("Synchronize EPG"), m_NewSetup.SyncEPG);
|
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);
|
||||||
SetCurrent(Get(0));
|
SetCurrent(Get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,8 +59,6 @@ void cStreamdevClientMenuSetupPage::Store(void) {
|
|||||||
if (m_NewSetup.StartClient != StreamdevClientSetup.StartClient) {
|
if (m_NewSetup.StartClient != StreamdevClientSetup.StartClient) {
|
||||||
if (m_NewSetup.StartClient)
|
if (m_NewSetup.StartClient)
|
||||||
cStreamdevDevice::Init();
|
cStreamdevDevice::Init();
|
||||||
else
|
|
||||||
INFO(tr("Please restart VDR to activate changes"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupStore("StartClient", m_NewSetup.StartClient);
|
SetupStore("StartClient", m_NewSetup.StartClient);
|
||||||
@ -67,10 +67,11 @@ void cStreamdevClientMenuSetupPage::Store(void) {
|
|||||||
else
|
else
|
||||||
SetupStore("RemoteIp", m_NewSetup.RemoteIp);
|
SetupStore("RemoteIp", m_NewSetup.RemoteIp);
|
||||||
SetupStore("RemotePort", m_NewSetup.RemotePort);
|
SetupStore("RemotePort", m_NewSetup.RemotePort);
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
SetupStore("StreamFilters", m_NewSetup.StreamFilters);
|
SetupStore("StreamFilters", m_NewSetup.StreamFilters);
|
||||||
#endif
|
|
||||||
SetupStore("SyncEPG", m_NewSetup.SyncEPG);
|
SetupStore("SyncEPG", m_NewSetup.SyncEPG);
|
||||||
|
SetupStore("HideMenuEntry", m_NewSetup.HideMenuEntry);
|
||||||
|
SetupStore("MinPriority", m_NewSetup.MinPriority);
|
||||||
|
SetupStore("MaxPriority", m_NewSetup.MaxPriority);
|
||||||
|
|
||||||
StreamdevClientSetup = m_NewSetup;
|
StreamdevClientSetup = m_NewSetup;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: setup.h,v 1.2 2005/02/08 15:34:38 lordjaxom Exp $
|
* $Id: setup.h,v 1.5 2009/01/29 07:48:59 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_SETUPCLIENT_H
|
#ifndef VDR_STREAMDEV_SETUPCLIENT_H
|
||||||
@ -15,10 +15,11 @@ struct cStreamdevClientSetup {
|
|||||||
int StartClient;
|
int StartClient;
|
||||||
char RemoteIp[20];
|
char RemoteIp[20];
|
||||||
int RemotePort;
|
int RemotePort;
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
int StreamFilters;
|
int StreamFilters;
|
||||||
#endif
|
|
||||||
int SyncEPG;
|
int SyncEPG;
|
||||||
|
int HideMenuEntry;
|
||||||
|
int MinPriority;
|
||||||
|
int MaxPriority;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cStreamdevClientSetup StreamdevClientSetup;
|
extern cStreamdevClientSetup StreamdevClientSetup;
|
||||||
|
239
client/socket.c
239
client/socket.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: socket.c,v 1.9 2008/03/13 16:01:17 schmirl Exp $
|
* $Id: socket.c,v 1.12 2008/04/08 14:18:16 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <tools/select.h>
|
#include <tools/select.h>
|
||||||
@ -13,9 +13,7 @@
|
|||||||
|
|
||||||
#include "client/socket.h"
|
#include "client/socket.h"
|
||||||
#include "client/setup.h"
|
#include "client/setup.h"
|
||||||
#include "client/remote.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
cClientSocket ClientSocket;
|
cClientSocket ClientSocket;
|
||||||
|
|
||||||
@ -141,10 +139,8 @@ bool cClientSocket::CheckConnection(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *Filters = "";
|
const char *Filters = "";
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
if(Command("CAPS FILTERS", 220))
|
if(Command("CAPS FILTERS", 220))
|
||||||
Filters = ",FILTERS";
|
Filters = ",FILTERS";
|
||||||
#endif
|
|
||||||
|
|
||||||
isyslog("Streamdev: Connected to server %s:%d using capabilities TSPIDS%s",
|
isyslog("Streamdev: Connected to server %s:%d using capabilities TSPIDS%s",
|
||||||
RemoteIp().c_str(), RemotePort(), Filters);
|
RemoteIp().c_str(), RemotePort(), Filters);
|
||||||
@ -270,7 +266,6 @@ bool cClientSocket::SetPid(int Pid, bool On) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
|
bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
|
||||||
if (!CheckConnection()) return false;
|
if (!CheckConnection()) return false;
|
||||||
|
|
||||||
@ -286,7 +281,6 @@ bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool cClientSocket::CloseDvr(void) {
|
bool cClientSocket::CloseDvr(void) {
|
||||||
if (!CheckConnection()) return false;
|
if (!CheckConnection()) return false;
|
||||||
@ -342,11 +336,7 @@ bool cClientSocket::SynchronizeEPG(void) {
|
|||||||
|
|
||||||
rewind(epgfd);
|
rewind(epgfd);
|
||||||
if (cSchedules::Read(epgfd))
|
if (cSchedules::Read(epgfd))
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
cSIProcessor::TriggerDump();
|
|
||||||
#else
|
|
||||||
cSchedules::Cleanup(true);
|
cSchedules::Cleanup(true);
|
||||||
#endif
|
|
||||||
else {
|
else {
|
||||||
esyslog("ERROR: Streamdev: Parsing EPG data failed");
|
esyslog("ERROR: Streamdev: Parsing EPG data failed");
|
||||||
fclose(epgfd);
|
fclose(epgfd);
|
||||||
@ -370,128 +360,6 @@ bool cClientSocket::Quit(void) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cClientSocket::LoadRecordings(cRemoteRecordings &Recordings) {
|
|
||||||
bool res;
|
|
||||||
|
|
||||||
if (!CheckConnection()) return false;
|
|
||||||
|
|
||||||
CMD_LOCK;
|
|
||||||
|
|
||||||
if (!Command("LSTR"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::string buffer;
|
|
||||||
while ((res = Expect(250, &buffer))) {
|
|
||||||
cRemoteRecording *rec = new cRemoteRecording(buffer.c_str() + 4);
|
|
||||||
Dprintf("recording valid: %d\n", rec->IsValid());
|
|
||||||
if (rec->IsValid())
|
|
||||||
Recordings.Add(rec);
|
|
||||||
else
|
|
||||||
delete rec;
|
|
||||||
if (buffer[3] == ' ') break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res && buffer.substr(0, 3) != "550") {
|
|
||||||
if (errno == 0)
|
|
||||||
esyslog("ERROR: Streamdev: Couldn't fetch recordings from %s:%d",
|
|
||||||
RemoteIp().c_str(), RemotePort());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cRemoteRecording *r = Recordings.First(); r; r = Recordings.Next(r)) {
|
|
||||||
std::string command = (std::string)"LSTR " + (const char*)itoa(r->Index());
|
|
||||||
if (!Command(command))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Expect(250, &buffer))
|
|
||||||
r->ParseInfo(buffer.c_str() + 4);
|
|
||||||
else if (buffer.substr(0, 3) != "550") {
|
|
||||||
if (errno == 0)
|
|
||||||
esyslog("ERROR: Streamdev: Couldn't fetch details for recording from %s:%d",
|
|
||||||
RemoteIp().c_str(), RemotePort());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Dprintf("recording complete: %d\n", r->Index());
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cClientSocket::StartReplay(const char *Filename) {
|
|
||||||
if (!CheckConnection()) return false;
|
|
||||||
|
|
||||||
CMD_LOCK;
|
|
||||||
|
|
||||||
std::string command = (std::string)"PLAY " + Filename;
|
|
||||||
if (!Command(command, 220)) {
|
|
||||||
if (errno == 0)
|
|
||||||
esyslog("ERROR: Streamdev: Couldn't replay \"%s\" from %s:%d",
|
|
||||||
Filename, RemoteIp().c_str(), RemotePort());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cClientSocket::AbortReplay(void) {
|
|
||||||
if (!CheckConnection()) return false;
|
|
||||||
|
|
||||||
CMD_LOCK;
|
|
||||||
|
|
||||||
if (m_DataSockets[siReplay] != NULL) {
|
|
||||||
std::string command = (std::string)"ABRT " + (const char*)itoa(siReplay);
|
|
||||||
if (!Command(command, 220)) {
|
|
||||||
if (errno == 0)
|
|
||||||
esyslog("ERROR: Streamdev: Couldn't cleanly close data connection");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DELETENULL(m_DataSockets[siReplay]);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cClientSocket::DeleteRecording(cRemoteRecording *Recording) {
|
|
||||||
bool res;
|
|
||||||
cRemoteRecording *rec = NULL;
|
|
||||||
|
|
||||||
if (!CheckConnection())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CMD_LOCK;
|
|
||||||
|
|
||||||
if (!Command("LSTR"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::string buffer;
|
|
||||||
while ((res = Expect(250, &buffer))) {
|
|
||||||
if (rec == NULL) {
|
|
||||||
rec = new cRemoteRecording(buffer.c_str() + 4);
|
|
||||||
if (!rec->IsValid() || rec->Index() != Recording->Index())
|
|
||||||
DELETENULL(rec);
|
|
||||||
}
|
|
||||||
if (buffer[3] == ' ') break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res && buffer.substr(0, 3) != "550") {
|
|
||||||
if (errno == 0)
|
|
||||||
esyslog("ERROR: Streamdev: Couldn't fetch recordings from %s:%d",
|
|
||||||
RemoteIp().c_str(), RemotePort());
|
|
||||||
if (rec != NULL) delete rec;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rec == NULL || *rec != *Recording) {
|
|
||||||
ERROR(tr("Recordings not in sync! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string command = (std::string)"DELR " + (const char*)itoa(Recording->Index());
|
|
||||||
if (!Command(command, 250)) {
|
|
||||||
ERROR(tr("Couldn't delete recording! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cClientSocket::SuspendServer(void) {
|
bool cClientSocket::SuspendServer(void) {
|
||||||
if (!CheckConnection()) return false;
|
if (!CheckConnection()) return false;
|
||||||
|
|
||||||
@ -504,108 +372,3 @@ bool cClientSocket::SuspendServer(void) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cClientSocket::LoadTimers(cRemoteTimers &Timers) {
|
|
||||||
if (!CheckConnection()) return false;
|
|
||||||
|
|
||||||
CMD_LOCK;
|
|
||||||
|
|
||||||
if (!Command("LSTT"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool res;
|
|
||||||
std::string buffer;
|
|
||||||
while ((res = Expect(250, &buffer))) {
|
|
||||||
cRemoteTimer *timer = new cRemoteTimer(buffer.c_str() + 4);
|
|
||||||
Dprintf("timer valid: %d\n", timer->IsValid());
|
|
||||||
if (timer->IsValid())
|
|
||||||
Timers.Add(timer);
|
|
||||||
if (buffer[3] == ' ') break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res && buffer.substr(0, 3) != "550") {
|
|
||||||
if (errno == 0)
|
|
||||||
esyslog("ERROR: Streamdev: Couldn't fetch recordings from %s:%d",
|
|
||||||
RemoteIp().c_str(), RemotePort());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cClientSocket::SaveTimer(cRemoteTimer *Old, cRemoteTimer &New) {
|
|
||||||
if (!CheckConnection()) return false;
|
|
||||||
|
|
||||||
CMD_LOCK;
|
|
||||||
|
|
||||||
if (New.Index() == -1) { // New timer
|
|
||||||
std::string command = (std::string)"NEWT " + (const char*)New.ToText();
|
|
||||||
if (!Command(command, 250)) {
|
|
||||||
ERROR(tr("Couldn't save timer! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else { // Modified timer
|
|
||||||
std::string command = (std::string)"LSTT " + (const char*)itoa(New.Index());
|
|
||||||
if (!Command(command))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::string buffer;
|
|
||||||
if (!Expect(250, &buffer)) {
|
|
||||||
if (errno == 0)
|
|
||||||
ERROR(tr("Timers not in sync! Try again..."));
|
|
||||||
else
|
|
||||||
ERROR(tr("Server error! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cRemoteTimer oldstate(buffer.c_str() + 4);
|
|
||||||
if (oldstate != *Old) {
|
|
||||||
/*Dprintf("old timer: %d,%d,%d,%d,%d,%d,%s,%d,%s,%d\n", oldstate.m_Index,
|
|
||||||
oldstate.m_Active,oldstate.m_Day,oldstate.m_Start,oldstate.m_StartTime,oldstate.m_Priority,oldstate.m_File,oldstate.m_FirstDay,(const char*)oldstate.m_Summary,oldstate.m_Channel->Number());
|
|
||||||
Dprintf("new timer: %d,%d,%d,%d,%d,%d,%s,%d,%s,%d\n", Old->m_Index,
|
|
||||||
Old->m_Active,Old->m_Day,Old->m_Start,Old->m_StartTime,Old->m_Priority,Old->m_File,Old->m_FirstDay,(const char*)Old->m_Summary,Old->m_Channel->Number());*/
|
|
||||||
ERROR(tr("Timers not in sync! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
command = (std::string)"MODT " + (const char*)itoa(New.Index()) + " "
|
|
||||||
+ (const char*)New.ToText();
|
|
||||||
if (!Command(command, 250)) {
|
|
||||||
ERROR(tr("Couldn't save timer! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cClientSocket::DeleteTimer(cRemoteTimer *Timer) {
|
|
||||||
if (!CheckConnection()) return false;
|
|
||||||
|
|
||||||
CMD_LOCK;
|
|
||||||
|
|
||||||
std::string command = (std::string)"LSTT " + (const char*)itoa(Timer->Index());
|
|
||||||
if (!Command(command))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::string buffer;
|
|
||||||
if (!Expect(250, &buffer)) {
|
|
||||||
if (errno == 0)
|
|
||||||
ERROR(tr("Timers not in sync! Try again..."));
|
|
||||||
else
|
|
||||||
ERROR(tr("Server error! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cRemoteTimer oldstate(buffer.c_str() + 4);
|
|
||||||
if (oldstate != *Timer) {
|
|
||||||
ERROR(tr("Timers not in sync! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
command = (std::string)"DELT " + (const char*)itoa(Timer->Index());
|
|
||||||
if (!Command(command, 250)) {
|
|
||||||
ERROR(tr("Couldn't delete timer! Try again..."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: socket.h,v 1.4 2007/04/24 10:57:34 schmirl Exp $
|
* $Id: socket.h,v 1.6 2008/04/07 14:40:40 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_CLIENT_CONNECTION_H
|
#ifndef VDR_STREAMDEV_CLIENT_CONNECTION_H
|
||||||
@ -13,10 +13,6 @@
|
|||||||
|
|
||||||
#define CMD_LOCK cMutexLock CmdLock((cMutex*)&m_Mutex)
|
#define CMD_LOCK cMutexLock CmdLock((cMutex*)&m_Mutex)
|
||||||
|
|
||||||
class cRemoteRecordings;
|
|
||||||
class cRemoteRecording;
|
|
||||||
class cRemoteTimers;
|
|
||||||
class cRemoteTimer;
|
|
||||||
class cPES2TSRemux;
|
class cPES2TSRemux;
|
||||||
|
|
||||||
class cClientSocket: public cTBSocket {
|
class cClientSocket: public cTBSocket {
|
||||||
@ -50,18 +46,9 @@ public:
|
|||||||
bool CloseDataConnection(eSocketId Id);
|
bool CloseDataConnection(eSocketId Id);
|
||||||
bool SetChannelDevice(const cChannel *Channel);
|
bool SetChannelDevice(const cChannel *Channel);
|
||||||
bool SetPid(int Pid, bool On);
|
bool SetPid(int Pid, bool On);
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On);
|
bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On);
|
||||||
#endif
|
|
||||||
bool CloseDvr(void);
|
bool CloseDvr(void);
|
||||||
bool SynchronizeEPG(void);
|
bool SynchronizeEPG(void);
|
||||||
bool LoadRecordings(cRemoteRecordings &Recordings);
|
|
||||||
bool StartReplay(const char *Filename);
|
|
||||||
bool AbortReplay(void);
|
|
||||||
bool DeleteRecording(cRemoteRecording *Recording);
|
|
||||||
bool LoadTimers(cRemoteTimers &Timers);
|
|
||||||
bool SaveTimer(cRemoteTimer *Old, cRemoteTimer &New);
|
|
||||||
bool DeleteTimer(cRemoteTimer *Timer);
|
|
||||||
bool SuspendServer(void);
|
bool SuspendServer(void);
|
||||||
bool Quit(void);
|
bool Quit(void);
|
||||||
|
|
||||||
|
24
common.c
24
common.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: common.c,v 1.6 2008/03/31 10:34:26 schmirl Exp $
|
* $Id: common.c,v 1.9 2009/01/16 11:35:43 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vdr/channels.h>
|
#include <vdr/channels.h>
|
||||||
@ -7,15 +7,16 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "tools/select.h"
|
#include "tools/select.h"
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const char *VERSION = "0.3.4";
|
const char *VERSION = "0.5.0-pre-20090611";
|
||||||
|
|
||||||
const char *StreamTypes[st_Count] = {
|
const char *StreamTypes[st_Count] = {
|
||||||
"TS",
|
"TS",
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
"PES",
|
"PES",
|
||||||
|
#endif
|
||||||
"PS",
|
"PS",
|
||||||
"ES",
|
"ES",
|
||||||
"Extern",
|
"Extern",
|
||||||
@ -23,9 +24,9 @@ const char *StreamTypes[st_Count] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const char *SuspendModes[sm_Count] = {
|
const char *SuspendModes[sm_Count] = {
|
||||||
"Offer suspend mode",
|
trNOOP("Offer suspend mode"),
|
||||||
"Always suspended",
|
trNOOP("Always suspended"),
|
||||||
"Never suspended"
|
trNOOP("Never suspended")
|
||||||
};
|
};
|
||||||
|
|
||||||
const char IpCharacters[] = "0123456789.";
|
const char IpCharacters[] = "0123456789.";
|
||||||
@ -113,16 +114,7 @@ void cStreamdevMenuSetupPage::AddCategory(const char *Title) {
|
|||||||
|
|
||||||
cOsdItem *item = new cOsdItem(buffer);
|
cOsdItem *item = new cOsdItem(buffer);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
item->SetSelectable(false);
|
||||||
#if VDRVERSNUM < 10307
|
|
||||||
# ifdef HAVE_BEAUTYPATCH
|
|
||||||
item->SetColor(clrScrolLine, clrBackground);
|
|
||||||
# else
|
|
||||||
item->SetColor(clrCyan, clrBackground);
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
item->SetSelectable(false);
|
|
||||||
#endif
|
|
||||||
Add(item);
|
Add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
common.h
22
common.h
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: common.h,v 1.9 2008/03/12 09:36:27 schmirl Exp $
|
* $Id: common.h,v 1.12 2009/01/16 11:35:43 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_COMMON_H
|
#ifndef VDR_STREAMDEV_COMMON_H
|
||||||
@ -23,27 +23,9 @@
|
|||||||
# define Dprintf(x...)
|
# define Dprintf(x...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
# define TRANSPONDER(c1, c2) (ISTRANSPONDER(c1->Frequency(), c2->Frequency()))
|
|
||||||
#else
|
|
||||||
# define TRANSPONDER(c1, c2) (c1->Transponder() == c2->Transponder())
|
# define TRANSPONDER(c1, c2) (c1->Transponder() == c2->Transponder())
|
||||||
#endif
|
|
||||||
|
|
||||||
#if VDRVERSNUM < 10307
|
|
||||||
# define INFO(s) Interface->Info(s)
|
|
||||||
# define STATUS(s) Interface->Status(s)
|
|
||||||
# define ERROR(s) Interface->Status(s)
|
|
||||||
# define FLUSH() Interface->Flush()
|
|
||||||
#else
|
|
||||||
# define INFO(s) Skins.Message(mtInfo, s)
|
|
||||||
# define STATUS(s) Skins.Message(mtInfo, s)
|
|
||||||
# define ERROR(s) Skins.Message(mtStatus, s)
|
|
||||||
# define FLUSH() Skins.Flush()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10336
|
|
||||||
# define MAXPARSEBUFFER KILOBYTE(16)
|
# define MAXPARSEBUFFER KILOBYTE(16)
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Check if a channel is a radio station. */
|
/* Check if a channel is a radio station. */
|
||||||
#define ISRADIO(x) ((x)->Vpid()==0||(x)->Vpid()==1||(x)->Vpid()==0x1fff)
|
#define ISRADIO(x) ((x)->Vpid()==0||(x)->Vpid()==1||(x)->Vpid()==0x1fff)
|
||||||
@ -69,7 +51,9 @@ const cChannel *ChannelFromString(const char *String, int *Apid = NULL);
|
|||||||
|
|
||||||
enum eStreamType {
|
enum eStreamType {
|
||||||
stTS,
|
stTS,
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
stPES,
|
stPES,
|
||||||
|
#endif
|
||||||
stPS,
|
stPS,
|
||||||
stES,
|
stES,
|
||||||
stExtern,
|
stExtern,
|
||||||
|
831
i18n.c
831
i18n.c
@ -1,831 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: i18n.c,v 1.5 2006/08/17 09:26:00 thomas Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
const char *i18n_name = NULL;
|
|
||||||
|
|
||||||
const tI18nPhrase Phrases[] = {
|
|
||||||
{ "VDR Streaming Server", // English
|
|
||||||
"VDR Streaming Server", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"VDR-suoratoistopalvelin", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika / Greek
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "VTP Streaming Client", // English
|
|
||||||
"VTP Streaming Client", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"VTP-suoratoistoasiakas ", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika / Greek
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Start VDR-to-VDR Server",// English
|
|
||||||
"VDR-zu-VDR Server starten",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Avvia il Server VDR-toVDR",// Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Käynnistä VDR-palvelin", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika / Greek
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Start HTTP Server", // English
|
|
||||||
"HTTP Server starten", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Avvia il Server HTTP", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Käynnistä HTTP-palvelin", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "HTTP Streamtype", // English
|
|
||||||
"HTTP Streamtyp", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Tipo di Stream HTTP", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"HTTP-lähetysmuoto", // Suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Start Client", // English
|
|
||||||
"Client starten", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Avvia il Client", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Käynnistä VDR-asiakas", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "VDR-to-VDR Server Port",// English
|
|
||||||
"Port des VDR-zu-VDR Servers",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Porta del Server VDR-to-VDR",// Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"VDR-palvelimen portti", // Suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "HTTP Server Port", // English
|
|
||||||
"Port des HTTP Servers",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Porta del Server HTTP",// Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"HTTP-palvelimen portti", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Maximum Number of Clients",// English
|
|
||||||
"Maximalanzahl an Clients",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Numero Massimo di Client",// Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Suurin sallittu asiakkaiden määrä", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Remote IP", // English
|
|
||||||
"IP der Gegenseite", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Indirizzo IP del Server",// Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Etäkoneen IP-osoite", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Remote Port", // English
|
|
||||||
"Port der Gegenseite", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Porta del Server Remoto",// Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Etäkoneen portti", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Remote Streamtype", // English
|
|
||||||
"Streamtyp von Gegenseite",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Tipo di Stream", // Italiano (oppure Flusso ?)
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Etäkoneen lähetysmuoto", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Common Settings", // English
|
|
||||||
"Allgemeines", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Settaggi Comuni", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Yleiset asetukset", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "VDR-to-VDR Server", // English
|
|
||||||
"VDR-zu-VDR Server", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Server VDR-to-VDR", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"VDR-palvelin", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "HTTP Server", // English
|
|
||||||
"HTTP Server", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Server HTTP", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"HTTP-palvelin", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "VDR-to-VDR Client", // English
|
|
||||||
"VDR-zu-VDR Client", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Client VDR-to-VDR", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"VDR-asiakas", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Please restart VDR to activate changes",// English
|
|
||||||
"Bitte starten Sie für die Änderungen VDR neu",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"Riavviare VDR per attivare i cambiamenti",// Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Aktivoi muutokset käynnistämällä VDR uudelleen", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Synchronize EPG", // English
|
|
||||||
"EPG synchronisieren", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Päivitä ohjelmaopas", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Suspend Live TV", // English
|
|
||||||
"Live-TV pausieren", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Pysäytä suora TV-lähetys", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Suspend behaviour", // English
|
|
||||||
"Pausierverhalten", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Pysäytystoiminto", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Offer suspend mode", // English
|
|
||||||
"Pausieren anbieten", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"tyrkytä", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Always suspended", // English
|
|
||||||
"Immer pausiert", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"aina", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Never suspended", // English
|
|
||||||
"Nie pausiert", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"ei koskaan", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Streaming Control", // English
|
|
||||||
"Streamkontrolle", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Suoratoiston hallinta", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Fetching recordings...",// English
|
|
||||||
"Hole Aufnahmen...", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Haetaan tallenteita...", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Remote Recordings", // English
|
|
||||||
"Entfernte Aufnahmen", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Etätallenteet", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Remote Timers", // English
|
|
||||||
"Entfernte Timer", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Etäajastimet", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Suspend Server", // English
|
|
||||||
"Server pausieren", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Pysäytä palvelin", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Server is suspended", // English
|
|
||||||
"Server ist pausiert", // Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Palvelin on pysäytetty", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Couldn't suspend Server!",// English
|
|
||||||
"Konnte Server nicht pausieren!",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Palvelinta ei onnistuttu pysäyttämään!", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Edit remote timer", // English
|
|
||||||
"Entfernten Timer editieren",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Muokkaa etäajastinta", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Timers not in sync! Try again...",// Englisch
|
|
||||||
"Timer nicht synchron! Bitte wiederholen...",//Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Ajastimet eivät täsmää! Yritä uudelleen...", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Couldn't save timer! Try again...",// English
|
|
||||||
"Konnte Timer nicht speichern! Bitte wiederholen...",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Ajastimen tallennus epäonnistui! Yritä uudelleen...", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Couldn't delete timer! Try again...",// English
|
|
||||||
"Konnte Timer nicht löschen! Bitte wiederholen...",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Ajastimen poistaminen epäonnistui! Yritä uudelleen...", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Server error! Try again...",// English
|
|
||||||
"Serverfehler! Bitte wiederholen...",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Palvelimessa virhe! Yritä uudelleen...", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "MultiPID Streaming", // English
|
|
||||||
"Multiple PIDs streamen",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Usean PID:in suoratoisto", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Client may suspend", // English
|
|
||||||
"Client darf pausieren",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Asiakas saa pysäyttää palvelimen", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Bind to IP", // English
|
|
||||||
"",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Sido osoitteeseen", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Remote Schedule", // English
|
|
||||||
"",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Etäkoneen ohjelmaopas", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Filter Streaming", // English
|
|
||||||
"",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Suodatetun tiedon suoratoisto", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ "Streaming active", // English
|
|
||||||
"Streamen im Gange",// Deutsch
|
|
||||||
"", // Slovenski
|
|
||||||
"", // Italiano
|
|
||||||
"", // Nederlands
|
|
||||||
"", // Português
|
|
||||||
"", // Français
|
|
||||||
"", // Norsk
|
|
||||||
"Suoratoistopalvelin aktiivinen", // suomi
|
|
||||||
"", // Polski
|
|
||||||
"", // Español
|
|
||||||
"", // Ellinika
|
|
||||||
"", // Svenska
|
|
||||||
"", // Romaneste
|
|
||||||
"", // Magyar
|
|
||||||
"", // Catala
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
"" // Russian
|
|
||||||
#endif
|
|
||||||
},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
16
i18n.h
16
i18n.h
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: i18n.h,v 1.1.1.1 2004/12/30 22:43:58 lordjaxom Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_I18N_H
|
|
||||||
#define VDR_STREAMDEV_I18N_H
|
|
||||||
|
|
||||||
#include <vdr/i18n.h>
|
|
||||||
|
|
||||||
extern const char *i18n_name;
|
|
||||||
extern const tI18nPhrase Phrases[];
|
|
||||||
|
|
||||||
#undef tr
|
|
||||||
#define tr(s) I18nTranslate(s, i18n_name)
|
|
||||||
|
|
||||||
#endif // VDR_STREAMDEV_I18N_H
|
|
@ -1,446 +0,0 @@
|
|||||||
#ifndef _DVB_DEV_HH_
|
|
||||||
#define _DVB_DEV_HH_
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <asm/errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#define NEWSTRUCT
|
|
||||||
#include <channel.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#include <osd.hh>
|
|
||||||
#include <devices.hh>
|
|
||||||
|
|
||||||
#ifndef MAXNAM
|
|
||||||
#define MAXNAM 80
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define FRONT_DVBS 1
|
|
||||||
#define FRONT_DVBC 2
|
|
||||||
#define FRONT_DVBT 3
|
|
||||||
|
|
||||||
#define VTXDIR "/var/vtx"
|
|
||||||
|
|
||||||
#define DEC(N) dec << setw(N) << setfill('0')
|
|
||||||
#define HEX(N) hex << setw(N) << setfill('0')
|
|
||||||
|
|
||||||
#define MAXSECSIZE 4096
|
|
||||||
|
|
||||||
#define NK 10
|
|
||||||
enum {LNB=0,DIS,ROTOR,TRANS,CHAN,BOU,SAT,PICS,SWI,NTW};
|
|
||||||
static const int nums[]={LNB,DIS,ROTOR,TRANS,CHAN,BOU,SAT,PICS,SWI,NTW};
|
|
||||||
static const int maxs[]={ 32, 32, 32, 512,16384,512,100, 50, 10, 100};
|
|
||||||
|
|
||||||
#define MAX_TRANS_CHAN 1024
|
|
||||||
|
|
||||||
enum{DVB_ORIG=0, DVB_NOKIA, DVB_XML, DVB_SATCO};
|
|
||||||
|
|
||||||
typedef struct frontend_stat_s{
|
|
||||||
fe_status_t status;
|
|
||||||
uint16_t snr;
|
|
||||||
uint16_t strength;
|
|
||||||
uint32_t ber;
|
|
||||||
uint32_t u_blocks;
|
|
||||||
} frontend_stat;
|
|
||||||
|
|
||||||
|
|
||||||
extern uint8_t hamtab[256];
|
|
||||||
extern uint8_t invtab[256];
|
|
||||||
|
|
||||||
#define MAX_MAG 8
|
|
||||||
typedef struct mag_struct_ {
|
|
||||||
int valid;
|
|
||||||
int magn;
|
|
||||||
uint8_t flags;
|
|
||||||
uint8_t lang;
|
|
||||||
int pnum,sub;
|
|
||||||
uint8_t pagebuf[25*40];
|
|
||||||
} magazin_t;
|
|
||||||
|
|
||||||
|
|
||||||
class DVB {
|
|
||||||
public:
|
|
||||||
int no_open;
|
|
||||||
int fd_frontend;
|
|
||||||
int fd_demuxa;
|
|
||||||
int fd_demuxv;
|
|
||||||
int fd_demuxpcr;
|
|
||||||
int fd_demuxtt;
|
|
||||||
int fdvb;
|
|
||||||
|
|
||||||
int minor;
|
|
||||||
int adapter;
|
|
||||||
int max_tpid;
|
|
||||||
int max_satid;
|
|
||||||
int max_chanid;
|
|
||||||
|
|
||||||
frontend_stat festat;
|
|
||||||
|
|
||||||
struct dvb_diseqc_master_cmd dcmd;
|
|
||||||
fe_sec_tone_mode_t tone;
|
|
||||||
fe_sec_voltage_t voltage;
|
|
||||||
int burst;
|
|
||||||
struct dmx_pes_filter_params pesFilterParamsV;
|
|
||||||
struct dmx_pes_filter_params pesFilterParamsA;
|
|
||||||
struct dmx_pes_filter_params pesFilterParamsP;
|
|
||||||
struct dmx_pes_filter_params pesFilterParamsTT;
|
|
||||||
struct dvb_frontend_parameters front_param;
|
|
||||||
int front_type;
|
|
||||||
int dvr_enabled;
|
|
||||||
OSD osd;
|
|
||||||
uint32_t transponder_freq;
|
|
||||||
char transponder_pol;
|
|
||||||
uint32_t transponder_srate;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fe_status_t status;
|
|
||||||
uint32_t ber, uncorrected_blocks;
|
|
||||||
uint16_t snr, signal;
|
|
||||||
|
|
||||||
|
|
||||||
struct Lnb *lnbs;
|
|
||||||
struct DiSEqC *diseqcs;
|
|
||||||
struct Rotor *rotors;
|
|
||||||
struct Transponder *tps;
|
|
||||||
struct Channel *chans;
|
|
||||||
struct Bouquet *bouqs;
|
|
||||||
struct Sat *sats;
|
|
||||||
struct Picture *pics;
|
|
||||||
struct Switch *swis;
|
|
||||||
struct Network *ntws;
|
|
||||||
int num[NK];
|
|
||||||
int oldsec;
|
|
||||||
int tryit;
|
|
||||||
int oldpol;
|
|
||||||
|
|
||||||
char *vtxdir;
|
|
||||||
magazin_t magazin[MAX_MAG];
|
|
||||||
|
|
||||||
DVB(){
|
|
||||||
no_open = 0;
|
|
||||||
max_tpid = 0;
|
|
||||||
max_satid = 0;
|
|
||||||
max_chanid = 0;
|
|
||||||
minor = 0;
|
|
||||||
|
|
||||||
fd_frontend = -1;
|
|
||||||
fd_demuxa = -1;
|
|
||||||
fd_demuxpcr = -1;
|
|
||||||
fd_demuxv = -1;
|
|
||||||
fd_demuxtt = -1;
|
|
||||||
fdvb = -1;
|
|
||||||
vtxdir = NULL;
|
|
||||||
transponder_freq=0;
|
|
||||||
transponder_pol=0;
|
|
||||||
transponder_srate=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DVB(int i){
|
|
||||||
if (i >= 0)
|
|
||||||
no_open = 0;
|
|
||||||
else
|
|
||||||
no_open = 1;
|
|
||||||
max_tpid = 0;
|
|
||||||
max_satid = 0;
|
|
||||||
max_chanid = 0;
|
|
||||||
|
|
||||||
fd_frontend = -1;
|
|
||||||
fd_demuxa = -1;
|
|
||||||
fd_demuxpcr = -1;
|
|
||||||
fd_demuxv = -1;
|
|
||||||
fd_demuxtt = -1;
|
|
||||||
fdvb = -1;
|
|
||||||
vtxdir = NULL;
|
|
||||||
transponder_freq=0;
|
|
||||||
transponder_pol=0;
|
|
||||||
transponder_srate=0;
|
|
||||||
|
|
||||||
init("","",i);
|
|
||||||
}
|
|
||||||
|
|
||||||
DVB(char *a, char *b) {
|
|
||||||
max_tpid = 0;
|
|
||||||
max_satid = 0;
|
|
||||||
max_chanid = 0;
|
|
||||||
|
|
||||||
fd_frontend = -1;
|
|
||||||
fd_demuxa = -1;
|
|
||||||
fd_demuxpcr = -1;
|
|
||||||
fd_demuxv = -1;
|
|
||||||
fd_demuxtt = -1;
|
|
||||||
|
|
||||||
fdvb = -1;
|
|
||||||
vtxdir = NULL;
|
|
||||||
init(a,b,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
~DVB();
|
|
||||||
|
|
||||||
void use_osd(int fd = -1){
|
|
||||||
char dvn[32];
|
|
||||||
if (no_open) return;
|
|
||||||
if (fd < 0) fd = 0;
|
|
||||||
sprintf(dvn,OSD_DEV,adapter,fd);
|
|
||||||
fdvb = open(dvn, O_RDWR);
|
|
||||||
|
|
||||||
if (fdvb >= 0){
|
|
||||||
cerr << dvn << " for OSD" << endl;
|
|
||||||
osd.init(fdvb);
|
|
||||||
} else perror("osd");
|
|
||||||
osd.Open(80, 500, 640, 540, 2, 0, 2);
|
|
||||||
osd.SetColor(0, 0, 0, 0, 255);
|
|
||||||
osd.SetColor(1, 240, 240, 240, 255);
|
|
||||||
osd.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_vtxdir(char *newname){
|
|
||||||
if (!newname) return;
|
|
||||||
if (vtxdir) free(vtxdir);
|
|
||||||
vtxdir = (char *) malloc(sizeof(char)*(strlen(newname)+1));
|
|
||||||
if (vtxdir)
|
|
||||||
strncpy(vtxdir, newname, strlen(newname));
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_osd(){
|
|
||||||
osd.Close(fdvb);
|
|
||||||
close(fdvb);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DVR_enabled(){
|
|
||||||
if (no_open) return -1;
|
|
||||||
return dvr_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_DVR(){
|
|
||||||
if (no_open) return;
|
|
||||||
dvr_enabled = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_DVR_other(){
|
|
||||||
if (no_open) return;
|
|
||||||
dvr_enabled = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable_DVR(){
|
|
||||||
if (no_open) return;
|
|
||||||
dvr_enabled = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(char *a="/dev/video0", char *b="/dev/vbi0",int adapt=0,
|
|
||||||
int minor = 0);
|
|
||||||
|
|
||||||
|
|
||||||
inline void init(char *a, char *b){
|
|
||||||
if (no_open) return;
|
|
||||||
init(a,b,0,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int check_frontend();
|
|
||||||
|
|
||||||
void set_apid(ushort apid);
|
|
||||||
void set_vpid(ushort vpid);
|
|
||||||
void set_pcrpid(ushort vpid);
|
|
||||||
void set_ttpid(ushort ttpid);
|
|
||||||
int set_apid_fd(ushort apid, int fd);
|
|
||||||
int set_vpid_fd(ushort vpid, int fd);
|
|
||||||
int set_ttpid_fd(ushort ttpid, int fd);
|
|
||||||
int set_pcrpid_fd(ushort pcrpid, int fd);
|
|
||||||
int set_otherpid_fd(ushort otherpid, int fd);
|
|
||||||
|
|
||||||
|
|
||||||
int set_lnb(int dis);
|
|
||||||
void set_diseqc_nb(int nr);
|
|
||||||
int set_front(void);
|
|
||||||
void get_front(void);
|
|
||||||
|
|
||||||
void scan_pf_eit(int chnr,
|
|
||||||
int (*callback)(uint8_t *data, int l, int pnr,
|
|
||||||
int c_n, uint8_t *t));
|
|
||||||
|
|
||||||
void scan_pf_eit(Channel *chan,
|
|
||||||
int (*callback)(uint8_t *data, int l, int pnr,
|
|
||||||
int c_n, uint8_t *t));
|
|
||||||
void scan_pf_eit(int chnr);
|
|
||||||
|
|
||||||
|
|
||||||
int search_in_TP(Transponder &tp, int show=1, int verbose=0);
|
|
||||||
int search_in_TP(uint16_t tpid, uint16_t satid, int show=1,
|
|
||||||
int verbose=0);
|
|
||||||
int scan_TP(uint16_t tpid, uint16_t satid, int timeout=-1, int verbose=0);
|
|
||||||
|
|
||||||
int GetSection(uint8_t *buf,
|
|
||||||
uint16_t PID, uint8_t TID, uint16_t TIDExt,
|
|
||||||
uint16_t FilterTIDExt,
|
|
||||||
uint8_t secnum, uint8_t &msecnum);
|
|
||||||
int GetSection(uint8_t *buf,
|
|
||||||
uint16_t PID, uint8_t *filter, uint8_t *mask,
|
|
||||||
uint8_t secnum, uint8_t &msecnum);
|
|
||||||
int GetSection(uint8_t *buf, ushort PID, uint8_t sec,
|
|
||||||
uint8_t secnum, uint8_t &msecnum);
|
|
||||||
int SetFilter(uint16_t pid, uint8_t *filter,
|
|
||||||
uint8_t *mask,
|
|
||||||
uint32_t timeout, uint32_t flags);
|
|
||||||
uint16_t SetFilter(uint16_t pid, uint16_t section, uint16_t mode);
|
|
||||||
int CloseFilter(int h);
|
|
||||||
|
|
||||||
|
|
||||||
void bar2(int x, int y, int w, int h, int val, int col1, int col2);
|
|
||||||
|
|
||||||
int SetTP(unsigned int, unsigned int);
|
|
||||||
int scan(void);
|
|
||||||
int scan_all_tps(void);
|
|
||||||
int scan_lnb(struct Lnb &);
|
|
||||||
int scan_cable(Sat &sat);
|
|
||||||
int scan_sat(struct Sat &);
|
|
||||||
int scan_tp(struct Transponder &);
|
|
||||||
|
|
||||||
int AddLNB(int id, int t, uint l1, uint l2, uint sl,
|
|
||||||
int dnr, int dis, int sw);
|
|
||||||
int AddSat(Sat &sat);
|
|
||||||
int AddSat(int satid, unsigned int lnbid, char *name, uint fmin, uint fmax);
|
|
||||||
int AddTP(Transponder &tp);
|
|
||||||
int AddChannel(Channel &chan);
|
|
||||||
int parse_descriptor(Channel *chan, uint8_t *data, int length);
|
|
||||||
int parse_pmt(Channel *chan, uint8_t *data);
|
|
||||||
int parse_pat(Channel *chan, uint8_t *data);
|
|
||||||
|
|
||||||
int check_pids(Channel *chan);
|
|
||||||
void check_all_pids();
|
|
||||||
void scan_sdt(Channel *chan);
|
|
||||||
int scan_sdts(int *chs, int n);
|
|
||||||
|
|
||||||
int channel_num(void) {
|
|
||||||
return num[CHAN];
|
|
||||||
};
|
|
||||||
|
|
||||||
int channel_change(int n) {
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int SetChannel(uint16_t, uint16_t, uint16_t, uint16_t);
|
|
||||||
int SetChannel(Channel *chan, char* apref=NULL, uint16_t *apidp=NULL,
|
|
||||||
uint16_t *vpidp=NULL) ;
|
|
||||||
int SetChannel(int chnr, char *apref=NULL, uint16_t *apidp=NULL,
|
|
||||||
uint16_t *vpidp=NULL);
|
|
||||||
int GetChannel(int chnr, struct channel *);
|
|
||||||
int NumChannel(void) {
|
|
||||||
return num[CHAN];
|
|
||||||
}
|
|
||||||
int tune_it(struct dvb_frontend_parameters *qpsk);
|
|
||||||
void find_satid(Channel &chan);
|
|
||||||
int check_input_format(istream &ins);
|
|
||||||
void read_original(istream &ins);
|
|
||||||
int get_all_progs(uint16_t *progbuf, uint16_t *pnrbuf, int length);
|
|
||||||
uint16_t find_pnr(uint16_t vpid, uint16_t apid);
|
|
||||||
int get_pids(uint16_t prog_pid, uint16_t *vpid, uint16_t *apids,
|
|
||||||
uint16_t *ttpid, uint8_t *apids_name=NULL);
|
|
||||||
void AddECM(Channel *chan, uint8_t *data, int length);
|
|
||||||
int check_ecm(Channel *chan);
|
|
||||||
void add_vtx_line(magazin_t *mag, int line, uint8_t *data, int pnr);
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, DVB &x);
|
|
||||||
friend istream &operator>>(istream &stream, DVB &x);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NOKIA_MAX_SAT 4
|
|
||||||
class nokiaconv{
|
|
||||||
public:
|
|
||||||
DVB *dvb;
|
|
||||||
struct lnb_sat_l{
|
|
||||||
int n;
|
|
||||||
int diseqc[NOKIA_MAX_SAT];
|
|
||||||
char sat_names[NOKIA_MAX_SAT][MAXNAM+1];
|
|
||||||
int satid[NOKIA_MAX_SAT];
|
|
||||||
} lnb_sat;
|
|
||||||
|
|
||||||
nokiaconv(DVB *d){
|
|
||||||
dvb = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend istream &operator>>(istream &stream, nokiaconv &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define XML_MAX_SAT 4
|
|
||||||
class xmlconv{
|
|
||||||
public:
|
|
||||||
DVB *dvb;
|
|
||||||
struct lnb_sat_l{
|
|
||||||
int n;
|
|
||||||
int diseqc[XML_MAX_SAT];
|
|
||||||
char sat_names[XML_MAX_SAT][MAXNAM+1];
|
|
||||||
int satid[XML_MAX_SAT];
|
|
||||||
} lnb_sat;
|
|
||||||
|
|
||||||
xmlconv(DVB *d){
|
|
||||||
dvb = d;
|
|
||||||
}
|
|
||||||
int read_stream(istream &ins, int nchan);
|
|
||||||
int read_desc(istream &ins, int nchan);
|
|
||||||
int read_serv(istream &ins, int ctp, int csat);
|
|
||||||
int read_trans(istream &ins, int satid);
|
|
||||||
int read_sat(istream &ins, int satid = -1);
|
|
||||||
int skip_tag(istream &ins, char *tag);
|
|
||||||
int read_iso639(istream &ins, int nchan, int apids);
|
|
||||||
|
|
||||||
friend istream &operator>>(istream &stream, xmlconv &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define SATCO_MAX_SAT 10
|
|
||||||
class satcoconv{
|
|
||||||
public:
|
|
||||||
DVB *dvb;
|
|
||||||
int nlnb;
|
|
||||||
|
|
||||||
satcoconv(DVB *d){
|
|
||||||
dvb = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend istream &operator>>(istream &stream, satcoconv &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
void hdump(uint8_t *buf, int n);
|
|
||||||
int get_dvbrc(char *path, DVB &dv, int dev, int len);
|
|
||||||
int set_dvbrc(char *path, DVB &dv, int dev, int len);
|
|
||||||
void dvb2txt(char *out, char *in, int len);
|
|
||||||
int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum, fe_code_rate_t fec);
|
|
||||||
void set_pes_filt(int fd,uint16_t pes_pid);
|
|
||||||
void set_diseqc(int fdf, int snum, fe_sec_voltage_t v, fe_sec_tone_mode_t t);
|
|
||||||
int tune(int fdf, uint32_t freq, uint32_t sr, fe_code_rate_t fec);
|
|
||||||
int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum,
|
|
||||||
fe_code_rate_t fec);
|
|
||||||
|
|
||||||
|
|
||||||
struct in_addr getaddress (const char *name);
|
|
||||||
int tcp_client_connect(const char *hostname, int sckt);
|
|
||||||
int udp_client_connect(const char *filename);
|
|
||||||
void client_send_msg(int fd, uint8_t *msg, int size);
|
|
||||||
int chck_frontend (int fefd, frontend_stat *festat);
|
|
||||||
|
|
||||||
uint8_t deham(uint8_t x, uint8_t y);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,14 +1,12 @@
|
|||||||
INCS = -I.
|
INCS = -I.
|
||||||
CFLAGS = -g -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fPIC
|
CFLAGS = -g -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fPIC
|
||||||
MFLAG = -M
|
MFLAG = -M
|
||||||
OBJS = ctools.o ringbuffy.o remux.o transform.o cpptools.o
|
OBJS = ctools.o ringbuffy.o remux.o transform.o
|
||||||
SRC = $(wildcard *.c)
|
SRC = $(wildcard *.c)
|
||||||
CPPSRC = $(wildcard *.cpp)
|
|
||||||
CSRC = $(wildcard *.cc)
|
|
||||||
|
|
||||||
DESTDIR = /usr/local
|
DESTDIR = /usr/local
|
||||||
|
|
||||||
.PHONY: depend clean install uninstall
|
.PHONY: clean
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
- rm -f *.o *~ *.a .depend
|
- rm -f *.o *~ *.a .depend
|
||||||
@ -16,17 +14,11 @@ clean:
|
|||||||
libdvbmpegtools.a: $(OBJS)
|
libdvbmpegtools.a: $(OBJS)
|
||||||
ar -rcs libdvbmpegtools.a $(OBJS)
|
ar -rcs libdvbmpegtools.a $(OBJS)
|
||||||
|
|
||||||
%.o: %.cc
|
|
||||||
$(CXX) -c $(CFLAGS) $(INCS) $(DEFINES) $<
|
|
||||||
|
|
||||||
%.o: %.cpp
|
|
||||||
$(CXX) -c $(CFLAGS) $(INCS) $(DEFINES) $<
|
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) -c $(CFLAGS) $(INCS) $(DEFINES) $<
|
$(CC) -c $(CFLAGS) $(INCS) $(DEFINES) $<
|
||||||
|
|
||||||
.depend:
|
.depend:
|
||||||
$(CXX) $(DEFINES) $(MFLAG) $(SRC) $(CSRC) $(CPPSRC) $(INCS)> .depend
|
$(CXX) $(DEFINES) $(MFLAG) $(SRC) $(INCS)> .depend
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
#ifndef _OSD_H_
|
|
||||||
#define _OSD_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
int OSDClose(int dev);
|
|
||||||
int OSDOpen(int dev, int x0, int y0, int x1, int y1, int BitPerPixel, int mix);
|
|
||||||
int OSDShow(int dev);
|
|
||||||
int OSDHide(int dev);
|
|
||||||
int OSDClear(int dev);
|
|
||||||
int OSDFill(int dev, int color);
|
|
||||||
int OSDSetColor(int dev, int color, int r, int g, int b, int op);
|
|
||||||
int OSDText(int dev, int x, int y, int size, int color, const char *text);
|
|
||||||
int OSDSetPalette(int dev, int first, int last, unsigned char *data);
|
|
||||||
int OSDSetTrans(int dev, int trans);
|
|
||||||
int OSDSetPixel(int dev, int x, int y, unsigned int color);
|
|
||||||
int OSDGetPixel(int dev, int x, int y);
|
|
||||||
int OSDSetRow(int dev, int x, int y, int x1, unsigned char *data);
|
|
||||||
int OSDSetBlock(int dev, int x, int y, int x1, int y1, int inc, unsigned char *data);
|
|
||||||
int OSDFillRow(int dev, int x, int y, int x1, int color);
|
|
||||||
int OSDFillBlock(int dev, int x, int y, int x1, int y1, int color);
|
|
||||||
int OSDLine(int dev, int x, int y, int x1, int y1, int color);
|
|
||||||
int OSDQuery(int dev);
|
|
||||||
int OSDSetWindow(int dev, int win);
|
|
||||||
int OSDMoveWindow(int dev, int x, int y);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||||||
#ifndef _CHANNEL_H
|
|
||||||
#define _CHANNEL_H
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
struct channel {
|
|
||||||
int id;
|
|
||||||
char name[81];
|
|
||||||
int type;
|
|
||||||
ushort pnr;
|
|
||||||
ushort vpid;
|
|
||||||
ushort apids[8];
|
|
||||||
ushort apidnum;
|
|
||||||
ushort ac3pid;
|
|
||||||
ushort pcrpid;
|
|
||||||
|
|
||||||
uint freq;
|
|
||||||
int pol;
|
|
||||||
int qam;
|
|
||||||
uint srate;
|
|
||||||
int fec;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef NEWSTRUCT
|
|
||||||
|
|
||||||
#include <linux/dvb/dmx.h>
|
|
||||||
#include <linux/dvb/frontend.h>
|
|
||||||
#include <linux/dvb/video.h>
|
|
||||||
#include <linux/dvb/audio.h>
|
|
||||||
|
|
||||||
#define DVR_DEV "/dev/dvb/adapter%d/dvr%d"
|
|
||||||
#define VIDEO_DEV "/dev/dvb/adapter%d/video%d"
|
|
||||||
#define AUDIO_DEV "/dev/dvb/adapter%d/audio%d"
|
|
||||||
#define DEMUX_DEV "/dev/dvb/adapter%d/demux%d"
|
|
||||||
#define FRONT_DEV "/dev/dvb/adapter%d/frontend%d"
|
|
||||||
#define OSD_DEV "/dev/dvb/adapter%d/osd%d"
|
|
||||||
#define CA_DEV "/dev/dvb/adapter%d/ca%d"
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <ost/dmx.h>
|
|
||||||
#include <ost/frontend.h>
|
|
||||||
#include <ost/sec.h>
|
|
||||||
#include <ost/video.h>
|
|
||||||
#include <ost/audio.h>
|
|
||||||
|
|
||||||
#define DVR_DEV "/dev/ost/dvr%d"
|
|
||||||
#define VIDEO_DEV "/dev/ost/video%d"
|
|
||||||
#define AUDIO_DEV "/dev/ost/audio%d"
|
|
||||||
#define DEMUX_DEV "/dev/ost/demux%d"
|
|
||||||
#define FRONT_DEV "/dev/ost/frontend%d"
|
|
||||||
#define OSD_DEV "/dev/ost/osd%d"
|
|
||||||
#define CA_DEV "/dev/ost/ca%d"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
167
libdvbmpeg/ci.hh
167
libdvbmpeg/ci.hh
@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
* ci.hh: Common Interface
|
|
||||||
*
|
|
||||||
* Copyright (C) 2000 Klaus Schmidinger
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
|
||||||
*
|
|
||||||
* The author can be reached at kls@cadsoft.de
|
|
||||||
*
|
|
||||||
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __CI_H
|
|
||||||
#define __CI_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/uio.h>
|
|
||||||
|
|
||||||
#define MAXCASYSTEMIDS 16
|
|
||||||
|
|
||||||
class cMutex {
|
|
||||||
friend class cCondVar;
|
|
||||||
private:
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
pid_t lockingPid;
|
|
||||||
int locked;
|
|
||||||
public:
|
|
||||||
cMutex(void);
|
|
||||||
~cMutex();
|
|
||||||
void Lock(void);
|
|
||||||
void Unlock(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
class cMutexLock {
|
|
||||||
private:
|
|
||||||
cMutex *mutex;
|
|
||||||
bool locked;
|
|
||||||
public:
|
|
||||||
cMutexLock(cMutex *Mutex = NULL);
|
|
||||||
~cMutexLock();
|
|
||||||
bool Lock(cMutex *Mutex);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class cCiMMI;
|
|
||||||
|
|
||||||
class cCiMenu {
|
|
||||||
friend class cCiMMI;
|
|
||||||
private:
|
|
||||||
enum { MAX_CIMENU_ENTRIES = 64 }; ///< XXX is there a specified maximum?
|
|
||||||
cCiMMI *mmi;
|
|
||||||
bool selectable;
|
|
||||||
char *titleText;
|
|
||||||
char *subTitleText;
|
|
||||||
char *bottomText;
|
|
||||||
char *entries[MAX_CIMENU_ENTRIES];
|
|
||||||
int numEntries;
|
|
||||||
bool AddEntry(char *s);
|
|
||||||
cCiMenu(cCiMMI *MMI, bool Selectable);
|
|
||||||
public:
|
|
||||||
~cCiMenu();
|
|
||||||
const char *TitleText(void) { return titleText; }
|
|
||||||
const char *SubTitleText(void) { return subTitleText; }
|
|
||||||
const char *BottomText(void) { return bottomText; }
|
|
||||||
const char *Entry(int n) { return n < numEntries ? entries[n] : NULL; }
|
|
||||||
int NumEntries(void) { return numEntries; }
|
|
||||||
bool Selectable(void) { return selectable; }
|
|
||||||
bool Select(int Index);
|
|
||||||
bool Cancel(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
class cCiEnquiry {
|
|
||||||
friend class cCiMMI;
|
|
||||||
private:
|
|
||||||
cCiMMI *mmi;
|
|
||||||
char *text;
|
|
||||||
bool blind;
|
|
||||||
int expectedLength;
|
|
||||||
cCiEnquiry(cCiMMI *MMI);
|
|
||||||
public:
|
|
||||||
~cCiEnquiry();
|
|
||||||
const char *Text(void) { return text; }
|
|
||||||
bool Blind(void) { return blind; }
|
|
||||||
int ExpectedLength(void) { return expectedLength; }
|
|
||||||
bool Reply(const char *s);
|
|
||||||
bool Cancel(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
class cCiCaPmt {
|
|
||||||
friend class cCiConditionalAccessSupport;
|
|
||||||
private:
|
|
||||||
int length;
|
|
||||||
int esInfoLengthPos;
|
|
||||||
uint8_t capmt[2048]; ///< XXX is there a specified maximum?
|
|
||||||
public:
|
|
||||||
cCiCaPmt(int ProgramNumber);
|
|
||||||
void AddPid(int Pid);
|
|
||||||
void AddCaDescriptor(int Length, uint8_t *Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_CI_SESSION 16 //XXX
|
|
||||||
|
|
||||||
class cCiSession;
|
|
||||||
class cCiTransportLayer;
|
|
||||||
class cCiTransportConnection;
|
|
||||||
|
|
||||||
class cCiHandler {
|
|
||||||
private:
|
|
||||||
cMutex mutex;
|
|
||||||
int numSlots;
|
|
||||||
bool newCaSupport;
|
|
||||||
bool hasUserIO;
|
|
||||||
cCiSession *sessions[MAX_CI_SESSION];
|
|
||||||
cCiTransportLayer *tpl;
|
|
||||||
cCiTransportConnection *tc;
|
|
||||||
int ResourceIdToInt(const uint8_t *Data);
|
|
||||||
bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1);
|
|
||||||
cCiSession *GetSessionBySessionId(int SessionId);
|
|
||||||
cCiSession *GetSessionByResourceId(int ResourceId, int Slot);
|
|
||||||
cCiSession *CreateSession(int ResourceId);
|
|
||||||
bool OpenSession(int Length, const uint8_t *Data);
|
|
||||||
bool CloseSession(int SessionId);
|
|
||||||
int CloseAllSessions(int Slot);
|
|
||||||
cCiHandler(int Fd, int NumSlots);
|
|
||||||
public:
|
|
||||||
~cCiHandler();
|
|
||||||
static cCiHandler *CreateCiHandler(const char *FileName);
|
|
||||||
int NumSlots(void) { return numSlots; }
|
|
||||||
bool Process(void);
|
|
||||||
bool HasUserIO(void) { return hasUserIO; }
|
|
||||||
bool EnterMenu(int Slot);
|
|
||||||
cCiMenu *GetMenu(void);
|
|
||||||
cCiEnquiry *GetEnquiry(void);
|
|
||||||
bool SetCaPmt(cCiCaPmt &CaPmt);
|
|
||||||
const unsigned short *GetCaSystemIds(int Slot);
|
|
||||||
bool SetCaPmt(cCiCaPmt &CaPmt, int Slot);
|
|
||||||
bool Reset(int Slot);
|
|
||||||
};
|
|
||||||
|
|
||||||
int tcp_listen(struct sockaddr_in *name,int sckt,unsigned long address=INADDR_ANY);
|
|
||||||
int accept_tcp(int ip_sock,struct sockaddr_in *ip_name);
|
|
||||||
int udp_listen(struct sockaddr_un *name,char const * const filename);
|
|
||||||
int accept_udp(int ip_sock,struct sockaddr_un *ip_name);
|
|
||||||
|
|
||||||
#endif //__CI_H
|
|
@ -1,948 +0,0 @@
|
|||||||
/*
|
|
||||||
* dvb-mpegtools for the Siemens Fujitsu DVB PCI card
|
|
||||||
*
|
|
||||||
* Copyright (C) 2000, 2001 Marcus Metzler
|
|
||||||
* for convergence integrated media GmbH
|
|
||||||
* Copyright (C) 2002 Marcus Metzler
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
|
||||||
*
|
|
||||||
|
|
||||||
* The author can be reached at mocm@metzlerbros.de
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "cpptools.hh"
|
|
||||||
|
|
||||||
#define HEX(N) "0x" << hex << setw(2) << setfill('0') \
|
|
||||||
<< int(N) << " " << dec
|
|
||||||
#define HHEX(N,M) "0x" << hex << setw(M) << setfill('0') \
|
|
||||||
<< int(N) << " " << dec
|
|
||||||
#define LHEX(N,M) "0x" << hex << setw(M) << setfill('0') \
|
|
||||||
<< long(N) << " " << dec
|
|
||||||
|
|
||||||
#define MAX_SEARCH 1024 * 1024
|
|
||||||
|
|
||||||
ostream & operator << (ostream & stream, PES_Packet & x){
|
|
||||||
|
|
||||||
if (x.info){
|
|
||||||
cerr << "PES Packet: " ;
|
|
||||||
switch ( x.p.stream_id ) {
|
|
||||||
|
|
||||||
case PROG_STREAM_MAP:
|
|
||||||
cerr << "Program Stream Map";
|
|
||||||
break;
|
|
||||||
case PRIVATE_STREAM2:
|
|
||||||
cerr << "Private Stream 2";
|
|
||||||
break;
|
|
||||||
case PROG_STREAM_DIR:
|
|
||||||
cerr << "Program Stream Directory";
|
|
||||||
break;
|
|
||||||
case ECM_STREAM :
|
|
||||||
cerr << "ECM Stream";
|
|
||||||
break;
|
|
||||||
case EMM_STREAM :
|
|
||||||
cerr << "EMM Stream";
|
|
||||||
break;
|
|
||||||
case PADDING_STREAM :
|
|
||||||
cerr << "Padding Stream";
|
|
||||||
break;
|
|
||||||
case DSM_CC_STREAM :
|
|
||||||
cerr << "DSM Stream";
|
|
||||||
break;
|
|
||||||
case ISO13522_STREAM:
|
|
||||||
cerr << "ISO13522 Stream";
|
|
||||||
break;
|
|
||||||
case PRIVATE_STREAM1:
|
|
||||||
cerr << "Private Stream 1";
|
|
||||||
break;
|
|
||||||
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
|
|
||||||
cerr << "Audio Stream " << HEX(x.p.stream_id);
|
|
||||||
break;
|
|
||||||
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
|
|
||||||
cerr << "Video Stream " << HEX(x.p.stream_id);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
cerr << " MPEG" << x.p.mpeg << endl;
|
|
||||||
if ( x.p.mpeg == 2 ){
|
|
||||||
cerr << " FLAGS: ";
|
|
||||||
|
|
||||||
if (x.p.flags1 & SCRAMBLE_FLAGS){
|
|
||||||
cerr << " SCRAMBLE(";
|
|
||||||
cerr << ((x.p.flags1 & SCRAMBLE_FLAGS)>>4);
|
|
||||||
cerr << ")";
|
|
||||||
}
|
|
||||||
if (x.p.flags1 & PRIORITY_FLAG)
|
|
||||||
cerr << " PRIORITY";
|
|
||||||
if (x.p.flags1 & DATA_ALIGN_FLAG)
|
|
||||||
cerr << " DATA_ALIGN";
|
|
||||||
if (x.p.flags1 & COPYRIGHT_FLAG)
|
|
||||||
cerr << " COPYRIGHT";
|
|
||||||
if (x.p.flags1 & ORIGINAL_FLAG)
|
|
||||||
cerr << " ORIGINAL";
|
|
||||||
|
|
||||||
if (x.p.flags2 & PTS_DTS_FLAGS){
|
|
||||||
cerr << " PTS_DTS(";
|
|
||||||
cerr << ((x.p.flags2 & PTS_DTS_FLAGS)>>6);
|
|
||||||
cerr << ")";
|
|
||||||
}
|
|
||||||
if (x.p.flags2 & ESCR_FLAG)
|
|
||||||
cerr << " ESCR";
|
|
||||||
if (x.p.flags2 & ES_RATE_FLAG)
|
|
||||||
cerr << " ES_RATE";
|
|
||||||
if (x.p.flags2 & DSM_TRICK_FLAG)
|
|
||||||
cerr << " DSM_TRICK";
|
|
||||||
if (x.p.flags2 & ADD_CPY_FLAG)
|
|
||||||
cerr << " ADD_CPY";
|
|
||||||
if (x.p.flags2 & PES_CRC_FLAG)
|
|
||||||
cerr << " CRC";
|
|
||||||
if (x.p.flags2 & PES_EXT_FLAG)
|
|
||||||
cerr << " EXT";
|
|
||||||
|
|
||||||
cerr << endl;
|
|
||||||
|
|
||||||
if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY)
|
|
||||||
cerr << " PTS: "
|
|
||||||
<< LHEX(ntohl(x.WPTS()),8)
|
|
||||||
<< "(h" << int(x.high_pts()) << ")"
|
|
||||||
<< endl;
|
|
||||||
else if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){
|
|
||||||
cerr << " PTS: "
|
|
||||||
<< LHEX(ntohl(x.WPTS()),8)
|
|
||||||
<< "(h" << int(x.high_pts()) << ")";
|
|
||||||
cerr << " DTS: "
|
|
||||||
<< LHEX(ntohl(x.WDTS()),8)
|
|
||||||
<< "(h" << int(x.high_dts()) << ")"
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (x.p.flags2 & ESCR_FLAG)
|
|
||||||
|
|
||||||
|
|
||||||
if (x.p.flags2 & ES_RATE_FLAG)
|
|
||||||
|
|
||||||
|
|
||||||
if (x.p.flags2 & DSM_TRICK_FLAG)
|
|
||||||
|
|
||||||
|
|
||||||
if (x.p.flags2 & ADD_CPY_FLAG)
|
|
||||||
|
|
||||||
|
|
||||||
if (x.p.flags2 & PES_CRC_FLAG)
|
|
||||||
|
|
||||||
|
|
||||||
if (x.p.flags2 & PES_EXT_FLAG){
|
|
||||||
|
|
||||||
if (x.p.priv_flags & PRIVATE_DATA)
|
|
||||||
stream.write(x.p.pes_priv_data,16);
|
|
||||||
|
|
||||||
if (x.p.priv_flags & HEADER_FIELD){
|
|
||||||
stream.write(&x.p.pack_field_length,1);
|
|
||||||
x.p.pack_header = new
|
|
||||||
uint8_t[x.p.pack_field_length];
|
|
||||||
stream.write(x.p.pack_header,
|
|
||||||
x.p.pack_field_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( x.p.priv_flags & PACK_SEQ_CTR){
|
|
||||||
stream.write(&x.p.pck_sqnc_cntr,1);
|
|
||||||
stream.write(&x.p.org_stuff_length,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( x.p.priv_flags & P_STD_BUFFER)
|
|
||||||
stream.write(x.p.p_std,2);
|
|
||||||
|
|
||||||
if ( x.p.priv_flags & PES_EXT_FLAG2){
|
|
||||||
stream.write(&x.p.pes_ext_lngth,1);
|
|
||||||
x.p.pes_ext = new
|
|
||||||
uint8_t[x.p.pes_ext_lngth];
|
|
||||||
stream.write(x.p.pes_ext,
|
|
||||||
x.p.pes_ext_lngth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY)
|
|
||||||
stream.write(x.p.pts,5);
|
|
||||||
else if ((x.p.flags2 & PTS_DTS_FLAGS) ==
|
|
||||||
PTS_DTS){
|
|
||||||
stream.write(x.p.pts,5);
|
|
||||||
stream.write(x.p.dts,5);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
cerr << endl << endl;
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
int l = x.p.length+x.p.pes_hlength+9;
|
|
||||||
uint8_t buf[l];
|
|
||||||
int length = cwrite_pes(buf,&(x.p),l);
|
|
||||||
stream.write((char *)buf,length);
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int find_length(istream & stream){
|
|
||||||
streampos p = 0;
|
|
||||||
streampos start = 0;
|
|
||||||
streampos q = 0;
|
|
||||||
int found = 0;
|
|
||||||
uint8_t sync4[4];
|
|
||||||
|
|
||||||
start = stream.tellg();
|
|
||||||
start -=2;
|
|
||||||
stream.seekg(start);
|
|
||||||
while ( !stream.eof() && !found ){
|
|
||||||
p = stream.tellg();
|
|
||||||
stream.read((char *)&sync4,4);
|
|
||||||
if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) {
|
|
||||||
switch ( sync4[3] ) {
|
|
||||||
|
|
||||||
case PROG_STREAM_MAP:
|
|
||||||
case PRIVATE_STREAM2:
|
|
||||||
case PROG_STREAM_DIR:
|
|
||||||
case ECM_STREAM :
|
|
||||||
case EMM_STREAM :
|
|
||||||
case PADDING_STREAM :
|
|
||||||
case DSM_CC_STREAM :
|
|
||||||
case ISO13522_STREAM:
|
|
||||||
case PRIVATE_STREAM1:
|
|
||||||
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
|
|
||||||
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
q = stream.tellg();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
q = stream.tellg();
|
|
||||||
stream.seekg(streampos(2)+start);
|
|
||||||
if (found) return (unsigned int)(q-start)-4-2;
|
|
||||||
else return (unsigned int)(q-start)-2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
istream & operator >> (istream & stream, PES_Packet & x){
|
|
||||||
|
|
||||||
uint8_t sync4[4];
|
|
||||||
int found=0;
|
|
||||||
int done=0;
|
|
||||||
streampos p = 0;
|
|
||||||
|
|
||||||
while (!stream.eof() && !found) {
|
|
||||||
p = stream.tellg();
|
|
||||||
stream.read((char *)&sync4,4);
|
|
||||||
if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) {
|
|
||||||
x.p.stream_id = sync4[3];
|
|
||||||
|
|
||||||
switch ( sync4[3] ) {
|
|
||||||
|
|
||||||
case PROG_STREAM_MAP:
|
|
||||||
case PRIVATE_STREAM2:
|
|
||||||
case PROG_STREAM_DIR:
|
|
||||||
case ECM_STREAM :
|
|
||||||
case EMM_STREAM :
|
|
||||||
found = 1;
|
|
||||||
stream.read((char *)x.p.llength,2);
|
|
||||||
x.setlength();
|
|
||||||
if (!x.p.length){
|
|
||||||
x.p.length = find_length(stream);
|
|
||||||
x.Nlength();
|
|
||||||
}
|
|
||||||
stream.read((char *)x.p.pes_pckt_data,x.p.length);
|
|
||||||
done = 1;
|
|
||||||
break;
|
|
||||||
case PADDING_STREAM :
|
|
||||||
found = 1;
|
|
||||||
stream.read((char *)x.p.llength,2);
|
|
||||||
x.setlength();
|
|
||||||
if (!x.p.length){
|
|
||||||
x.p.length = find_length(stream);
|
|
||||||
x.Nlength();
|
|
||||||
}
|
|
||||||
x.p.padding = x.p.length;
|
|
||||||
stream.read((char *)x.p.pes_pckt_data,x.p.length);
|
|
||||||
done = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DSM_CC_STREAM :
|
|
||||||
case ISO13522_STREAM:
|
|
||||||
case PRIVATE_STREAM1:
|
|
||||||
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
|
|
||||||
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
|
|
||||||
stream.read((char *)x.p.llength,2);
|
|
||||||
x.setlength();
|
|
||||||
if (!x.p.length){
|
|
||||||
x.p.length = find_length(stream);
|
|
||||||
x.Nlength();
|
|
||||||
}
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
stream.seekg(p+streampos(1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else stream.seekg(p+streampos(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( found && !done) {
|
|
||||||
p = stream.tellg();
|
|
||||||
stream.read((char *)&x.p.flags1,1);
|
|
||||||
if ( (x.p.flags1 & 0xC0) == 0x80 )
|
|
||||||
x.p.mpeg = 2;
|
|
||||||
else
|
|
||||||
x.p.mpeg = 1;
|
|
||||||
if ( x.p.mpeg == 2 ){
|
|
||||||
stream.read((char *)&x.p.flags2,1);
|
|
||||||
stream.read((char *)&x.p.pes_hlength,1);
|
|
||||||
|
|
||||||
if ((int)x.p.length > x.p.pes_hlength+3)
|
|
||||||
x.p.length -=x.p.pes_hlength+3;
|
|
||||||
else
|
|
||||||
return stream;
|
|
||||||
|
|
||||||
uint8_t count = x.p.pes_hlength;
|
|
||||||
|
|
||||||
if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY){
|
|
||||||
stream.read((char *)x.p.pts,5);
|
|
||||||
count -=5;
|
|
||||||
} else
|
|
||||||
if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){
|
|
||||||
stream.read((char *)x.p.pts,5);
|
|
||||||
stream.read((char *)x.p.dts,5);
|
|
||||||
count -= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.p.flags2 & ESCR_FLAG){
|
|
||||||
stream.read((char *)x.p.escr,6);
|
|
||||||
count -= 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.p.flags2 & ES_RATE_FLAG){
|
|
||||||
stream.read((char *)x.p.es_rate,3);
|
|
||||||
count -= 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.p.flags2 & DSM_TRICK_FLAG){
|
|
||||||
stream.read((char *)&x.p.trick,1);
|
|
||||||
count -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.p.flags2 & ADD_CPY_FLAG){
|
|
||||||
stream.read((char *)&x.p.add_cpy,1);
|
|
||||||
count -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.p.flags2 & PES_CRC_FLAG){
|
|
||||||
stream.read((char *)x.p.prev_pes_crc,2);
|
|
||||||
count -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.p.flags2 & PES_EXT_FLAG){
|
|
||||||
stream.read((char *)&x.p.priv_flags,1);
|
|
||||||
count -= 1;
|
|
||||||
|
|
||||||
if (x.p.priv_flags & PRIVATE_DATA){
|
|
||||||
stream.read((char *)x.p.pes_priv_data,16);
|
|
||||||
count -= 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x.p.priv_flags & HEADER_FIELD){
|
|
||||||
stream.read((char *)&x.p.pack_field_length,1);
|
|
||||||
x.p.pack_header = new
|
|
||||||
uint8_t[x.p.pack_field_length];
|
|
||||||
stream.read((char *)x.p.pack_header,
|
|
||||||
x.p.pack_field_length);
|
|
||||||
count -= 1+x.p.pack_field_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( x.p.priv_flags & PACK_SEQ_CTR){
|
|
||||||
stream.read((char *)&x.p.pck_sqnc_cntr,1);
|
|
||||||
stream.read((char *)&x.p.org_stuff_length,1);
|
|
||||||
count -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( x.p.priv_flags & P_STD_BUFFER){
|
|
||||||
stream.read((char *)x.p.p_std,2);
|
|
||||||
count -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( x.p.priv_flags & PES_EXT_FLAG2){
|
|
||||||
stream.read((char *)&x.p.pes_ext_lngth,1);
|
|
||||||
x.p.pes_ext = new
|
|
||||||
uint8_t[x.p.pes_ext_lngth];
|
|
||||||
stream.read((char *)x.p.pes_ext,
|
|
||||||
x.p.pes_ext_lngth);
|
|
||||||
count -= 1+x.p.pes_ext_lngth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x.p.stuffing = count;
|
|
||||||
uint8_t dummy;
|
|
||||||
for(int i = 0; i< count ;i++)
|
|
||||||
stream.read((char *)&dummy,1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
uint8_t check;
|
|
||||||
x.p.mpeg1_pad = 1;
|
|
||||||
check = x.p.flags1;
|
|
||||||
while (check == 0xFF){
|
|
||||||
stream.read((char *)&check,1);
|
|
||||||
x.p.mpeg1_pad++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (check & 0xC0) == 0x40){
|
|
||||||
stream.read((char *)&check,1);
|
|
||||||
x.p.mpeg1_pad++;
|
|
||||||
stream.read((char *)&check,1);
|
|
||||||
x.p.mpeg1_pad++;
|
|
||||||
}
|
|
||||||
x.p.flags2 = 0;
|
|
||||||
x.p.length -= x.p.mpeg1_pad;
|
|
||||||
|
|
||||||
stream.seekg(p);
|
|
||||||
if ( (check & 0x30)){
|
|
||||||
x.p.length ++;
|
|
||||||
x.p.mpeg1_pad --;
|
|
||||||
|
|
||||||
if (check == x.p.flags1){
|
|
||||||
x.p.pes_hlength = 0;
|
|
||||||
} else {
|
|
||||||
x.p.mpeg1_headr =
|
|
||||||
new uint8_t[x.p.mpeg1_pad];
|
|
||||||
x.p.pes_hlength = x.p.mpeg1_pad;
|
|
||||||
stream.read((char *)x.p.mpeg1_headr,
|
|
||||||
x.p.mpeg1_pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
x.p.flags2 = (check & 0xF0) << 2;
|
|
||||||
if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY){
|
|
||||||
stream.read((char *)x.p.pts,5);
|
|
||||||
x.p.length -= 5;
|
|
||||||
x.p.pes_hlength += 5;
|
|
||||||
}
|
|
||||||
else if ((x.p.flags2 & PTS_DTS_FLAGS) ==
|
|
||||||
PTS_DTS){
|
|
||||||
stream.read((char *)x.p.pts,5);
|
|
||||||
stream.read((char *)x.p.dts,5);
|
|
||||||
x.p.length -= 10;
|
|
||||||
x.p.pes_hlength += 10;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
x.p.mpeg1_headr = new uint8_t[x.p.mpeg1_pad];
|
|
||||||
x.p.pes_hlength = x.p.mpeg1_pad;
|
|
||||||
stream.read((char *)x.p.mpeg1_headr,x.p.mpeg1_pad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.read((char *)x.p.pes_pckt_data,x.p.length);
|
|
||||||
}
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
ostream & operator << (ostream & stream, TS_Packet & x){
|
|
||||||
|
|
||||||
uint8_t buf[TS_SIZE];
|
|
||||||
int length = cwrite_ts(buf,&(x.p),TS_SIZE);
|
|
||||||
stream.write((char *)buf,length);
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
istream & operator >> (istream & stream, TS_Packet & x){
|
|
||||||
uint8_t sync;
|
|
||||||
int found=0;
|
|
||||||
streampos p,q;
|
|
||||||
|
|
||||||
sync=0;
|
|
||||||
while (!stream.eof() && !found) {
|
|
||||||
stream.read((char *)&sync,1);
|
|
||||||
if (sync == 0x47)
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
stream.read((char *)x.p.pid,2);
|
|
||||||
stream.read((char *)&x.p.flags,1);
|
|
||||||
x.p.count = x.p.flags & COUNT_MASK;
|
|
||||||
|
|
||||||
if (!(x.p.flags & ADAPT_FIELD) && (x.p.flags & PAYLOAD)){
|
|
||||||
//no adapt. field only payload
|
|
||||||
stream.read((char *)x.p.data,184);
|
|
||||||
x.p.rest = 184;
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( x.p.flags & ADAPT_FIELD ) {
|
|
||||||
// adaption field
|
|
||||||
stream.read((char *)&x.p.adapt_length,1);
|
|
||||||
if (x.p.adapt_length){
|
|
||||||
p = stream.tellg();
|
|
||||||
stream.read((char *)&x.p.adapt_flags,1);
|
|
||||||
|
|
||||||
if ( x.p.adapt_flags & PCR_FLAG )
|
|
||||||
stream.read((char *) x.p.pcr,6);
|
|
||||||
|
|
||||||
if ( x.p.adapt_flags & OPCR_FLAG )
|
|
||||||
stream.read((char *) x.p.opcr,6);
|
|
||||||
|
|
||||||
if ( x.p.adapt_flags & SPLICE_FLAG )
|
|
||||||
stream.read((char *) &x.p.splice_count,1);
|
|
||||||
|
|
||||||
if( x.p.adapt_flags & TRANS_PRIV){
|
|
||||||
stream.read((char *)&x.p.priv_dat_len,1);
|
|
||||||
x.p.priv_dat = new uint8_t[x.p.priv_dat_len];
|
|
||||||
stream.read((char *)x.p.priv_dat,x.p.priv_dat_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( x.p.adapt_flags & ADAP_EXT_FLAG){
|
|
||||||
stream.read((char *)&x.p.adapt_ext_len,1);
|
|
||||||
stream.read((char *)&x.p.adapt_eflags,1);
|
|
||||||
if( x.p.adapt_eflags & LTW_FLAG)
|
|
||||||
stream.read((char *)x.p.ltw,2);
|
|
||||||
|
|
||||||
if( x.p.adapt_eflags & PIECE_RATE)
|
|
||||||
stream.read((char *)x.p.piece_rate,3);
|
|
||||||
|
|
||||||
if( x.p.adapt_eflags & SEAM_SPLICE)
|
|
||||||
stream.read((char *)x.p.dts,5);
|
|
||||||
}
|
|
||||||
q = stream.tellg();
|
|
||||||
x.p.stuffing = x.p.adapt_length -(q-p);
|
|
||||||
x.p.rest = 183-x.p.adapt_length;
|
|
||||||
stream.seekg(q+streampos(x.p.stuffing));
|
|
||||||
if (x.p.flags & PAYLOAD) // payload
|
|
||||||
stream.read((char *)x.p.data,x.p.rest);
|
|
||||||
else
|
|
||||||
stream.seekg(q+streampos(x.p.rest));
|
|
||||||
} else {
|
|
||||||
x.p.rest = 182;
|
|
||||||
stream.read((char *)x.p.data, 183);
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ostream & operator << (ostream & stream, PS_Packet & x){
|
|
||||||
|
|
||||||
uint8_t buf[PS_MAX];
|
|
||||||
int length = cwrite_ps(buf,&(x.p),PS_MAX);
|
|
||||||
stream.write((char *)buf,length);
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
istream & operator >> (istream & stream, PS_Packet & x){
|
|
||||||
uint8_t headr[4];
|
|
||||||
int found=0;
|
|
||||||
streampos p = 0;
|
|
||||||
streampos q = 0;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
p = stream.tellg();
|
|
||||||
while (!stream.eof() && !found && count < MAX_SEARCH) {
|
|
||||||
stream.read((char *)&headr,4);
|
|
||||||
if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01) {
|
|
||||||
if ( headr[3] == 0xBA )
|
|
||||||
found = 1;
|
|
||||||
else if ( headr[3] == 0xB9 ) break;
|
|
||||||
else stream.seekg(p+streampos(1));
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found){
|
|
||||||
stream.read((char *)x.p.scr,6);
|
|
||||||
if (x.p.scr[0] & 0x40)
|
|
||||||
x.p.mpeg = 2;
|
|
||||||
else
|
|
||||||
x.p.mpeg = 1;
|
|
||||||
|
|
||||||
if (x.p.mpeg == 2){
|
|
||||||
stream.read((char *)x.p.mux_rate,3);
|
|
||||||
stream.read((char *)&x.p.stuff_length,1);
|
|
||||||
p = stream.tellg();
|
|
||||||
stream.seekg(p+streampos(x.p.stuff_length & 3));
|
|
||||||
} else {
|
|
||||||
x.p.mux_rate[0] = x.p.scr[5]; //mpeg1 scr is only 5 bytes
|
|
||||||
stream.read((char *)x.p.mux_rate+1,2);
|
|
||||||
}
|
|
||||||
|
|
||||||
p=stream.tellg();
|
|
||||||
stream.read((char *)headr,4);
|
|
||||||
if (headr[0] == 0x00 && headr[1] == 0x00 &&
|
|
||||||
headr[2] == 0x01 && headr[3] == 0xBB ) {
|
|
||||||
stream.read((char *)x.p.sheader_llength,2);
|
|
||||||
x.setlength();
|
|
||||||
if (x.p.mpeg == 2){
|
|
||||||
stream.read((char *)x.p.rate_bound,3);
|
|
||||||
stream.read((char *)&x.p.audio_bound,1);
|
|
||||||
stream.read((char *)&x.p.video_bound,1);
|
|
||||||
stream.read((char *)&x.p.reserved,1);
|
|
||||||
}
|
|
||||||
stream.read((char *)x.p.data,x.p.sheader_length);
|
|
||||||
} else {
|
|
||||||
stream.seekg(p);
|
|
||||||
x.p.sheader_length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
int done = 0;
|
|
||||||
q = stream.tellg();
|
|
||||||
PES_Packet pes;
|
|
||||||
do {
|
|
||||||
p=stream.tellg();
|
|
||||||
stream.read((char *)headr,4);
|
|
||||||
stream.seekg(p);
|
|
||||||
if ( headr[0] == 0x00 && headr[1] == 0x00
|
|
||||||
&& headr[2] == 0x01 && headr[3] != 0xBA){
|
|
||||||
pes.init();
|
|
||||||
stream >> pes;
|
|
||||||
i++;
|
|
||||||
} else done = 1;
|
|
||||||
} while (!stream.eof() && !done);
|
|
||||||
x.p.npes = i;
|
|
||||||
stream.seekg(q);
|
|
||||||
}
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
void extract_audio_from_PES(istream &in, ostream &out){
|
|
||||||
PES_Packet pes;
|
|
||||||
|
|
||||||
while(!in.eof()){
|
|
||||||
pes.init();
|
|
||||||
in >> pes ;
|
|
||||||
if (pes.Stream_ID() == 0xC0)
|
|
||||||
out << pes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void extract_video_from_PES(istream &in, ostream &out){
|
|
||||||
PES_Packet pes;
|
|
||||||
|
|
||||||
while(!in.eof()){
|
|
||||||
pes.init();
|
|
||||||
in >> pes ;
|
|
||||||
if (pes.Stream_ID() == 0xE0)
|
|
||||||
out << pes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void extract_es_audio_from_PES(istream &in, ostream &out){
|
|
||||||
PES_Packet pes;
|
|
||||||
|
|
||||||
while(!in.eof()){
|
|
||||||
pes.init();
|
|
||||||
in >> pes ;
|
|
||||||
if (pes.Stream_ID() == 0xC0)
|
|
||||||
out.write((char *)pes.Data(),pes.Length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void extract_es_video_from_PES(istream &in, ostream &out){
|
|
||||||
PES_Packet pes;
|
|
||||||
|
|
||||||
while(!in.eof()){
|
|
||||||
pes.init();
|
|
||||||
in >> pes ;
|
|
||||||
if (pes.Stream_ID() == 0xE0)
|
|
||||||
out.write((char *)pes.Data(),pes.Length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_PID 20
|
|
||||||
int TS_PIDS(istream &in, ostream &out){
|
|
||||||
int pid[MAX_PID];
|
|
||||||
TS_Packet ts;
|
|
||||||
int npid=0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<MAX_PID; i++)
|
|
||||||
pid[i] = -1;
|
|
||||||
while (!in.eof()) {
|
|
||||||
ts.init();
|
|
||||||
in >> ts;
|
|
||||||
int j;
|
|
||||||
int found = 0;
|
|
||||||
for (j=0;j<npid;j++){
|
|
||||||
if ( ts.PID() == pid[j] )
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
if (! found){
|
|
||||||
out << ts.PID() << " ";
|
|
||||||
pid[npid] = ts.PID();
|
|
||||||
npid++;
|
|
||||||
if (npid == MAX_PID) return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tv_norm(istream &stream){
|
|
||||||
uint8_t headr[4];
|
|
||||||
int found=0;
|
|
||||||
streampos p = 0;
|
|
||||||
streampos q = 0;
|
|
||||||
int hsize,vsize;
|
|
||||||
int form= 0;
|
|
||||||
|
|
||||||
q = stream.tellg();
|
|
||||||
while (!stream.eof() && !found) {
|
|
||||||
p = stream.tellg();
|
|
||||||
stream.read((char *)headr,4);
|
|
||||||
if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01)
|
|
||||||
if ( headr[3] == 0xB3 ){
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
if (! found) stream.seekg(p+streampos(1));
|
|
||||||
}
|
|
||||||
stream.read((char *)headr,4);
|
|
||||||
|
|
||||||
hsize = (headr[1] &0xF0) >> 4 | headr[0] << 4;
|
|
||||||
vsize = (headr[1] &0x0F) << 8 | headr[2];
|
|
||||||
cerr << "SIZE: " << hsize << "x" << vsize << endl;
|
|
||||||
|
|
||||||
switch(((headr[3]&0xF0) >>4)){
|
|
||||||
case 1:
|
|
||||||
cerr << "ASPECT: 1:1" << endl;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
cerr << "ASPECT: 4:3" << endl;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
cerr << "ASPECT: 16:9" << endl;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
cerr << "ASPECT: 2.21:1" << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (int(headr[3]&0x0F)){
|
|
||||||
case 1:
|
|
||||||
cerr << "FRAMERATE: 23.976" << endl;
|
|
||||||
form = pDUNNO;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
cerr << "FRAMERATE: 24" << endl;
|
|
||||||
form = pDUNNO;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
cerr << "FRAMERATE: 25" << endl;
|
|
||||||
form = pPAL;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
cerr << "FRAMERATE: 29.97" << endl;
|
|
||||||
form = pNTSC;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
cerr << "FRAMERATE: 30" << endl;
|
|
||||||
form = pNTSC;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
cerr << "FRAMERATE: 50" << endl;
|
|
||||||
form = pPAL;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
cerr << "FRAMERATE: 59.94" << endl;
|
|
||||||
form = pNTSC;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
cerr << "FRAMERATE: 60" << endl;
|
|
||||||
form = pNTSC;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mpeg = 0;
|
|
||||||
found = 0;
|
|
||||||
while (!stream.eof() && !found) {
|
|
||||||
p = stream.tellg();
|
|
||||||
stream.read((char *)headr,4);
|
|
||||||
if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01) {
|
|
||||||
if ( headr[3] == 0xB5 ){
|
|
||||||
const char *profile[] = {"reserved", "High", "Spatially Scalable",
|
|
||||||
"SNR Scalable", "Main", "Simple", "undef",
|
|
||||||
"undef"};
|
|
||||||
const char *level[] = {"res", "res", "res", "res",
|
|
||||||
"High","res", "High 1440", "res",
|
|
||||||
"Main","res", "Low", "res",
|
|
||||||
"res", "res", "res", "res"};
|
|
||||||
const char *chroma[] = {"res", "4:2:0", "4:2:2", "4:4:4:"};
|
|
||||||
mpeg = 2;
|
|
||||||
stream.read((char *)headr,4);
|
|
||||||
cerr << "PROFILE: " << profile[headr[0] & 0x7] << endl;
|
|
||||||
cerr << "LEVEL: " << level[headr[1]>>4 & 0xF] << endl;
|
|
||||||
cerr << "CHROMA: " << chroma[headr[1]>>1 & 0x3] << endl;
|
|
||||||
found = 1;
|
|
||||||
} else {
|
|
||||||
mpeg = 1;
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (! found) stream.seekg(p+streampos(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.seekg(q);
|
|
||||||
return (form | mpeg << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int stream_type(istream &fin){
|
|
||||||
uint8_t headr[4];
|
|
||||||
streampos p=fin.tellg();
|
|
||||||
|
|
||||||
TS_Packet ts;
|
|
||||||
fin >> ts;
|
|
||||||
fin.read((char *)headr,1);
|
|
||||||
fin.seekg(p);
|
|
||||||
if(fin && headr[0] == 0x47){
|
|
||||||
return TS_STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
PS_Packet ps;
|
|
||||||
fin >> ps;
|
|
||||||
PES_Packet pes;
|
|
||||||
for(int j=0;j < ps.NPES();j++){
|
|
||||||
fin >> pes;
|
|
||||||
}
|
|
||||||
fin.read((char *)headr,4);
|
|
||||||
fin.seekg(p);
|
|
||||||
if (fin && headr[0] == 0x00 && headr[1] == 0x00
|
|
||||||
&& headr[2] == 0x01 && headr[3] == 0xBA){
|
|
||||||
return PS_STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
fin >> pes;
|
|
||||||
fin.read((char *)NULL,4);
|
|
||||||
fin.seekg(p);
|
|
||||||
if (fin && headr[0] == 0x00 && headr[1] == 0x00
|
|
||||||
&& headr[2] == 0x01 ){
|
|
||||||
int found = 0;
|
|
||||||
switch ( headr[3] ) {
|
|
||||||
|
|
||||||
case PROG_STREAM_MAP:
|
|
||||||
case PRIVATE_STREAM2:
|
|
||||||
case PROG_STREAM_DIR:
|
|
||||||
case ECM_STREAM :
|
|
||||||
case EMM_STREAM :
|
|
||||||
case PADDING_STREAM :
|
|
||||||
case DSM_CC_STREAM :
|
|
||||||
case ISO13522_STREAM:
|
|
||||||
case PRIVATE_STREAM1:
|
|
||||||
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
|
|
||||||
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (found){
|
|
||||||
return PES_STREAM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void analyze(istream &fin)
|
|
||||||
{
|
|
||||||
PS_Packet ps;
|
|
||||||
PES_Packet pes;
|
|
||||||
int fc = 0;
|
|
||||||
const char *frames[3] = {"I-Frame","P-Frame","B-Frame"};
|
|
||||||
|
|
||||||
while(fin){
|
|
||||||
uint32_t pts;
|
|
||||||
fin >> ps;
|
|
||||||
cerr << "SCR base: " << hex << setw(5)
|
|
||||||
<< setfill('0') \
|
|
||||||
<< ps.SCR_base() << " " << dec
|
|
||||||
<< "ext : " << ps.SCR_ext();
|
|
||||||
|
|
||||||
cerr << " MUX rate: " << ps.MUX()*50*8/1000000.0
|
|
||||||
<< " Mbit/s ";
|
|
||||||
cerr << "RATE bound: " << ps.Rate()*50*8/1000000.0
|
|
||||||
<< " Mbit/s" << endl;
|
|
||||||
cerr << " Audio bound: "
|
|
||||||
<< hex << "0x"
|
|
||||||
<< int(ps.P()->audio_bound);
|
|
||||||
cerr << " Video bound: " << hex << "0x"
|
|
||||||
<< int(ps.P()->video_bound)
|
|
||||||
<< dec
|
|
||||||
<< endl;
|
|
||||||
cerr << endl;
|
|
||||||
|
|
||||||
for (int i=0; i < ps.NPES(); i++){
|
|
||||||
pes.init();
|
|
||||||
fin >> pes;
|
|
||||||
pts2pts((uint8_t *)&pts,pes.PTS());
|
|
||||||
pes.Info() = 1;
|
|
||||||
cerr << pes;
|
|
||||||
|
|
||||||
uint8_t *buf = pes.P()->pes_pckt_data;
|
|
||||||
int c = 0;
|
|
||||||
int l;
|
|
||||||
switch (pes.P()->stream_id){
|
|
||||||
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
|
|
||||||
l=pes.P()->length;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
l = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while ( c < l - 6){
|
|
||||||
if (buf[c] == 0x00 &&
|
|
||||||
buf[c+1] == 0x00 &&
|
|
||||||
buf[c+2] == 0x01 &&
|
|
||||||
buf[c+3] == 0xB8) {
|
|
||||||
c += 4;
|
|
||||||
cerr << "TIME hours: "
|
|
||||||
<< int((buf[c]>>2)& 0x1F)
|
|
||||||
<< " minutes: "
|
|
||||||
<< int(((buf[c]<<4)& 0x30)|
|
|
||||||
((buf[c+1]>>4)& 0x0F))
|
|
||||||
<< " seconds: "
|
|
||||||
<< int(((buf[c+1]<<3)& 0x38)|
|
|
||||||
((buf[c+2]>>5)& 0x0F))
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( buf[c] == 0x00 &&
|
|
||||||
buf[c+1] == 0x00 &&
|
|
||||||
buf[c+2] == 0x01 &&
|
|
||||||
buf[c+3] == 0x00) {
|
|
||||||
fc++;
|
|
||||||
c += 4;
|
|
||||||
cerr << "picture: "
|
|
||||||
<< fc
|
|
||||||
<< " ("
|
|
||||||
<< frames[((buf[c+1]&0x38) >>3)-1]
|
|
||||||
<< ")" << endl << endl;
|
|
||||||
} else c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,330 +0,0 @@
|
|||||||
/*
|
|
||||||
* dvb-mpegtools for the Siemens Fujitsu DVB PCI card
|
|
||||||
*
|
|
||||||
* Copyright (C) 2000, 2001 Marcus Metzler
|
|
||||||
* for convergence integrated media GmbH
|
|
||||||
* Copyright (C) 2002 Marcus Metzler
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
|
||||||
*
|
|
||||||
|
|
||||||
* The author can be reached at mocm@metzlerbros.de,
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _CPPTOOLS_HH_
|
|
||||||
#define _CPPTOOLS_HH_
|
|
||||||
|
|
||||||
#include "ctools.h"
|
|
||||||
|
|
||||||
|
|
||||||
class PES_Packet{
|
|
||||||
int info;
|
|
||||||
pes_packet p;
|
|
||||||
public:
|
|
||||||
PES_Packet(){
|
|
||||||
info = 0;
|
|
||||||
init_pes(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PES_Packet(){
|
|
||||||
if (p.pack_header)
|
|
||||||
delete [] p.pack_header;
|
|
||||||
if (p.pes_ext)
|
|
||||||
delete [] p.pes_ext;
|
|
||||||
if (p.pes_pckt_data)
|
|
||||||
delete [] p.pes_pckt_data;
|
|
||||||
if (p.mpeg1_headr)
|
|
||||||
delete [] p.mpeg1_headr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void init(){
|
|
||||||
if (p.pack_header)
|
|
||||||
delete [] p.pack_header;
|
|
||||||
if (p.pes_ext)
|
|
||||||
delete [] p.pes_ext;
|
|
||||||
if (p.pes_pckt_data)
|
|
||||||
delete [] p.pes_pckt_data;
|
|
||||||
if (p.mpeg1_headr)
|
|
||||||
delete [] p.mpeg1_headr;
|
|
||||||
|
|
||||||
info = 0;
|
|
||||||
init_pes(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline pes_packet *P(){
|
|
||||||
return &p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setlength(){
|
|
||||||
setlength_pes(&p);
|
|
||||||
if (p.length)
|
|
||||||
p.pes_pckt_data = new uint8_t[p.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Nlength(){
|
|
||||||
nlength_pes(&p);
|
|
||||||
p.pes_pckt_data = new uint8_t[p.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline uint8_t &Stream_ID(){
|
|
||||||
return p.stream_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t &Flags1(){
|
|
||||||
return p.flags1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t &Flags2(){
|
|
||||||
return p.flags2;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t &Length(){
|
|
||||||
return p.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t &HLength(){
|
|
||||||
return p.pes_hlength;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t &Stuffing(){
|
|
||||||
return p.stuffing;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t *Data(){
|
|
||||||
return p.pes_pckt_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int has_pts(){
|
|
||||||
return (p.flags2 & PTS_DTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int &MPEG(){
|
|
||||||
return p.mpeg;
|
|
||||||
}
|
|
||||||
inline uint8_t *PTS(){
|
|
||||||
return p.pts;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t *DTS(){
|
|
||||||
return p.dts;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int &Info(){
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline uint8_t high_pts(){
|
|
||||||
if (has_pts())
|
|
||||||
return ((p.pts[0] & 0x08)>>3);
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t high_dts(){
|
|
||||||
return ((p.dts[0] & 0x08)>>3);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int WDTS(){
|
|
||||||
int w_dts;
|
|
||||||
w_dts = (int)trans_pts_dts(p.dts);
|
|
||||||
return w_dts;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int WPTS(){
|
|
||||||
int w_dts;
|
|
||||||
w_dts = (int)trans_pts_dts(p.pts);
|
|
||||||
return w_dts;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend ostream & operator << (ostream & stream, PES_Packet & x);
|
|
||||||
friend istream & operator >> (istream & stream, PES_Packet & x);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class TS_Packet{
|
|
||||||
ts_packet p;
|
|
||||||
int info;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TS_Packet(){
|
|
||||||
init_ts(&p);
|
|
||||||
info = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
~TS_Packet(){
|
|
||||||
if (p.priv_dat)
|
|
||||||
delete [] p.priv_dat;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void init(){
|
|
||||||
if (p.priv_dat)
|
|
||||||
delete [] p.priv_dat;
|
|
||||||
|
|
||||||
init_ts(&p);
|
|
||||||
info = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ts_packet *P(){
|
|
||||||
return &p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int &Rest(){
|
|
||||||
return p.rest;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t *Data(){
|
|
||||||
return p.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline short PID(){
|
|
||||||
return pid_ts(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t FLAG1(){
|
|
||||||
return (p.pid[0] & ~PID_MASK_HI);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int &Info(){
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend ostream & operator << (ostream & stream, TS_Packet & x);
|
|
||||||
friend istream & operator >> (istream & stream, TS_Packet & x);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PS_Packet{
|
|
||||||
int info;
|
|
||||||
ps_packet p;
|
|
||||||
public:
|
|
||||||
|
|
||||||
PS_Packet(){
|
|
||||||
init_ps(&p);
|
|
||||||
info = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
~PS_Packet(){
|
|
||||||
if (p.data)
|
|
||||||
delete [] p.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void init(){
|
|
||||||
if (p.data)
|
|
||||||
delete [] p.data;
|
|
||||||
|
|
||||||
init_ps(&p);
|
|
||||||
info = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ps_packet *P(){
|
|
||||||
return &p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int MUX(){
|
|
||||||
return mux_ps(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int Rate(){
|
|
||||||
return rate_ps(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setlength(){
|
|
||||||
setlength_ps(&p);
|
|
||||||
p.data = new uint8_t[p.sheader_length];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int Stuffing(){
|
|
||||||
return p.stuff_length & PACK_STUFF_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int NPES(){
|
|
||||||
return p.npes;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int &MPEG(){
|
|
||||||
return p.mpeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t &operator()(int l){
|
|
||||||
return p.data[l];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline char * Data() {
|
|
||||||
return (char *)p.data+p.stuff_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int &SLENGTH(){
|
|
||||||
return p.sheader_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int &Info(){
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t SCR_base(){
|
|
||||||
return scr_base_ps(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t SCR_ext(){
|
|
||||||
return scr_ext_ps(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend ostream & operator << (ostream & stream, PS_Packet & x);
|
|
||||||
friend istream & operator >> (istream & stream, PS_Packet & x);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (* FILTER)(istream &in, ostream &out);
|
|
||||||
|
|
||||||
typedef struct thread_args_{
|
|
||||||
FILTER function;
|
|
||||||
int *fd;
|
|
||||||
int in;
|
|
||||||
int out;
|
|
||||||
} thread_args;
|
|
||||||
|
|
||||||
|
|
||||||
void extract_audio_from_PES(istream &in, ostream &out);
|
|
||||||
void extract_video_from_PES(istream &in, ostream &out);
|
|
||||||
void extract_es_audio_from_PES(istream &in, ostream &out);
|
|
||||||
void extract_es_video_from_PES(istream &in, ostream &out);
|
|
||||||
int TS_PIDS(istream &in, ostream &out);
|
|
||||||
int ifilter (istream &in, FILTER function);
|
|
||||||
int ofilter (istream &in, FILTER function);
|
|
||||||
int itfilter (int in, FILTER function);
|
|
||||||
int otfilter (istream &in, FILTER function);
|
|
||||||
int stream_type(int fd);
|
|
||||||
int stream_type(istream &stream);
|
|
||||||
int tv_norm(istream &fin);
|
|
||||||
|
|
||||||
void analyze(istream &fin);
|
|
||||||
|
|
||||||
|
|
||||||
#endif //_CPPTOOLS_HH_
|
|
||||||
|
|
@ -1,310 +0,0 @@
|
|||||||
#ifndef _channel_hh
|
|
||||||
#define _channel_hh
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "DVB.hh"
|
|
||||||
|
|
||||||
#define MAXNAM 80
|
|
||||||
#define MAXKEY 15
|
|
||||||
|
|
||||||
const int maxname=80;
|
|
||||||
const int MAXAPIDS=32;
|
|
||||||
const uint32_t UNSET=0xffffffff;
|
|
||||||
const uint16_t NOID=0xffff;
|
|
||||||
const uint16_t NOPID=0xffff;
|
|
||||||
|
|
||||||
class Transponder {
|
|
||||||
public:
|
|
||||||
uint16_t id;
|
|
||||||
uint16_t onid;
|
|
||||||
uint16_t satid;
|
|
||||||
int type;
|
|
||||||
char name[maxname+1];
|
|
||||||
uint32_t freq;
|
|
||||||
int pol;
|
|
||||||
int qam;
|
|
||||||
uint32_t srate;
|
|
||||||
int fec;
|
|
||||||
int band;
|
|
||||||
int hp_rate;
|
|
||||||
int lp_rate;
|
|
||||||
int mod;
|
|
||||||
int transmode;
|
|
||||||
int guard;
|
|
||||||
int hierarchy;
|
|
||||||
|
|
||||||
struct Sat *sat;
|
|
||||||
|
|
||||||
Transponder() {
|
|
||||||
name[0]='\0';
|
|
||||||
id = NOID;
|
|
||||||
onid = NOID;
|
|
||||||
satid = NOID;
|
|
||||||
type = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Transponder &x);
|
|
||||||
friend istream &operator>>(istream &stream, Transponder &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Sat {
|
|
||||||
public:
|
|
||||||
uint16_t id;
|
|
||||||
char name[maxname+1];
|
|
||||||
unsigned int lnbid;
|
|
||||||
struct Lnb *lnb;
|
|
||||||
unsigned int rotorid;
|
|
||||||
unsigned int fmin;
|
|
||||||
unsigned int fmax;
|
|
||||||
|
|
||||||
Sat() {
|
|
||||||
id=NOID;
|
|
||||||
name[0]='\0';
|
|
||||||
lnb=NULL;
|
|
||||||
rotorid=NOID;
|
|
||||||
lnbid=NOID;
|
|
||||||
fmin=fmax=0;
|
|
||||||
};
|
|
||||||
int set(int sid, char *sname, int slnbid, int srotorid) {
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Sat &x);
|
|
||||||
friend istream &operator>>(istream &stream, Sat &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Lnb {
|
|
||||||
public:
|
|
||||||
Sat *sat;
|
|
||||||
uint16_t id;
|
|
||||||
struct DVB *dvbd;
|
|
||||||
char name[maxname+1];
|
|
||||||
int type;
|
|
||||||
unsigned int lof1;
|
|
||||||
unsigned int lof2;
|
|
||||||
unsigned int slof;
|
|
||||||
int diseqcnr;
|
|
||||||
uint16_t diseqcid;
|
|
||||||
uint16_t swiid;
|
|
||||||
|
|
||||||
|
|
||||||
void cpy (const Lnb &olnb){
|
|
||||||
this->id=olnb.id;
|
|
||||||
this->type=olnb.type;
|
|
||||||
this->lof1=olnb.lof1;
|
|
||||||
this->lof2=olnb.lof2;
|
|
||||||
this->slof=olnb.slof;
|
|
||||||
this->diseqcnr=olnb.diseqcnr;
|
|
||||||
this->diseqcid=olnb.diseqcid;
|
|
||||||
this->swiid=olnb.swiid;
|
|
||||||
strncpy(this->name,olnb.name,maxname);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(int t, uint l1, uint l2, uint sl,
|
|
||||||
int dnr, int disid, int sw) {
|
|
||||||
type=t;
|
|
||||||
lof1=l1;
|
|
||||||
lof2=l2;
|
|
||||||
slof=sl;
|
|
||||||
diseqcnr=dnr;
|
|
||||||
diseqcid=disid;
|
|
||||||
swiid=sw;
|
|
||||||
dvbd=0;
|
|
||||||
name[0]='\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
Lnb () {
|
|
||||||
lof1=lof2=slof=0;
|
|
||||||
swiid=NOID;
|
|
||||||
diseqcid=NOID;
|
|
||||||
diseqcnr=-1;
|
|
||||||
name[0]='\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
Lnb (const Lnb &olnb){
|
|
||||||
cpy(olnb);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Lnb &x);
|
|
||||||
friend istream &operator>>(istream &stream, Lnb &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct diseqcmsg {
|
|
||||||
int burst;
|
|
||||||
int len;
|
|
||||||
unsigned char msg[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
class DiSEqC {
|
|
||||||
public:
|
|
||||||
uint16_t id;
|
|
||||||
char name[maxname+1];
|
|
||||||
diseqcmsg msgs[4];
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, DiSEqC &x);
|
|
||||||
friend istream &operator>>(istream &stream, DiSEqC &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Rotor {
|
|
||||||
public:
|
|
||||||
uint16_t id;
|
|
||||||
char name[maxname+1];
|
|
||||||
diseqcmsg msgs[4];
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Rotor &x);
|
|
||||||
friend istream &operator>>(istream &stream, Rotor &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Switch {
|
|
||||||
public:
|
|
||||||
uint16_t id;
|
|
||||||
int switchid;
|
|
||||||
char name[maxname+1];
|
|
||||||
diseqcmsg msg;
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Switch &x);
|
|
||||||
friend istream &operator>>(istream &stream, Switch &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Network {
|
|
||||||
public:
|
|
||||||
uint16_t id;
|
|
||||||
char name[maxname+1];
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Network &x);
|
|
||||||
friend istream &operator>>(istream &stream, Network &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Bouquet {
|
|
||||||
public:
|
|
||||||
uint16_t id;
|
|
||||||
char name[maxname+1];
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Bouquet &x);
|
|
||||||
friend istream &operator>>(istream &stream, Bouquet &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_ECM 16
|
|
||||||
#define MAX_ECM_DESC 256
|
|
||||||
typedef struct ecm_struct {
|
|
||||||
int num;
|
|
||||||
uint16_t sysid[MAX_ECM];
|
|
||||||
uint16_t pid[MAX_ECM];
|
|
||||||
uint16_t length[MAX_ECM];
|
|
||||||
uint8_t data[MAX_ECM*MAX_ECM_DESC];
|
|
||||||
} ecm_t;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Channel{
|
|
||||||
public:
|
|
||||||
Channel *next;
|
|
||||||
uint32_t id;
|
|
||||||
char name[maxname+1];
|
|
||||||
int32_t type;
|
|
||||||
int checked;
|
|
||||||
|
|
||||||
uint16_t pnr;
|
|
||||||
uint16_t vpid;
|
|
||||||
uint16_t apids[MAXAPIDS];
|
|
||||||
char apids_name[MAXAPIDS*4];
|
|
||||||
int32_t apidnum;
|
|
||||||
int last_apidn;
|
|
||||||
uint16_t ac3pid;
|
|
||||||
uint16_t ttpid;
|
|
||||||
uint16_t pmtpid;
|
|
||||||
uint16_t pcrpid;
|
|
||||||
uint16_t casystem;
|
|
||||||
uint16_t capid;
|
|
||||||
|
|
||||||
ecm_t ecm;
|
|
||||||
int (*ecm_callback)(Channel *chan);
|
|
||||||
|
|
||||||
int has_eit;
|
|
||||||
int pres_follow;
|
|
||||||
|
|
||||||
uint16_t satid;
|
|
||||||
uint16_t tpid;
|
|
||||||
uint16_t onid;
|
|
||||||
uint16_t bid;
|
|
||||||
int8_t eit_ver_n;
|
|
||||||
int8_t eit_ver_c;
|
|
||||||
|
|
||||||
void clearall(void) {
|
|
||||||
id=UNSET;
|
|
||||||
name[0]='\0';
|
|
||||||
type=0;
|
|
||||||
checked = 0;
|
|
||||||
has_eit = -1;
|
|
||||||
pres_follow = -1;
|
|
||||||
eit_ver_c = -1;
|
|
||||||
eit_ver_n = -1;
|
|
||||||
|
|
||||||
pnr=NOPID;
|
|
||||||
vpid=NOPID;
|
|
||||||
memset(apids, 0, sizeof(uint16_t)*MAXAPIDS);
|
|
||||||
memset(apids_name, 0, sizeof(char)*MAXAPIDS*4);
|
|
||||||
apidnum=0;
|
|
||||||
last_apidn=-1;
|
|
||||||
ac3pid=NOPID;
|
|
||||||
ttpid=NOPID;
|
|
||||||
pmtpid=NOPID;
|
|
||||||
pcrpid=NOPID;
|
|
||||||
capid=NOPID;
|
|
||||||
|
|
||||||
satid=NOID;
|
|
||||||
tpid=NOID;
|
|
||||||
onid=NOID;
|
|
||||||
bid=NOID;
|
|
||||||
ecm_callback = NULL;
|
|
||||||
memset(&ecm,0, sizeof(ecm_t));
|
|
||||||
};
|
|
||||||
|
|
||||||
Channel() {
|
|
||||||
clearall();
|
|
||||||
}
|
|
||||||
|
|
||||||
Channel(int cid, char *nam, int ty, int prognr,
|
|
||||||
int vid, int aid, int tid) {
|
|
||||||
int l=strlen(nam);
|
|
||||||
|
|
||||||
clearall();
|
|
||||||
if (l>maxname){
|
|
||||||
cerr << "" << endl;
|
|
||||||
l=maxname;
|
|
||||||
}
|
|
||||||
strncpy(name, nam, l);
|
|
||||||
name[l]='\0';
|
|
||||||
type=ty;
|
|
||||||
pnr=prognr;
|
|
||||||
vpid=vid;
|
|
||||||
apids[0]=aid;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
~Channel(){
|
|
||||||
cerr <<"Channel " << name << " destroyed" << endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
friend ostream &operator<<(ostream &stream, Channel &x);
|
|
||||||
friend istream &operator>>(istream &stream, Channel &x);
|
|
||||||
};
|
|
||||||
|
|
||||||
int findkey(char *name, char *keys[]);
|
|
||||||
void getname(char *name,istream &ins);
|
|
||||||
#endif /*channel.h*/
|
|
@ -1,84 +0,0 @@
|
|||||||
#ifndef _OSD_HH_
|
|
||||||
#define _OSD_HH_
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "OSD.h"
|
|
||||||
}
|
|
||||||
struct OSD {
|
|
||||||
int dev;
|
|
||||||
|
|
||||||
void init(int d) {
|
|
||||||
dev=d;
|
|
||||||
}
|
|
||||||
int Open(int x0, int y0, int x1, int y1, int BitPerPixel, int mix, int win) {
|
|
||||||
if (OSDSetWindow(dev, win))
|
|
||||||
return -1;
|
|
||||||
return OSDOpen(dev, x0, y0, x1, y1, BitPerPixel, mix);
|
|
||||||
}
|
|
||||||
int Open(int x0, int y0, int x1, int y1, int BitPerPixel, int mix) {
|
|
||||||
return OSDOpen(dev, x0, y0, x1, y1, BitPerPixel, mix);
|
|
||||||
}
|
|
||||||
int Close(int win) {
|
|
||||||
if (OSDSetWindow(dev, win))
|
|
||||||
return -1;
|
|
||||||
return OSDClose(dev);
|
|
||||||
}
|
|
||||||
int Close(void) {
|
|
||||||
return OSDClose(dev);
|
|
||||||
}
|
|
||||||
int Show(void) {
|
|
||||||
return OSDShow(dev);
|
|
||||||
}
|
|
||||||
int Hide(void) {
|
|
||||||
return OSDHide(dev);
|
|
||||||
}
|
|
||||||
int Clear(void) {
|
|
||||||
return OSDClear(dev);
|
|
||||||
}
|
|
||||||
int Fill(int color) {
|
|
||||||
return OSDFill(dev, color);
|
|
||||||
}
|
|
||||||
int SetColor(int color, int r, int g, int b, int op) {
|
|
||||||
return OSDSetColor(dev, color, r, g, b, op);
|
|
||||||
}
|
|
||||||
int Text(int x, int y, int size, int color, const char *text) {
|
|
||||||
return OSDText(dev, x, y, size, color, text);
|
|
||||||
}
|
|
||||||
int SetPalette(int first, int last, unsigned char *data) {
|
|
||||||
return OSDSetPalette(dev, first, last, data);
|
|
||||||
|
|
||||||
}
|
|
||||||
int SetTrans(int trans) {
|
|
||||||
return OSDSetTrans(dev, trans);
|
|
||||||
|
|
||||||
}
|
|
||||||
int SetPixel(int dev, int x, int y, unsigned int color) {
|
|
||||||
return OSDSetPixel(dev, x, y, color);
|
|
||||||
}
|
|
||||||
int GetPixel(int dev, int x, int y) {
|
|
||||||
return OSDGetPixel(dev, x, y);
|
|
||||||
}
|
|
||||||
int SetRow(int x, int y, int x1, unsigned char *data) {
|
|
||||||
return OSDSetRow(dev, x, y, x1, data);
|
|
||||||
}
|
|
||||||
int SetBlock(int x, int y, int x1, int y1, int inc, unsigned char *data) {
|
|
||||||
return OSDSetBlock(dev, x, y, x1, y1, inc, data);
|
|
||||||
}
|
|
||||||
int FillRow(int x, int y, int x1, int color) {
|
|
||||||
return OSDFillRow(dev, x, y, x1, color);
|
|
||||||
}
|
|
||||||
int FillBlock(int x, int y, int x1, int y1, int color) {
|
|
||||||
return OSDFillBlock(dev, x, y, x1, y1, color);
|
|
||||||
}
|
|
||||||
int Line(int x, int y, int x1, int y1, int color) {
|
|
||||||
return OSDLine(dev, x, y, x1, y1, color);
|
|
||||||
}
|
|
||||||
int Query() {
|
|
||||||
return OSDQuery(dev);
|
|
||||||
}
|
|
||||||
int SetWindow(int win) {
|
|
||||||
return OSDSetWindow(dev, win);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||||||
# The cannels.conf ca field can be used to bind a channel to a specific
|
|
||||||
# device. The streamdev-client does not consider this information, so
|
|
||||||
# there's no way to keep VDR from using streamdev for a specific
|
|
||||||
# channel. Apply this patch if you need this feature.
|
|
||||||
#
|
|
||||||
# This fix should probably become part of streamdev. However as it
|
|
||||||
# changes the behaviour of streamdev, I decided to keep it as a separate
|
|
||||||
# patch until there is something like a new official streamdev release.
|
|
||||||
#
|
|
||||||
--- client/device.h.bak 2006-11-09 12:25:21.000000000 +0100
|
|
||||||
+++ client/device.h 2006-11-09 12:26:57.000000000 +0100
|
|
||||||
@@ -50,6 +50,7 @@
|
|
||||||
cStreamdevDevice(void);
|
|
||||||
virtual ~cStreamdevDevice();
|
|
||||||
|
|
||||||
+ virtual int ProvidesCa(const cChannel *Channel) const;
|
|
||||||
virtual bool ProvidesSource(int Source) const;
|
|
||||||
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1,
|
|
||||||
--- client/device.c.bak 2006-11-09 12:23:24.000000000 +0100
|
|
||||||
+++ client/device.c 2006-11-09 12:35:48.000000000 +0100
|
|
||||||
@@ -57,6 +57,12 @@
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
+int cStreamdevDevice::ProvidesCa(const cChannel *Channel) const
|
|
||||||
+{
|
|
||||||
+ // Encrypted is acceptable for now. Will ask the server later.
|
|
||||||
+ return Channel->Ca() <= CA_DVB_MAX ? cDevice::ProvidesCa(Channel) : 1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
bool cStreamdevDevice::ProvidesSource(int Source) const {
|
|
||||||
Dprintf("ProvidesSource, Source=%d\n", Source);
|
|
||||||
return false;
|
|
||||||
@@ -78,7 +84,7 @@
|
|
||||||
if (ClientSocket.DataSocket(siLive) != NULL
|
|
||||||
&& TRANSPONDER(Channel, m_Channel))
|
|
||||||
res = true;
|
|
||||||
- else {
|
|
||||||
+ else if (ProvidesCa(Channel)) {
|
|
||||||
res = prio && ClientSocket.ProvidesChannel(Channel, Priority);
|
|
||||||
ndr = true;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
--- vdr-vanilla/thread.c 2003-10-10 18:19:15.000000000 +0200
|
|
||||||
+++ vdr-vanilla-thread/thread.c 2003-10-10 18:43:36.000000000 +0200
|
|
||||||
@@ -158,12 +158,21 @@
|
|
||||||
|
|
||||||
bool cThread::Active(void)
|
|
||||||
{
|
|
||||||
- if (threadPid) {
|
|
||||||
- if (kill(threadPid, SIGIO) < 0) { // couldn't find another way of checking whether the thread is still running - any ideas?
|
|
||||||
- if (errno == ESRCH)
|
|
||||||
- threadPid = 0;
|
|
||||||
- else
|
|
||||||
+ if (thread) {
|
|
||||||
+ /*
|
|
||||||
+ * Single UNIX Spec v2 says:
|
|
||||||
+ *
|
|
||||||
+ * The pthread_kill() function is used to request
|
|
||||||
+ * that a signal be delivered to the specified thread.
|
|
||||||
+ *
|
|
||||||
+ * As in kill(), if sig is zero, error checking is
|
|
||||||
+ * performed but no signal is actually sent.
|
|
||||||
+ */
|
|
||||||
+ int err;
|
|
||||||
+ if ((err = pthread_kill(thread, 0)) != 0) {
|
|
||||||
+ if (err != ESRCH)
|
|
||||||
LOG_ERROR;
|
|
||||||
+ thread = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return true;
|
|
@ -1,61 +0,0 @@
|
|||||||
diff -u vdr-1.3.11/config.c vdr-1.3.11.LocalChannelProvide/config.c
|
|
||||||
--- vdr-1.3.11/config.c 2004-05-16 14:43:55.000000000 +0200
|
|
||||||
+++ vdr-1.3.11.LocalChannelProvide/config.c 2004-08-29 17:55:59.000000000 +0200
|
|
||||||
@@ -297,6 +297,7 @@
|
|
||||||
ResumeID = 0;
|
|
||||||
CurrentChannel = -1;
|
|
||||||
CurrentVolume = MAXVOLUME;
|
|
||||||
+ LocalChannelProvide = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cSetup& cSetup::operator= (const cSetup &s)
|
|
||||||
@@ -450,6 +451,7 @@
|
|
||||||
else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value);
|
|
||||||
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
|
|
||||||
else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value);
|
|
||||||
+ else if (!strcasecmp(Name, "LocalChannelProvide")) LocalChannelProvide = atoi(Value);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
@@ -510,6 +512,7 @@
|
|
||||||
Store("ResumeID", ResumeID);
|
|
||||||
Store("CurrentChannel", CurrentChannel);
|
|
||||||
Store("CurrentVolume", CurrentVolume);
|
|
||||||
+ Store("LocalChannelProvide",LocalChannelProvide);
|
|
||||||
|
|
||||||
Sort();
|
|
||||||
|
|
||||||
diff -u vdr-1.3.11/config.h vdr-1.3.11.LocalChannelProvide/config.h
|
|
||||||
--- vdr-1.3.11/config.h 2004-06-10 15:18:50.000000000 +0200
|
|
||||||
+++ vdr-1.3.11.LocalChannelProvide/config.h 2004-08-29 17:47:32.000000000 +0200
|
|
||||||
@@ -251,6 +251,7 @@
|
|
||||||
int ResumeID;
|
|
||||||
int CurrentChannel;
|
|
||||||
int CurrentVolume;
|
|
||||||
+ int LocalChannelProvide;
|
|
||||||
int __EndData__;
|
|
||||||
cSetup(void);
|
|
||||||
cSetup& operator= (const cSetup &s);
|
|
||||||
diff -u vdr-1.3.11/dvbdevice.c vdr-1.3.11.LocalChannelProvide/dvbdevice.c
|
|
||||||
--- vdr-1.3.11/dvbdevice.c 2004-06-19 11:33:42.000000000 +0200
|
|
||||||
+++ vdr-1.3.11.LocalChannelProvide/dvbdevice.c 2004-08-29 18:00:37.000000000 +0200
|
|
||||||
@@ -674,6 +674,8 @@
|
|
||||||
|
|
||||||
bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
|
||||||
{
|
|
||||||
+ if (Setup.LocalChannelProvide != 1)
|
|
||||||
+ return false;
|
|
||||||
bool result = false;
|
|
||||||
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
|
||||||
bool needsDetachReceivers = false;
|
|
||||||
diff -u vdr-1.3.11/menu.c vdr-1.3.11.LocalChannelProvide/menu.c
|
|
||||||
--- vdr-1.3.11/menu.c 2004-06-13 22:26:51.000000000 +0200
|
|
||||||
+++ vdr-1.3.11.LocalChannelProvide/menu.c 2004-08-29 17:52:31.000000000 +0200
|
|
||||||
@@ -1878,6 +1878,7 @@
|
|
||||||
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
|
|
||||||
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
|
|
||||||
Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 5, updateChannelsTexts));
|
|
||||||
+ Add(new cMenuEditBoolItem(tr("Channels available locally"), &data.LocalChannelProvide));
|
|
||||||
}
|
|
||||||
|
|
||||||
eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
|
|
@ -1,93 +0,0 @@
|
|||||||
diff -Nu vdr-1.3.24/config.c vdr-1.3.24.LocalChannelProvide/config.c
|
|
||||||
--- vdr-1.3.24/config.c 2005-02-20 13:52:59.000000000 +0100
|
|
||||||
+++ vdr-1.3.24.LocalChannelProvide/config.c 2005-05-12 19:23:58.000000000 +0200
|
|
||||||
@@ -301,6 +301,7 @@
|
|
||||||
CurrentChannel = -1;
|
|
||||||
CurrentVolume = MAXVOLUME;
|
|
||||||
CurrentDolby = 0;
|
|
||||||
+ LocalChannelProvide = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cSetup& cSetup::operator= (const cSetup &s)
|
|
||||||
@@ -458,6 +459,7 @@
|
|
||||||
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
|
|
||||||
else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value);
|
|
||||||
else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value);
|
|
||||||
+ else if (!strcasecmp(Name, "LocalChannelProvide")) LocalChannelProvide = atoi(Value);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
@@ -522,6 +524,7 @@
|
|
||||||
Store("CurrentChannel", CurrentChannel);
|
|
||||||
Store("CurrentVolume", CurrentVolume);
|
|
||||||
Store("CurrentDolby", CurrentDolby);
|
|
||||||
+ Store("LocalChannelProvide",LocalChannelProvide);
|
|
||||||
|
|
||||||
Sort();
|
|
||||||
|
|
||||||
diff -Nu vdr-1.3.24/config.h vdr-1.3.24.LocalChannelProvide/config.h
|
|
||||||
--- vdr-1.3.24/config.h 2005-05-05 13:04:18.000000000 +0200
|
|
||||||
+++ vdr-1.3.24.LocalChannelProvide/config.h 2005-05-12 19:24:31.000000000 +0200
|
|
||||||
@@ -255,6 +255,7 @@
|
|
||||||
int CurrentChannel;
|
|
||||||
int CurrentVolume;
|
|
||||||
int CurrentDolby;
|
|
||||||
+ int LocalChannelProvide;
|
|
||||||
int __EndData__;
|
|
||||||
cSetup(void);
|
|
||||||
cSetup& operator= (const cSetup &s);
|
|
||||||
diff -Nu vdr-1.3.24/dvbdevice.c vdr-1.3.24.LocalChannelProvide/dvbdevice.c
|
|
||||||
--- vdr-1.3.24/dvbdevice.c 2005-03-20 11:10:38.000000000 +0100
|
|
||||||
+++ vdr-1.3.24.LocalChannelProvide/dvbdevice.c 2005-05-12 19:19:29.000000000 +0200
|
|
||||||
@@ -746,6 +746,8 @@
|
|
||||||
|
|
||||||
bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
|
||||||
{
|
|
||||||
+ if (Setup.LocalChannelProvide != 1)
|
|
||||||
+ return false;
|
|
||||||
bool result = false;
|
|
||||||
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
|
||||||
bool needsDetachReceivers = false;
|
|
||||||
diff -Nu vdr-1.3.24/i18n.c vdr-1.3.24.LocalChannelProvide/i18n.c
|
|
||||||
--- vdr-1.3.24/i18n.c 2005-05-05 15:12:54.000000000 +0200
|
|
||||||
+++ vdr-1.3.24.LocalChannelProvide/i18n.c 2005-05-12 19:30:50.000000000 +0200
|
|
||||||
@@ -5325,6 +5325,27 @@
|
|
||||||
"ST:TNG konsool",
|
|
||||||
"ST:TNG konsol",
|
|
||||||
},
|
|
||||||
+ { "Channels available locally",
|
|
||||||
+ "Kanäle lokal beziehen",
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",
|
|
||||||
+ "",
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",
|
|
||||||
+ "",
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",// TODO
|
|
||||||
+ "",
|
|
||||||
+ "",
|
|
||||||
+ "",
|
|
||||||
+ "",
|
|
||||||
+ },
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
diff -Nu vdr-1.3.24/menu.c vdr-1.3.24.LocalChannelProvide/menu.c
|
|
||||||
--- vdr-1.3.24/menu.c 2005-03-20 16:14:51.000000000 +0100
|
|
||||||
+++ vdr-1.3.24.LocalChannelProvide/menu.c 2005-05-12 19:26:57.000000000 +0200
|
|
||||||
@@ -1968,7 +1968,7 @@
|
|
||||||
Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nNumLanguages));
|
|
||||||
for (int i = 0; i < numAudioLanguages; i++)
|
|
||||||
Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nNumLanguages, I18nLanguages()));
|
|
||||||
-
|
|
||||||
+ Add(new cMenuEditBoolItem(tr("Channels available locally"), &data.LocalChannelProvide));
|
|
||||||
SetCurrent(Get(current));
|
|
||||||
Display();
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
--- vdr-1.3.6/sections.c 2004-02-07 17:51:57.000000000 +0200
|
|
||||||
+++ sections.c 2004-03-21 18:34:47.000000000 +0200
|
|
||||||
@@ -185,11 +185,17 @@
|
|
||||||
if (fh) {
|
|
||||||
// Read section data:
|
|
||||||
unsigned char buf[4096]; // max. allowed size for any EIT section
|
|
||||||
- int r = safe_read(fh->handle, buf, sizeof(buf));
|
|
||||||
+ struct stat statbuf;
|
|
||||||
+ int st = fstat(fh->handle, &statbuf);
|
|
||||||
+ int ispipe = (st == 0 && !S_ISCHR(statbuf.st_mode));
|
|
||||||
+ /*printf("ispipe %d\n", ispipe);*/
|
|
||||||
+ int r = safe_read(fh->handle, buf, ispipe ? 3 : sizeof(buf));
|
|
||||||
if (!DeviceHasLock)
|
|
||||||
continue; // we do the read anyway, to flush any data that might have come from a different transponder
|
|
||||||
- if (r > 3) { // minimum number of bytes necessary to get section length
|
|
||||||
+ if (r >= 3) { // minimum number of bytes necessary to get section length
|
|
||||||
int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
|
|
||||||
+ if (ispipe)
|
|
||||||
+ r += safe_read(fh->handle, buf+3, len-3);
|
|
||||||
if (len == r) {
|
|
||||||
// Distribute data to all attached filters:
|
|
||||||
int pid = fh->filterData.pid;
|
|
13
patches/vdr-1.6.0-ignore_missing_cam.diff
Normal file
13
patches/vdr-1.6.0-ignore_missing_cam.diff
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
--- device.c.orig 2008-03-28 11:47:25.000000000 +0100
|
||||||
|
+++ device.c 2008-03-28 11:47:09.000000000 +0100
|
||||||
|
@@ -375,8 +375,8 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if (!NumUsableSlots)
|
||||||
|
- return NULL; // no CAM is able to decrypt this channel
|
||||||
|
+// if (!NumUsableSlots)
|
||||||
|
+// return NULL; // no CAM is able to decrypt this channel
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeedsDetachReceivers = false;
|
78
patches/vdr-1.6.0-intcamdevices.patch
Normal file
78
patches/vdr-1.6.0-intcamdevices.patch
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
Index: vdr-1.6.0-nocamdevices/device.c
|
||||||
|
===================================================================
|
||||||
|
--- vdr-1.6.0-nocamdevices/device.c
|
||||||
|
+++ vdr-1.6.0-nocamdevices/device.c 2008-04-27 18:55:37.000000000 +0300
|
||||||
|
@@ -363,6 +363,7 @@
|
||||||
|
int NumCamSlots = CamSlots.Count();
|
||||||
|
int SlotPriority[NumCamSlots];
|
||||||
|
int NumUsableSlots = 0;
|
||||||
|
+ bool InternalCamNeeded = false;
|
||||||
|
if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
|
||||||
|
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
|
||||||
|
SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
|
||||||
|
@@ -376,7 +377,7 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!NumUsableSlots)
|
||||||
|
- return NULL; // no CAM is able to decrypt this channel
|
||||||
|
+ InternalCamNeeded = true; // no CAM is able to decrypt this channel
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeedsDetachReceivers = false;
|
||||||
|
@@ -392,11 +393,13 @@
|
||||||
|
continue; // this device shall be temporarily avoided
|
||||||
|
if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1)
|
||||||
|
continue; // a specific card was requested, but not this one
|
||||||
|
- if (NumUsableSlots && !CamSlots.Get(j)->Assign(device[i], true))
|
||||||
|
+ if (InternalCamNeeded && !device[i]->HasInternalCam())
|
||||||
|
+ continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
|
||||||
|
+ if (NumUsableSlots && !device[i]->HasInternalCam() && !CamSlots.Get(j)->Assign(device[i], true))
|
||||||
|
continue; // CAM slot can't be used with this device
|
||||||
|
bool ndr;
|
||||||
|
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
|
||||||
|
- if (NumUsableSlots && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
|
||||||
|
+ if (NumUsableSlots && !device[i]->HasInternalCam() && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
|
||||||
|
ndr = true; // using a different CAM slot requires detaching receivers
|
||||||
|
// Put together an integer number that reflects the "impact" using
|
||||||
|
// this device would have on the overall system. Each condition is represented
|
||||||
|
@@ -410,18 +413,18 @@
|
||||||
|
imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving
|
||||||
|
imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
|
||||||
|
imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
|
||||||
|
- imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
|
||||||
|
+ imp <<= 8; imp |= min(max(((NumUsableSlots && !device[i]->HasInternalCam()) ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
|
||||||
|
imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
|
||||||
|
imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
|
||||||
|
- imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
|
||||||
|
+ imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
|
||||||
|
imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards
|
||||||
|
- imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
|
||||||
|
+ imp <<= 1; imp |= (NumUsableSlots && !device[i]->HasInternalCam()) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
|
||||||
|
if (imp < Impact) {
|
||||||
|
// This device has less impact than any previous one, so we take it.
|
||||||
|
Impact = imp;
|
||||||
|
d = device[i];
|
||||||
|
NeedsDetachReceivers = ndr;
|
||||||
|
- if (NumUsableSlots)
|
||||||
|
+ if (NumUsableSlots && !device[i]->HasInternalCam())
|
||||||
|
s = CamSlots.Get(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Index: vdr-1.6.0-nocamdevices/device.h
|
||||||
|
===================================================================
|
||||||
|
--- vdr-1.6.0-nocamdevices/device.h
|
||||||
|
+++ vdr-1.6.0-nocamdevices/device.h 2008-04-27 18:55:49.000000000 +0300
|
||||||
|
@@ -335,6 +335,12 @@
|
||||||
|
public:
|
||||||
|
virtual bool HasCi(void);
|
||||||
|
///< Returns true if this device has a Common Interface.
|
||||||
|
+ virtual bool HasInternalCam(void) { return false; }
|
||||||
|
+ ///< Returns true if this device handles encrypted channels itself
|
||||||
|
+ ///< without VDR assistance. This can be e.g. when the device is a
|
||||||
|
+ ///< client that gets the stream from another VDR instance that has
|
||||||
|
+ ///< already decrypted the stream. In this case ProvidesChannel()
|
||||||
|
+ ///< shall check whether the channel can be decrypted.
|
||||||
|
void SetCamSlot(cCamSlot *CamSlot);
|
||||||
|
///< Sets the given CamSlot to be used with this device.
|
||||||
|
cCamSlot *CamSlot(void) const { return camSlot; }
|
||||||
|
|
11
patches/vdr-cap_net_raw.diff
Normal file
11
patches/vdr-cap_net_raw.diff
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
--- vdr.c.orig 2009-02-13 09:45:55.000000000 +0100
|
||||||
|
+++ vdr.c 2009-02-13 09:46:24.000000000 +0100
|
||||||
|
@@ -115,7 +115,7 @@
|
||||||
|
static bool SetCapSysTime(void)
|
||||||
|
{
|
||||||
|
// drop all capabilities except cap_sys_time
|
||||||
|
- cap_t caps = cap_from_text("= cap_sys_time=ep");
|
||||||
|
+ cap_t caps = cap_from_text("= cap_sys_time,cap_net_raw=ep");
|
||||||
|
if (!caps) {
|
||||||
|
fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
|
||||||
|
return false;
|
@ -1,113 +0,0 @@
|
|||||||
diff -Nru -x PLUGINS vdr-1.3.12-orig/i18n.c vdr-1.3.12/i18n.c
|
|
||||||
--- vdr-1.3.12-orig/i18n.c 2004-05-28 15:19:29.000000000 +0200
|
|
||||||
+++ vdr-1.3.12/i18n.c 2004-08-17 16:01:07.000000000 +0200
|
|
||||||
@@ -1033,8 +1033,8 @@
|
|
||||||
"´ÕÙáâÒØâÕÛìÝÞ ßÕàÕ×ÐßãáâØâì?",
|
|
||||||
"Zaista ponovo pokrenuti?",
|
|
||||||
},
|
|
||||||
- { "Recording - restart anyway?",
|
|
||||||
- "Aufnahme läuft - trotzdem neu starten?",
|
|
||||||
+ { "Busy - restart anyway?",
|
|
||||||
+ "Beschäftigt - trotzdem neu starten?",
|
|
||||||
"Snemanje - zares ponoven zagon?",
|
|
||||||
"In registrazione - restart comunque?",
|
|
||||||
"Opname loopt - toch opnieuw starten?",
|
|
||||||
@@ -1052,8 +1052,8 @@
|
|
||||||
"¸Ôñâ ×ÐßØáì - ÔÕÙáâÒØâÕÛìÝÞ ßÕàÕ×ÐßãáâØâì?",
|
|
||||||
"Snimanje traje - svejedno restart sistema?",
|
|
||||||
},
|
|
||||||
- { "Recording - shut down anyway?",
|
|
||||||
- "Aufnahme läuft - trotzdem ausschalten?",
|
|
||||||
+ { "Busy - shut down anyway?",
|
|
||||||
+ "Beschäftigt - trotzdem ausschalten?",
|
|
||||||
"Snemanje - zares izklopi?",
|
|
||||||
"In registrazione - spengo comunque?",
|
|
||||||
"Opname loopt - toch uitschakelen?",
|
|
||||||
diff -Nru -x PLUGINS vdr-1.3.12-orig/menu.c vdr-1.3.12/menu.c
|
|
||||||
--- vdr-1.3.12-orig/menu.c 2004-06-13 22:26:51.000000000 +0200
|
|
||||||
+++ vdr-1.3.12/menu.c 2004-08-17 16:00:07.000000000 +0200
|
|
||||||
@@ -2201,7 +2201,7 @@
|
|
||||||
|
|
||||||
eOSState cMenuSetup::Restart(void)
|
|
||||||
{
|
|
||||||
- if (Interface->Confirm(cRecordControls::Active() ? tr("Recording - restart anyway?") : tr("Really restart?"))) {
|
|
||||||
+ if (Interface->Confirm((cRecordControls::Active() || cPluginManager::Active()) ? tr("Busy - restart anyway?") : tr("Really restart?"))) {
|
|
||||||
cThread::EmergencyExit(true);
|
|
||||||
return osEnd;
|
|
||||||
}
|
|
||||||
diff -Nru -x PLUGINS vdr-1.3.12-orig/plugin.c vdr-1.3.12/plugin.c
|
|
||||||
--- vdr-1.3.12-orig/plugin.c 2004-05-22 13:25:22.000000000 +0200
|
|
||||||
+++ vdr-1.3.12/plugin.c 2004-08-17 15:57:52.000000000 +0200
|
|
||||||
@@ -64,6 +64,11 @@
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
+bool cPlugin::Active(void)
|
|
||||||
+{
|
|
||||||
+ return false;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
const char *cPlugin::MainMenuEntry(void)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
@@ -369,6 +374,18 @@
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+bool cPluginManager::Active(void)
|
|
||||||
+{
|
|
||||||
+ if (pluginManager) {
|
|
||||||
+ for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) {
|
|
||||||
+ cPlugin *p = dll->Plugin();
|
|
||||||
+ if (p && p->Active())
|
|
||||||
+ return true;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return false;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void cPluginManager::Shutdown(bool Log)
|
|
||||||
{
|
|
||||||
cDll *dll;
|
|
||||||
diff -Nru -x PLUGINS vdr-1.3.12-orig/plugin.h vdr-1.3.12/plugin.h
|
|
||||||
--- vdr-1.3.12-orig/plugin.h 2004-04-30 15:46:21.000000000 +0200
|
|
||||||
+++ vdr-1.3.12/plugin.h 2004-08-17 15:56:51.000000000 +0200
|
|
||||||
@@ -36,6 +36,7 @@
|
|
||||||
virtual bool Initialize(void);
|
|
||||||
virtual bool Start(void);
|
|
||||||
virtual void Housekeeping(void);
|
|
||||||
+ virtual bool Active(void);
|
|
||||||
|
|
||||||
virtual const char *MainMenuEntry(void);
|
|
||||||
virtual cOsdObject *MainMenuAction(void);
|
|
||||||
@@ -85,6 +86,7 @@
|
|
||||||
static bool HasPlugins(void);
|
|
||||||
static cPlugin *GetPlugin(int Index);
|
|
||||||
static cPlugin *GetPlugin(const char *Name);
|
|
||||||
+ static bool Active(void);
|
|
||||||
void Shutdown(bool Log = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
diff -Nru -x PLUGINS vdr-1.3.12-orig/vdr.c vdr-1.3.12/vdr.c
|
|
||||||
--- vdr-1.3.12-orig/vdr.c 2004-06-13 15:52:09.000000000 +0200
|
|
||||||
+++ vdr-1.3.12/vdr.c 2004-08-17 15:59:18.000000000 +0200
|
|
||||||
@@ -707,8 +707,8 @@
|
|
||||||
Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
- if (cRecordControls::Active()) {
|
|
||||||
- if (Interface->Confirm(tr("Recording - shut down anyway?")))
|
|
||||||
+ if (cRecordControls::Active() || cPluginManager::Active()) {
|
|
||||||
+ if (Interface->Confirm(tr("Busy - shut down anyway?")))
|
|
||||||
ForceShutdown = true;
|
|
||||||
}
|
|
||||||
LastActivity = 1; // not 0, see below!
|
|
||||||
@@ -821,7 +821,7 @@
|
|
||||||
Skins.Message(mtInfo, tr("Editing process finished"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- if (!Interact && ((!cRecordControls::Active() && !cCutter::Active() && (!Interface->HasSVDRPConnection() || UserShutdown)) || ForceShutdown)) {
|
|
||||||
+ if (!Interact && ((!cRecordControls::Active() && !cCutter::Active() && !cPluginManager::Active() && (!Interface->HasSVDRPConnection() || UserShutdown)) || ForceShutdown)) {
|
|
||||||
time_t Now = time(NULL);
|
|
||||||
if (Now - LastActivity > ACTIVITYTIMEOUT) {
|
|
||||||
// Shutdown:
|
|
118
po/de_DE.po
Normal file
118
po/de_DE.po
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# 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 <vdrdev@schmirler.de>, 2008
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: streamdev 0.5.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
|
||||||
|
"POT-Creation-Date: 2009-02-13 11:53+0100\n"
|
||||||
|
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
|
||||||
|
"Last-Translator: Frank Schmirler <vdrdev@schmirler.de>\n"
|
||||||
|
"Language-Team: <vdr@linuxtv.org>\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 "Hauptmenüeintrag 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 Priorität"
|
||||||
|
|
||||||
|
msgid "Maximum Priority"
|
||||||
|
msgstr "Maximale Priorität"
|
||||||
|
|
||||||
|
msgid "VDR Streaming Server"
|
||||||
|
msgstr "VDR Streaming Server"
|
||||||
|
|
||||||
|
msgid "Streaming active"
|
||||||
|
msgstr "Streamen im Gange"
|
||||||
|
|
||||||
|
msgid "Suspend Live TV"
|
||||||
|
msgstr "Live-TV pausieren"
|
||||||
|
|
||||||
|
msgid "Common Settings"
|
||||||
|
msgstr "Allgemeines"
|
||||||
|
|
||||||
|
msgid "Maximum Number of Clients"
|
||||||
|
msgstr "Maximalanzahl an Clients"
|
||||||
|
|
||||||
|
msgid "Suspend behaviour"
|
||||||
|
msgstr "Pausierverhalten"
|
||||||
|
|
||||||
|
msgid "Client may suspend"
|
||||||
|
msgstr "Client darf pausieren"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server"
|
||||||
|
msgstr "VDR-zu-VDR Server"
|
||||||
|
|
||||||
|
msgid "Start VDR-to-VDR Server"
|
||||||
|
msgstr "VDR-zu-VDR Server starten"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server Port"
|
||||||
|
msgstr "Port des VDR-zu-VDR Servers"
|
||||||
|
|
||||||
|
msgid "Bind to IP"
|
||||||
|
msgstr "Binde an IP"
|
||||||
|
|
||||||
|
msgid "HTTP Server"
|
||||||
|
msgstr "HTTP Server"
|
||||||
|
|
||||||
|
msgid "Start HTTP Server"
|
||||||
|
msgstr "HTTP Server starten"
|
||||||
|
|
||||||
|
msgid "HTTP Server Port"
|
||||||
|
msgstr "Port des HTTP Servers"
|
||||||
|
|
||||||
|
msgid "HTTP Streamtype"
|
||||||
|
msgstr "HTTP Streamtyp"
|
||||||
|
|
||||||
|
msgid "Multicast Streaming Server"
|
||||||
|
msgstr "Multicast Streaming Server"
|
||||||
|
|
||||||
|
msgid "Start IGMP Server"
|
||||||
|
msgstr "IGMP Server starten"
|
||||||
|
|
||||||
|
msgid "Multicast Client Port"
|
||||||
|
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"
|
118
po/fi_FI.po
Normal file
118
po/fi_FI.po
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# 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 <rahrenbe@cc.hut.fi>, 2008
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: streamdev 0.5.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
|
||||||
|
"POT-Creation-Date: 2009-02-13 11:53+0100\n"
|
||||||
|
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
|
||||||
|
"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
|
||||||
|
"Language-Team: <vdr@linuxtv.org>\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 "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 "Multicast Streaming Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Start IGMP Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Multicast Client Port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Multicast Streamtype"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Offer suspend mode"
|
||||||
|
msgstr "tyrkytä"
|
||||||
|
|
||||||
|
msgid "Always suspended"
|
||||||
|
msgstr "aina"
|
||||||
|
|
||||||
|
msgid "Never suspended"
|
||||||
|
msgstr "ei koskaan"
|
106
po/fi_FI.po.bak
Normal file
106
po/fi_FI.po.bak
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
# 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 <rahrenbe@cc.hut.fi>, 2008
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: streamdev 0.5.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\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 <rahrenbe@cc.hut.fi>\n"
|
||||||
|
"Language-Team: <vdr@linuxtv.org>\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"
|
118
po/fr_FR.po
Normal file
118
po/fr_FR.po
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# 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 <vdrdev@schmirler.de>, 2008
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: streamdev 0.5.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
|
||||||
|
"POT-Creation-Date: 2009-02-13 11:53+0100\n"
|
||||||
|
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
|
||||||
|
"Last-Translator: micky979 <micky979@free.fr>\n"
|
||||||
|
"Language-Team: <vdr@linuxtv.org>\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 "Démarrage 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"
|
||||||
|
|
||||||
|
msgid "Streaming active"
|
||||||
|
msgstr "Streaming actif"
|
||||||
|
|
||||||
|
msgid "Suspend Live TV"
|
||||||
|
msgstr "Suspendre Live TV"
|
||||||
|
|
||||||
|
msgid "Common Settings"
|
||||||
|
msgstr "Paramètres communs"
|
||||||
|
|
||||||
|
msgid "Maximum Number of Clients"
|
||||||
|
msgstr "Nombre maximun de clients"
|
||||||
|
|
||||||
|
msgid "Suspend behaviour"
|
||||||
|
msgstr "Suspendre"
|
||||||
|
|
||||||
|
msgid "Client may suspend"
|
||||||
|
msgstr "Le client peut suspendre"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server"
|
||||||
|
msgstr "VDR-to-VDR Serveur"
|
||||||
|
|
||||||
|
msgid "Start VDR-to-VDR Server"
|
||||||
|
msgstr "Démarrer le serveur VDR-to-VDR"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server Port"
|
||||||
|
msgstr "Port du serveur VDR-to-VDR"
|
||||||
|
|
||||||
|
msgid "Bind to IP"
|
||||||
|
msgstr "Attacher aux IP"
|
||||||
|
|
||||||
|
msgid "HTTP Server"
|
||||||
|
msgstr "Serveur HTTP"
|
||||||
|
|
||||||
|
msgid "Start HTTP Server"
|
||||||
|
msgstr "Démarrer le serveur HTTP"
|
||||||
|
|
||||||
|
msgid "HTTP Server Port"
|
||||||
|
msgstr "Port du serveur HTTP"
|
||||||
|
|
||||||
|
msgid "HTTP Streamtype"
|
||||||
|
msgstr "Type de Streaming HTTP"
|
||||||
|
|
||||||
|
msgid "Multicast Streaming Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Start IGMP Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Multicast Client Port"
|
||||||
|
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"
|
120
po/it_IT.po
Executable file
120
po/it_IT.po
Executable file
@ -0,0 +1,120 @@
|
|||||||
|
# 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 <bertocar@tin.it>, 2001
|
||||||
|
# Antonio Ospite <ospite@studenti.unina.it>, 2003
|
||||||
|
# Sean Carlos <seanc@libero.it>, 2005
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: streamdev 0.5.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
|
||||||
|
"POT-Creation-Date: 2009-02-13 11:53+0100\n"
|
||||||
|
"PO-Revision-Date: 2008-04-13 23:42+0100\n"
|
||||||
|
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
||||||
|
"Language-Team: <vdr@linuxtv.org>\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 "Synchronize EPG"
|
||||||
|
msgstr "Sincronizza EPG"
|
||||||
|
|
||||||
|
msgid "Minimum Priority"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Maximum Priority"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "VDR Streaming Server"
|
||||||
|
msgstr "Server trasmissione VDR"
|
||||||
|
|
||||||
|
msgid "Streaming active"
|
||||||
|
msgstr "Trasmissione attiva"
|
||||||
|
|
||||||
|
msgid "Suspend Live TV"
|
||||||
|
msgstr "Sospendi TV dal vivo"
|
||||||
|
|
||||||
|
msgid "Common Settings"
|
||||||
|
msgstr "Impostazioni comuni"
|
||||||
|
|
||||||
|
msgid "Maximum Number of Clients"
|
||||||
|
msgstr "Numero massimo di Client"
|
||||||
|
|
||||||
|
msgid "Suspend behaviour"
|
||||||
|
msgstr "Tipo sospensione"
|
||||||
|
|
||||||
|
msgid "Client may suspend"
|
||||||
|
msgstr "Permetti sospensione al Client"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server"
|
||||||
|
msgstr "Server VDR-a-VDR"
|
||||||
|
|
||||||
|
msgid "Start VDR-to-VDR Server"
|
||||||
|
msgstr "Avvia Server VDR-a-VDR"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server Port"
|
||||||
|
msgstr "Porta Server VDR-a-VDR"
|
||||||
|
|
||||||
|
msgid "Bind to IP"
|
||||||
|
msgstr "IP associati"
|
||||||
|
|
||||||
|
msgid "HTTP Server"
|
||||||
|
msgstr "Server HTTP"
|
||||||
|
|
||||||
|
msgid "Start HTTP Server"
|
||||||
|
msgstr "Avvia Server HTTP"
|
||||||
|
|
||||||
|
msgid "HTTP Server Port"
|
||||||
|
msgstr "Porta Server HTTP"
|
||||||
|
|
||||||
|
msgid "HTTP Streamtype"
|
||||||
|
msgstr "Tipo flusso HTTP"
|
||||||
|
|
||||||
|
msgid "Multicast Streaming Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Start IGMP Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Multicast Client Port"
|
||||||
|
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"
|
118
po/ru_RU.po
Normal file
118
po/ru_RU.po
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# 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 <vdrdev@schmirler.de>, 2008
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: streamdev 0.5.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
|
||||||
|
"POT-Creation-Date: 2009-02-13 11:53+0100\n"
|
||||||
|
"PO-Revision-Date: 2008-06-26 15:36+0100\n"
|
||||||
|
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
|
||||||
|
"Language-Team: <vdr@linuxtv.org>\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 "Synchronize EPG"
|
||||||
|
msgstr "ÁØÝåàÞÝØ×ÐæØï EPG"
|
||||||
|
|
||||||
|
msgid "Minimum Priority"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Maximum Priority"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "VDR Streaming Server"
|
||||||
|
msgstr "VDR Streaming áÕàÒÕà"
|
||||||
|
|
||||||
|
msgid "Streaming active"
|
||||||
|
msgstr "ÁâàØÜØÝÓ ÐÚâØÒÕÝ"
|
||||||
|
|
||||||
|
msgid "Suspend Live TV"
|
||||||
|
msgstr "¾áâÐÝÞÒÚÐ Live TV"
|
||||||
|
|
||||||
|
msgid "Common Settings"
|
||||||
|
msgstr "½ÐáâàÞÙÚØ"
|
||||||
|
|
||||||
|
msgid "Maximum Number of Clients"
|
||||||
|
msgstr "¼ÐÚá. ÚÞÛØçÕáâÒÞ ÚÛØÕÝâÞÒ"
|
||||||
|
|
||||||
|
msgid "Suspend behaviour"
|
||||||
|
msgstr "¿ÞÒÕÔÕÝØÕ ÞáâÐÝÞÒÚØ"
|
||||||
|
|
||||||
|
msgid "Client may suspend"
|
||||||
|
msgstr "ºÛØÕÝâ ÜÞÖÕâ ÞáâÐÝÐÒÛØÒÐâì"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server"
|
||||||
|
msgstr "VDR-to-VDR áÕàÒÕà"
|
||||||
|
|
||||||
|
msgid "Start VDR-to-VDR Server"
|
||||||
|
msgstr "ÁâÐàâ VDR-to-VDR áÕàÒÕà"
|
||||||
|
|
||||||
|
msgid "VDR-to-VDR Server Port"
|
||||||
|
msgstr "VDR-to-VDR ßÞàâ áÕàÒÕàÐ"
|
||||||
|
|
||||||
|
msgid "Bind to IP"
|
||||||
|
msgstr "¿àØáÞÕÔØÝØâìáï Ú IP"
|
||||||
|
|
||||||
|
msgid "HTTP Server"
|
||||||
|
msgstr "HTTP áÕàÒÕà"
|
||||||
|
|
||||||
|
msgid "Start HTTP Server"
|
||||||
|
msgstr "ÁâÐàâ HTTP áÕàÒÕàÐ"
|
||||||
|
|
||||||
|
msgid "HTTP Server Port"
|
||||||
|
msgstr "HTTP áÕàÒÕà ¿Þàâ"
|
||||||
|
|
||||||
|
msgid "HTTP Streamtype"
|
||||||
|
msgstr "ÂØß HTTP ßÞâÞÚÐ"
|
||||||
|
|
||||||
|
msgid "Multicast Streaming Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Start IGMP Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Multicast Client Port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Multicast Streamtype"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Offer suspend mode"
|
||||||
|
msgstr "¿àÕÔÛÐÓÐâì ÞáâÐÝÞÒÚã"
|
||||||
|
|
||||||
|
msgid "Always suspended"
|
||||||
|
msgstr "²áÕÓÔÐ ÞáâÐÝÞÒÛÕÝ"
|
||||||
|
|
||||||
|
msgid "Never suspended"
|
||||||
|
msgstr "½ØÚÞÓÔÐ ÝÕ ÞáâÐÝÞÒÛÕÝ"
|
@ -1,4 +1,5 @@
|
|||||||
#include "remux/extern.h"
|
#include "remux/extern.h"
|
||||||
|
#include "server/server.h"
|
||||||
#include "server/streamer.h"
|
#include "server/streamer.h"
|
||||||
#include <vdr/tools.h>
|
#include <vdr/tools.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -6,8 +7,6 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
const char *g_ExternRemux = "/root/externremux.sh";
|
|
||||||
|
|
||||||
class cTSExt: public cThread {
|
class cTSExt: public cThread {
|
||||||
private:
|
private:
|
||||||
cRingBufferLinear *m_ResultBuffer;
|
cRingBufferLinear *m_ResultBuffer;
|
||||||
@ -28,7 +27,7 @@ public:
|
|||||||
cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter):
|
cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter):
|
||||||
m_ResultBuffer(ResultBuffer),
|
m_ResultBuffer(ResultBuffer),
|
||||||
m_Active(false),
|
m_Active(false),
|
||||||
m_Process(0),
|
m_Process(-1),
|
||||||
m_Inpipe(0),
|
m_Inpipe(0),
|
||||||
m_Outpipe(0)
|
m_Outpipe(0)
|
||||||
{
|
{
|
||||||
@ -67,9 +66,13 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter):
|
|||||||
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
||||||
close(i); //close all dup'ed filedescriptors
|
close(i); //close all dup'ed filedescriptors
|
||||||
|
|
||||||
std::string cmd = std::string(g_ExternRemux) + " " + Parameter;
|
std::string cmd = std::string(opt_remux) + " " + Parameter;
|
||||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
|
if (execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL) == -1) {
|
||||||
_exit(-1);
|
esyslog("streamdev-server: externremux script '%s' execution failed: %m", cmd.c_str());
|
||||||
|
_exit(-1);
|
||||||
|
}
|
||||||
|
// should never be reached
|
||||||
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(inpipe[0]);
|
close(inpipe[0]);
|
||||||
@ -84,16 +87,31 @@ cTSExt::~cTSExt()
|
|||||||
m_Active = false;
|
m_Active = false;
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
if (m_Process > 0) {
|
if (m_Process > 0) {
|
||||||
|
// close pipes
|
||||||
close(m_Outpipe);
|
close(m_Outpipe);
|
||||||
close(m_Inpipe);
|
close(m_Inpipe);
|
||||||
kill(m_Process, SIGTERM);
|
// signal and wait for termination
|
||||||
for (int i = 0; waitpid(m_Process, NULL, WNOHANG) == 0; i++) {
|
if (kill(m_Process, SIGINT) < 0) {
|
||||||
if (i == 20) {
|
esyslog("streamdev-server: externremux SIGINT failed: %m");
|
||||||
esyslog("streamdev-server: externremux process won't stop - killing it");
|
|
||||||
kill(m_Process, SIGKILL);
|
|
||||||
}
|
|
||||||
cCondWait::SleepMs(100);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
int i = 0;
|
||||||
|
int retval;
|
||||||
|
while ((retval = waitpid(m_Process, NULL, WNOHANG)) == 0) {
|
||||||
|
|
||||||
|
if ((++i % 20) == 0) {
|
||||||
|
esyslog("streamdev-server: externremux process won't stop - killing it");
|
||||||
|
kill(m_Process, SIGKILL);
|
||||||
|
}
|
||||||
|
cCondWait::SleepMs(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval < 0)
|
||||||
|
esyslog("streamdev-server: externremux process waitpid failed: %m");
|
||||||
|
else
|
||||||
|
Dprintf("streamdev-server: externremux child (%d) exited as expected\n", m_Process);
|
||||||
|
}
|
||||||
|
m_Process = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#include <vdr/ringbuffer.h>
|
#include <vdr/ringbuffer.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
extern const char *g_ExternRemux;
|
|
||||||
|
|
||||||
class cTSExt;
|
class cTSExt;
|
||||||
|
|
||||||
class cExternRemux: public cTSRemux {
|
class cExternRemux: public cTSRemux {
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
#include <vdr/remux.h>
|
#include <vdr/remux.h>
|
||||||
#include <vdr/ringbuffer.h>
|
#include <vdr/ringbuffer.h>
|
||||||
|
|
||||||
|
#ifndef MAXTRACKS
|
||||||
|
#define MAXTRACKS 64
|
||||||
|
#endif
|
||||||
|
|
||||||
class cTS2PS;
|
class cTS2PS;
|
||||||
|
|
||||||
class cTS2PSRemux: public cTSRemux {
|
class cTS2PSRemux: public cTSRemux {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "remux/tsremux.h"
|
#include "remux/tsremux.h"
|
||||||
|
|
||||||
#define SC_PICTURE 0x00 // "picture header"
|
#define SC_PICTURE 0x00 // "picture header"
|
||||||
|
#define PID_MASK_HI 0x1F
|
||||||
|
|
||||||
void cTSRemux::SetBrokenLink(uchar *Data, int Length)
|
void cTSRemux::SetBrokenLink(uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
#include "libdvbmpeg/transform.h"
|
#include "libdvbmpeg/transform.h"
|
||||||
#include <vdr/remux.h>
|
#include <vdr/remux.h>
|
||||||
|
|
||||||
|
#ifndef NO_PICTURE
|
||||||
|
#define NO_PICTURE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define RESULTBUFFERSIZE KILOBYTE(256)
|
#define RESULTBUFFERSIZE KILOBYTE(256)
|
||||||
|
|
||||||
class cTSRemux {
|
class cTSRemux {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: component.c,v 1.3 2005/05/09 20:22:29 lordjaxom Exp $
|
* $Id: component.c,v 1.4 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "server/component.h"
|
#include "server/component.h"
|
||||||
#include "server/connection.h"
|
#include "server/connection.h"
|
||||||
|
|
||||||
cServerComponent::cServerComponent(const char *Protocol, const char *ListenIp,
|
cServerComponent::cServerComponent(const char *Protocol, const char *ListenIp,
|
||||||
uint ListenPort):
|
uint ListenPort, int Type, int IpProto):
|
||||||
m_Protocol(Protocol),
|
m_Protocol(Protocol),
|
||||||
|
m_Listen(Type, IpProto),
|
||||||
m_ListenIp(ListenIp),
|
m_ListenIp(ListenIp),
|
||||||
m_ListenPort(ListenPort)
|
m_ListenPort(ListenPort)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: component.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
|
* $Id: component.h,v 1.3 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_SERVERS_COMPONENT_H
|
#ifndef VDR_STREAMDEV_SERVERS_COMPONENT_H
|
||||||
@ -17,8 +17,8 @@ class cServerConnection;
|
|||||||
|
|
||||||
class cServerComponent: public cListObject {
|
class cServerComponent: public cListObject {
|
||||||
private:
|
private:
|
||||||
cTBSocket m_Listen;
|
|
||||||
const char *m_Protocol;
|
const char *m_Protocol;
|
||||||
|
cTBSocket m_Listen;
|
||||||
const char *m_ListenIp;
|
const char *m_ListenIp;
|
||||||
uint m_ListenPort;
|
uint m_ListenPort;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ protected:
|
|||||||
virtual cServerConnection *NewClient(void) = 0;
|
virtual cServerConnection *NewClient(void) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cServerComponent(const char *Protocol, const char *ListenIp, uint ListenPort);
|
cServerComponent(const char *Protocol, const char *ListenIp, uint ListenPort, int Type = SOCK_STREAM, int IpProto = 0);
|
||||||
virtual ~cServerComponent();
|
virtual ~cServerComponent();
|
||||||
|
|
||||||
/* Starts listening on the specified Port, override if you want to do things
|
/* Starts listening on the specified Port, override if you want to do things
|
||||||
|
447
server/componentIGMP.c
Normal file
447
server/componentIGMP.c
Normal file
@ -0,0 +1,447 @@
|
|||||||
|
/*
|
||||||
|
* $Id: componentIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $
|
||||||
|
*/
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/igmp.h>
|
||||||
|
|
||||||
|
#include "server/componentIGMP.h"
|
||||||
|
#include "server/connectionIGMP.h"
|
||||||
|
#include "server/setup.h"
|
||||||
|
|
||||||
|
#ifndef IGMP_ALL_HOSTS
|
||||||
|
#define IGMP_ALL_HOSTS htonl(0xE0000001L)
|
||||||
|
#endif
|
||||||
|
#ifndef IGMP_ALL_ROUTER
|
||||||
|
#define IGMP_ALL_ROUTER htonl(0xE0000002L)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// IGMP parameters according to RFC2236. All time values in seconds.
|
||||||
|
#define IGMP_ROBUSTNESS 2
|
||||||
|
#define IGMP_QUERY_INTERVAL 125
|
||||||
|
#define IGMP_QUERY_RESPONSE_INTERVAL 10
|
||||||
|
#define IGMP_GROUP_MEMBERSHIP_INTERVAL (2 * IGMP_QUERY_INTERVAL + IGMP_QUERY_RESPONSE_INTERVAL)
|
||||||
|
#define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (2 * IGMP_QUERY_INTERVAL + IGMP_QUERY_RESPONSE_INTERVAL / 2)
|
||||||
|
#define IGMP_STARTUP_QUERY_INTERVAL (IGMP_QUERY_INTERVAL / 4)
|
||||||
|
#define IGMP_STARTUP_QUERY_COUNT IGMP_ROBUSTNESS
|
||||||
|
// This value is 1/10 sec. RFC default is 10. Reduced to minimum to free unused channels ASAP
|
||||||
|
#define IGMP_LAST_MEMBER_QUERY_INTERVAL_TS 1
|
||||||
|
#define IGMP_LAST_MEMBER_QUERY_COUNT IGMP_ROBUSTNESS
|
||||||
|
|
||||||
|
// operations on struct timeval
|
||||||
|
#define TV_CMP(a, cmp, b) (a.tv_sec == b.tv_sec ? a.tv_usec cmp b.tv_usec : a.tv_sec cmp b.tv_sec)
|
||||||
|
#define TV_SET(tv) (tv.tv_sec || tv.tv_usec)
|
||||||
|
#define TV_CLR(tv) memset(&tv, 0, sizeof(tv))
|
||||||
|
#define TV_CPY(dst, src) memcpy(&dst, &src, sizeof(dst))
|
||||||
|
#define TV_ADD(dst, ts) dst.tv_sec += ts / 10; dst.tv_usec += (ts % 10) * 100000; if (dst.tv_usec >= 1000000) { dst.tv_usec -= 1000000; dst.tv_sec++; }
|
||||||
|
|
||||||
|
class cMulticastGroup: public cListObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cConnectionIGMP *connection;
|
||||||
|
in_addr_t group;
|
||||||
|
in_addr_t reporter;
|
||||||
|
struct timeval timeout;
|
||||||
|
struct timeval v1timer;
|
||||||
|
struct timeval retransmit;
|
||||||
|
|
||||||
|
cMulticastGroup(in_addr_t Group);
|
||||||
|
};
|
||||||
|
|
||||||
|
cMulticastGroup::cMulticastGroup(in_addr_t Group) :
|
||||||
|
connection(NULL),
|
||||||
|
group(Group),
|
||||||
|
reporter(0)
|
||||||
|
{
|
||||||
|
TV_CLR(timeout);
|
||||||
|
TV_CLR(v1timer);
|
||||||
|
TV_CLR(retransmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logIGMP(uint8_t type, struct in_addr Src, struct in_addr Dst, struct in_addr Grp)
|
||||||
|
{
|
||||||
|
const char* msg;
|
||||||
|
switch (type) {
|
||||||
|
case IGMP_MEMBERSHIP_QUERY: msg = "membership query"; break;
|
||||||
|
case IGMP_V1_MEMBERSHIP_REPORT: msg = "V1 membership report"; break;
|
||||||
|
case IGMP_V2_MEMBERSHIP_REPORT: msg = "V2 membership report"; break;
|
||||||
|
case IGMP_V2_LEAVE_GROUP: msg = "leave group"; break;
|
||||||
|
default: msg = "unknown"; break;
|
||||||
|
}
|
||||||
|
char* s = strdup(inet_ntoa(Src));
|
||||||
|
char* d = strdup(inet_ntoa(Dst));
|
||||||
|
dsyslog("streamdev-server IGMP: Received %s from %s (dst %s) for %s", msg, s, d, inet_ntoa(Grp));
|
||||||
|
free(s);
|
||||||
|
free(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Taken from http://tools.ietf.org/html/rfc1071 */
|
||||||
|
uint16_t inetChecksum(uint16_t *addr, int count)
|
||||||
|
{
|
||||||
|
uint32_t sum = 0;
|
||||||
|
while (count > 1) {
|
||||||
|
sum += *addr++;
|
||||||
|
count -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( count > 0 )
|
||||||
|
sum += * (uint8_t *) addr;
|
||||||
|
|
||||||
|
while (sum>>16)
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
|
||||||
|
return ~sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
cComponentIGMP::cComponentIGMP(void):
|
||||||
|
cServerComponent("IGMP", "0.0.0.0", 0, SOCK_RAW, IPPROTO_IGMP),
|
||||||
|
cThread("IGMP timeout handler"),
|
||||||
|
m_BindIp(inet_addr(StreamdevServerSetup.IGMPBindIP)),
|
||||||
|
m_MaxChannelNumber(0),
|
||||||
|
m_StartupQueryCount(IGMP_STARTUP_QUERY_COUNT),
|
||||||
|
m_Querier(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cComponentIGMP::~cComponentIGMP(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cMulticastGroup* cComponentIGMP::FindGroup(in_addr_t Group) const
|
||||||
|
{
|
||||||
|
cMulticastGroup *group = m_Groups.First();
|
||||||
|
while (group && group->group != Group)
|
||||||
|
group = m_Groups.Next(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cComponentIGMP::Initialize(void)
|
||||||
|
{
|
||||||
|
if (cServerComponent::Initialize() && IGMPMembership(IGMP_ALL_ROUTER))
|
||||||
|
{
|
||||||
|
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
|
||||||
|
{
|
||||||
|
if (channel->GroupSep())
|
||||||
|
continue;
|
||||||
|
int num = channel->Number();
|
||||||
|
if (!IGMPMembership(htonl(MULTICAST_PRIV_MIN + num)))
|
||||||
|
break;
|
||||||
|
m_MaxChannelNumber = num;
|
||||||
|
}
|
||||||
|
if (m_MaxChannelNumber == 0)
|
||||||
|
{
|
||||||
|
IGMPMembership(IGMP_ALL_ROUTER, false);
|
||||||
|
esyslog("streamdev-server IGMP: no multicast group joined");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m_MaxChannelNumber > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::Destruct(void)
|
||||||
|
{
|
||||||
|
if (m_MaxChannelNumber > 0)
|
||||||
|
{
|
||||||
|
Cancel(3);
|
||||||
|
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
|
||||||
|
{
|
||||||
|
if (channel->GroupSep())
|
||||||
|
continue;
|
||||||
|
int num = channel->Number();
|
||||||
|
if (num > m_MaxChannelNumber)
|
||||||
|
break;
|
||||||
|
IGMPMembership(htonl(MULTICAST_PRIV_MIN + num), false);
|
||||||
|
}
|
||||||
|
IGMPMembership(IGMP_ALL_ROUTER, false);
|
||||||
|
}
|
||||||
|
m_MaxChannelNumber = 0;
|
||||||
|
cServerComponent::Destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
cServerConnection *cComponentIGMP::NewClient(void)
|
||||||
|
{
|
||||||
|
return new cConnectionIGMP("IGMP", StreamdevServerSetup.IGMPClientPort, (eStreamType) StreamdevServerSetup.IGMPStreamType);
|
||||||
|
}
|
||||||
|
|
||||||
|
cServerConnection* cComponentIGMP::Accept(void)
|
||||||
|
{
|
||||||
|
ssize_t recv_len;
|
||||||
|
int ip_hdrlen, ip_datalen;
|
||||||
|
struct ip *ip;
|
||||||
|
struct igmp *igmp;
|
||||||
|
|
||||||
|
while ((recv_len = ::recvfrom(Socket(), m_ReadBuffer, sizeof(m_ReadBuffer), 0, NULL, NULL)) < 0 && errno == EINTR)
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
if (recv_len < 0) {
|
||||||
|
esyslog("streamdev-server IGMP: read failed: %m");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (recv_len < (ssize_t) sizeof(struct ip)) {
|
||||||
|
esyslog("streamdev-server IGMP: IP packet too short");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = (struct ip*) m_ReadBuffer;
|
||||||
|
|
||||||
|
// filter out my own packets
|
||||||
|
if (ip->ip_src.s_addr == m_BindIp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ip_hdrlen = ip->ip_hl << 2;
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
ip_datalen = ip->ip_len;
|
||||||
|
#else
|
||||||
|
ip_datalen = ntohs(ip->ip_len) - ip_hdrlen;
|
||||||
|
#endif
|
||||||
|
if (ip->ip_p != IPPROTO_IGMP) {
|
||||||
|
esyslog("streamdev-server IGMP: Unexpected protocol %hhu", ip->ip_p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (recv_len < ip_hdrlen + IGMP_MINLEN) {
|
||||||
|
esyslog("streamdev-server IGMP: packet too short");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
igmp = (struct igmp*) (m_ReadBuffer + ip_hdrlen);
|
||||||
|
uint16_t chksum = igmp->igmp_cksum;
|
||||||
|
igmp->igmp_cksum = 0;
|
||||||
|
if (chksum != inetChecksum((uint16_t *)igmp, ip_datalen))
|
||||||
|
{
|
||||||
|
esyslog("INVALID CHECKSUM %d %d %d %d 0x%x 0x%x", ntohs(ip->ip_len), ip_hdrlen, ip_datalen, recv_len, chksum, inetChecksum((uint16_t *)igmp, ip_datalen));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
logIGMP(igmp->igmp_type, ip->ip_src, ip->ip_dst, igmp->igmp_group);
|
||||||
|
return ProcessMessage(igmp, igmp->igmp_group.s_addr, ip->ip_src.s_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
cServerConnection* cComponentIGMP::ProcessMessage(struct igmp *Igmp, in_addr_t Group, in_addr_t Sender)
|
||||||
|
{
|
||||||
|
cServerConnection* conn = NULL;
|
||||||
|
cMulticastGroup* group;
|
||||||
|
LOCK_THREAD;
|
||||||
|
switch (Igmp->igmp_type) {
|
||||||
|
case IGMP_MEMBERSHIP_QUERY:
|
||||||
|
if (ntohl(Sender) < ntohl(m_BindIp))
|
||||||
|
IGMPStartOtherQuerierPresentTimer();
|
||||||
|
break;
|
||||||
|
case IGMP_V1_MEMBERSHIP_REPORT:
|
||||||
|
case IGMP_V2_MEMBERSHIP_REPORT:
|
||||||
|
group = FindGroup(Group);
|
||||||
|
if (!group) {
|
||||||
|
group = new cMulticastGroup(Group);
|
||||||
|
m_Groups.Add(group);
|
||||||
|
}
|
||||||
|
if (!group->connection) {
|
||||||
|
IGMPStartMulticast(group);
|
||||||
|
conn = group->connection;
|
||||||
|
}
|
||||||
|
IGMPStartTimer(group, Sender);
|
||||||
|
if (Igmp->igmp_type == IGMP_V1_MEMBERSHIP_REPORT)
|
||||||
|
IGMPStartV1HostTimer(group);
|
||||||
|
break;
|
||||||
|
case IGMP_V2_LEAVE_GROUP:
|
||||||
|
group = FindGroup(Group);
|
||||||
|
if (group && !TV_SET(group->v1timer)) {
|
||||||
|
if (group->reporter == Sender) {
|
||||||
|
IGMPStartTimerAfterLeave(group, m_Querier ? IGMP_LAST_MEMBER_QUERY_INTERVAL_TS : Igmp->igmp_code);
|
||||||
|
if (m_Querier)
|
||||||
|
IGMPSendGroupQuery(group);
|
||||||
|
IGMPStartRetransmitTimer(group);
|
||||||
|
}
|
||||||
|
m_CondWait.Signal();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::Action()
|
||||||
|
{
|
||||||
|
while (Running()) {
|
||||||
|
struct timeval now;
|
||||||
|
struct timeval next;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
TV_CPY(next, now);
|
||||||
|
next.tv_sec += IGMP_QUERY_INTERVAL;
|
||||||
|
|
||||||
|
cMulticastGroup *del = NULL;
|
||||||
|
{
|
||||||
|
LOCK_THREAD;
|
||||||
|
if (TV_CMP(m_GeneralQueryTimer, <, now)) {
|
||||||
|
dsyslog("General Query");
|
||||||
|
IGMPSendGeneralQuery();
|
||||||
|
IGMPStartGeneralQueryTimer();
|
||||||
|
}
|
||||||
|
if (TV_CMP(next, >, m_GeneralQueryTimer))
|
||||||
|
TV_CPY(next, m_GeneralQueryTimer);
|
||||||
|
|
||||||
|
for (cMulticastGroup *group = m_Groups.First(); group; group = m_Groups.Next(group)) {
|
||||||
|
if (TV_CMP(group->timeout, <, now)) {
|
||||||
|
IGMPStopMulticast(group);
|
||||||
|
IGMPClearRetransmitTimer(group);
|
||||||
|
if (del)
|
||||||
|
m_Groups.Del(del);
|
||||||
|
del = group;
|
||||||
|
}
|
||||||
|
else if (m_Querier && TV_SET(group->retransmit) && TV_CMP(group->retransmit, <, now)) {
|
||||||
|
IGMPSendGroupQuery(group);
|
||||||
|
IGMPStartRetransmitTimer(group);
|
||||||
|
if (TV_CMP(next, >, group->retransmit))
|
||||||
|
TV_CPY(next, group->retransmit);
|
||||||
|
}
|
||||||
|
else if (TV_SET(group->v1timer) && TV_CMP(group->v1timer, <, now)) {
|
||||||
|
TV_CLR(group->v1timer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (TV_CMP(next, >, group->timeout))
|
||||||
|
TV_CPY(next, group->timeout);
|
||||||
|
if (TV_SET(group->retransmit) && TV_CMP(next, >, group->retransmit))
|
||||||
|
TV_CPY(next, group->retransmit);
|
||||||
|
if (TV_SET(group->v1timer) && TV_CMP(next, >, group->v1timer))
|
||||||
|
TV_CPY(next, group->v1timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (del)
|
||||||
|
m_Groups.Del(del);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sleep = (next.tv_sec - now.tv_sec) * 1000;
|
||||||
|
sleep += (next.tv_usec - now.tv_usec) / 1000;
|
||||||
|
if (next.tv_usec < now.tv_usec)
|
||||||
|
sleep += 1000;
|
||||||
|
dsyslog("Sleeping %d ms", sleep);
|
||||||
|
m_CondWait.Wait(sleep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cComponentIGMP::IGMPMembership(in_addr_t Group, bool Add)
|
||||||
|
{
|
||||||
|
struct ip_mreqn mreq;
|
||||||
|
mreq.imr_multiaddr.s_addr = Group;
|
||||||
|
mreq.imr_address.s_addr = INADDR_ANY;
|
||||||
|
mreq.imr_ifindex = 0;
|
||||||
|
if (setsockopt(Socket(), IPPROTO_IP, Add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||||
|
{
|
||||||
|
esyslog("streamdev-server IGMP: unable to %s %s: %m", Add ? "join" : "leave", inet_ntoa(mreq.imr_multiaddr));
|
||||||
|
if (errno == ENOBUFS)
|
||||||
|
esyslog("consider increasing sys.net.ipv4.igmp_max_memberships");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPSendQuery(in_addr_t Group, int Timeout)
|
||||||
|
{
|
||||||
|
struct sockaddr_in dst;
|
||||||
|
struct igmp query;
|
||||||
|
|
||||||
|
dst.sin_family = AF_INET;
|
||||||
|
dst.sin_port = IPPROTO_IGMP;
|
||||||
|
dst.sin_addr.s_addr = Group;
|
||||||
|
query.igmp_type = IGMP_MEMBERSHIP_QUERY;
|
||||||
|
query.igmp_code = Timeout * 10;
|
||||||
|
query.igmp_cksum = 0;
|
||||||
|
query.igmp_group.s_addr = (Group == IGMP_ALL_HOSTS) ? 0 : Group;
|
||||||
|
query.igmp_cksum = inetChecksum((uint16_t *) &query, sizeof(query));
|
||||||
|
|
||||||
|
for (int i = 0; i < 5 && ::sendto(Socket(), &query, sizeof(query), 0, (sockaddr*)&dst, sizeof(dst)) == -1; i++) {
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||||
|
esyslog("streamdev-server IGMP: unable to query group %s: %m", inet_ntoa(dst.sin_addr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cCondWait::SleepMs(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Querier state actions
|
||||||
|
void cComponentIGMP::IGMPStartGeneralQueryTimer()
|
||||||
|
{
|
||||||
|
m_Querier = true;
|
||||||
|
if (m_StartupQueryCount) {
|
||||||
|
gettimeofday(&m_GeneralQueryTimer, NULL);
|
||||||
|
m_GeneralQueryTimer.tv_sec += IGMP_STARTUP_QUERY_INTERVAL;
|
||||||
|
m_StartupQueryCount--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gettimeofday(&m_GeneralQueryTimer, NULL);
|
||||||
|
m_GeneralQueryTimer.tv_sec += IGMP_QUERY_INTERVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPStartOtherQuerierPresentTimer()
|
||||||
|
{
|
||||||
|
m_Querier = false;
|
||||||
|
m_StartupQueryCount = 0;
|
||||||
|
gettimeofday(&m_GeneralQueryTimer, NULL);
|
||||||
|
m_GeneralQueryTimer.tv_sec += IGMP_OTHER_QUERIER_PRESENT_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPSendGeneralQuery()
|
||||||
|
{
|
||||||
|
IGMPSendQuery(IGMP_ALL_HOSTS, IGMP_QUERY_RESPONSE_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group state actions
|
||||||
|
void cComponentIGMP::IGMPStartTimer(cMulticastGroup* Group, in_addr_t Member)
|
||||||
|
{
|
||||||
|
gettimeofday(&Group->timeout, NULL);
|
||||||
|
Group->timeout.tv_sec += IGMP_GROUP_MEMBERSHIP_INTERVAL;
|
||||||
|
TV_CLR(Group->retransmit);
|
||||||
|
Group->reporter = Member;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPStartV1HostTimer(cMulticastGroup* Group)
|
||||||
|
{
|
||||||
|
gettimeofday(&Group->v1timer, NULL);
|
||||||
|
Group->v1timer.tv_sec += IGMP_GROUP_MEMBERSHIP_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPStartTimerAfterLeave(cMulticastGroup* Group, unsigned int MaxResponseTimeTs)
|
||||||
|
{
|
||||||
|
//Group->Update(time(NULL) + MaxResponseTime * IGMP_LAST_MEMBER_QUERY_COUNT / 10);
|
||||||
|
MaxResponseTimeTs *= IGMP_LAST_MEMBER_QUERY_COUNT;
|
||||||
|
gettimeofday(&Group->timeout, NULL);
|
||||||
|
TV_ADD(Group->timeout, MaxResponseTimeTs);
|
||||||
|
TV_CLR(Group->retransmit);
|
||||||
|
Group->reporter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPStartRetransmitTimer(cMulticastGroup* Group)
|
||||||
|
{
|
||||||
|
gettimeofday(&Group->retransmit, NULL);
|
||||||
|
TV_ADD(Group->retransmit, IGMP_LAST_MEMBER_QUERY_INTERVAL_TS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPClearRetransmitTimer(cMulticastGroup* Group)
|
||||||
|
{
|
||||||
|
TV_CLR(Group->retransmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPSendGroupQuery(cMulticastGroup* Group)
|
||||||
|
{
|
||||||
|
IGMPSendQuery(Group->group, IGMP_LAST_MEMBER_QUERY_INTERVAL_TS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group)
|
||||||
|
{
|
||||||
|
in_addr_t g = ntohl(Group->group);
|
||||||
|
if (g > MULTICAST_PRIV_MIN && g <= MULTICAST_PRIV_MAX) {
|
||||||
|
cChannel *channel = Channels.GetByNumber(g - MULTICAST_PRIV_MIN);
|
||||||
|
Group->connection = (cConnectionIGMP*) NewClient();
|
||||||
|
if (!Group->connection->Start(channel, Group->group)) {
|
||||||
|
DELETENULL(Group->connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cComponentIGMP::IGMPStopMulticast(cMulticastGroup* Group)
|
||||||
|
{
|
||||||
|
if (Group->connection)
|
||||||
|
Group->connection->Stop();
|
||||||
|
}
|
62
server/componentIGMP.h
Normal file
62
server/componentIGMP.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* $Id: componentIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VDR_STREAMDEV_IGMPSERVER_H
|
||||||
|
#define VDR_STREAMDEV_IGMPSERVER_H
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <vdr/thread.h>
|
||||||
|
#include "server/component.h"
|
||||||
|
|
||||||
|
class cConnectionIGMP;
|
||||||
|
class cMulticastGroup;
|
||||||
|
|
||||||
|
class cComponentIGMP: public cServerComponent, public cThread {
|
||||||
|
private:
|
||||||
|
char m_ReadBuffer[2048];
|
||||||
|
cList<cMulticastGroup> m_Groups;
|
||||||
|
in_addr_t m_BindIp;
|
||||||
|
int m_MaxChannelNumber;
|
||||||
|
struct timeval m_GeneralQueryTimer;
|
||||||
|
int m_StartupQueryCount;
|
||||||
|
bool m_Querier;
|
||||||
|
cCondWait m_CondWait;
|
||||||
|
|
||||||
|
cMulticastGroup* FindGroup(in_addr_t Group) const;
|
||||||
|
|
||||||
|
/* Add or remove local host to multicast group */
|
||||||
|
bool IGMPMembership(in_addr_t Group, bool Add = true);
|
||||||
|
void IGMPSendQuery(in_addr_t Group, int Timeout);
|
||||||
|
|
||||||
|
cServerConnection* ProcessMessage(struct igmp *Igmp, in_addr_t Group, in_addr_t Sender);
|
||||||
|
|
||||||
|
void IGMPStartGeneralQueryTimer();
|
||||||
|
void IGMPStartOtherQuerierPresentTimer();
|
||||||
|
void IGMPSendGeneralQuery();
|
||||||
|
|
||||||
|
void IGMPStartTimer(cMulticastGroup* Group, in_addr_t Member);
|
||||||
|
void IGMPStartV1HostTimer(cMulticastGroup* Group);
|
||||||
|
void IGMPStartTimerAfterLeave(cMulticastGroup* Group, unsigned int MaxResponseTime);
|
||||||
|
void IGMPStartRetransmitTimer(cMulticastGroup* Group);
|
||||||
|
void IGMPClearRetransmitTimer(cMulticastGroup* Group);
|
||||||
|
void IGMPSendGroupQuery(cMulticastGroup* Group);
|
||||||
|
void IGMPStartMulticast(cMulticastGroup* Group);
|
||||||
|
void IGMPStopMulticast(cMulticastGroup* Group);
|
||||||
|
|
||||||
|
virtual void Action();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual cServerConnection *NewClient(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool Initialize(void);
|
||||||
|
virtual void Destruct(void);
|
||||||
|
virtual cServerConnection* Accept(void);
|
||||||
|
|
||||||
|
cComponentIGMP(void);
|
||||||
|
~cComponentIGMP(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VDR_STREAMDEV_IGMPSERVER_H
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: connection.c,v 1.10 2007/05/07 12:25:11 schmirl Exp $
|
* $Id: connection.c,v 1.12 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "server/connection.h"
|
#include "server/connection.h"
|
||||||
@ -12,7 +12,8 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
cServerConnection::cServerConnection(const char *Protocol):
|
cServerConnection::cServerConnection(const char *Protocol, int Type):
|
||||||
|
cTBSocket(Type),
|
||||||
m_Protocol(Protocol),
|
m_Protocol(Protocol),
|
||||||
m_DeferClose(false),
|
m_DeferClose(false),
|
||||||
m_Pending(false),
|
m_Pending(false),
|
||||||
@ -139,11 +140,7 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
|
|||||||
Dprintf(" * GetDevice(const cChannel*, int)\n");
|
Dprintf(" * GetDevice(const cChannel*, int)\n");
|
||||||
Dprintf(" * -------------------------------\n");
|
Dprintf(" * -------------------------------\n");
|
||||||
|
|
||||||
#if VDRVERSNUM < 10500
|
|
||||||
device = cDevice::GetDevice(Channel, Priority);
|
|
||||||
#else
|
|
||||||
device = cDevice::GetDevice(Channel, Priority, false);
|
device = cDevice::GetDevice(Channel, Priority, false);
|
||||||
#endif
|
|
||||||
|
|
||||||
Dprintf(" * Found following device: %p (%d)\n", device,
|
Dprintf(" * Found following device: %p (%d)\n", device,
|
||||||
device ? device->CardIndex() + 1 : 0);
|
device ? device->CardIndex() + 1 : 0);
|
||||||
@ -161,11 +158,7 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
|
|||||||
const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
|
const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||||
isyslog("streamdev-server: Detaching current receiver");
|
isyslog("streamdev-server: Detaching current receiver");
|
||||||
Detach();
|
Detach();
|
||||||
#if VDRVERSNUM < 10500
|
|
||||||
device = cDevice::GetDevice(Channel, Priority);
|
|
||||||
#else
|
|
||||||
device = cDevice::GetDevice(Channel, Priority, false);
|
device = cDevice::GetDevice(Channel, Priority, false);
|
||||||
#endif
|
|
||||||
Attach();
|
Attach();
|
||||||
Dprintf(" * Found following device: %p (%d)\n", device,
|
Dprintf(" * Found following device: %p (%d)\n", device,
|
||||||
device ? device->CardIndex() + 1 : 0);
|
device ? device->CardIndex() + 1 : 0);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: connection.h,v 1.5 2007/04/16 11:01:02 schmirl Exp $
|
* $Id: connection.h,v 1.7 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_SERVER_CONNECTION_H
|
#ifndef VDR_STREAMDEV_SERVER_CONNECTION_H
|
||||||
@ -44,9 +44,12 @@ protected:
|
|||||||
public:
|
public:
|
||||||
/* If you derive, specify a short string such as HTTP for Protocol, which
|
/* If you derive, specify a short string such as HTTP for Protocol, which
|
||||||
will be displayed in error messages */
|
will be displayed in error messages */
|
||||||
cServerConnection(const char *Protocol);
|
cServerConnection(const char *Protocol, int Type = SOCK_STREAM);
|
||||||
virtual ~cServerConnection();
|
virtual ~cServerConnection();
|
||||||
|
|
||||||
|
/* If true, any client IP will be accepted */
|
||||||
|
virtual bool CanAuthenticate(void) { return false; }
|
||||||
|
|
||||||
/* Gets called if the client has been accepted by the core */
|
/* Gets called if the client has been accepted by the core */
|
||||||
virtual void Welcome(void) { }
|
virtual void Welcome(void) { }
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: connectionHTTP.c,v 1.13 2008/03/28 15:11:40 schmirl Exp $
|
* $Id: connectionHTTP.c,v 1.16 2009/02/13 07:02:19 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "server/connectionHTTP.h"
|
#include "server/connectionHTTP.h"
|
||||||
#include "server/menuHTTP.h"
|
#include "server/menuHTTP.h"
|
||||||
|
#include "server/server.h"
|
||||||
#include "server/setup.h"
|
#include "server/setup.h"
|
||||||
|
|
||||||
cConnectionHTTP::cConnectionHTTP(void):
|
cConnectionHTTP::cConnectionHTTP(void):
|
||||||
@ -26,6 +27,11 @@ cConnectionHTTP::~cConnectionHTTP()
|
|||||||
delete m_LiveStreamer;
|
delete m_LiveStreamer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cConnectionHTTP::CanAuthenticate(void)
|
||||||
|
{
|
||||||
|
return opt_auth != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool cConnectionHTTP::Command(char *Cmd)
|
bool cConnectionHTTP::Command(char *Cmd)
|
||||||
{
|
{
|
||||||
Dprintf("command %s\n", Cmd);
|
Dprintf("command %s\n", Cmd);
|
||||||
@ -44,10 +50,22 @@ bool cConnectionHTTP::Command(char *Cmd)
|
|||||||
if (strncasecmp(Cmd, "Host:", 5) == 0) {
|
if (strncasecmp(Cmd, "Host:", 5) == 0) {
|
||||||
Dprintf("Host-Header\n");
|
Dprintf("Host-Header\n");
|
||||||
m_Host = (std::string) skipspace(Cmd + 5);
|
m_Host = (std::string) skipspace(Cmd + 5);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Dprintf("header\n");
|
Dprintf("header\n");
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
// skip additional blank lines
|
||||||
|
if (*Cmd == '\0')
|
||||||
|
return true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false; // ??? shouldn't happen
|
return false; // ??? shouldn't happen
|
||||||
@ -56,6 +74,16 @@ bool cConnectionHTTP::Command(char *Cmd)
|
|||||||
bool cConnectionHTTP::ProcessRequest(void)
|
bool cConnectionHTTP::ProcessRequest(void)
|
||||||
{
|
{
|
||||||
Dprintf("process\n");
|
Dprintf("process\n");
|
||||||
|
if (!StreamdevHosts.Acceptable(RemoteIpAddr()))
|
||||||
|
{
|
||||||
|
if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) {
|
||||||
|
isyslog("streamdev-server: HTTP authorization required");
|
||||||
|
DeferClose();
|
||||||
|
return Respond("HTTP/1.0 401 Authorization Required")
|
||||||
|
&& Respond("WWW-authenticate: basic Realm=\"Streamdev-Server\")")
|
||||||
|
&& Respond("");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) {
|
if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) {
|
||||||
switch (m_Job) {
|
switch (m_Job) {
|
||||||
case hjListing:
|
case hjListing:
|
||||||
@ -183,8 +211,10 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts)
|
|||||||
const char* pType = type.c_str();
|
const char* pType = type.c_str();
|
||||||
if (strcasecmp(pType, "PS") == 0) {
|
if (strcasecmp(pType, "PS") == 0) {
|
||||||
m_StreamType = stPS;
|
m_StreamType = stPS;
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
} else if (strcasecmp(pType, "PES") == 0) {
|
} else if (strcasecmp(pType, "PES") == 0) {
|
||||||
m_StreamType = stPES;
|
m_StreamType = stPES;
|
||||||
|
#endif
|
||||||
} else if (strcasecmp(pType, "TS") == 0) {
|
} else if (strcasecmp(pType, "TS") == 0) {
|
||||||
m_StreamType = stTS;
|
m_StreamType = stTS;
|
||||||
} else if (strcasecmp(pType, "ES") == 0) {
|
} else if (strcasecmp(pType, "ES") == 0) {
|
||||||
@ -236,7 +266,9 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts)
|
|||||||
{
|
{
|
||||||
case stTS: base += "TS/"; break;
|
case stTS: base += "TS/"; break;
|
||||||
case stPS: base += "PS/"; break;
|
case stPS: base += "PS/"; break;
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
case stPES: base += "PES/"; break;
|
case stPES: base += "PES/"; break;
|
||||||
|
#endif
|
||||||
case stES: base += "ES/"; break;
|
case stES: base += "ES/"; break;
|
||||||
case stExtern: base += "Extern/"; break;
|
case stExtern: base += "Extern/"; break;
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: connectionHTTP.h,v 1.5 2008/03/28 15:11:40 schmirl Exp $
|
* $Id: connectionHTTP.h,v 1.6 2008/10/14 11:05:48 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
|
#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
|
||||||
@ -30,6 +30,7 @@ private:
|
|||||||
|
|
||||||
std::string m_Request;
|
std::string m_Request;
|
||||||
std::string m_Host;
|
std::string m_Host;
|
||||||
|
std::string m_Authorization;
|
||||||
//std::map<std::string,std::string> m_Headers; TODO: later?
|
//std::map<std::string,std::string> m_Headers; TODO: later?
|
||||||
eHTTPStatus m_Status;
|
eHTTPStatus m_Status;
|
||||||
eHTTPJob m_Job;
|
eHTTPJob m_Job;
|
||||||
@ -52,6 +53,8 @@ public:
|
|||||||
virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
|
virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
|
||||||
virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
|
virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
|
||||||
|
|
||||||
|
virtual bool CanAuthenticate(void);
|
||||||
|
|
||||||
virtual bool Command(char *Cmd);
|
virtual bool Command(char *Cmd);
|
||||||
bool CmdGET(const std::string &Opts);
|
bool CmdGET(const std::string &Opts);
|
||||||
|
|
||||||
|
64
server/connectionIGMP.c
Normal file
64
server/connectionIGMP.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* $Id: connectionIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "server/connectionIGMP.h"
|
||||||
|
#include "server/server.h"
|
||||||
|
#include "server/setup.h"
|
||||||
|
#include <vdr/channels.h>
|
||||||
|
|
||||||
|
cConnectionIGMP::cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType) :
|
||||||
|
cServerConnection(Name, SOCK_DGRAM),
|
||||||
|
m_LiveStreamer(NULL),
|
||||||
|
m_ClientPort(ClientPort),
|
||||||
|
m_StreamType(StreamType)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cConnectionIGMP::~cConnectionIGMP()
|
||||||
|
{
|
||||||
|
delete m_LiveStreamer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst)
|
||||||
|
{
|
||||||
|
if (Channel != NULL) {
|
||||||
|
cDevice *device = GetDevice(Channel, 0);
|
||||||
|
if (device != NULL) {
|
||||||
|
device->SwitchChannel(Channel, false);
|
||||||
|
struct in_addr ip;
|
||||||
|
ip.s_addr = Dst;
|
||||||
|
if (Connect(inet_ntoa(ip), m_ClientPort)) {
|
||||||
|
m_LiveStreamer = new cStreamdevLiveStreamer(0);
|
||||||
|
if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) {
|
||||||
|
m_LiveStreamer->SetDevice(device);
|
||||||
|
if (!SetDSCP())
|
||||||
|
LOG_ERROR_STR("unable to set DSCP sockopt");
|
||||||
|
Dprintf("streamer start\n");
|
||||||
|
m_LiveStreamer->Start(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("streamdev-server IGMP: SetDevice failed");
|
||||||
|
DELETENULL(m_LiveStreamer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("streamdev-server IGMP: Connect failed: %m");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("streamdev-server IGMP: GetDevice failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("streamdev-server IGMP: Channel not found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cConnectionIGMP::Stop()
|
||||||
|
{
|
||||||
|
if (m_LiveStreamer) {
|
||||||
|
m_LiveStreamer->Stop();
|
||||||
|
DELETENULL(m_LiveStreamer);
|
||||||
|
}
|
||||||
|
}
|
45
server/connectionIGMP.h
Normal file
45
server/connectionIGMP.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* $Id: connectionIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H
|
||||||
|
#define VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
#include "server/livestreamer.h"
|
||||||
|
|
||||||
|
#include <tools/select.h>
|
||||||
|
|
||||||
|
#define MULTICAST_PRIV_MIN ((uint32_t) 0xefff0000)
|
||||||
|
#define MULTICAST_PRIV_MAX ((uint32_t) 0xeffffeff)
|
||||||
|
|
||||||
|
class cStreamdevLiveStreamer;
|
||||||
|
|
||||||
|
class cConnectionIGMP: public cServerConnection {
|
||||||
|
private:
|
||||||
|
cStreamdevLiveStreamer *m_LiveStreamer;
|
||||||
|
int m_ClientPort;
|
||||||
|
eStreamType m_StreamType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType);
|
||||||
|
virtual ~cConnectionIGMP();
|
||||||
|
|
||||||
|
bool Start(cChannel *Channel, in_addr_t Dst);
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
/* Not used here */
|
||||||
|
virtual bool Command(char *Cmd) { return false; }
|
||||||
|
|
||||||
|
virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
|
||||||
|
virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
|
||||||
|
|
||||||
|
virtual bool Abort(void) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool cConnectionIGMP::Abort(void) const
|
||||||
|
{
|
||||||
|
return !m_LiveStreamer || m_LiveStreamer->Abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: connectionVTP.c,v 1.17 2008/03/13 16:01:18 schmirl Exp $
|
* $Id: connectionVTP.c,v 1.19 2009/01/16 11:35:44 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "server/connectionVTP.h"
|
#include "server/connectionVTP.h"
|
||||||
@ -595,17 +595,18 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
|
|||||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
if (strcasecmp(Opts, "PES") == 0) {
|
if (strcasecmp(Opts, "PES") == 0) {
|
||||||
m_StreamType = stPES;
|
m_StreamType = stPES;
|
||||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (strcasecmp(Opts, "EXTERN") == 0) {
|
if (strcasecmp(Opts, "EXTERN") == 0) {
|
||||||
m_StreamType = stExtern;
|
m_StreamType = stExtern;
|
||||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
//
|
//
|
||||||
// Deliver section filters data in separate, channel-independent data stream
|
// Deliver section filters data in separate, channel-independent data stream
|
||||||
//
|
//
|
||||||
@ -613,7 +614,6 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
|
|||||||
m_FiltersSupport = true;
|
m_FiltersSupport = true;
|
||||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return Respond(561, "Capability \"%s\" not known", Opts);
|
return Respond(561, "Capability \"%s\" not known", Opts);
|
||||||
}
|
}
|
||||||
@ -648,13 +648,8 @@ bool cConnectionVTP::CmdPORT(char *Opts)
|
|||||||
if (ep == Opts || !isspace(*ep))
|
if (ep == Opts || !isspace(*ep))
|
||||||
return Respond(500, "Use: PORT Id Destination");
|
return Respond(500, "Use: PORT Id Destination");
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
if (id != siLive && id != siLiveFilter)
|
if (id != siLive && id != siLiveFilter)
|
||||||
return Respond(501, "Wrong connection id %d", id);
|
return Respond(501, "Wrong connection id %d", id);
|
||||||
#else
|
|
||||||
if (id != siLive)
|
|
||||||
return Respond(501, "Wrong connection id %d", id);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Opts = skipspace(ep);
|
Opts = skipspace(ep);
|
||||||
n = 0;
|
n = 0;
|
||||||
@ -681,7 +676,6 @@ bool cConnectionVTP::CmdPORT(char *Opts)
|
|||||||
|
|
||||||
isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport);
|
isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport);
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
if (id == siLiveFilter) {
|
if (id == siLiveFilter) {
|
||||||
m_FiltersSupport = true;
|
m_FiltersSupport = true;
|
||||||
if(m_FilterStreamer)
|
if(m_FilterStreamer)
|
||||||
@ -703,7 +697,6 @@ bool cConnectionVTP::CmdPORT(char *Opts)
|
|||||||
|
|
||||||
return Respond(220, "Port command ok, data connection opened");
|
return Respond(220, "Port command ok, data connection opened");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if(m_LiveSocket && m_LiveStreamer)
|
if(m_LiveSocket && m_LiveStreamer)
|
||||||
m_LiveStreamer->Stop();
|
m_LiveStreamer->Stop();
|
||||||
@ -746,14 +739,12 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
|
|||||||
if(m_LiveSocket)
|
if(m_LiveSocket)
|
||||||
m_LiveStreamer->Start(m_LiveSocket);
|
m_LiveStreamer->Start(m_LiveSocket);
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
if(m_FiltersSupport) {
|
if(m_FiltersSupport) {
|
||||||
if(!m_FilterStreamer)
|
if(!m_FilterStreamer)
|
||||||
m_FilterStreamer = new cStreamdevFilterStreamer;
|
m_FilterStreamer = new cStreamdevFilterStreamer;
|
||||||
m_FilterStreamer->SetDevice(dev);
|
m_FilterStreamer->SetDevice(dev);
|
||||||
//m_FilterStreamer->SetChannel(chan);
|
//m_FilterStreamer->SetChannel(chan);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return Respond(220, "Channel tuned");
|
return Respond(220, "Channel tuned");
|
||||||
}
|
}
|
||||||
@ -788,7 +779,6 @@ bool cConnectionVTP::CmdDELP(char *Opts)
|
|||||||
|
|
||||||
bool cConnectionVTP::CmdADDF(char *Opts)
|
bool cConnectionVTP::CmdADDF(char *Opts)
|
||||||
{
|
{
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
int pid, tid, mask;
|
int pid, tid, mask;
|
||||||
char *ep;
|
char *ep;
|
||||||
|
|
||||||
@ -810,14 +800,10 @@ bool cConnectionVTP::CmdADDF(char *Opts)
|
|||||||
return m_FilterStreamer->SetFilter(pid, tid, mask, true)
|
return m_FilterStreamer->SetFilter(pid, tid, mask, true)
|
||||||
? Respond(220, "Filter %d transferring", pid)
|
? Respond(220, "Filter %d transferring", pid)
|
||||||
: Respond(560, "Filter %d not available", pid);
|
: Respond(560, "Filter %d not available", pid);
|
||||||
#else
|
|
||||||
return Respond(500, "ADDF known but unimplemented with VDR < 1.3.0");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cConnectionVTP::CmdDELF(char *Opts)
|
bool cConnectionVTP::CmdDELF(char *Opts)
|
||||||
{
|
{
|
||||||
#if VDRVERSNUM >= 10307
|
|
||||||
int pid, tid, mask;
|
int pid, tid, mask;
|
||||||
char *ep;
|
char *ep;
|
||||||
|
|
||||||
@ -838,9 +824,6 @@ bool cConnectionVTP::CmdDELF(char *Opts)
|
|||||||
|
|
||||||
m_FilterStreamer->SetFilter(pid, tid, mask, false);
|
m_FilterStreamer->SetFilter(pid, tid, mask, false);
|
||||||
return Respond(220, "Filter %d stopped", pid);
|
return Respond(220, "Filter %d stopped", pid);
|
||||||
#else
|
|
||||||
return Respond(500, "DELF known but unimplemented with VDR < 1.3.0");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cConnectionVTP::CmdABRT(char *Opts)
|
bool cConnectionVTP::CmdABRT(char *Opts)
|
||||||
@ -857,12 +840,10 @@ bool cConnectionVTP::CmdABRT(char *Opts)
|
|||||||
DELETENULL(m_LiveStreamer);
|
DELETENULL(m_LiveStreamer);
|
||||||
DELETENULL(m_LiveSocket);
|
DELETENULL(m_LiveSocket);
|
||||||
break;
|
break;
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
case siLiveFilter:
|
case siLiveFilter:
|
||||||
DELETENULL(m_FilterStreamer);
|
DELETENULL(m_FilterStreamer);
|
||||||
DELETENULL(m_FilterSocket);
|
DELETENULL(m_FilterSocket);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
return Respond(501, "Wrong connection id %d", id);
|
return Respond(501, "Wrong connection id %d", id);
|
||||||
break;
|
break;
|
||||||
|
@ -12,9 +12,9 @@ class cLSTTHandler;
|
|||||||
|
|
||||||
class cConnectionVTP: public cServerConnection {
|
class cConnectionVTP: public cServerConnection {
|
||||||
friend class cLSTEHandler;
|
friend class cLSTEHandler;
|
||||||
// if your compiler doesn't understand the following statement
|
#if !defined __GNUC__ || __GNUC__ >= 3
|
||||||
// (e.g. gcc 2.x), simply remove it and try again ;-)
|
|
||||||
using cServerConnection::Respond;
|
using cServerConnection::Respond;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cTBSocket *m_LiveSocket;
|
cTBSocket *m_LiveSocket;
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: livefilter.c,v 1.4 2007/04/24 11:06:12 schmirl Exp $
|
* $Id: livefilter.c,v 1.7 2009/02/13 13:02:40 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "server/livefilter.h"
|
#include "server/livefilter.h"
|
||||||
#include "server/streamer.h"
|
#include "server/streamer.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#ifndef TS_SIZE
|
|
||||||
# define TS_SIZE 188
|
|
||||||
#endif
|
|
||||||
#ifndef TS_SYNC_BYTE
|
#ifndef TS_SYNC_BYTE
|
||||||
# define TS_SYNC_BYTE 0x47
|
# define TS_SYNC_BYTE 0x47
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
|
|
||||||
cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevStreamer *Streamer) {
|
cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevStreamer *Streamer) {
|
||||||
m_Streamer = Streamer;
|
m_Streamer = Streamer;
|
||||||
}
|
}
|
||||||
@ -31,6 +26,7 @@ void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data,
|
|||||||
buffer[1] = ((Pid >> 8) & 0x3f) | (pos==0 ? 0x40 : 0); /* bit 6: payload unit start indicator (PUSI) */
|
buffer[1] = ((Pid >> 8) & 0x3f) | (pos==0 ? 0x40 : 0); /* bit 6: payload unit start indicator (PUSI) */
|
||||||
buffer[2] = Pid & 0xff;
|
buffer[2] = Pid & 0xff;
|
||||||
buffer[3] = Tid;
|
buffer[3] = Tid;
|
||||||
|
// this makes it a proprietary stream
|
||||||
buffer[4] = (uchar)chunk;
|
buffer[4] = (uchar)chunk;
|
||||||
memcpy(buffer + 5, Data + pos, chunk);
|
memcpy(buffer + 5, Data + pos, chunk);
|
||||||
length -= chunk;
|
length -= chunk;
|
||||||
@ -41,5 +37,3 @@ void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data,
|
|||||||
m_Streamer->ReportOverflow(TS_SIZE - p);
|
m_Streamer->ReportOverflow(TS_SIZE - p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // VDRVERSNUM >= 10300
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: livefilter.h,v 1.4 2007/04/24 11:29:29 schmirl Exp $
|
* $Id: livefilter.h,v 1.5 2008/04/07 14:27:31 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMEV_LIVEFILTER_H
|
#ifndef VDR_STREAMEV_LIVEFILTER_H
|
||||||
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
#include <vdr/config.h>
|
#include <vdr/config.h>
|
||||||
|
|
||||||
# if VDRVERSNUM >= 10300
|
|
||||||
|
|
||||||
#include <vdr/filter.h>
|
#include <vdr/filter.h>
|
||||||
|
|
||||||
class cStreamdevStreamer;
|
class cStreamdevStreamer;
|
||||||
@ -31,5 +29,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
# endif // VDRVERSNUM >= 10300
|
|
||||||
#endif // VDR_STREAMEV_LIVEFILTER_H
|
#endif // VDR_STREAMEV_LIVEFILTER_H
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
#include <libsi/section.h>
|
#include <libsi/section.h>
|
||||||
#include <libsi/descriptor.h>
|
#include <libsi/descriptor.h>
|
||||||
|
|
||||||
|
#include "remux/ts2ps.h"
|
||||||
|
#include "remux/ts2es.h"
|
||||||
|
#include "remux/extern.h"
|
||||||
|
|
||||||
#include <vdr/ringbuffer.h>
|
#include <vdr/ringbuffer.h>
|
||||||
|
|
||||||
#include "server/livestreamer.h"
|
#include "server/livestreamer.h"
|
||||||
#include "server/livefilter.h"
|
#include "server/livefilter.h"
|
||||||
#include "remux/ts2ps.h"
|
|
||||||
#include "remux/ts2es.h"
|
|
||||||
#include "remux/extern.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define TSPATREPACKER
|
#define TSPATREPACKER
|
||||||
@ -27,23 +28,13 @@ protected:
|
|||||||
virtual void Receive(uchar *Data, int Length);
|
virtual void Receive(uchar *Data, int Length);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#if VDRVERSNUM < 10500
|
|
||||||
cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, int Priority, const int *Pids);
|
|
||||||
#else
|
|
||||||
cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
|
cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
|
||||||
#endif
|
|
||||||
virtual ~cStreamdevLiveReceiver();
|
virtual ~cStreamdevLiveReceiver();
|
||||||
};
|
};
|
||||||
|
|
||||||
#if VDRVERSNUM < 10500
|
|
||||||
cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca,
|
|
||||||
int Priority, const int *Pids):
|
|
||||||
cReceiver(Ca, Priority, 0, Pids),
|
|
||||||
#else
|
|
||||||
cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID,
|
cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID,
|
||||||
int Priority, const int *Pids):
|
int Priority, const int *Pids):
|
||||||
cReceiver(ChannelID, Priority, 0, Pids),
|
cReceiver(ChannelID, Priority, 0, Pids),
|
||||||
#endif
|
|
||||||
m_Streamer(Streamer)
|
m_Streamer(Streamer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -86,7 +77,7 @@ public:
|
|||||||
|
|
||||||
cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel)
|
cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel)
|
||||||
{
|
{
|
||||||
Dprintf("cStreamdevPatFilter(\"%s\")", Channel->Name());
|
Dprintf("cStreamdevPatFilter(\"%s\")\n", Channel->Name());
|
||||||
assert(Streamer);
|
assert(Streamer);
|
||||||
m_Channel = Channel;
|
m_Channel = Channel;
|
||||||
m_Streamer = Streamer;
|
m_Streamer = Streamer;
|
||||||
@ -145,7 +136,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
|
|||||||
case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4)
|
case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4)
|
||||||
case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
|
case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
|
||||||
case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)
|
case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)
|
||||||
Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)",
|
Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)\n",
|
||||||
stream.getPid(), psStreamTypes[stream.getStreamType()]);
|
stream.getPid(), psStreamTypes[stream.getStreamType()]);
|
||||||
return stream.getPid();
|
return stream.getPid();
|
||||||
case 0x05: // ISO/IEC 13818-1 private sections
|
case 0x05: // ISO/IEC 13818-1 private sections
|
||||||
@ -153,19 +144,19 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
|
|||||||
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
|
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
|
||||||
switch (d->getDescriptorTag()) {
|
switch (d->getDescriptorTag()) {
|
||||||
case SI::AC3DescriptorTag:
|
case SI::AC3DescriptorTag:
|
||||||
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s",
|
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
|
||||||
stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3");
|
stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3");
|
||||||
return stream.getPid();
|
return stream.getPid();
|
||||||
case SI::TeletextDescriptorTag:
|
case SI::TeletextDescriptorTag:
|
||||||
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s",
|
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
|
||||||
stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext");
|
stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext");
|
||||||
return stream.getPid();
|
return stream.getPid();
|
||||||
case SI::SubtitlingDescriptorTag:
|
case SI::SubtitlingDescriptorTag:
|
||||||
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s",
|
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
|
||||||
stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB");
|
stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB");
|
||||||
return stream.getPid();
|
return stream.getPid();
|
||||||
default:
|
default:
|
||||||
Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s",
|
Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n",
|
||||||
stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN");
|
stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -210,7 +201,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
|
|||||||
return stream.getPid();
|
return stream.getPid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s",
|
Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n",
|
||||||
stream.getPid(), psStreamTypes[stream.getStreamType()<0x1c?stream.getStreamType():0], "UNKNOWN");
|
stream.getPid(), psStreamTypes[stream.getStreamType()<0x1c?stream.getStreamType():0], "UNKNOWN");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -220,7 +211,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
|
|||||||
void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
||||||
{
|
{
|
||||||
if (Pid == 0x00) {
|
if (Pid == 0x00) {
|
||||||
if (Tid == 0x00 && !pmtPid) {
|
if (Tid == 0x00) {
|
||||||
SI::PAT pat(Data, false);
|
SI::PAT pat(Data, false);
|
||||||
if (!pat.CheckCRCAndParse())
|
if (!pat.CheckCRCAndParse())
|
||||||
return;
|
return;
|
||||||
@ -229,8 +220,9 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
|||||||
if (!assoc.isNITPid()) {
|
if (!assoc.isNITPid()) {
|
||||||
const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
|
const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
|
||||||
if (Channel && (Channel == m_Channel)) {
|
if (Channel && (Channel == m_Channel)) {
|
||||||
|
int prevPmtPid = pmtPid;
|
||||||
if (0 != (pmtPid = assoc.getPid())) {
|
if (0 != (pmtPid = assoc.getPid())) {
|
||||||
Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d", Channel->Name(), pmtPid);
|
Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d\n", Channel->Name(), pmtPid);
|
||||||
pmtSid = assoc.getServiceId();
|
pmtSid = assoc.getServiceId();
|
||||||
if (Length < TS_SIZE-5) {
|
if (Length < TS_SIZE-5) {
|
||||||
// repack PAT to TS frame and send to client
|
// repack PAT to TS frame and send to client
|
||||||
@ -242,25 +234,27 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
|||||||
int ts_id;
|
int ts_id;
|
||||||
unsigned int crc, i, len;
|
unsigned int crc, i, len;
|
||||||
uint8_t *tmp, tspat_buf[TS_SIZE];
|
uint8_t *tmp, tspat_buf[TS_SIZE];
|
||||||
|
static uint8_t ccounter = 0;
|
||||||
|
ccounter = (ccounter + 1) % 16;
|
||||||
memset(tspat_buf, 0xff, TS_SIZE);
|
memset(tspat_buf, 0xff, TS_SIZE);
|
||||||
memset(tspat_buf, 0x0, 4 + 12 + 5); // TS_HDR_LEN + PAT_TABLE_LEN + 5
|
|
||||||
ts_id = Channel->Tid(); // Get transport stream id of the channel
|
ts_id = Channel->Tid(); // Get transport stream id of the channel
|
||||||
tspat_buf[0] = TS_SYNC_BYTE; // Transport packet header sunchronization byte (1000011 = 0x47h)
|
tspat_buf[0] = TS_SYNC_BYTE; // Transport packet header sunchronization byte (1000011 = 0x47h)
|
||||||
tspat_buf[1] = 0x40; // Set payload unit start indicator bit
|
tspat_buf[1] = 0x40; // Set payload unit start indicator bit
|
||||||
tspat_buf[2] = 0x0; // PID
|
tspat_buf[2] = 0x0; // PID
|
||||||
tspat_buf[3] = 0x10; // Set payload flag to indicate precence of payload data
|
tspat_buf[3] = 0x10 | ccounter; // Set payload flag, Continuity counter
|
||||||
tspat_buf[4] = 0x0; // PSI
|
tspat_buf[4] = 0x0; // SI pointer field
|
||||||
tspat_buf[5] = 0x0; // PAT table id
|
tspat_buf[5] = 0x0; // PAT table id
|
||||||
tspat_buf[6] = 0xb0; // Section syntax indicator bit and reserved bits set
|
tspat_buf[6] = 0xb0; // Section syntax indicator bit and reserved bits set
|
||||||
tspat_buf[7] = 12 + 1; // Section length (12 bit): PAT_TABLE_LEN + 1
|
tspat_buf[7] = 12 + 1; // Section length (12 bit): PAT_TABLE_LEN + 1
|
||||||
tspat_buf[8] = (ts_id >> 8) & 0xff; // Transport stream ID (bits 8-15)
|
tspat_buf[8] = (ts_id >> 8); // Transport stream ID (bits 8-15)
|
||||||
tspat_buf[9] = (ts_id & 0xff); // Transport stream ID (bits 0-7)
|
tspat_buf[9] = (ts_id & 0xff); // Transport stream ID (bits 0-7)
|
||||||
tspat_buf[10] = 0x01; // Version number 0, Current next indicator bit set
|
tspat_buf[10] = 0xc0 | ((pat.getVersionNumber() << 1) & 0x3e) |
|
||||||
|
pat.getCurrentNextIndicator();// Version number, Current next indicator
|
||||||
tspat_buf[11] = 0x0; // Section number
|
tspat_buf[11] = 0x0; // Section number
|
||||||
tspat_buf[12] = 0x0; // Last section number
|
tspat_buf[12] = 0x0; // Last section number
|
||||||
tspat_buf[13] = (pmtSid >> 8) & 0xff; // Program number (bits 8-15)
|
tspat_buf[13] = (pmtSid >> 8); // Program number (bits 8-15)
|
||||||
tspat_buf[14] = (pmtSid & 0xff); // Program number (bits 0-7)
|
tspat_buf[14] = (pmtSid & 0xff); // Program number (bits 0-7)
|
||||||
tspat_buf[15] = (pmtPid >> 8) & 0xff; // Network ID (bits 8-12)
|
tspat_buf[15] = 0xe0 | (pmtPid >> 8); // Network ID (bits 8-12)
|
||||||
tspat_buf[16] = (pmtPid & 0xff); // Network ID (bits 0-7)
|
tspat_buf[16] = (pmtPid & 0xff); // Network ID (bits 0-7)
|
||||||
crc = 0xffffffff;
|
crc = 0xffffffff;
|
||||||
len = 12; // PAT_TABLE_LEN
|
len = 12; // PAT_TABLE_LEN
|
||||||
@ -278,9 +272,11 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
|||||||
#endif
|
#endif
|
||||||
} else
|
} else
|
||||||
isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length);
|
isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length);
|
||||||
m_Streamer->SetPids(pmtPid);
|
if (pmtPid != prevPmtPid) {
|
||||||
Add(pmtPid, 0x02);
|
m_Streamer->SetPids(pmtPid);
|
||||||
pmtVersion = -1;
|
Add(pmtPid, 0x02);
|
||||||
|
pmtVersion = -1;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,7 +291,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
|||||||
return; // skip broken PMT records
|
return; // skip broken PMT records
|
||||||
if (pmtVersion != -1) {
|
if (pmtVersion != -1) {
|
||||||
if (pmtVersion != pmt.getVersionNumber()) {
|
if (pmtVersion != pmt.getVersionNumber()) {
|
||||||
Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids");
|
Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids\n");
|
||||||
Del(pmtPid, 0x02);
|
Del(pmtPid, 0x02);
|
||||||
pmtPid = 0; // this triggers PAT scan
|
pmtPid = 0; // this triggers PAT scan
|
||||||
}
|
}
|
||||||
@ -333,7 +329,9 @@ cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Paramet
|
|||||||
m_Device(NULL),
|
m_Device(NULL),
|
||||||
m_Receiver(NULL),
|
m_Receiver(NULL),
|
||||||
m_PatFilter(NULL),
|
m_PatFilter(NULL),
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
m_PESRemux(NULL),
|
m_PESRemux(NULL),
|
||||||
|
#endif
|
||||||
m_ESRemux(NULL),
|
m_ESRemux(NULL),
|
||||||
m_PSRemux(NULL),
|
m_PSRemux(NULL),
|
||||||
m_ExtRemux(NULL)
|
m_ExtRemux(NULL)
|
||||||
@ -349,7 +347,9 @@ cStreamdevLiveStreamer::~cStreamdevLiveStreamer()
|
|||||||
DELETENULL(m_PatFilter);
|
DELETENULL(m_PatFilter);
|
||||||
}
|
}
|
||||||
DELETENULL(m_Receiver);
|
DELETENULL(m_Receiver);
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
delete m_PESRemux;
|
delete m_PESRemux;
|
||||||
|
#endif
|
||||||
delete m_ESRemux;
|
delete m_ESRemux;
|
||||||
delete m_PSRemux;
|
delete m_PSRemux;
|
||||||
delete m_ExtRemux;
|
delete m_ExtRemux;
|
||||||
@ -434,11 +434,7 @@ void cStreamdevLiveStreamer::StartReceiver(void)
|
|||||||
DELETENULL(m_Receiver);
|
DELETENULL(m_Receiver);
|
||||||
if (m_NumPids > 0) {
|
if (m_NumPids > 0) {
|
||||||
Dprintf("Creating Receiver to respect changed pids\n");
|
Dprintf("Creating Receiver to respect changed pids\n");
|
||||||
#if VDRVERSNUM < 10500
|
|
||||||
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->Ca(), m_Priority, m_Pids);
|
|
||||||
#else
|
|
||||||
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids);
|
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids);
|
||||||
#endif
|
|
||||||
if (IsRunning() && m_Device != NULL) {
|
if (IsRunning() && m_Device != NULL) {
|
||||||
Dprintf("Attaching new receiver\n");
|
Dprintf("Attaching new receiver\n");
|
||||||
Attach();
|
Attach();
|
||||||
@ -467,10 +463,12 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
|
|||||||
return SetPids(pid);
|
return SetPids(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
case stPES:
|
case stPES:
|
||||||
m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
|
m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
|
||||||
m_Channel->Spids(), false);
|
m_Channel->Spids(), false);
|
||||||
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
|
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
|
||||||
|
#endif
|
||||||
|
|
||||||
case stPS:
|
case stPS:
|
||||||
m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
|
m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
|
||||||
@ -483,6 +481,10 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
|
|||||||
Detach();
|
Detach();
|
||||||
DELETENULL(m_PatFilter);
|
DELETENULL(m_PatFilter);
|
||||||
}
|
}
|
||||||
|
// Set pids from cChannel
|
||||||
|
SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
|
||||||
|
if (m_Channel->Vpid() != m_Channel->Ppid())
|
||||||
|
SetPid(m_Channel->Ppid(), true);
|
||||||
// Set pids from PMT
|
// Set pids from PMT
|
||||||
m_PatFilter = new cStreamdevPatFilter(this, m_Channel);
|
m_PatFilter = new cStreamdevPatFilter(this, m_Channel);
|
||||||
return true;
|
return true;
|
||||||
@ -506,8 +508,10 @@ int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
|
|||||||
case stTSPIDS:
|
case stTSPIDS:
|
||||||
return cStreamdevStreamer::Put(Data, Count);
|
return cStreamdevStreamer::Put(Data, Count);
|
||||||
|
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
case stPES:
|
case stPES:
|
||||||
return m_PESRemux->Put(Data, Count);
|
return m_PESRemux->Put(Data, Count);
|
||||||
|
#endif
|
||||||
|
|
||||||
case stES:
|
case stES:
|
||||||
return m_ESRemux->Put(Data, Count);
|
return m_ESRemux->Put(Data, Count);
|
||||||
@ -530,8 +534,10 @@ uchar *cStreamdevLiveStreamer::Get(int &Count)
|
|||||||
case stTSPIDS:
|
case stTSPIDS:
|
||||||
return cStreamdevStreamer::Get(Count);
|
return cStreamdevStreamer::Get(Count);
|
||||||
|
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
case stPES:
|
case stPES:
|
||||||
return m_PESRemux->Get(Count);
|
return m_PESRemux->Get(Count);
|
||||||
|
#endif
|
||||||
|
|
||||||
case stES:
|
case stES:
|
||||||
return m_ESRemux->Get(Count);
|
return m_ESRemux->Get(Count);
|
||||||
@ -555,9 +561,11 @@ void cStreamdevLiveStreamer::Del(int Count)
|
|||||||
cStreamdevStreamer::Del(Count);
|
cStreamdevStreamer::Del(Count);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
case stPES:
|
case stPES:
|
||||||
m_PESRemux->Del(Count);
|
m_PESRemux->Del(Count);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case stES:
|
case stES:
|
||||||
m_ESRemux->Del(Count);
|
m_ESRemux->Del(Count);
|
||||||
@ -618,7 +626,6 @@ std::string cStreamdevLiveStreamer::Report(void)
|
|||||||
|
|
||||||
// --- cStreamdevFilterStreamer -------------------------------------------------
|
// --- cStreamdevFilterStreamer -------------------------------------------------
|
||||||
|
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
cStreamdevFilterStreamer::cStreamdevFilterStreamer():
|
cStreamdevFilterStreamer::cStreamdevFilterStreamer():
|
||||||
cStreamdevStreamer("streamdev-filterstreaming"),
|
cStreamdevStreamer("streamdev-filterstreaming"),
|
||||||
m_Device(NULL),
|
m_Device(NULL),
|
||||||
@ -720,5 +727,3 @@ void cStreamdevFilterStreamer::ChannelSwitch(const cDevice *Device, int ChannelN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // if VDRVERSNUM >= 10300
|
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
class cTS2PSRemux;
|
class cTS2PSRemux;
|
||||||
class cTS2ESRemux;
|
class cTS2ESRemux;
|
||||||
class cExternRemux;
|
class cExternRemux;
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
class cRemux;
|
class cRemux;
|
||||||
|
#endif
|
||||||
class cStreamdevPatFilter;
|
class cStreamdevPatFilter;
|
||||||
class cStreamdevLiveReceiver;
|
class cStreamdevLiveReceiver;
|
||||||
|
|
||||||
@ -27,7 +29,9 @@ private:
|
|||||||
cDevice *m_Device;
|
cDevice *m_Device;
|
||||||
cStreamdevLiveReceiver *m_Receiver;
|
cStreamdevLiveReceiver *m_Receiver;
|
||||||
cStreamdevPatFilter *m_PatFilter;
|
cStreamdevPatFilter *m_PatFilter;
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
cRemux *m_PESRemux;
|
cRemux *m_PESRemux;
|
||||||
|
#endif
|
||||||
cTS2ESRemux *m_ESRemux;
|
cTS2ESRemux *m_ESRemux;
|
||||||
cTS2PSRemux *m_PSRemux;
|
cTS2PSRemux *m_PSRemux;
|
||||||
cExternRemux *m_ExtRemux;
|
cExternRemux *m_ExtRemux;
|
||||||
@ -58,8 +62,6 @@ public:
|
|||||||
|
|
||||||
// --- cStreamdevFilterStreamer -------------------------------------------------
|
// --- cStreamdevFilterStreamer -------------------------------------------------
|
||||||
|
|
||||||
# if VDRVERSNUM >= 10300
|
|
||||||
|
|
||||||
//#include <vdr/status.h>
|
//#include <vdr/status.h>
|
||||||
|
|
||||||
class cStreamdevLiveFilter;
|
class cStreamdevLiveFilter;
|
||||||
@ -85,6 +87,4 @@ public:
|
|||||||
//virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
|
//virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
|
||||||
};
|
};
|
||||||
|
|
||||||
# endif // if VDRVERSNUM >= 10300
|
|
||||||
|
|
||||||
#endif // VDR_STREAMDEV_LIVESTREAMER_H
|
#endif // VDR_STREAMDEV_LIVESTREAMER_H
|
||||||
|
@ -112,10 +112,10 @@ const cChannel* cChannelList::GetGroup(int Index)
|
|||||||
|
|
||||||
// ******************** cHtmlChannelList ******************
|
// ******************** cHtmlChannelList ******************
|
||||||
const char* cHtmlChannelList::menu =
|
const char* cHtmlChannelList::menu =
|
||||||
"[<a href=\"/\">Home</a> (<a href=\"all.html\">no script</a>)] "
|
"[<a href=\"/\">Home</a> (<a href=\"all.html\" tvid=\"RED\">no script</a>)] "
|
||||||
"[<a href=\"tree.html\">Tree View</a>] "
|
"[<a href=\"tree.html\" tvid=\"GREEN\">Tree View</a>] "
|
||||||
"[<a href=\"groups.html\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] "
|
"[<a href=\"groups.html\" tvid=\"YELLOW\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] "
|
||||||
"[<a href=\"channels.html\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] ";
|
"[<a href=\"channels.html\" tvid=\"BLUE\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] ";
|
||||||
|
|
||||||
const char* cHtmlChannelList::css =
|
const char* cHtmlChannelList::css =
|
||||||
"<style type=\"text/css\">\n"
|
"<style type=\"text/css\">\n"
|
||||||
@ -201,8 +201,10 @@ std::string cHtmlChannelList::StreamTypeMenu()
|
|||||||
(std::string) "[<a href=\"/TS/" + self + "\">TS</a>] ");
|
(std::string) "[<a href=\"/TS/" + self + "\">TS</a>] ");
|
||||||
typeMenu += (streamType == stPS ? (std::string) "[PS] " :
|
typeMenu += (streamType == stPS ? (std::string) "[PS] " :
|
||||||
(std::string) "[<a href=\"/PS/" + self + "\">PS</a>] ");
|
(std::string) "[<a href=\"/PS/" + self + "\">PS</a>] ");
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
typeMenu += (streamType == stPES ? (std::string) "[PES] " :
|
typeMenu += (streamType == stPES ? (std::string) "[PES] " :
|
||||||
(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
|
(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
|
||||||
|
#endif
|
||||||
typeMenu += (streamType == stES ? (std::string) "[ES] " :
|
typeMenu += (streamType == stES ? (std::string) "[ES] " :
|
||||||
(std::string) "[<a href=\"/ES/" + self + "\">ES</a>] ");
|
(std::string) "[<a href=\"/ES/" + self + "\">ES</a>] ");
|
||||||
typeMenu += (streamType == stExtern ? (std::string) "[Extern] " :
|
typeMenu += (streamType == stExtern ? (std::string) "[Extern] " :
|
||||||
@ -336,9 +338,26 @@ std::string cHtmlChannelList::GroupTitle()
|
|||||||
std::string cHtmlChannelList::ItemText()
|
std::string cHtmlChannelList::ItemText()
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
|
std::string suffix;
|
||||||
|
|
||||||
|
switch (streamType) {
|
||||||
|
case stTS: suffix = (std::string) ".ts"; break;
|
||||||
|
case stPS: suffix = (std::string) ".vob"; break;
|
||||||
|
#if APIVERSNUM < 10703
|
||||||
|
// for Network Media Tank
|
||||||
|
case stPES: suffix = (std::string) ".vdr"; break;
|
||||||
|
#endif
|
||||||
|
default: suffix = "";
|
||||||
|
}
|
||||||
line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">";
|
line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">";
|
||||||
line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + "\">" +
|
line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + suffix + "\"";
|
||||||
current->Name() + "</a>";
|
|
||||||
|
// for Network Media Tank
|
||||||
|
line += (std::string) " vod ";
|
||||||
|
if (current->Number() < 1000)
|
||||||
|
line += (std::string) " tvid=\"" + (const char*) itoa(current->Number()) + "\"";
|
||||||
|
|
||||||
|
line += (std::string) ">" + current->Name() + "</a>";
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; current->Apid(i) != 0; ++i, ++count)
|
for (int i = 0; current->Apid(i) != 0; ++i, ++count)
|
||||||
@ -351,11 +370,11 @@ std::string cHtmlChannelList::ItemText()
|
|||||||
int index = 1;
|
int index = 1;
|
||||||
for (int i = 0; current->Apid(i) != 0; ++i, ++index) {
|
for (int i = 0; current->Apid(i) != 0; ++i, ++index) {
|
||||||
line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
|
line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
|
||||||
"+" + (const char*)itoa(index) + "\" class=\"apid\">" + current->Alang(i) + "</a>";
|
"+" + (const char*)itoa(index) + suffix + "\" class=\"apid\" vod>" + current->Alang(i) + "</a>";
|
||||||
}
|
}
|
||||||
for (int i = 0; current->Dpid(i) != 0; ++i, ++index) {
|
for (int i = 0; current->Dpid(i) != 0; ++i, ++index) {
|
||||||
line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
|
line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
|
||||||
"+" + (const char*)itoa(index) + "\" class=\"dpid\">" + current->Dlang(i) + "</a>";
|
"+" + (const char*)itoa(index) + suffix + "\" class=\"dpid\" vod>" + current->Dlang(i) + "</a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
line += "</li>";
|
line += "</li>";
|
||||||
@ -364,10 +383,8 @@ std::string cHtmlChannelList::ItemText()
|
|||||||
|
|
||||||
// ******************** cM3uChannelList ******************
|
// ******************** cM3uChannelList ******************
|
||||||
cM3uChannelList::cM3uChannelList(cChannelIterator *Iterator, const char* Base)
|
cM3uChannelList::cM3uChannelList(cChannelIterator *Iterator, const char* Base)
|
||||||
: cChannelList(Iterator)
|
: cChannelList(Iterator),
|
||||||
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
|
m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
|
||||||
, m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
base = strdup(Base);
|
base = strdup(Base);
|
||||||
m3uState = msFirst;
|
m3uState = msFirst;
|
||||||
@ -398,11 +415,7 @@ std::string cM3uChannelList::Next()
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
|
|
||||||
std::string name = (std::string) m_IConv.Convert(channel->Name());
|
std::string name = (std::string) m_IConv.Convert(channel->Name());
|
||||||
#else
|
|
||||||
std::string name = channel->Name();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (channel->GroupSep())
|
if (channel->GroupSep())
|
||||||
{
|
{
|
||||||
|
@ -126,9 +126,7 @@ class cM3uChannelList: public cChannelList
|
|||||||
char *base;
|
char *base;
|
||||||
enum eM3uState { msFirst, msContinue, msLast };
|
enum eM3uState { msFirst, msContinue, msLast };
|
||||||
eM3uState m3uState;
|
eM3uState m3uState;
|
||||||
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
|
|
||||||
cCharSetConv m_IConv;
|
cCharSetConv m_IConv;
|
||||||
#endif
|
|
||||||
public:
|
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\r\n"; };
|
||||||
virtual bool HasNext();
|
virtual bool HasNext();
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: server.c,v 1.5 2007/04/02 10:32:34 schmirl Exp $
|
* $Id: server.c,v 1.10 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "server/server.h"
|
#include "server/server.h"
|
||||||
#include "server/componentVTP.h"
|
#include "server/componentVTP.h"
|
||||||
#include "server/componentHTTP.h"
|
#include "server/componentHTTP.h"
|
||||||
|
#include "server/componentIGMP.h"
|
||||||
#include "server/setup.h"
|
#include "server/setup.h"
|
||||||
|
|
||||||
#include <vdr/tools.h>
|
#include <vdr/tools.h>
|
||||||
@ -13,14 +14,15 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
cSVDRPhosts StreamdevHosts;
|
cSVDRPhosts StreamdevHosts;
|
||||||
|
char *opt_auth = NULL;
|
||||||
|
char *opt_remux = NULL;
|
||||||
|
|
||||||
cStreamdevServer *cStreamdevServer::m_Instance = NULL;
|
cStreamdevServer *cStreamdevServer::m_Instance = NULL;
|
||||||
cList<cServerComponent> cStreamdevServer::m_Servers;
|
cList<cServerComponent> cStreamdevServer::m_Servers;
|
||||||
cList<cServerConnection> cStreamdevServer::m_Clients;
|
cList<cServerConnection> cStreamdevServer::m_Clients;
|
||||||
|
|
||||||
cStreamdevServer::cStreamdevServer(void):
|
cStreamdevServer::cStreamdevServer(void):
|
||||||
cThread("streamdev server"),
|
cThread("streamdev server")
|
||||||
m_Active(false)
|
|
||||||
{
|
{
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
@ -35,6 +37,12 @@ void cStreamdevServer::Initialize(void)
|
|||||||
if (m_Instance == NULL) {
|
if (m_Instance == NULL) {
|
||||||
if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP);
|
if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP);
|
||||||
if (StreamdevServerSetup.StartHTTPServer) Register(new cComponentHTTP);
|
if (StreamdevServerSetup.StartHTTPServer) Register(new cComponentHTTP);
|
||||||
|
if (StreamdevServerSetup.StartIGMPServer) {
|
||||||
|
if (strcmp(StreamdevServerSetup.IGMPBindIP, "0.0.0.0") == 0)
|
||||||
|
esyslog("streamdev-server: Not starting IGMP. IGMP must be bound to a local IP");
|
||||||
|
else
|
||||||
|
Register(new cComponentIGMP);
|
||||||
|
}
|
||||||
|
|
||||||
m_Instance = new cStreamdevServer;
|
m_Instance = new cStreamdevServer;
|
||||||
}
|
}
|
||||||
@ -47,10 +55,8 @@ void cStreamdevServer::Destruct(void)
|
|||||||
|
|
||||||
void cStreamdevServer::Stop(void)
|
void cStreamdevServer::Stop(void)
|
||||||
{
|
{
|
||||||
if (m_Active) {
|
if (Running())
|
||||||
m_Active = false;
|
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cStreamdevServer::Register(cServerComponent *Server)
|
void cStreamdevServer::Register(cServerComponent *Server)
|
||||||
@ -60,8 +66,6 @@ void cStreamdevServer::Register(cServerComponent *Server)
|
|||||||
|
|
||||||
void cStreamdevServer::Action(void)
|
void cStreamdevServer::Action(void)
|
||||||
{
|
{
|
||||||
m_Active = true;
|
|
||||||
|
|
||||||
/* Initialize Server components, deleting those that failed */
|
/* Initialize Server components, deleting those that failed */
|
||||||
for (cServerComponent *c = m_Servers.First(); c;) {
|
for (cServerComponent *c = m_Servers.First(); c;) {
|
||||||
cServerComponent *next = m_Servers.Next(c);
|
cServerComponent *next = m_Servers.Next(c);
|
||||||
@ -72,11 +76,11 @@ void cStreamdevServer::Action(void)
|
|||||||
|
|
||||||
if (m_Servers.Count() == 0) {
|
if (m_Servers.Count() == 0) {
|
||||||
esyslog("ERROR: no streamdev server activated, exiting");
|
esyslog("ERROR: no streamdev server activated, exiting");
|
||||||
m_Active = false;
|
Cancel(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cTBSelect select;
|
cTBSelect select;
|
||||||
while (m_Active) {
|
while (Running()) {
|
||||||
select.Clear();
|
select.Clear();
|
||||||
|
|
||||||
/* Ask all Server components to register to the selector */
|
/* Ask all Server components to register to the selector */
|
||||||
@ -102,9 +106,9 @@ void cStreamdevServer::Action(void)
|
|||||||
sel = 0;
|
sel = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (sel < 0 && errno == ETIMEDOUT && m_Active);
|
} while (sel < 0 && errno == ETIMEDOUT && Running());
|
||||||
|
|
||||||
if (!m_Active)
|
if (!Running())
|
||||||
break;
|
break;
|
||||||
if (sel < 0) {
|
if (sel < 0) {
|
||||||
esyslog("fatal error, server exiting: %m");
|
esyslog("fatal error, server exiting: %m");
|
||||||
@ -115,13 +119,15 @@ void cStreamdevServer::Action(void)
|
|||||||
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c)){
|
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c)){
|
||||||
if (sel && select.CanRead(c->Socket())) {
|
if (sel && select.CanRead(c->Socket())) {
|
||||||
cServerConnection *client = c->Accept();
|
cServerConnection *client = c->Accept();
|
||||||
|
if (!client)
|
||||||
|
continue;
|
||||||
m_Clients.Add(client);
|
m_Clients.Add(client);
|
||||||
|
|
||||||
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
|
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
|
||||||
esyslog("streamdev: too many clients, rejecting %s:%d",
|
esyslog("streamdev: too many clients, rejecting %s:%d",
|
||||||
client->RemoteIp().c_str(), client->RemotePort());
|
client->RemoteIp().c_str(), client->RemotePort());
|
||||||
client->Reject();
|
client->Reject();
|
||||||
} else if (!StreamdevHosts.Acceptable(client->RemoteIpAddr())) {
|
} else if (!client->CanAuthenticate() && !StreamdevHosts.Acceptable(client->RemoteIpAddr())) {
|
||||||
esyslog("streamdev: client %s:%d not allowed to connect",
|
esyslog("streamdev: client %s:%d not allowed to connect",
|
||||||
client->RemoteIp().c_str(), client->RemotePort());
|
client->RemoteIp().c_str(), client->RemotePort());
|
||||||
client->Reject();
|
client->Reject();
|
||||||
@ -164,6 +170,4 @@ void cStreamdevServer::Action(void)
|
|||||||
c->Destruct();
|
c->Destruct();
|
||||||
m_Servers.Del(c);
|
m_Servers.Del(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Active = false;
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: server.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
|
* $Id: server.h,v 1.6 2008/10/22 11:59:32 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_SERVER_H
|
#ifndef VDR_STREAMDEV_SERVER_H
|
||||||
@ -10,12 +10,14 @@
|
|||||||
#include "server/component.h"
|
#include "server/component.h"
|
||||||
#include "server/connection.h"
|
#include "server/connection.h"
|
||||||
|
|
||||||
#define STREAMDEVHOSTSPATH (*AddDirectory(cPlugin::ConfigDirectory(), "streamdevhosts.conf"))
|
#define DEFAULT_EXTERNREMUX (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "externremux.sh"))
|
||||||
|
#define STREAMDEVHOSTSPATH (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "streamdevhosts.conf"))
|
||||||
|
|
||||||
|
extern char *opt_auth;
|
||||||
|
extern char *opt_remux;
|
||||||
|
|
||||||
class cStreamdevServer: public cThread {
|
class cStreamdevServer: public cThread {
|
||||||
private:
|
private:
|
||||||
bool m_Active;
|
|
||||||
|
|
||||||
static cStreamdevServer *m_Instance;
|
static cStreamdevServer *m_Instance;
|
||||||
static cList<cServerComponent> m_Servers;
|
static cList<cServerComponent> m_Servers;
|
||||||
static cList<cServerConnection> m_Clients;
|
static cList<cServerConnection> m_Clients;
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: setup.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
|
* $Id: setup.c,v 1.6 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vdr/menuitems.h>
|
#include <vdr/menuitems.h>
|
||||||
|
|
||||||
#include "server/setup.h"
|
#include "server/setup.h"
|
||||||
#include "server/server.h"
|
#include "server/server.h"
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
cStreamdevServerSetup StreamdevServerSetup;
|
cStreamdevServerSetup StreamdevServerSetup;
|
||||||
|
|
||||||
@ -16,11 +15,15 @@ cStreamdevServerSetup::cStreamdevServerSetup(void) {
|
|||||||
VTPServerPort = 2004;
|
VTPServerPort = 2004;
|
||||||
StartHTTPServer = true;
|
StartHTTPServer = true;
|
||||||
HTTPServerPort = 3000;
|
HTTPServerPort = 3000;
|
||||||
HTTPStreamType = stPES;
|
HTTPStreamType = stTS;
|
||||||
SuspendMode = smOffer;
|
StartIGMPServer = false;
|
||||||
|
IGMPClientPort = 1234;
|
||||||
|
IGMPStreamType = stTS;
|
||||||
|
SuspendMode = smAlways;
|
||||||
AllowSuspend = false;
|
AllowSuspend = false;
|
||||||
strcpy(VTPBindIP, "0.0.0.0");
|
strcpy(VTPBindIP, "0.0.0.0");
|
||||||
strcpy(HTTPBindIP, "0.0.0.0");
|
strcpy(HTTPBindIP, "0.0.0.0");
|
||||||
|
strcpy(IGMPBindIP, "0.0.0.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) {
|
bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) {
|
||||||
@ -32,6 +35,10 @@ bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) {
|
|||||||
else if (strcmp(Name, "HTTPServerPort") == 0) HTTPServerPort = atoi(Value);
|
else if (strcmp(Name, "HTTPServerPort") == 0) HTTPServerPort = atoi(Value);
|
||||||
else if (strcmp(Name, "HTTPStreamType") == 0) HTTPStreamType = atoi(Value);
|
else if (strcmp(Name, "HTTPStreamType") == 0) HTTPStreamType = atoi(Value);
|
||||||
else if (strcmp(Name, "HTTPBindIP") == 0) strcpy(HTTPBindIP, Value);
|
else if (strcmp(Name, "HTTPBindIP") == 0) strcpy(HTTPBindIP, Value);
|
||||||
|
else if (strcmp(Name, "StartIGMPServer") == 0) StartIGMPServer = atoi(Value);
|
||||||
|
else if (strcmp(Name, "IGMPClientPort") == 0) IGMPClientPort = atoi(Value);
|
||||||
|
else if (strcmp(Name, "IGMPStreamType") == 0) IGMPStreamType = atoi(Value);
|
||||||
|
else if (strcmp(Name, "IGMPBindIP") == 0) strcpy(IGMPBindIP, Value);
|
||||||
else if (strcmp(Name, "SuspendMode") == 0) SuspendMode = atoi(Value);
|
else if (strcmp(Name, "SuspendMode") == 0) SuspendMode = atoi(Value);
|
||||||
else if (strcmp(Name, "AllowSuspend") == 0) AllowSuspend = atoi(Value);
|
else if (strcmp(Name, "AllowSuspend") == 0) AllowSuspend = atoi(Value);
|
||||||
else return false;
|
else return false;
|
||||||
@ -56,7 +63,11 @@ cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) {
|
|||||||
AddShortEdit(tr("HTTP Server Port"), m_NewSetup.HTTPServerPort);
|
AddShortEdit(tr("HTTP Server Port"), m_NewSetup.HTTPServerPort);
|
||||||
AddTypeEdit (tr("HTTP Streamtype"), m_NewSetup.HTTPStreamType);
|
AddTypeEdit (tr("HTTP Streamtype"), m_NewSetup.HTTPStreamType);
|
||||||
AddIpEdit (tr("Bind to IP"), m_NewSetup.HTTPBindIP);
|
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));
|
SetCurrent(Get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +81,10 @@ void cStreamdevServerMenuSetupPage::Store(void) {
|
|||||||
|| strcmp(m_NewSetup.VTPBindIP, StreamdevServerSetup.VTPBindIP) != 0
|
|| strcmp(m_NewSetup.VTPBindIP, StreamdevServerSetup.VTPBindIP) != 0
|
||||||
|| m_NewSetup.StartHTTPServer != StreamdevServerSetup.StartHTTPServer
|
|| m_NewSetup.StartHTTPServer != StreamdevServerSetup.StartHTTPServer
|
||||||
|| m_NewSetup.HTTPServerPort != StreamdevServerSetup.HTTPServerPort
|
|| m_NewSetup.HTTPServerPort != StreamdevServerSetup.HTTPServerPort
|
||||||
|| strcmp(m_NewSetup.HTTPBindIP, StreamdevServerSetup.HTTPBindIP) != 0) {
|
|| strcmp(m_NewSetup.HTTPBindIP, StreamdevServerSetup.HTTPBindIP) != 0
|
||||||
|
|| m_NewSetup.StartIGMPServer != StreamdevServerSetup.StartIGMPServer
|
||||||
|
|| m_NewSetup.IGMPClientPort != StreamdevServerSetup.IGMPClientPort
|
||||||
|
|| strcmp(m_NewSetup.IGMPBindIP, StreamdevServerSetup.IGMPBindIP) != 0) {
|
||||||
restart = true;
|
restart = true;
|
||||||
cStreamdevServer::Destruct();
|
cStreamdevServer::Destruct();
|
||||||
}
|
}
|
||||||
@ -83,6 +97,10 @@ void cStreamdevServerMenuSetupPage::Store(void) {
|
|||||||
SetupStore("HTTPServerPort", m_NewSetup.HTTPServerPort);
|
SetupStore("HTTPServerPort", m_NewSetup.HTTPServerPort);
|
||||||
SetupStore("HTTPStreamType", m_NewSetup.HTTPStreamType);
|
SetupStore("HTTPStreamType", m_NewSetup.HTTPStreamType);
|
||||||
SetupStore("HTTPBindIP", m_NewSetup.HTTPBindIP);
|
SetupStore("HTTPBindIP", m_NewSetup.HTTPBindIP);
|
||||||
|
SetupStore("StartIGMPServer", m_NewSetup.StartIGMPServer);
|
||||||
|
SetupStore("IGMPClientPort", m_NewSetup.IGMPClientPort);
|
||||||
|
SetupStore("IGMPStreamType", m_NewSetup.IGMPStreamType);
|
||||||
|
SetupStore("IGMPBindIP", m_NewSetup.IGMPBindIP);
|
||||||
SetupStore("SuspendMode", m_NewSetup.SuspendMode);
|
SetupStore("SuspendMode", m_NewSetup.SuspendMode);
|
||||||
SetupStore("AllowSuspend", m_NewSetup.AllowSuspend);
|
SetupStore("AllowSuspend", m_NewSetup.AllowSuspend);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: setup.h,v 1.1.1.1 2004/12/30 22:44:21 lordjaxom Exp $
|
* $Id: setup.h,v 1.2 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_SETUPSERVER_H
|
#ifndef VDR_STREAMDEV_SETUPSERVER_H
|
||||||
@ -20,6 +20,10 @@ struct cStreamdevServerSetup {
|
|||||||
int HTTPServerPort;
|
int HTTPServerPort;
|
||||||
int HTTPStreamType;
|
int HTTPStreamType;
|
||||||
char HTTPBindIP[20];
|
char HTTPBindIP[20];
|
||||||
|
int StartIGMPServer;
|
||||||
|
int IGMPClientPort;
|
||||||
|
int IGMPStreamType;
|
||||||
|
char IGMPBindIP[20];
|
||||||
int SuspendMode;
|
int SuspendMode;
|
||||||
int AllowSuspend;
|
int AllowSuspend;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: streamer.c,v 1.16 2007/09/21 11:45:53 schmirl Exp $
|
* $Id: streamer.c,v 1.18 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vdr/ringbuffer.h>
|
#include <vdr/ringbuffer.h>
|
||||||
@ -20,16 +20,15 @@ cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket,
|
|||||||
cStreamdevStreamer *Streamer):
|
cStreamdevStreamer *Streamer):
|
||||||
cThread("streamdev-writer"),
|
cThread("streamdev-writer"),
|
||||||
m_Streamer(Streamer),
|
m_Streamer(Streamer),
|
||||||
m_Socket(Socket),
|
m_Socket(Socket)
|
||||||
m_Active(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
cStreamdevWriter::~cStreamdevWriter()
|
cStreamdevWriter::~cStreamdevWriter()
|
||||||
{
|
{
|
||||||
Dprintf("destructing writer\n");
|
Dprintf("destructing writer\n");
|
||||||
m_Active = false;
|
if (Running())
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cStreamdevWriter::Action(void)
|
void cStreamdevWriter::Action(void)
|
||||||
@ -39,11 +38,10 @@ void cStreamdevWriter::Action(void)
|
|||||||
int max = 0;
|
int max = 0;
|
||||||
uchar *block = NULL;
|
uchar *block = NULL;
|
||||||
int count, offset = 0;
|
int count, offset = 0;
|
||||||
m_Active = true;
|
|
||||||
|
|
||||||
sel.Clear();
|
sel.Clear();
|
||||||
sel.Add(*m_Socket, true);
|
sel.Add(*m_Socket, true);
|
||||||
while (m_Active) {
|
while (Running()) {
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
block = m_Streamer->Get(count);
|
block = m_Streamer->Get(count);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
@ -57,23 +55,39 @@ void cStreamdevWriter::Action(void)
|
|||||||
|
|
||||||
if (sel.CanWrite(*m_Socket)) {
|
if (sel.CanWrite(*m_Socket)) {
|
||||||
int written;
|
int written;
|
||||||
if ((written = m_Socket->Write(block + offset, count)) == -1) {
|
int pkgsize = count;
|
||||||
esyslog("ERROR: streamdev-server: couldn't send data: %m");
|
// SOCK_DGRAM indicates multicast
|
||||||
|
if (m_Socket->Type() == SOCK_DGRAM) {
|
||||||
|
// don't fragment multicast packets
|
||||||
|
// max. payload on standard local ethernet is 1416 to 1456 bytes
|
||||||
|
// and some STBs expect complete TS packets
|
||||||
|
// so let's always limit to 7 * TS_SIZE = 1316
|
||||||
|
if (pkgsize > 7 * TS_SIZE)
|
||||||
|
pkgsize = 7 * TS_SIZE;
|
||||||
|
else
|
||||||
|
pkgsize -= pkgsize % TS_SIZE;
|
||||||
|
}
|
||||||
|
if ((written = m_Socket->Write(block + offset, pkgsize)) == -1) {
|
||||||
|
esyslog("ERROR: streamdev-server: couldn't send %d bytes: %m", pkgsize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// statistics
|
||||||
if (count > max)
|
if (count > max)
|
||||||
max = count;
|
max = count;
|
||||||
|
|
||||||
offset += written;
|
offset += written;
|
||||||
count -= written;
|
count -= written;
|
||||||
if (count == 0) {
|
|
||||||
|
// less than one TS packet left:
|
||||||
|
// delete what we've written so far and get next chunk
|
||||||
|
if (count < TS_SIZE) {
|
||||||
m_Streamer->Del(offset);
|
m_Streamer->Del(offset);
|
||||||
block = NULL;
|
block = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_Active = false;
|
|
||||||
Dprintf("Max. Transmit Blocksize was: %d\n", max);
|
Dprintf("Max. Transmit Blocksize was: %d\n", max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +95,6 @@ void cStreamdevWriter::Action(void)
|
|||||||
|
|
||||||
cStreamdevStreamer::cStreamdevStreamer(const char *Name):
|
cStreamdevStreamer::cStreamdevStreamer(const char *Name):
|
||||||
cThread(Name),
|
cThread(Name),
|
||||||
m_Active(false),
|
|
||||||
m_Running(false),
|
m_Running(false),
|
||||||
m_Writer(NULL),
|
m_Writer(NULL),
|
||||||
m_RingBuffer(new cRingBufferLinear(STREAMERBUFSIZE, TS_SIZE * 2,
|
m_RingBuffer(new cRingBufferLinear(STREAMERBUFSIZE, TS_SIZE * 2,
|
||||||
@ -109,7 +122,7 @@ void cStreamdevStreamer::Start(cTBSocket *Socket)
|
|||||||
|
|
||||||
void cStreamdevStreamer::Activate(bool On)
|
void cStreamdevStreamer::Activate(bool On)
|
||||||
{
|
{
|
||||||
if (On && !m_Active) {
|
if (On && !Active()) {
|
||||||
Dprintf("activate streamer\n");
|
Dprintf("activate streamer\n");
|
||||||
m_Writer->Start();
|
m_Writer->Start();
|
||||||
cThread::Start();
|
cThread::Start();
|
||||||
@ -118,9 +131,8 @@ void cStreamdevStreamer::Activate(bool On)
|
|||||||
|
|
||||||
void cStreamdevStreamer::Stop(void)
|
void cStreamdevStreamer::Stop(void)
|
||||||
{
|
{
|
||||||
if (m_Active) {
|
if (Running()) {
|
||||||
Dprintf("stopping streamer\n");
|
Dprintf("stopping streamer\n");
|
||||||
m_Active = false;
|
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
}
|
}
|
||||||
if (m_Running) {
|
if (m_Running) {
|
||||||
@ -132,8 +144,7 @@ void cStreamdevStreamer::Stop(void)
|
|||||||
|
|
||||||
void cStreamdevStreamer::Action(void)
|
void cStreamdevStreamer::Action(void)
|
||||||
{
|
{
|
||||||
m_Active = true;
|
while (Running()) {
|
||||||
while (m_Active) {
|
|
||||||
int got;
|
int got;
|
||||||
uchar *block = m_RingBuffer->Get(got);
|
uchar *block = m_RingBuffer->Get(got);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: streamer.h,v 1.8 2007/04/02 10:32:34 schmirl Exp $
|
* $Id: streamer.h,v 1.10 2009/02/13 10:39:22 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_STREAMER_H
|
#ifndef VDR_STREAMDEV_STREAMER_H
|
||||||
@ -12,6 +12,10 @@
|
|||||||
class cTBSocket;
|
class cTBSocket;
|
||||||
class cStreamdevStreamer;
|
class cStreamdevStreamer;
|
||||||
|
|
||||||
|
#ifndef TS_SIZE
|
||||||
|
#define TS_SIZE 188
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STREAMERBUFSIZE MEGABYTE(4)
|
#define STREAMERBUFSIZE MEGABYTE(4)
|
||||||
#define WRITERBUFSIZE KILOBYTE(256)
|
#define WRITERBUFSIZE KILOBYTE(256)
|
||||||
|
|
||||||
@ -21,7 +25,6 @@ class cStreamdevWriter: public cThread {
|
|||||||
private:
|
private:
|
||||||
cStreamdevStreamer *m_Streamer;
|
cStreamdevStreamer *m_Streamer;
|
||||||
cTBSocket *m_Socket;
|
cTBSocket *m_Socket;
|
||||||
bool m_Active;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Action(void);
|
virtual void Action(void);
|
||||||
@ -29,15 +32,12 @@ protected:
|
|||||||
public:
|
public:
|
||||||
cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer);
|
cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer);
|
||||||
virtual ~cStreamdevWriter();
|
virtual ~cStreamdevWriter();
|
||||||
|
|
||||||
bool IsActive(void) const { return m_Active; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- cStreamdevStreamer -----------------------------------------------------
|
// --- cStreamdevStreamer -----------------------------------------------------
|
||||||
|
|
||||||
class cStreamdevStreamer: public cThread {
|
class cStreamdevStreamer: public cThread {
|
||||||
private:
|
private:
|
||||||
bool m_Active;
|
|
||||||
bool m_Running;
|
bool m_Running;
|
||||||
cStreamdevWriter *m_Writer;
|
cStreamdevWriter *m_Writer;
|
||||||
cRingBufferLinear *m_RingBuffer;
|
cRingBufferLinear *m_RingBuffer;
|
||||||
@ -54,7 +54,7 @@ public:
|
|||||||
|
|
||||||
virtual void Start(cTBSocket *Socket);
|
virtual void Start(cTBSocket *Socket);
|
||||||
virtual void Stop(void);
|
virtual void Stop(void);
|
||||||
bool Abort(void) const;
|
bool Abort(void);
|
||||||
|
|
||||||
void Activate(bool On);
|
void Activate(bool On);
|
||||||
int Receive(uchar *Data, int Length) { return m_RingBuffer->Put(Data, Length); }
|
int Receive(uchar *Data, int Length) { return m_RingBuffer->Put(Data, Length); }
|
||||||
@ -68,9 +68,9 @@ public:
|
|||||||
virtual void Attach(void) {}
|
virtual void Attach(void) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool cStreamdevStreamer::Abort(void) const
|
inline bool cStreamdevStreamer::Abort(void)
|
||||||
{
|
{
|
||||||
return m_Active && !m_Writer->IsActive();
|
return Active() && !m_Writer->Active();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // VDR_STREAMDEV_STREAMER_H
|
#endif // VDR_STREAMDEV_STREAMER_H
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: suspend.c,v 1.1.1.1 2004/12/30 22:44:21 lordjaxom Exp $
|
* $Id: suspend.c,v 1.3 2008/10/22 11:59:32 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "server/suspend.h"
|
#include "server/suspend.h"
|
||||||
@ -7,13 +7,12 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
cSuspendLive::cSuspendLive(void)
|
cSuspendLive::cSuspendLive(void)
|
||||||
#if VDRVERSNUM >= 10300
|
|
||||||
: cThread("Streamdev: server suspend")
|
: cThread("Streamdev: server suspend")
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
cSuspendLive::~cSuspendLive() {
|
cSuspendLive::~cSuspendLive() {
|
||||||
|
Stop();
|
||||||
Detach();
|
Detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,26 +25,15 @@ void cSuspendLive::Activate(bool On) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cSuspendLive::Stop(void) {
|
void cSuspendLive::Stop(void) {
|
||||||
if (m_Active) {
|
if (Running())
|
||||||
m_Active = false;
|
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSuspendLive::Action(void) {
|
void cSuspendLive::Action(void) {
|
||||||
#if VDRVERSNUM < 10300
|
while (Running()) {
|
||||||
isyslog("Streamdev: Suspend Live thread started (pid = %d)", getpid());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_Active = true;
|
|
||||||
while (m_Active) {
|
|
||||||
DeviceStillPicture(suspend_mpg, sizeof(suspend_mpg));
|
DeviceStillPicture(suspend_mpg, sizeof(suspend_mpg));
|
||||||
usleep(100000);
|
cCondWait::SleepMs(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if VDRVERSNUM < 10300
|
|
||||||
isyslog("Streamdev: Suspend Live thread stopped");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSuspendCtl::m_Active = false;
|
bool cSuspendCtl::m_Active = false;
|
||||||
@ -61,7 +49,7 @@ cSuspendCtl::~cSuspendCtl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eOSState cSuspendCtl::ProcessKey(eKeys Key) {
|
eOSState cSuspendCtl::ProcessKey(eKeys Key) {
|
||||||
if (!m_Suspend->IsActive() || Key == kBack) {
|
if (!m_Suspend->Active() || Key == kBack) {
|
||||||
DELETENULL(m_Suspend);
|
DELETENULL(m_Suspend);
|
||||||
return osEnd;
|
return osEnd;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: suspend.h,v 1.1.1.1 2004/12/30 22:44:26 lordjaxom Exp $
|
* $Id: suspend.h,v 1.2 2008/10/22 11:59:32 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VDR_STREAMDEV_SUSPEND_H
|
#ifndef VDR_STREAMDEV_SUSPEND_H
|
||||||
@ -7,10 +7,7 @@
|
|||||||
|
|
||||||
#include <vdr/player.h>
|
#include <vdr/player.h>
|
||||||
|
|
||||||
class cSuspendLive: public cPlayer, cThread {
|
class cSuspendLive: public cPlayer, public cThread {
|
||||||
private:
|
|
||||||
bool m_Active;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Activate(bool On);
|
virtual void Activate(bool On);
|
||||||
virtual void Action(void);
|
virtual void Action(void);
|
||||||
@ -20,8 +17,6 @@ protected:
|
|||||||
public:
|
public:
|
||||||
cSuspendLive(void);
|
cSuspendLive(void);
|
||||||
virtual ~cSuspendLive();
|
virtual ~cSuspendLive();
|
||||||
|
|
||||||
bool IsActive(void) const { return m_Active; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class cSuspendCtl: public cControl {
|
class cSuspendCtl: public cControl {
|
||||||
|
@ -3,16 +3,18 @@
|
|||||||
*
|
*
|
||||||
* See the README file for copyright information and how to reach the author.
|
* See the README file for copyright information and how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: streamdev-client.c,v 1.2 2005/04/24 16:19:44 lordjaxom Exp $
|
* $Id: streamdev-client.c,v 1.6 2008/04/08 14:18:15 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "streamdev-client.h"
|
#include "streamdev-client.h"
|
||||||
#include "client/device.h"
|
#include "client/device.h"
|
||||||
#include "client/setup.h"
|
#include "client/setup.h"
|
||||||
//#include "client/menu.h"
|
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
const char *cPluginStreamdevClient::DESCRIPTION = "VTP Streaming Client";
|
#if !defined(APIVERSNUM) || APIVERSNUM < 10509
|
||||||
|
#error "VDR-1.5.9 API version or greater is required!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *cPluginStreamdevClient::DESCRIPTION = trNOOP("VTP Streaming Client");
|
||||||
|
|
||||||
cPluginStreamdevClient::cPluginStreamdevClient(void) {
|
cPluginStreamdevClient::cPluginStreamdevClient(void) {
|
||||||
}
|
}
|
||||||
@ -25,12 +27,9 @@ const char *cPluginStreamdevClient::Description(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool cPluginStreamdevClient::Start(void) {
|
bool cPluginStreamdevClient::Start(void) {
|
||||||
i18n_name = Name();
|
I18nRegister(PLUGIN_NAME_I18N);
|
||||||
RegisterI18n(Phrases);
|
|
||||||
|
|
||||||
cStreamdevDevice::Init();
|
cStreamdevDevice::Init();
|
||||||
|
return true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPluginStreamdevClient::Housekeeping(void) {
|
void cPluginStreamdevClient::Housekeeping(void) {
|
||||||
@ -39,13 +38,15 @@ void cPluginStreamdevClient::Housekeeping(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *cPluginStreamdevClient::MainMenuEntry(void) {
|
const char *cPluginStreamdevClient::MainMenuEntry(void) {
|
||||||
return NULL;
|
return StreamdevClientSetup.StartClient && !StreamdevClientSetup.HideMenuEntry ? tr("Suspend Server") : NULL;
|
||||||
//return StreamdevClientSetup.StartClient ? tr("Streaming Control") : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cOsdObject *cPluginStreamdevClient::MainMenuAction(void) {
|
cOsdObject *cPluginStreamdevClient::MainMenuAction(void) {
|
||||||
|
if (ClientSocket.SuspendServer())
|
||||||
|
Skins.Message(mtInfo, tr("Server is suspended"));
|
||||||
|
else
|
||||||
|
Skins.Message(mtError, tr("Couldn't suspend Server!"));
|
||||||
return NULL;
|
return NULL;
|
||||||
//return StreamdevClientSetup.StartClient ? new cStreamdevMenu : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cMenuSetupPage *cPluginStreamdevClient::SetupMenu(void) {
|
cMenuSetupPage *cPluginStreamdevClient::SetupMenu(void) {
|
||||||
|
@ -3,18 +3,22 @@
|
|||||||
*
|
*
|
||||||
* See the README file for copyright information and how to reach the author.
|
* See the README file for copyright information and how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: streamdev-server.c,v 1.6 2007/04/16 11:01:02 schmirl Exp $
|
* $Id: streamdev-server.c,v 1.11 2008/10/14 11:05:47 schmirl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <vdr/tools.h>
|
||||||
|
#include "remux/extern.h"
|
||||||
#include "streamdev-server.h"
|
#include "streamdev-server.h"
|
||||||
#include "server/setup.h"
|
#include "server/setup.h"
|
||||||
#include "server/server.h"
|
#include "server/server.h"
|
||||||
#include "server/suspend.h"
|
#include "server/suspend.h"
|
||||||
#include "remux/extern.h"
|
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
const char *cPluginStreamdevServer::DESCRIPTION = "VDR Streaming Server";
|
#if !defined(APIVERSNUM) || APIVERSNUM < 10509
|
||||||
|
#error "VDR-1.5.9 API version or greater is required!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *cPluginStreamdevServer::DESCRIPTION = trNOOP("VDR Streaming Server");
|
||||||
|
|
||||||
cPluginStreamdevServer::cPluginStreamdevServer(void)
|
cPluginStreamdevServer::cPluginStreamdevServer(void)
|
||||||
{
|
{
|
||||||
@ -22,6 +26,8 @@ cPluginStreamdevServer::cPluginStreamdevServer(void)
|
|||||||
|
|
||||||
cPluginStreamdevServer::~cPluginStreamdevServer()
|
cPluginStreamdevServer::~cPluginStreamdevServer()
|
||||||
{
|
{
|
||||||
|
free(opt_auth);
|
||||||
|
free(opt_remux);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *cPluginStreamdevServer::Description(void)
|
const char *cPluginStreamdevServer::Description(void)
|
||||||
@ -32,22 +38,39 @@ const char *cPluginStreamdevServer::Description(void)
|
|||||||
const char *cPluginStreamdevServer::CommandLineHelp(void)
|
const char *cPluginStreamdevServer::CommandLineHelp(void)
|
||||||
{
|
{
|
||||||
// return a string that describes all known command line options.
|
// return a string that describes all known command line options.
|
||||||
return " -r <CMD>, --remux=<CMD> Define an external command for remuxing.\n";
|
return
|
||||||
|
" -a <LOGIN:PASSWORD>, --auth=<LOGIN:PASSWORD> Credentials for HTTP authentication.\n"
|
||||||
|
" -r <CMD>, --remux=<CMD> Define an external command for remuxing.\n"
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cPluginStreamdevServer::ProcessArgs(int argc, char *argv[])
|
bool cPluginStreamdevServer::ProcessArgs(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// implement command line argument processing here if applicable.
|
// implement command line argument processing here if applicable.
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
|
{ "auth", required_argument, NULL, 'a' },
|
||||||
{ "remux", required_argument, NULL, 'r' },
|
{ "remux", required_argument, NULL, 'r' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while((c = getopt_long(argc, argv, "r:", long_options, NULL)) != -1) {
|
while((c = getopt_long(argc, argv, "a:r:", long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 'a':
|
||||||
|
{
|
||||||
|
if (opt_auth)
|
||||||
|
free(opt_auth);
|
||||||
|
int l = strlen(optarg);
|
||||||
|
cBase64Encoder Base64((uchar*) optarg, l, l * 4 / 3 + 3);
|
||||||
|
const char *s = Base64.NextLine();
|
||||||
|
if (s)
|
||||||
|
opt_auth = strdup(s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
g_ExternRemux = optarg;
|
if (opt_remux)
|
||||||
|
free(opt_remux);
|
||||||
|
opt_remux = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -58,9 +81,7 @@ bool cPluginStreamdevServer::ProcessArgs(int argc, char *argv[])
|
|||||||
|
|
||||||
bool cPluginStreamdevServer::Start(void)
|
bool cPluginStreamdevServer::Start(void)
|
||||||
{
|
{
|
||||||
i18n_name = Name();
|
I18nRegister(PLUGIN_NAME_I18N);
|
||||||
RegisterI18n(Phrases);
|
|
||||||
|
|
||||||
if (!StreamdevHosts.Load(STREAMDEVHOSTSPATH, true, true)) {
|
if (!StreamdevHosts.Load(STREAMDEVHOSTSPATH, true, true)) {
|
||||||
esyslog("streamdev-server: error while loading %s", STREAMDEVHOSTSPATH);
|
esyslog("streamdev-server: error while loading %s", STREAMDEVHOSTSPATH);
|
||||||
fprintf(stderr, "streamdev-server: error while loading %s\n", STREAMDEVHOSTSPATH);
|
fprintf(stderr, "streamdev-server: error while loading %s\n", STREAMDEVHOSTSPATH);
|
||||||
@ -73,6 +94,8 @@ bool cPluginStreamdevServer::Start(void)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!opt_remux)
|
||||||
|
opt_remux = strdup(DEFAULT_EXTERNREMUX);
|
||||||
|
|
||||||
cStreamdevServer::Initialize();
|
cStreamdevServer::Initialize();
|
||||||
|
|
||||||
|
48
streamdev/externremux.sh
Executable file
48
streamdev/externremux.sh
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/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
|
@ -10,4 +10,5 @@
|
|||||||
127.0.0.1 # always accept localhost
|
127.0.0.1 # always accept localhost
|
||||||
#192.168.100.0/24 # any host on the local net
|
#192.168.100.0/24 # any host on the local net
|
||||||
#204.152.189.113 # a specific host
|
#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 (USE THIS WITH CARE!)
|
@ -1,5 +1,6 @@
|
|||||||
#include "tools/socket.h"
|
#include "tools/socket.h"
|
||||||
|
|
||||||
|
#include <vdr/tools.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -15,10 +16,11 @@
|
|||||||
// actual DSCP value used
|
// actual DSCP value used
|
||||||
#define STREAMDEV_DSCP DSCP_AF41
|
#define STREAMDEV_DSCP DSCP_AF41
|
||||||
|
|
||||||
cTBSocket::cTBSocket(int Type) {
|
cTBSocket::cTBSocket(int Type, int Protocol) {
|
||||||
memset(&m_LocalAddr, 0, sizeof(m_LocalAddr));
|
memset(&m_LocalAddr, 0, sizeof(m_LocalAddr));
|
||||||
memset(&m_RemoteAddr, 0, sizeof(m_RemoteAddr));
|
memset(&m_RemoteAddr, 0, sizeof(m_RemoteAddr));
|
||||||
m_Type = Type;
|
m_Type = Type;
|
||||||
|
m_Protocol = Protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
cTBSocket::~cTBSocket() {
|
cTBSocket::~cTBSocket() {
|
||||||
@ -31,7 +33,7 @@ bool cTBSocket::Connect(const std::string &Host, unsigned int Port) {
|
|||||||
|
|
||||||
if (IsOpen()) Close();
|
if (IsOpen()) Close();
|
||||||
|
|
||||||
if ((socket = ::socket(PF_INET, m_Type, IPPROTO_IP)) == -1)
|
if ((socket = ::socket(PF_INET, m_Type, m_Protocol)) == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_LocalAddr.sin_family = AF_INET;
|
m_LocalAddr.sin_family = AF_INET;
|
||||||
@ -52,10 +54,12 @@ bool cTBSocket::Connect(const std::string &Host, unsigned int Port) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = sizeof(struct sockaddr_in);
|
if (m_Type == SOCK_STREAM) {
|
||||||
if (::getpeername(socket, (struct sockaddr*)&m_RemoteAddr, &len) == -1) {
|
len = sizeof(struct sockaddr_in);
|
||||||
::close(socket);
|
if (::getpeername(socket, (struct sockaddr*)&m_RemoteAddr, &len) == -1) {
|
||||||
return false;
|
::close(socket);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
len = sizeof(struct sockaddr_in);
|
len = sizeof(struct sockaddr_in);
|
||||||
@ -64,7 +68,11 @@ bool cTBSocket::Connect(const std::string &Host, unsigned int Port) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cTBSource::Open(socket);
|
if (!cTBSource::Open(socket)) {
|
||||||
|
::close(socket);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cTBSocket::Listen(const std::string &Ip, unsigned int Port, int BackLog) {
|
bool cTBSocket::Listen(const std::string &Ip, unsigned int Port, int BackLog) {
|
||||||
@ -74,7 +82,7 @@ bool cTBSocket::Listen(const std::string &Ip, unsigned int Port, int BackLog) {
|
|||||||
|
|
||||||
if (IsOpen()) Close();
|
if (IsOpen()) Close();
|
||||||
|
|
||||||
if ((socket = ::socket(PF_INET, m_Type, IPPROTO_IP)) == -1)
|
if ((socket = ::socket(PF_INET, m_Type, m_Protocol)) == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
val = 1;
|
val = 1;
|
||||||
|
@ -18,9 +18,10 @@ private:
|
|||||||
struct sockaddr_in m_RemoteAddr;
|
struct sockaddr_in m_RemoteAddr;
|
||||||
|
|
||||||
int m_Type;
|
int m_Type;
|
||||||
|
int m_Protocol;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cTBSocket(int Type = SOCK_STREAM);
|
cTBSocket(int Type = SOCK_STREAM, int Protocol = 0);
|
||||||
virtual ~cTBSocket();
|
virtual ~cTBSocket();
|
||||||
|
|
||||||
/* See cTBSource::SysRead()
|
/* See cTBSource::SysRead()
|
||||||
@ -97,15 +98,22 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline ssize_t cTBSocket::SysRead(void *Buffer, size_t Length) const {
|
inline ssize_t cTBSocket::SysRead(void *Buffer, size_t Length) const {
|
||||||
if (m_Type == SOCK_DGRAM) {
|
if (m_Type == SOCK_STREAM)
|
||||||
|
return ::recv(*this, Buffer, Length, 0);
|
||||||
|
else {
|
||||||
socklen_t len = sizeof(m_RemoteAddr);
|
socklen_t len = sizeof(m_RemoteAddr);
|
||||||
return ::recvfrom(*this, Buffer, Length, 0, (sockaddr*)&m_RemoteAddr, &len);
|
return ::recvfrom(*this, Buffer, Length, 0, (sockaddr*)&m_RemoteAddr, &len);
|
||||||
} else
|
}
|
||||||
return ::recv(*this, Buffer, Length, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ssize_t cTBSocket::SysWrite(const void *Buffer, size_t Length) const {
|
inline ssize_t cTBSocket::SysWrite(const void *Buffer, size_t Length) const {
|
||||||
return ::send(*this, Buffer, Length, 0);
|
return ::send(*this, Buffer, Length, 0);
|
||||||
|
if (m_Type == SOCK_STREAM)
|
||||||
|
return ::send(*this, Buffer, Length, 0);
|
||||||
|
else {
|
||||||
|
socklen_t len = sizeof(m_RemoteAddr);
|
||||||
|
return ::sendto(*this, Buffer, Length, 0, (sockaddr*)&m_RemoteAddr, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TOOLBOX_SOCKET_H
|
#endif // TOOLBOX_SOCKET_H
|
||||||
|
Loading…
Reference in New Issue
Block a user