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 a TS PAT repacker based on Petri Laine's VDR TS recording patch
|
||||
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
|
||||
for providing vdr-incompletesections.diff
|
||||
@ -42,6 +48,7 @@ Udo Richter
|
||||
for fixing streamdev-server shutdown
|
||||
for speeding up cPluginStreamdevServer::Active()
|
||||
for adapting to VDR 1.5.0 API
|
||||
for adapting to VDR 1.7.1
|
||||
|
||||
greenman
|
||||
for reporting that the log could get flooded on connection failures.
|
||||
@ -70,3 +77,37 @@ Olli Lammi
|
||||
|
||||
Joerg Pulz
|
||||
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
|
||||
---------------------------------------
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
#
|
||||
# $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.
|
||||
# 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:
|
||||
|
||||
CXX ?= g++
|
||||
CXXFLAGS ?= -fPIC -Wall -Woverloaded-virtual
|
||||
CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
|
||||
|
||||
### The directory environment:
|
||||
|
||||
DVBDIR = ../../../../DVB
|
||||
VDRDIR = ../../..
|
||||
LIBDIR = ../../lib
|
||||
TMPDIR = /tmp
|
||||
@ -40,55 +39,39 @@ PACKAGE = vdr-$(ARCHIVE)
|
||||
|
||||
### 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):
|
||||
|
||||
COMMONOBJS = common.o i18n.o \
|
||||
COMMONOBJS = common.o \
|
||||
\
|
||||
tools/source.o tools/select.o tools/socket.o tools/tools.o
|
||||
|
||||
CLIENTOBJS = $(PLUGIN)-client.o \
|
||||
\
|
||||
client/socket.o client/device.o client/setup.o \
|
||||
client/remote.o client/assembler.o client/filter.o
|
||||
client/filter.o
|
||||
|
||||
|
||||
SERVEROBJS = $(PLUGIN)-server.o \
|
||||
\
|
||||
server/server.o server/connectionVTP.o server/connectionHTTP.o \
|
||||
server/componentHTTP.o server/componentVTP.o server/connection.o \
|
||||
server/component.o server/suspend.o server/setup.o server/streamer.o \
|
||||
server/livestreamer.o server/livefilter.o server/menuHTTP.o \
|
||||
\
|
||||
server/server.o server/component.o server/connection.o \
|
||||
server/componentVTP.o server/componentHTTP.o server/componentIGMP.o \
|
||||
server/connectionVTP.o server/connectionHTTP.o server/connectionIGMP.o \
|
||||
server/streamer.o server/livestreamer.o server/livefilter.o \
|
||||
server/suspend.o server/setup.o server/menuHTTP.o \
|
||||
remux/tsremux.o remux/ts2ps.o remux/ts2es.o remux/extern.o
|
||||
|
||||
ifdef DEBUG
|
||||
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
|
||||
|
||||
### The main target:
|
||||
|
||||
.PHONY: all dist clean
|
||||
all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so
|
||||
.PHONY: all i18n dist clean
|
||||
all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so i18n
|
||||
|
||||
### Implicit rules:
|
||||
|
||||
@ -97,7 +80,7 @@ all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so
|
||||
|
||||
# Dependencies:
|
||||
|
||||
MAKEDEP = g++ -MM -MG
|
||||
MAKEDEP = $(CXX) -MM -MG
|
||||
DEPFILE = .dependencies
|
||||
ifdef GCC3
|
||||
$(DEPFILE): Makefile
|
||||
@ -113,12 +96,35 @@ endif
|
||||
|
||||
-include $(DEPFILE)
|
||||
|
||||
### Internationalization (I18N):
|
||||
|
||||
PODIR = po
|
||||
LOCALEDIR = $(VDRDIR)/locale
|
||||
I18Npo = $(wildcard $(PODIR)/*.po)
|
||||
I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
|
||||
I18Npot = $(PODIR)/$(PLUGIN).pot
|
||||
|
||||
%.mo: %.po
|
||||
msgfmt -c -o $@ $<
|
||||
|
||||
$(I18Npot): $(CLIENTOBJS:%.o=%.c) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c)
|
||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<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:
|
||||
|
||||
libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.cc libdvbmpeg/*.h libdvbmpeg/*.hh
|
||||
libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.h
|
||||
$(MAKE) -C ./libdvbmpeg libdvbmpegtools.a
|
||||
|
||||
|
||||
libvdr-$(PLUGIN)-client.so: $(CLIENTOBJS) $(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
|
||||
|
||||
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
|
||||
|
225
README
225
README
@ -15,13 +15,18 @@ Contents:
|
||||
|
||||
1. Description
|
||||
2. Installation
|
||||
2.1 VDR 1.2.X
|
||||
2.2 VDR 1.3.X and above
|
||||
2.1 VDR 1.4.x and older
|
||||
2.2 VDR 1.6.0 and above
|
||||
2.3 Updating from streamdev 0.3.x
|
||||
3. Usage
|
||||
3.1 Usage HTTP server
|
||||
3.2 Usage VDR-to-VDR server
|
||||
3.3 Usage VDR-to-VDR client
|
||||
3.2 Usage IGMP multicast server
|
||||
3.3 Usage VDR-to-VDR server
|
||||
3.4 Usage VDR-to-VDR client
|
||||
4. Other useful Plugins
|
||||
4.1 Plugins for VDR-to-VDR clients
|
||||
4.2 Plugins for Server
|
||||
4.3 Alternatives
|
||||
5. Known Problems
|
||||
|
||||
|
||||
@ -57,7 +62,7 @@ the PROTOCOL file.
|
||||
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
|
||||
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
|
||||
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
|
||||
channels.conf on the client, preferably after scanning (in case you use 1.2.X
|
||||
with AutoPID or 1.3.X).
|
||||
channels.conf on the client, preferably after scanning.
|
||||
|
||||
If you want to drive additional Input-Devices (with different sources) on the
|
||||
client, you can merge the channels.conf files. VDR will detect if the local
|
||||
device or the network device can receive the channels.
|
||||
|
||||
Last, but not least you have to put the provided streamdevhosts.conf.example
|
||||
into the "plugins" subfolder of your config-directory (which is equal to your
|
||||
video-directory if not specified otherwise), rename it to streamdevhosts.conf
|
||||
and adjust it 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. 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
|
||||
/video0/plugins/streamdevhosts.conf.
|
||||
Last, but not least you have to copy the streamdev folder into the
|
||||
"plugins/streamdev" subfolder of VDR's config-directory (which is equal to your
|
||||
video-directory if not specified otherwise). For example, if you didn't specify
|
||||
a separate config-directory, and specified your video directory as "/video0",
|
||||
the directory has to be copied to /video0/plugins/streamdev.
|
||||
|
||||
The directory contains a file named streamdevhosts.conf which you must adjust
|
||||
to your needs. The syntax is the same as for svdrphosts.conf, so please consult
|
||||
VDR's documentation on how to fill that file, if you can't do it on-the-fly.
|
||||
|
||||
There's also a sample externremux.sh script in this directory. It is used by
|
||||
streamdev's external remux feature. The sample script uses mencoder. Please
|
||||
check the script for further information. You can specify a different script
|
||||
location with the -r parameter. The VDR commandline would then include a
|
||||
"-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
|
||||
cancellation. You can work without it, but you _might_ have delays in switching
|
||||
(especially when using VDR-to-VDR streaming) that are around three seconds.
|
||||
This version is not compatible to VDR releases older than 1.5.9. Take one of
|
||||
the streamdev-0.4.x releases if you are running at least VDR 1.4.x. For older
|
||||
VDRs you will probably need one of the streamdev-0.3.x releases.
|
||||
|
||||
cd vdr-1.X.X/PLUGINS/src
|
||||
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:
|
||||
2.2 VDR 1.6.0 and above:
|
||||
------------------------
|
||||
|
||||
cd vdr-1.X.X/PLUGINS/src
|
||||
tar xvfz vdr-streamdev-0.3.1.tgz
|
||||
ln -s streamdev-0.3.1 streamdev
|
||||
tar xvfz vdr-streamdev-0.4.0.tgz
|
||||
ln -s streamdev-0.4.0 streamdev
|
||||
cp -r streamdev/streamdev VDRCONFDIR/plugins/
|
||||
cd ../..
|
||||
make [options, if necessary] vdr
|
||||
make [options, if necessary] plugins
|
||||
|
||||
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:
|
||||
---------
|
||||
@ -120,12 +144,12 @@ can run in one VDR instance, if necessary.
|
||||
|
||||
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
|
||||
primary device (i.e. disrupt live-tv). If set to "Offer suspend mode" (the
|
||||
default), you will have a new entry in the main menu. Activating that will put
|
||||
the server into "Suspend Mode" (a picture is displayed on TV). Then, a client
|
||||
may switch the primary card to wherever it likes to. While watching TV (Suspend
|
||||
deactivated), the client may not switch the transponder on the primary device.
|
||||
If you set the behaviour to "Always suspended", there will be normal live-tv
|
||||
primary device (i.e. disrupt live-tv). If set to "Offer suspend mode", you will
|
||||
have a new entry in the main menu. Activating that will put the server into
|
||||
"Suspend Mode" (a picture is displayed on TV). Then, a client may switch the
|
||||
primary card to wherever it likes to. While watching TV (Suspend deactivated),
|
||||
the client may not switch the transponder on the primary device. If you set
|
||||
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
|
||||
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
|
||||
@ -186,7 +210,78 @@ externremux script.
|
||||
|
||||
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
|
||||
@ -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
|
||||
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 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
|
||||
@ -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
|
||||
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
|
||||
client, you will have to restart VDR. All other settings can be changed without
|
||||
restarting VDR.
|
||||
client, you will have to restart VDR. However requests to switch channels will
|
||||
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
|
||||
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.
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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:
|
||||
------------------------
|
||||
|
||||
@ -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
|
||||
problem here. However timers usually have a higher priority. Either avoid
|
||||
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/setup.h"
|
||||
#include "client/assembler.h"
|
||||
#include "client/filter.h"
|
||||
|
||||
#include "tools/select.h"
|
||||
@ -26,20 +25,10 @@ cStreamdevDevice *cStreamdevDevice::m_Device = NULL;
|
||||
cStreamdevDevice::cStreamdevDevice(void) {
|
||||
m_Channel = 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;
|
||||
StartSectionHandler();
|
||||
cSchedules::Read();
|
||||
#endif
|
||||
isyslog("streamdev-client: got device number %d", CardIndex() + 1);
|
||||
|
||||
m_Device = this;
|
||||
m_Pids = 0;
|
||||
@ -61,11 +50,11 @@ cStreamdevDevice::~cStreamdevDevice() {
|
||||
|
||||
Cancel(3);
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
DELETENULL(m_Filters);
|
||||
#if APIVERSNUM >= 10515
|
||||
StopSectionHandler();
|
||||
#endif
|
||||
DELETENULL(m_Filters);
|
||||
DELETENULL(m_TSBuffer);
|
||||
delete m_Assembler;
|
||||
}
|
||||
|
||||
bool cStreamdevDevice::ProvidesSource(int Source) const {
|
||||
@ -93,8 +82,25 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
|
||||
bool res = false;
|
||||
bool prio = Priority < 0 || Priority > this->Priority();
|
||||
bool ndr = false;
|
||||
|
||||
if (!StreamdevClientSetup.StartClient)
|
||||
return false;
|
||||
|
||||
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
|
||||
&& TRANSPONDER(Channel, m_Channel))
|
||||
res = true;
|
||||
@ -117,23 +123,14 @@ bool cStreamdevDevice::SetChannelDevice(const cChannel *Channel,
|
||||
if (LiveView)
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
if (ClientSocket.DataSocket(siLive) != NULL
|
||||
&& TRANSPONDER(Channel, m_Channel))
|
||||
&& TRANSPONDER(Channel, m_Channel)
|
||||
&& Channel->Ca() < CA_ENCRYPTED_MIN)
|
||||
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
|
||||
|
||||
DetachAllReceivers();
|
||||
m_Channel = Channel;
|
||||
bool r = ClientSocket.SetChannelDevice(m_Channel);
|
||||
Dprintf("setchanneldevice r=%d\n", r);
|
||||
@ -212,16 +209,11 @@ void cStreamdevDevice::CloseDvrInt(void) {
|
||||
}
|
||||
|
||||
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)
|
||||
// TODO: Find a clean solution to fix this
|
||||
ClientSocket.SetChannelDevice(m_Channel);
|
||||
ClientSocket.CloseDvr();
|
||||
DELETENULL(m_TSBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cStreamdevDevice::CloseDvr(void) {
|
||||
@ -268,7 +260,6 @@ esyslog("cStreamDevice::GetTSPacket: GetChecked: NOTHING (%d)", m_TSFails);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
|
||||
Dprintf("OpenFilter\n");
|
||||
|
||||
@ -290,7 +281,6 @@ int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool cStreamdevDevice::Init(void) {
|
||||
if (m_Device == NULL && StreamdevClientSetup.StartClient)
|
||||
@ -308,7 +298,6 @@ bool cStreamdevDevice::ReInit(void) {
|
||||
ClientSocket.Reset();
|
||||
if (m_Device != NULL) {
|
||||
//DELETENULL(m_Device->m_TSBuffer);
|
||||
DELETENULL(m_Device->m_Assembler);
|
||||
m_Device->Unlock();
|
||||
}
|
||||
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
|
||||
@ -8,7 +8,6 @@
|
||||
#include <vdr/device.h>
|
||||
|
||||
#include "client/socket.h"
|
||||
#include "client/assembler.h"
|
||||
#include "client/filter.h"
|
||||
|
||||
class cTBString;
|
||||
@ -21,10 +20,7 @@ class cStreamdevDevice: public cDevice {
|
||||
private:
|
||||
const cChannel *m_Channel;
|
||||
cTSBuffer *m_TSBuffer;
|
||||
cStreamdevAssembler *m_Assembler;
|
||||
#if VDRVERSNUM >= 10307
|
||||
cStreamdevFilters *m_Filters;
|
||||
#endif
|
||||
int m_Pids;
|
||||
bool m_DvrClosed;
|
||||
|
||||
@ -47,14 +43,13 @@ protected:
|
||||
virtual void CloseDvr(void);
|
||||
virtual bool GetTSPacket(uchar *&Data);
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
||||
#endif
|
||||
|
||||
public:
|
||||
cStreamdevDevice(void);
|
||||
virtual ~cStreamdevDevice();
|
||||
|
||||
virtual bool HasInternalCam(void) { return true; }
|
||||
virtual bool ProvidesSource(int Source) const;
|
||||
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
||||
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"
|
||||
@ -9,8 +9,7 @@
|
||||
|
||||
#include <vdr/device.h>
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
|
||||
#define PID_MASK_HI 0x1F
|
||||
// --- cStreamdevFilter ------------------------------------------------------
|
||||
|
||||
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_char tid = block[3];
|
||||
bool Pusi = block[1] & 0x40;
|
||||
// proprietary extension
|
||||
int len = block[4];
|
||||
#if 0
|
||||
if (block[1] == 0xff &&
|
||||
@ -290,5 +290,3 @@ void cStreamdevFilters::Action(void) {
|
||||
DELETENULL(m_TSBuffer);
|
||||
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
|
||||
#define VDR_STREAMDEV_FILTER_H
|
||||
|
||||
#include <vdr/config.h>
|
||||
|
||||
# if VDRVERSNUM >= 10300
|
||||
|
||||
#include <vdr/tools.h>
|
||||
#include <vdr/thread.h>
|
||||
|
||||
@ -33,5 +30,4 @@ public:
|
||||
int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
||||
};
|
||||
|
||||
# endif // VDRVERSNUM >= 10300
|
||||
#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 "client/setup.h"
|
||||
#include "client/device.h"
|
||||
#include "i18n.h"
|
||||
|
||||
cStreamdevClientSetup StreamdevClientSetup;
|
||||
|
||||
cStreamdevClientSetup::cStreamdevClientSetup(void) {
|
||||
StartClient = false;
|
||||
RemotePort = 2004;
|
||||
#if VDRVERSNUM >= 10300
|
||||
StreamFilters = false;
|
||||
#endif
|
||||
SyncEPG = false;
|
||||
HideMenuEntry = false;
|
||||
MinPriority = -1;
|
||||
MaxPriority = MAXPRIORITY;
|
||||
strcpy(RemoteIp, "");
|
||||
}
|
||||
|
||||
@ -29,10 +29,11 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
|
||||
strcpy(RemoteIp, Value);
|
||||
}
|
||||
else if (strcmp(Name, "RemotePort") == 0) RemotePort = atoi(Value);
|
||||
#if VDRVERSNUM >= 10300
|
||||
else if (strcmp(Name, "StreamFilters") == 0) StreamFilters = atoi(Value);
|
||||
#endif
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
@ -40,13 +41,14 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
|
||||
cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(void) {
|
||||
m_NewSetup = StreamdevClientSetup;
|
||||
|
||||
AddBoolEdit (tr("Hide Mainmenu Entry"),m_NewSetup.HideMenuEntry);
|
||||
AddBoolEdit (tr("Start Client"), m_NewSetup.StartClient);
|
||||
AddIpEdit (tr("Remote IP"), m_NewSetup.RemoteIp);
|
||||
AddShortEdit(tr("Remote Port"), m_NewSetup.RemotePort);
|
||||
#if VDRVERSNUM >= 10300
|
||||
AddBoolEdit (tr("Filter Streaming"), m_NewSetup.StreamFilters);
|
||||
#endif
|
||||
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));
|
||||
}
|
||||
|
||||
@ -57,8 +59,6 @@ void cStreamdevClientMenuSetupPage::Store(void) {
|
||||
if (m_NewSetup.StartClient != StreamdevClientSetup.StartClient) {
|
||||
if (m_NewSetup.StartClient)
|
||||
cStreamdevDevice::Init();
|
||||
else
|
||||
INFO(tr("Please restart VDR to activate changes"));
|
||||
}
|
||||
|
||||
SetupStore("StartClient", m_NewSetup.StartClient);
|
||||
@ -67,10 +67,11 @@ void cStreamdevClientMenuSetupPage::Store(void) {
|
||||
else
|
||||
SetupStore("RemoteIp", m_NewSetup.RemoteIp);
|
||||
SetupStore("RemotePort", m_NewSetup.RemotePort);
|
||||
#if VDRVERSNUM >= 10300
|
||||
SetupStore("StreamFilters", m_NewSetup.StreamFilters);
|
||||
#endif
|
||||
SetupStore("SyncEPG", m_NewSetup.SyncEPG);
|
||||
SetupStore("HideMenuEntry", m_NewSetup.HideMenuEntry);
|
||||
SetupStore("MinPriority", m_NewSetup.MinPriority);
|
||||
SetupStore("MaxPriority", m_NewSetup.MaxPriority);
|
||||
|
||||
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
|
||||
@ -15,10 +15,11 @@ struct cStreamdevClientSetup {
|
||||
int StartClient;
|
||||
char RemoteIp[20];
|
||||
int RemotePort;
|
||||
#if VDRVERSNUM >= 10300
|
||||
int StreamFilters;
|
||||
#endif
|
||||
int SyncEPG;
|
||||
int HideMenuEntry;
|
||||
int MinPriority;
|
||||
int MaxPriority;
|
||||
};
|
||||
|
||||
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>
|
||||
@ -13,9 +13,7 @@
|
||||
|
||||
#include "client/socket.h"
|
||||
#include "client/setup.h"
|
||||
#include "client/remote.h"
|
||||
#include "common.h"
|
||||
#include "i18n.h"
|
||||
|
||||
cClientSocket ClientSocket;
|
||||
|
||||
@ -141,10 +139,8 @@ bool cClientSocket::CheckConnection(void) {
|
||||
}
|
||||
|
||||
const char *Filters = "";
|
||||
#if VDRVERSNUM >= 10300
|
||||
if(Command("CAPS FILTERS", 220))
|
||||
Filters = ",FILTERS";
|
||||
#endif
|
||||
|
||||
isyslog("Streamdev: Connected to server %s:%d using capabilities TSPIDS%s",
|
||||
RemoteIp().c_str(), RemotePort(), Filters);
|
||||
@ -270,7 +266,6 @@ bool cClientSocket::SetPid(int Pid, bool On) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
|
||||
if (!CheckConnection()) return false;
|
||||
|
||||
@ -286,7 +281,6 @@ bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool cClientSocket::CloseDvr(void) {
|
||||
if (!CheckConnection()) return false;
|
||||
@ -342,11 +336,7 @@ bool cClientSocket::SynchronizeEPG(void) {
|
||||
|
||||
rewind(epgfd);
|
||||
if (cSchedules::Read(epgfd))
|
||||
#if VDRVERSNUM < 10300
|
||||
cSIProcessor::TriggerDump();
|
||||
#else
|
||||
cSchedules::Cleanup(true);
|
||||
#endif
|
||||
else {
|
||||
esyslog("ERROR: Streamdev: Parsing EPG data failed");
|
||||
fclose(epgfd);
|
||||
@ -370,128 +360,6 @@ bool cClientSocket::Quit(void) {
|
||||
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) {
|
||||
if (!CheckConnection()) return false;
|
||||
|
||||
@ -504,108 +372,3 @@ bool cClientSocket::SuspendServer(void) {
|
||||
}
|
||||
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
|
||||
@ -13,10 +13,6 @@
|
||||
|
||||
#define CMD_LOCK cMutexLock CmdLock((cMutex*)&m_Mutex)
|
||||
|
||||
class cRemoteRecordings;
|
||||
class cRemoteRecording;
|
||||
class cRemoteTimers;
|
||||
class cRemoteTimer;
|
||||
class cPES2TSRemux;
|
||||
|
||||
class cClientSocket: public cTBSocket {
|
||||
@ -50,18 +46,9 @@ public:
|
||||
bool CloseDataConnection(eSocketId Id);
|
||||
bool SetChannelDevice(const cChannel *Channel);
|
||||
bool SetPid(int Pid, bool On);
|
||||
#if VDRVERSNUM >= 10300
|
||||
bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On);
|
||||
#endif
|
||||
bool CloseDvr(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 Quit(void);
|
||||
|
||||
|
22
common.c
22
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>
|
||||
@ -7,15 +7,16 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "tools/select.h"
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const char *VERSION = "0.3.4";
|
||||
const char *VERSION = "0.5.0-pre-20090611";
|
||||
|
||||
const char *StreamTypes[st_Count] = {
|
||||
"TS",
|
||||
#if APIVERSNUM < 10703
|
||||
"PES",
|
||||
#endif
|
||||
"PS",
|
||||
"ES",
|
||||
"Extern",
|
||||
@ -23,9 +24,9 @@ const char *StreamTypes[st_Count] = {
|
||||
};
|
||||
|
||||
const char *SuspendModes[sm_Count] = {
|
||||
"Offer suspend mode",
|
||||
"Always suspended",
|
||||
"Never suspended"
|
||||
trNOOP("Offer suspend mode"),
|
||||
trNOOP("Always suspended"),
|
||||
trNOOP("Never suspended")
|
||||
};
|
||||
|
||||
const char IpCharacters[] = "0123456789.";
|
||||
@ -113,16 +114,7 @@ void cStreamdevMenuSetupPage::AddCategory(const char *Title) {
|
||||
|
||||
cOsdItem *item = new cOsdItem(buffer);
|
||||
free(buffer);
|
||||
|
||||
#if VDRVERSNUM < 10307
|
||||
# ifdef HAVE_BEAUTYPATCH
|
||||
item->SetColor(clrScrolLine, clrBackground);
|
||||
# else
|
||||
item->SetColor(clrCyan, clrBackground);
|
||||
# endif
|
||||
#else
|
||||
item->SetSelectable(false);
|
||||
#endif
|
||||
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
|
||||
@ -23,27 +23,9 @@
|
||||
# define Dprintf(x...)
|
||||
#endif
|
||||
|
||||
#if VDRVERSNUM < 10300
|
||||
# define TRANSPONDER(c1, c2) (ISTRANSPONDER(c1->Frequency(), c2->Frequency()))
|
||||
#else
|
||||
# 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)
|
||||
#endif
|
||||
|
||||
/* Check if a channel is a radio station. */
|
||||
#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 {
|
||||
stTS,
|
||||
#if APIVERSNUM < 10703
|
||||
stPES,
|
||||
#endif
|
||||
stPS,
|
||||
stES,
|
||||
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.
|
||||
CFLAGS = -g -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fPIC
|
||||
MFLAG = -M
|
||||
OBJS = ctools.o ringbuffy.o remux.o transform.o cpptools.o
|
||||
OBJS = ctools.o ringbuffy.o remux.o transform.o
|
||||
SRC = $(wildcard *.c)
|
||||
CPPSRC = $(wildcard *.cpp)
|
||||
CSRC = $(wildcard *.cc)
|
||||
|
||||
DESTDIR = /usr/local
|
||||
|
||||
.PHONY: depend clean install uninstall
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
- rm -f *.o *~ *.a .depend
|
||||
@ -16,17 +14,11 @@ clean:
|
||||
libdvbmpegtools.a: $(OBJS)
|
||||
ar -rcs libdvbmpegtools.a $(OBJS)
|
||||
|
||||
%.o: %.cc
|
||||
$(CXX) -c $(CFLAGS) $(INCS) $(DEFINES) $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CFLAGS) $(INCS) $(DEFINES) $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $(INCS) $(DEFINES) $<
|
||||
|
||||
.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 "server/server.h"
|
||||
#include "server/streamer.h"
|
||||
#include <vdr/tools.h>
|
||||
#include <sys/types.h>
|
||||
@ -6,8 +7,6 @@
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char *g_ExternRemux = "/root/externremux.sh";
|
||||
|
||||
class cTSExt: public cThread {
|
||||
private:
|
||||
cRingBufferLinear *m_ResultBuffer;
|
||||
@ -28,7 +27,7 @@ public:
|
||||
cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter):
|
||||
m_ResultBuffer(ResultBuffer),
|
||||
m_Active(false),
|
||||
m_Process(0),
|
||||
m_Process(-1),
|
||||
m_Inpipe(0),
|
||||
m_Outpipe(0)
|
||||
{
|
||||
@ -67,10 +66,14 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter):
|
||||
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
||||
close(i); //close all dup'ed filedescriptors
|
||||
|
||||
std::string cmd = std::string(g_ExternRemux) + " " + Parameter;
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
|
||||
std::string cmd = std::string(opt_remux) + " " + Parameter;
|
||||
if (execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL) == -1) {
|
||||
esyslog("streamdev-server: externremux script '%s' execution failed: %m", cmd.c_str());
|
||||
_exit(-1);
|
||||
}
|
||||
// should never be reached
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
close(inpipe[0]);
|
||||
close(outpipe[1]);
|
||||
@ -84,16 +87,31 @@ cTSExt::~cTSExt()
|
||||
m_Active = false;
|
||||
Cancel(3);
|
||||
if (m_Process > 0) {
|
||||
// close pipes
|
||||
close(m_Outpipe);
|
||||
close(m_Inpipe);
|
||||
kill(m_Process, SIGTERM);
|
||||
for (int i = 0; waitpid(m_Process, NULL, WNOHANG) == 0; i++) {
|
||||
if (i == 20) {
|
||||
// signal and wait for termination
|
||||
if (kill(m_Process, SIGINT) < 0) {
|
||||
esyslog("streamdev-server: externremux SIGINT failed: %m");
|
||||
}
|
||||
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 <string>
|
||||
|
||||
extern const char *g_ExternRemux;
|
||||
|
||||
class cTSExt;
|
||||
|
||||
class cExternRemux: public cTSRemux {
|
||||
|
@ -5,6 +5,10 @@
|
||||
#include <vdr/remux.h>
|
||||
#include <vdr/ringbuffer.h>
|
||||
|
||||
#ifndef MAXTRACKS
|
||||
#define MAXTRACKS 64
|
||||
#endif
|
||||
|
||||
class cTS2PS;
|
||||
|
||||
class cTS2PSRemux: public cTSRemux {
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "remux/tsremux.h"
|
||||
|
||||
#define SC_PICTURE 0x00 // "picture header"
|
||||
#define PID_MASK_HI 0x1F
|
||||
|
||||
void cTSRemux::SetBrokenLink(uchar *Data, int Length)
|
||||
{
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include "libdvbmpeg/transform.h"
|
||||
#include <vdr/remux.h>
|
||||
|
||||
#ifndef NO_PICTURE
|
||||
#define NO_PICTURE 0
|
||||
#endif
|
||||
|
||||
#define RESULTBUFFERSIZE KILOBYTE(256)
|
||||
|
||||
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/connection.h"
|
||||
|
||||
cServerComponent::cServerComponent(const char *Protocol, const char *ListenIp,
|
||||
uint ListenPort):
|
||||
uint ListenPort, int Type, int IpProto):
|
||||
m_Protocol(Protocol),
|
||||
m_Listen(Type, IpProto),
|
||||
m_ListenIp(ListenIp),
|
||||
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
|
||||
@ -17,8 +17,8 @@ class cServerConnection;
|
||||
|
||||
class cServerComponent: public cListObject {
|
||||
private:
|
||||
cTBSocket m_Listen;
|
||||
const char *m_Protocol;
|
||||
cTBSocket m_Listen;
|
||||
const char *m_ListenIp;
|
||||
uint m_ListenPort;
|
||||
|
||||
@ -27,7 +27,7 @@ protected:
|
||||
virtual cServerConnection *NewClient(void) = 0;
|
||||
|
||||
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();
|
||||
|
||||
/* 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"
|
||||
@ -12,7 +12,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
cServerConnection::cServerConnection(const char *Protocol):
|
||||
cServerConnection::cServerConnection(const char *Protocol, int Type):
|
||||
cTBSocket(Type),
|
||||
m_Protocol(Protocol),
|
||||
m_DeferClose(false),
|
||||
m_Pending(false),
|
||||
@ -139,11 +140,7 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
|
||||
Dprintf(" * GetDevice(const cChannel*, int)\n");
|
||||
Dprintf(" * -------------------------------\n");
|
||||
|
||||
#if VDRVERSNUM < 10500
|
||||
device = cDevice::GetDevice(Channel, Priority);
|
||||
#else
|
||||
device = cDevice::GetDevice(Channel, Priority, false);
|
||||
#endif
|
||||
|
||||
Dprintf(" * Found following device: %p (%d)\n", device,
|
||||
device ? device->CardIndex() + 1 : 0);
|
||||
@ -161,11 +158,7 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
|
||||
const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||
isyslog("streamdev-server: Detaching current receiver");
|
||||
Detach();
|
||||
#if VDRVERSNUM < 10500
|
||||
device = cDevice::GetDevice(Channel, Priority);
|
||||
#else
|
||||
device = cDevice::GetDevice(Channel, Priority, false);
|
||||
#endif
|
||||
Attach();
|
||||
Dprintf(" * Found following device: %p (%d)\n", device,
|
||||
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
|
||||
@ -44,9 +44,12 @@ protected:
|
||||
public:
|
||||
/* If you derive, specify a short string such as HTTP for Protocol, which
|
||||
will be displayed in error messages */
|
||||
cServerConnection(const char *Protocol);
|
||||
cServerConnection(const char *Protocol, int Type = SOCK_STREAM);
|
||||
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 */
|
||||
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 "server/connectionHTTP.h"
|
||||
#include "server/menuHTTP.h"
|
||||
#include "server/server.h"
|
||||
#include "server/setup.h"
|
||||
|
||||
cConnectionHTTP::cConnectionHTTP(void):
|
||||
@ -26,6 +27,11 @@ cConnectionHTTP::~cConnectionHTTP()
|
||||
delete m_LiveStreamer;
|
||||
}
|
||||
|
||||
bool cConnectionHTTP::CanAuthenticate(void)
|
||||
{
|
||||
return opt_auth != NULL;
|
||||
}
|
||||
|
||||
bool cConnectionHTTP::Command(char *Cmd)
|
||||
{
|
||||
Dprintf("command %s\n", Cmd);
|
||||
@ -44,10 +50,22 @@ bool cConnectionHTTP::Command(char *Cmd)
|
||||
if (strncasecmp(Cmd, "Host:", 5) == 0) {
|
||||
Dprintf("Host-Header\n");
|
||||
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");
|
||||
return true;
|
||||
default:
|
||||
// skip additional blank lines
|
||||
if (*Cmd == '\0')
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false; // ??? shouldn't happen
|
||||
@ -56,6 +74,16 @@ bool cConnectionHTTP::Command(char *Cmd)
|
||||
bool cConnectionHTTP::ProcessRequest(void)
|
||||
{
|
||||
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))) {
|
||||
switch (m_Job) {
|
||||
case hjListing:
|
||||
@ -183,8 +211,10 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts)
|
||||
const char* pType = type.c_str();
|
||||
if (strcasecmp(pType, "PS") == 0) {
|
||||
m_StreamType = stPS;
|
||||
#if APIVERSNUM < 10703
|
||||
} else if (strcasecmp(pType, "PES") == 0) {
|
||||
m_StreamType = stPES;
|
||||
#endif
|
||||
} else if (strcasecmp(pType, "TS") == 0) {
|
||||
m_StreamType = stTS;
|
||||
} else if (strcasecmp(pType, "ES") == 0) {
|
||||
@ -236,7 +266,9 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts)
|
||||
{
|
||||
case stTS: base += "TS/"; break;
|
||||
case stPS: base += "PS/"; break;
|
||||
#if APIVERSNUM < 10703
|
||||
case stPES: base += "PES/"; break;
|
||||
#endif
|
||||
case stES: base += "ES/"; break;
|
||||
case stExtern: base += "Extern/"; 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
|
||||
@ -30,6 +30,7 @@ private:
|
||||
|
||||
std::string m_Request;
|
||||
std::string m_Host;
|
||||
std::string m_Authorization;
|
||||
//std::map<std::string,std::string> m_Headers; TODO: later?
|
||||
eHTTPStatus m_Status;
|
||||
eHTTPJob m_Job;
|
||||
@ -52,6 +53,8 @@ public:
|
||||
virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
|
||||
virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
|
||||
|
||||
virtual bool CanAuthenticate(void);
|
||||
|
||||
virtual bool Command(char *Cmd);
|
||||
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"
|
||||
@ -595,17 +595,18 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
|
||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||
}
|
||||
|
||||
#if APIVERSNUM < 10703
|
||||
if (strcasecmp(Opts, "PES") == 0) {
|
||||
m_StreamType = stPES;
|
||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strcasecmp(Opts, "EXTERN") == 0) {
|
||||
m_StreamType = stExtern;
|
||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||
}
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
//
|
||||
// Deliver section filters data in separate, channel-independent data stream
|
||||
//
|
||||
@ -613,7 +614,6 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
|
||||
m_FiltersSupport = true;
|
||||
return Respond(220, "Capability \"%s\" accepted", Opts);
|
||||
}
|
||||
#endif
|
||||
|
||||
return Respond(561, "Capability \"%s\" not known", Opts);
|
||||
}
|
||||
@ -648,13 +648,8 @@ bool cConnectionVTP::CmdPORT(char *Opts)
|
||||
if (ep == Opts || !isspace(*ep))
|
||||
return Respond(500, "Use: PORT Id Destination");
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
if (id != siLive && id != siLiveFilter)
|
||||
return Respond(501, "Wrong connection id %d", id);
|
||||
#else
|
||||
if (id != siLive)
|
||||
return Respond(501, "Wrong connection id %d", id);
|
||||
#endif
|
||||
|
||||
Opts = skipspace(ep);
|
||||
n = 0;
|
||||
@ -681,7 +676,6 @@ bool cConnectionVTP::CmdPORT(char *Opts)
|
||||
|
||||
isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport);
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
if (id == siLiveFilter) {
|
||||
m_FiltersSupport = true;
|
||||
if(m_FilterStreamer)
|
||||
@ -703,7 +697,6 @@ bool cConnectionVTP::CmdPORT(char *Opts)
|
||||
|
||||
return Respond(220, "Port command ok, data connection opened");
|
||||
}
|
||||
#endif
|
||||
|
||||
if(m_LiveSocket && m_LiveStreamer)
|
||||
m_LiveStreamer->Stop();
|
||||
@ -746,14 +739,12 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
|
||||
if(m_LiveSocket)
|
||||
m_LiveStreamer->Start(m_LiveSocket);
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
if(m_FiltersSupport) {
|
||||
if(!m_FilterStreamer)
|
||||
m_FilterStreamer = new cStreamdevFilterStreamer;
|
||||
m_FilterStreamer->SetDevice(dev);
|
||||
//m_FilterStreamer->SetChannel(chan);
|
||||
}
|
||||
#endif
|
||||
|
||||
return Respond(220, "Channel tuned");
|
||||
}
|
||||
@ -788,7 +779,6 @@ bool cConnectionVTP::CmdDELP(char *Opts)
|
||||
|
||||
bool cConnectionVTP::CmdADDF(char *Opts)
|
||||
{
|
||||
#if VDRVERSNUM >= 10300
|
||||
int pid, tid, mask;
|
||||
char *ep;
|
||||
|
||||
@ -810,14 +800,10 @@ bool cConnectionVTP::CmdADDF(char *Opts)
|
||||
return m_FilterStreamer->SetFilter(pid, tid, mask, true)
|
||||
? Respond(220, "Filter %d transferring", 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)
|
||||
{
|
||||
#if VDRVERSNUM >= 10307
|
||||
int pid, tid, mask;
|
||||
char *ep;
|
||||
|
||||
@ -838,9 +824,6 @@ bool cConnectionVTP::CmdDELF(char *Opts)
|
||||
|
||||
m_FilterStreamer->SetFilter(pid, tid, mask, false);
|
||||
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)
|
||||
@ -857,12 +840,10 @@ bool cConnectionVTP::CmdABRT(char *Opts)
|
||||
DELETENULL(m_LiveStreamer);
|
||||
DELETENULL(m_LiveSocket);
|
||||
break;
|
||||
#if VDRVERSNUM >= 10300
|
||||
case siLiveFilter:
|
||||
DELETENULL(m_FilterStreamer);
|
||||
DELETENULL(m_FilterSocket);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return Respond(501, "Wrong connection id %d", id);
|
||||
break;
|
||||
|
@ -12,9 +12,9 @@ class cLSTTHandler;
|
||||
|
||||
class cConnectionVTP: public cServerConnection {
|
||||
friend class cLSTEHandler;
|
||||
// if your compiler doesn't understand the following statement
|
||||
// (e.g. gcc 2.x), simply remove it and try again ;-)
|
||||
#if !defined __GNUC__ || __GNUC__ >= 3
|
||||
using cServerConnection::Respond;
|
||||
#endif
|
||||
|
||||
private:
|
||||
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/streamer.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef TS_SIZE
|
||||
# define TS_SIZE 188
|
||||
#endif
|
||||
#ifndef TS_SYNC_BYTE
|
||||
# define TS_SYNC_BYTE 0x47
|
||||
#endif
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
|
||||
cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevStreamer *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[2] = Pid & 0xff;
|
||||
buffer[3] = Tid;
|
||||
// this makes it a proprietary stream
|
||||
buffer[4] = (uchar)chunk;
|
||||
memcpy(buffer + 5, Data + pos, 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);
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
#include <vdr/config.h>
|
||||
|
||||
# if VDRVERSNUM >= 10300
|
||||
|
||||
#include <vdr/filter.h>
|
||||
|
||||
class cStreamdevStreamer;
|
||||
@ -31,5 +29,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
# endif // VDRVERSNUM >= 10300
|
||||
#endif // VDR_STREAMEV_LIVEFILTER_H
|
||||
|
@ -3,13 +3,14 @@
|
||||
#include <libsi/section.h>
|
||||
#include <libsi/descriptor.h>
|
||||
|
||||
#include "remux/ts2ps.h"
|
||||
#include "remux/ts2es.h"
|
||||
#include "remux/extern.h"
|
||||
|
||||
#include <vdr/ringbuffer.h>
|
||||
|
||||
#include "server/livestreamer.h"
|
||||
#include "server/livefilter.h"
|
||||
#include "remux/ts2ps.h"
|
||||
#include "remux/ts2es.h"
|
||||
#include "remux/extern.h"
|
||||
#include "common.h"
|
||||
|
||||
#define TSPATREPACKER
|
||||
@ -27,23 +28,13 @@ protected:
|
||||
virtual void Receive(uchar *Data, int Length);
|
||||
|
||||
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);
|
||||
#endif
|
||||
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,
|
||||
int Priority, const int *Pids):
|
||||
cReceiver(ChannelID, Priority, 0, Pids),
|
||||
#endif
|
||||
m_Streamer(Streamer)
|
||||
{
|
||||
}
|
||||
@ -86,7 +77,7 @@ public:
|
||||
|
||||
cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel)
|
||||
{
|
||||
Dprintf("cStreamdevPatFilter(\"%s\")", Channel->Name());
|
||||
Dprintf("cStreamdevPatFilter(\"%s\")\n", Channel->Name());
|
||||
assert(Streamer);
|
||||
m_Channel = Channel;
|
||||
m_Streamer = Streamer;
|
||||
@ -145,7 +136,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
|
||||
case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4)
|
||||
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)
|
||||
Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)",
|
||||
Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)\n",
|
||||
stream.getPid(), psStreamTypes[stream.getStreamType()]);
|
||||
return stream.getPid();
|
||||
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)); ) {
|
||||
switch (d->getDescriptorTag()) {
|
||||
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");
|
||||
return stream.getPid();
|
||||
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");
|
||||
return stream.getPid();
|
||||
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");
|
||||
return stream.getPid();
|
||||
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");
|
||||
break;
|
||||
}
|
||||
@ -210,7 +201,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
|
||||
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");
|
||||
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)
|
||||
{
|
||||
if (Pid == 0x00) {
|
||||
if (Tid == 0x00 && !pmtPid) {
|
||||
if (Tid == 0x00) {
|
||||
SI::PAT pat(Data, false);
|
||||
if (!pat.CheckCRCAndParse())
|
||||
return;
|
||||
@ -229,8 +220,9 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
||||
if (!assoc.isNITPid()) {
|
||||
const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
|
||||
if (Channel && (Channel == m_Channel)) {
|
||||
int prevPmtPid = pmtPid;
|
||||
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();
|
||||
if (Length < TS_SIZE-5) {
|
||||
// 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;
|
||||
unsigned int crc, i, len;
|
||||
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, 0x0, 4 + 12 + 5); // TS_HDR_LEN + PAT_TABLE_LEN + 5
|
||||
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[1] = 0x40; // Set payload unit start indicator bit
|
||||
tspat_buf[2] = 0x0; // PID
|
||||
tspat_buf[3] = 0x10; // Set payload flag to indicate precence of payload data
|
||||
tspat_buf[4] = 0x0; // PSI
|
||||
tspat_buf[3] = 0x10 | ccounter; // Set payload flag, Continuity counter
|
||||
tspat_buf[4] = 0x0; // SI pointer field
|
||||
tspat_buf[5] = 0x0; // PAT table id
|
||||
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[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[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[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[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)
|
||||
crc = 0xffffffff;
|
||||
len = 12; // PAT_TABLE_LEN
|
||||
@ -278,9 +272,11 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
||||
#endif
|
||||
} else
|
||||
isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length);
|
||||
if (pmtPid != prevPmtPid) {
|
||||
m_Streamer->SetPids(pmtPid);
|
||||
Add(pmtPid, 0x02);
|
||||
pmtVersion = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -295,7 +291,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
||||
return; // skip broken PMT records
|
||||
if (pmtVersion != -1) {
|
||||
if (pmtVersion != pmt.getVersionNumber()) {
|
||||
Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids");
|
||||
Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids\n");
|
||||
Del(pmtPid, 0x02);
|
||||
pmtPid = 0; // this triggers PAT scan
|
||||
}
|
||||
@ -333,7 +329,9 @@ cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Paramet
|
||||
m_Device(NULL),
|
||||
m_Receiver(NULL),
|
||||
m_PatFilter(NULL),
|
||||
#if APIVERSNUM < 10703
|
||||
m_PESRemux(NULL),
|
||||
#endif
|
||||
m_ESRemux(NULL),
|
||||
m_PSRemux(NULL),
|
||||
m_ExtRemux(NULL)
|
||||
@ -349,7 +347,9 @@ cStreamdevLiveStreamer::~cStreamdevLiveStreamer()
|
||||
DELETENULL(m_PatFilter);
|
||||
}
|
||||
DELETENULL(m_Receiver);
|
||||
#if APIVERSNUM < 10703
|
||||
delete m_PESRemux;
|
||||
#endif
|
||||
delete m_ESRemux;
|
||||
delete m_PSRemux;
|
||||
delete m_ExtRemux;
|
||||
@ -434,11 +434,7 @@ void cStreamdevLiveStreamer::StartReceiver(void)
|
||||
DELETENULL(m_Receiver);
|
||||
if (m_NumPids > 0) {
|
||||
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);
|
||||
#endif
|
||||
if (IsRunning() && m_Device != NULL) {
|
||||
Dprintf("Attaching new receiver\n");
|
||||
Attach();
|
||||
@ -467,10 +463,12 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
|
||||
return SetPids(pid);
|
||||
}
|
||||
|
||||
#if APIVERSNUM < 10703
|
||||
case stPES:
|
||||
m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
|
||||
m_Channel->Spids(), false);
|
||||
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
|
||||
#endif
|
||||
|
||||
case stPS:
|
||||
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();
|
||||
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
|
||||
m_PatFilter = new cStreamdevPatFilter(this, m_Channel);
|
||||
return true;
|
||||
@ -506,8 +508,10 @@ int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
|
||||
case stTSPIDS:
|
||||
return cStreamdevStreamer::Put(Data, Count);
|
||||
|
||||
#if APIVERSNUM < 10703
|
||||
case stPES:
|
||||
return m_PESRemux->Put(Data, Count);
|
||||
#endif
|
||||
|
||||
case stES:
|
||||
return m_ESRemux->Put(Data, Count);
|
||||
@ -530,8 +534,10 @@ uchar *cStreamdevLiveStreamer::Get(int &Count)
|
||||
case stTSPIDS:
|
||||
return cStreamdevStreamer::Get(Count);
|
||||
|
||||
#if APIVERSNUM < 10703
|
||||
case stPES:
|
||||
return m_PESRemux->Get(Count);
|
||||
#endif
|
||||
|
||||
case stES:
|
||||
return m_ESRemux->Get(Count);
|
||||
@ -555,9 +561,11 @@ void cStreamdevLiveStreamer::Del(int Count)
|
||||
cStreamdevStreamer::Del(Count);
|
||||
break;
|
||||
|
||||
#if APIVERSNUM < 10703
|
||||
case stPES:
|
||||
m_PESRemux->Del(Count);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case stES:
|
||||
m_ESRemux->Del(Count);
|
||||
@ -618,7 +626,6 @@ std::string cStreamdevLiveStreamer::Report(void)
|
||||
|
||||
// --- cStreamdevFilterStreamer -------------------------------------------------
|
||||
|
||||
#if VDRVERSNUM >= 10300
|
||||
cStreamdevFilterStreamer::cStreamdevFilterStreamer():
|
||||
cStreamdevStreamer("streamdev-filterstreaming"),
|
||||
m_Device(NULL),
|
||||
@ -720,5 +727,3 @@ void cStreamdevFilterStreamer::ChannelSwitch(const cDevice *Device, int ChannelN
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // if VDRVERSNUM >= 10300
|
||||
|
@ -10,7 +10,9 @@
|
||||
class cTS2PSRemux;
|
||||
class cTS2ESRemux;
|
||||
class cExternRemux;
|
||||
#if APIVERSNUM < 10703
|
||||
class cRemux;
|
||||
#endif
|
||||
class cStreamdevPatFilter;
|
||||
class cStreamdevLiveReceiver;
|
||||
|
||||
@ -27,7 +29,9 @@ private:
|
||||
cDevice *m_Device;
|
||||
cStreamdevLiveReceiver *m_Receiver;
|
||||
cStreamdevPatFilter *m_PatFilter;
|
||||
#if APIVERSNUM < 10703
|
||||
cRemux *m_PESRemux;
|
||||
#endif
|
||||
cTS2ESRemux *m_ESRemux;
|
||||
cTS2PSRemux *m_PSRemux;
|
||||
cExternRemux *m_ExtRemux;
|
||||
@ -58,8 +62,6 @@ public:
|
||||
|
||||
// --- cStreamdevFilterStreamer -------------------------------------------------
|
||||
|
||||
# if VDRVERSNUM >= 10300
|
||||
|
||||
//#include <vdr/status.h>
|
||||
|
||||
class cStreamdevLiveFilter;
|
||||
@ -85,6 +87,4 @@ public:
|
||||
//virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
|
||||
};
|
||||
|
||||
# endif // if VDRVERSNUM >= 10300
|
||||
|
||||
#endif // VDR_STREAMDEV_LIVESTREAMER_H
|
||||
|
@ -112,10 +112,10 @@ const cChannel* cChannelList::GetGroup(int Index)
|
||||
|
||||
// ******************** cHtmlChannelList ******************
|
||||
const char* cHtmlChannelList::menu =
|
||||
"[<a href=\"/\">Home</a> (<a href=\"all.html\">no script</a>)] "
|
||||
"[<a href=\"tree.html\">Tree View</a>] "
|
||||
"[<a href=\"groups.html\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] "
|
||||
"[<a href=\"channels.html\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] ";
|
||||
"[<a href=\"/\">Home</a> (<a href=\"all.html\" tvid=\"RED\">no script</a>)] "
|
||||
"[<a href=\"tree.html\" tvid=\"GREEN\">Tree View</a>] "
|
||||
"[<a href=\"groups.html\" tvid=\"YELLOW\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] "
|
||||
"[<a href=\"channels.html\" tvid=\"BLUE\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] ";
|
||||
|
||||
const char* cHtmlChannelList::css =
|
||||
"<style type=\"text/css\">\n"
|
||||
@ -201,8 +201,10 @@ std::string cHtmlChannelList::StreamTypeMenu()
|
||||
(std::string) "[<a href=\"/TS/" + self + "\">TS</a>] ");
|
||||
typeMenu += (streamType == stPS ? (std::string) "[PS] " :
|
||||
(std::string) "[<a href=\"/PS/" + self + "\">PS</a>] ");
|
||||
#if APIVERSNUM < 10703
|
||||
typeMenu += (streamType == stPES ? (std::string) "[PES] " :
|
||||
(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
|
||||
#endif
|
||||
typeMenu += (streamType == stES ? (std::string) "[ES] " :
|
||||
(std::string) "[<a href=\"/ES/" + self + "\">ES</a>] ");
|
||||
typeMenu += (streamType == stExtern ? (std::string) "[Extern] " :
|
||||
@ -336,9 +338,26 @@ std::string cHtmlChannelList::GroupTitle()
|
||||
std::string cHtmlChannelList::ItemText()
|
||||
{
|
||||
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) "<a href=\"" + (std::string) current->GetChannelID().ToString() + "\">" +
|
||||
current->Name() + "</a>";
|
||||
line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + suffix + "\"";
|
||||
|
||||
// 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;
|
||||
for (int i = 0; current->Apid(i) != 0; ++i, ++count)
|
||||
@ -351,11 +370,11 @@ std::string cHtmlChannelList::ItemText()
|
||||
int index = 1;
|
||||
for (int i = 0; current->Apid(i) != 0; ++i, ++index) {
|
||||
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) {
|
||||
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>";
|
||||
@ -364,10 +383,8 @@ std::string cHtmlChannelList::ItemText()
|
||||
|
||||
// ******************** cM3uChannelList ******************
|
||||
cM3uChannelList::cM3uChannelList(cChannelIterator *Iterator, const char* Base)
|
||||
: cChannelList(Iterator)
|
||||
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
|
||||
, m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
|
||||
#endif
|
||||
: cChannelList(Iterator),
|
||||
m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
|
||||
{
|
||||
base = strdup(Base);
|
||||
m3uState = msFirst;
|
||||
@ -398,11 +415,7 @@ std::string cM3uChannelList::Next()
|
||||
return "";
|
||||
}
|
||||
|
||||
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
|
||||
std::string name = (std::string) m_IConv.Convert(channel->Name());
|
||||
#else
|
||||
std::string name = channel->Name();
|
||||
#endif
|
||||
|
||||
if (channel->GroupSep())
|
||||
{
|
||||
|
@ -126,9 +126,7 @@ class cM3uChannelList: public cChannelList
|
||||
char *base;
|
||||
enum eM3uState { msFirst, msContinue, msLast };
|
||||
eM3uState m3uState;
|
||||
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
|
||||
cCharSetConv m_IConv;
|
||||
#endif
|
||||
public:
|
||||
virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl\r\n"; };
|
||||
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/componentVTP.h"
|
||||
#include "server/componentHTTP.h"
|
||||
#include "server/componentIGMP.h"
|
||||
#include "server/setup.h"
|
||||
|
||||
#include <vdr/tools.h>
|
||||
@ -13,14 +14,15 @@
|
||||
#include <errno.h>
|
||||
|
||||
cSVDRPhosts StreamdevHosts;
|
||||
char *opt_auth = NULL;
|
||||
char *opt_remux = NULL;
|
||||
|
||||
cStreamdevServer *cStreamdevServer::m_Instance = NULL;
|
||||
cList<cServerComponent> cStreamdevServer::m_Servers;
|
||||
cList<cServerConnection> cStreamdevServer::m_Clients;
|
||||
|
||||
cStreamdevServer::cStreamdevServer(void):
|
||||
cThread("streamdev server"),
|
||||
m_Active(false)
|
||||
cThread("streamdev server")
|
||||
{
|
||||
Start();
|
||||
}
|
||||
@ -35,6 +37,12 @@ void cStreamdevServer::Initialize(void)
|
||||
if (m_Instance == NULL) {
|
||||
if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP);
|
||||
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;
|
||||
}
|
||||
@ -47,11 +55,9 @@ void cStreamdevServer::Destruct(void)
|
||||
|
||||
void cStreamdevServer::Stop(void)
|
||||
{
|
||||
if (m_Active) {
|
||||
m_Active = false;
|
||||
if (Running())
|
||||
Cancel(3);
|
||||
}
|
||||
}
|
||||
|
||||
void cStreamdevServer::Register(cServerComponent *Server)
|
||||
{
|
||||
@ -60,8 +66,6 @@ void cStreamdevServer::Register(cServerComponent *Server)
|
||||
|
||||
void cStreamdevServer::Action(void)
|
||||
{
|
||||
m_Active = true;
|
||||
|
||||
/* Initialize Server components, deleting those that failed */
|
||||
for (cServerComponent *c = m_Servers.First(); c;) {
|
||||
cServerComponent *next = m_Servers.Next(c);
|
||||
@ -72,11 +76,11 @@ void cStreamdevServer::Action(void)
|
||||
|
||||
if (m_Servers.Count() == 0) {
|
||||
esyslog("ERROR: no streamdev server activated, exiting");
|
||||
m_Active = false;
|
||||
Cancel(-1);
|
||||
}
|
||||
|
||||
cTBSelect select;
|
||||
while (m_Active) {
|
||||
while (Running()) {
|
||||
select.Clear();
|
||||
|
||||
/* Ask all Server components to register to the selector */
|
||||
@ -102,9 +106,9 @@ void cStreamdevServer::Action(void)
|
||||
sel = 0;
|
||||
}
|
||||
}
|
||||
} while (sel < 0 && errno == ETIMEDOUT && m_Active);
|
||||
} while (sel < 0 && errno == ETIMEDOUT && Running());
|
||||
|
||||
if (!m_Active)
|
||||
if (!Running())
|
||||
break;
|
||||
if (sel < 0) {
|
||||
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)){
|
||||
if (sel && select.CanRead(c->Socket())) {
|
||||
cServerConnection *client = c->Accept();
|
||||
if (!client)
|
||||
continue;
|
||||
m_Clients.Add(client);
|
||||
|
||||
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
|
||||
esyslog("streamdev: too many clients, rejecting %s:%d",
|
||||
client->RemoteIp().c_str(), client->RemotePort());
|
||||
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",
|
||||
client->RemoteIp().c_str(), client->RemotePort());
|
||||
client->Reject();
|
||||
@ -164,6 +170,4 @@ void cStreamdevServer::Action(void)
|
||||
c->Destruct();
|
||||
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
|
||||
@ -10,12 +10,14 @@
|
||||
#include "server/component.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 {
|
||||
private:
|
||||
bool m_Active;
|
||||
|
||||
static cStreamdevServer *m_Instance;
|
||||
static cList<cServerComponent> m_Servers;
|
||||
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 "server/setup.h"
|
||||
#include "server/server.h"
|
||||
#include "i18n.h"
|
||||
|
||||
cStreamdevServerSetup StreamdevServerSetup;
|
||||
|
||||
@ -16,11 +15,15 @@ cStreamdevServerSetup::cStreamdevServerSetup(void) {
|
||||
VTPServerPort = 2004;
|
||||
StartHTTPServer = true;
|
||||
HTTPServerPort = 3000;
|
||||
HTTPStreamType = stPES;
|
||||
SuspendMode = smOffer;
|
||||
HTTPStreamType = stTS;
|
||||
StartIGMPServer = false;
|
||||
IGMPClientPort = 1234;
|
||||
IGMPStreamType = stTS;
|
||||
SuspendMode = smAlways;
|
||||
AllowSuspend = false;
|
||||
strcpy(VTPBindIP, "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) {
|
||||
@ -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, "HTTPStreamType") == 0) HTTPStreamType = atoi(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, "AllowSuspend") == 0) AllowSuspend = atoi(Value);
|
||||
else return false;
|
||||
@ -56,7 +63,11 @@ cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) {
|
||||
AddShortEdit(tr("HTTP Server Port"), m_NewSetup.HTTPServerPort);
|
||||
AddTypeEdit (tr("HTTP Streamtype"), m_NewSetup.HTTPStreamType);
|
||||
AddIpEdit (tr("Bind to IP"), m_NewSetup.HTTPBindIP);
|
||||
|
||||
AddCategory (tr("Multicast Streaming Server"));
|
||||
AddBoolEdit (tr("Start IGMP Server"), m_NewSetup.StartIGMPServer);
|
||||
AddShortEdit(tr("Multicast Client Port"), m_NewSetup.IGMPClientPort);
|
||||
AddTypeEdit (tr("Multicast Streamtype"), m_NewSetup.IGMPStreamType);
|
||||
AddIpEdit (tr("Bind to IP"), m_NewSetup.IGMPBindIP);
|
||||
SetCurrent(Get(1));
|
||||
}
|
||||
|
||||
@ -70,7 +81,10 @@ void cStreamdevServerMenuSetupPage::Store(void) {
|
||||
|| strcmp(m_NewSetup.VTPBindIP, StreamdevServerSetup.VTPBindIP) != 0
|
||||
|| m_NewSetup.StartHTTPServer != StreamdevServerSetup.StartHTTPServer
|
||||
|| 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;
|
||||
cStreamdevServer::Destruct();
|
||||
}
|
||||
@ -83,6 +97,10 @@ void cStreamdevServerMenuSetupPage::Store(void) {
|
||||
SetupStore("HTTPServerPort", m_NewSetup.HTTPServerPort);
|
||||
SetupStore("HTTPStreamType", m_NewSetup.HTTPStreamType);
|
||||
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("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
|
||||
@ -20,6 +20,10 @@ struct cStreamdevServerSetup {
|
||||
int HTTPServerPort;
|
||||
int HTTPStreamType;
|
||||
char HTTPBindIP[20];
|
||||
int StartIGMPServer;
|
||||
int IGMPClientPort;
|
||||
int IGMPStreamType;
|
||||
char IGMPBindIP[20];
|
||||
int SuspendMode;
|
||||
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>
|
||||
@ -20,15 +20,14 @@ cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket,
|
||||
cStreamdevStreamer *Streamer):
|
||||
cThread("streamdev-writer"),
|
||||
m_Streamer(Streamer),
|
||||
m_Socket(Socket),
|
||||
m_Active(false)
|
||||
m_Socket(Socket)
|
||||
{
|
||||
}
|
||||
|
||||
cStreamdevWriter::~cStreamdevWriter()
|
||||
{
|
||||
Dprintf("destructing writer\n");
|
||||
m_Active = false;
|
||||
if (Running())
|
||||
Cancel(3);
|
||||
}
|
||||
|
||||
@ -39,11 +38,10 @@ void cStreamdevWriter::Action(void)
|
||||
int max = 0;
|
||||
uchar *block = NULL;
|
||||
int count, offset = 0;
|
||||
m_Active = true;
|
||||
|
||||
sel.Clear();
|
||||
sel.Add(*m_Socket, true);
|
||||
while (m_Active) {
|
||||
while (Running()) {
|
||||
if (block == NULL) {
|
||||
block = m_Streamer->Get(count);
|
||||
offset = 0;
|
||||
@ -57,23 +55,39 @@ void cStreamdevWriter::Action(void)
|
||||
|
||||
if (sel.CanWrite(*m_Socket)) {
|
||||
int written;
|
||||
if ((written = m_Socket->Write(block + offset, count)) == -1) {
|
||||
esyslog("ERROR: streamdev-server: couldn't send data: %m");
|
||||
int pkgsize = count;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// statistics
|
||||
if (count > max)
|
||||
max = count;
|
||||
|
||||
offset += 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);
|
||||
block = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Active = false;
|
||||
Dprintf("Max. Transmit Blocksize was: %d\n", max);
|
||||
}
|
||||
|
||||
@ -81,7 +95,6 @@ void cStreamdevWriter::Action(void)
|
||||
|
||||
cStreamdevStreamer::cStreamdevStreamer(const char *Name):
|
||||
cThread(Name),
|
||||
m_Active(false),
|
||||
m_Running(false),
|
||||
m_Writer(NULL),
|
||||
m_RingBuffer(new cRingBufferLinear(STREAMERBUFSIZE, TS_SIZE * 2,
|
||||
@ -109,7 +122,7 @@ void cStreamdevStreamer::Start(cTBSocket *Socket)
|
||||
|
||||
void cStreamdevStreamer::Activate(bool On)
|
||||
{
|
||||
if (On && !m_Active) {
|
||||
if (On && !Active()) {
|
||||
Dprintf("activate streamer\n");
|
||||
m_Writer->Start();
|
||||
cThread::Start();
|
||||
@ -118,9 +131,8 @@ void cStreamdevStreamer::Activate(bool On)
|
||||
|
||||
void cStreamdevStreamer::Stop(void)
|
||||
{
|
||||
if (m_Active) {
|
||||
if (Running()) {
|
||||
Dprintf("stopping streamer\n");
|
||||
m_Active = false;
|
||||
Cancel(3);
|
||||
}
|
||||
if (m_Running) {
|
||||
@ -132,8 +144,7 @@ void cStreamdevStreamer::Stop(void)
|
||||
|
||||
void cStreamdevStreamer::Action(void)
|
||||
{
|
||||
m_Active = true;
|
||||
while (m_Active) {
|
||||
while (Running()) {
|
||||
int 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
|
||||
@ -12,6 +12,10 @@
|
||||
class cTBSocket;
|
||||
class cStreamdevStreamer;
|
||||
|
||||
#ifndef TS_SIZE
|
||||
#define TS_SIZE 188
|
||||
#endif
|
||||
|
||||
#define STREAMERBUFSIZE MEGABYTE(4)
|
||||
#define WRITERBUFSIZE KILOBYTE(256)
|
||||
|
||||
@ -21,7 +25,6 @@ class cStreamdevWriter: public cThread {
|
||||
private:
|
||||
cStreamdevStreamer *m_Streamer;
|
||||
cTBSocket *m_Socket;
|
||||
bool m_Active;
|
||||
|
||||
protected:
|
||||
virtual void Action(void);
|
||||
@ -29,15 +32,12 @@ protected:
|
||||
public:
|
||||
cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer);
|
||||
virtual ~cStreamdevWriter();
|
||||
|
||||
bool IsActive(void) const { return m_Active; }
|
||||
};
|
||||
|
||||
// --- cStreamdevStreamer -----------------------------------------------------
|
||||
|
||||
class cStreamdevStreamer: public cThread {
|
||||
private:
|
||||
bool m_Active;
|
||||
bool m_Running;
|
||||
cStreamdevWriter *m_Writer;
|
||||
cRingBufferLinear *m_RingBuffer;
|
||||
@ -54,7 +54,7 @@ public:
|
||||
|
||||
virtual void Start(cTBSocket *Socket);
|
||||
virtual void Stop(void);
|
||||
bool Abort(void) const;
|
||||
bool Abort(void);
|
||||
|
||||
void Activate(bool On);
|
||||
int Receive(uchar *Data, int Length) { return m_RingBuffer->Put(Data, Length); }
|
||||
@ -68,9 +68,9 @@ public:
|
||||
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
|
||||
|
@ -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"
|
||||
@ -7,13 +7,12 @@
|
||||
#include "common.h"
|
||||
|
||||
cSuspendLive::cSuspendLive(void)
|
||||
#if VDRVERSNUM >= 10300
|
||||
: cThread("Streamdev: server suspend")
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
cSuspendLive::~cSuspendLive() {
|
||||
Stop();
|
||||
Detach();
|
||||
}
|
||||
|
||||
@ -26,26 +25,15 @@ void cSuspendLive::Activate(bool On) {
|
||||
}
|
||||
|
||||
void cSuspendLive::Stop(void) {
|
||||
if (m_Active) {
|
||||
m_Active = false;
|
||||
if (Running())
|
||||
Cancel(3);
|
||||
}
|
||||
}
|
||||
|
||||
void cSuspendLive::Action(void) {
|
||||
#if VDRVERSNUM < 10300
|
||||
isyslog("Streamdev: Suspend Live thread started (pid = %d)", getpid());
|
||||
#endif
|
||||
|
||||
m_Active = true;
|
||||
while (m_Active) {
|
||||
while (Running()) {
|
||||
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;
|
||||
@ -61,7 +49,7 @@ cSuspendCtl::~cSuspendCtl() {
|
||||
}
|
||||
|
||||
eOSState cSuspendCtl::ProcessKey(eKeys Key) {
|
||||
if (!m_Suspend->IsActive() || Key == kBack) {
|
||||
if (!m_Suspend->Active() || Key == kBack) {
|
||||
DELETENULL(m_Suspend);
|
||||
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
|
||||
@ -7,10 +7,7 @@
|
||||
|
||||
#include <vdr/player.h>
|
||||
|
||||
class cSuspendLive: public cPlayer, cThread {
|
||||
private:
|
||||
bool m_Active;
|
||||
|
||||
class cSuspendLive: public cPlayer, public cThread {
|
||||
protected:
|
||||
virtual void Activate(bool On);
|
||||
virtual void Action(void);
|
||||
@ -20,8 +17,6 @@ protected:
|
||||
public:
|
||||
cSuspendLive(void);
|
||||
virtual ~cSuspendLive();
|
||||
|
||||
bool IsActive(void) const { return m_Active; }
|
||||
};
|
||||
|
||||
class cSuspendCtl: public cControl {
|
||||
|
@ -3,16 +3,18 @@
|
||||
*
|
||||
* 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 "client/device.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) {
|
||||
}
|
||||
@ -25,11 +27,8 @@ const char *cPluginStreamdevClient::Description(void) {
|
||||
}
|
||||
|
||||
bool cPluginStreamdevClient::Start(void) {
|
||||
i18n_name = Name();
|
||||
RegisterI18n(Phrases);
|
||||
|
||||
I18nRegister(PLUGIN_NAME_I18N);
|
||||
cStreamdevDevice::Init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -39,13 +38,15 @@ void cPluginStreamdevClient::Housekeeping(void) {
|
||||
}
|
||||
|
||||
const char *cPluginStreamdevClient::MainMenuEntry(void) {
|
||||
return NULL;
|
||||
//return StreamdevClientSetup.StartClient ? tr("Streaming Control") : NULL;
|
||||
return StreamdevClientSetup.StartClient && !StreamdevClientSetup.HideMenuEntry ? tr("Suspend Server") : NULL;
|
||||
}
|
||||
|
||||
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 StreamdevClientSetup.StartClient ? new cStreamdevMenu : NULL;
|
||||
}
|
||||
|
||||
cMenuSetupPage *cPluginStreamdevClient::SetupMenu(void) {
|
||||
|
@ -3,18 +3,22 @@
|
||||
*
|
||||
* 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 <vdr/tools.h>
|
||||
#include "remux/extern.h"
|
||||
#include "streamdev-server.h"
|
||||
#include "server/setup.h"
|
||||
#include "server/server.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)
|
||||
{
|
||||
@ -22,6 +26,8 @@ cPluginStreamdevServer::cPluginStreamdevServer(void)
|
||||
|
||||
cPluginStreamdevServer::~cPluginStreamdevServer()
|
||||
{
|
||||
free(opt_auth);
|
||||
free(opt_remux);
|
||||
}
|
||||
|
||||
const char *cPluginStreamdevServer::Description(void)
|
||||
@ -32,22 +38,39 @@ const char *cPluginStreamdevServer::Description(void)
|
||||
const char *cPluginStreamdevServer::CommandLineHelp(void)
|
||||
{
|
||||
// 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[])
|
||||
{
|
||||
// implement command line argument processing here if applicable.
|
||||
static const struct option long_options[] = {
|
||||
{ "auth", required_argument, NULL, 'a' },
|
||||
{ "remux", required_argument, NULL, 'r' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
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) {
|
||||
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':
|
||||
g_ExternRemux = optarg;
|
||||
if (opt_remux)
|
||||
free(opt_remux);
|
||||
opt_remux = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@ -58,9 +81,7 @@ bool cPluginStreamdevServer::ProcessArgs(int argc, char *argv[])
|
||||
|
||||
bool cPluginStreamdevServer::Start(void)
|
||||
{
|
||||
i18n_name = Name();
|
||||
RegisterI18n(Phrases);
|
||||
|
||||
I18nRegister(PLUGIN_NAME_I18N);
|
||||
if (!StreamdevHosts.Load(STREAMDEVHOSTSPATH, true, true)) {
|
||||
esyslog("streamdev-server: error while loading %s", STREAMDEVHOSTSPATH);
|
||||
fprintf(stderr, "streamdev-server: error while loading %s\n", STREAMDEVHOSTSPATH);
|
||||
@ -73,6 +94,8 @@ bool cPluginStreamdevServer::Start(void)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!opt_remux)
|
||||
opt_remux = strdup(DEFAULT_EXTERNREMUX);
|
||||
|
||||
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
|
||||
#192.168.100.0/24 # any host on the local net
|
||||
#204.152.189.113 # a specific host
|
||||
#239.255.0.0/16 # uncomment for IGMP multicast streaming
|
||||
#0.0.0.0/0 # any host on any net (USE THIS WITH CARE!)
|
@ -1,5 +1,6 @@
|
||||
#include "tools/socket.h"
|
||||
|
||||
#include <vdr/tools.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
@ -15,10 +16,11 @@
|
||||
// actual DSCP value used
|
||||
#define STREAMDEV_DSCP DSCP_AF41
|
||||
|
||||
cTBSocket::cTBSocket(int Type) {
|
||||
cTBSocket::cTBSocket(int Type, int Protocol) {
|
||||
memset(&m_LocalAddr, 0, sizeof(m_LocalAddr));
|
||||
memset(&m_RemoteAddr, 0, sizeof(m_RemoteAddr));
|
||||
m_Type = Type;
|
||||
m_Protocol = Protocol;
|
||||
}
|
||||
|
||||
cTBSocket::~cTBSocket() {
|
||||
@ -31,7 +33,7 @@ bool cTBSocket::Connect(const std::string &Host, unsigned int Port) {
|
||||
|
||||
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;
|
||||
|
||||
m_LocalAddr.sin_family = AF_INET;
|
||||
@ -52,11 +54,13 @@ bool cTBSocket::Connect(const std::string &Host, unsigned int Port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_Type == SOCK_STREAM) {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
if (::getpeername(socket, (struct sockaddr*)&m_RemoteAddr, &len) == -1) {
|
||||
::close(socket);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
len = sizeof(struct sockaddr_in);
|
||||
if (::getsockname(socket, (struct sockaddr*)&m_LocalAddr, &len) == -1) {
|
||||
@ -64,7 +68,11 @@ bool cTBSocket::Connect(const std::string &Host, unsigned int Port) {
|
||||
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) {
|
||||
@ -74,7 +82,7 @@ bool cTBSocket::Listen(const std::string &Ip, unsigned int Port, int BackLog) {
|
||||
|
||||
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;
|
||||
|
||||
val = 1;
|
||||
|
@ -18,9 +18,10 @@ private:
|
||||
struct sockaddr_in m_RemoteAddr;
|
||||
|
||||
int m_Type;
|
||||
int m_Protocol;
|
||||
|
||||
public:
|
||||
cTBSocket(int Type = SOCK_STREAM);
|
||||
cTBSocket(int Type = SOCK_STREAM, int Protocol = 0);
|
||||
virtual ~cTBSocket();
|
||||
|
||||
/* See cTBSource::SysRead()
|
||||
@ -97,15 +98,22 @@ public:
|
||||
};
|
||||
|
||||
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);
|
||||
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 {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user