Snapshot 2009-06-11

This commit is contained in:
Frank Schmirler 2010-12-02 09:43:13 +01:00
parent 31df0eaf8e
commit 7254a67528
83 changed files with 2200 additions and 6221 deletions

View File

@ -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
View File

@ -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

View File

@ -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
View File

@ -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.

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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++;
}
}
}
}

View File

@ -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_

View File

@ -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*/

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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();
}

View File

@ -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;

View 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;

View 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; }

View 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;

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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 "½ØÚÞÓÔÐ ÝÕ ÞáâÐÝÞÒÛÕÝ"

View File

@ -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;
}
}

View File

@ -5,8 +5,6 @@
#include <vdr/ringbuffer.h>
#include <string>
extern const char *g_ExternRemux;
class cTSExt;
class cExternRemux: public cTSRemux {

View File

@ -5,6 +5,10 @@
#include <vdr/remux.h>
#include <vdr/ringbuffer.h>
#ifndef MAXTRACKS
#define MAXTRACKS 64
#endif
class cTS2PS;
class cTS2PSRemux: public cTSRemux {

View File

@ -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)
{

View File

@ -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 {

View File

@ -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)
{

View File

@ -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
View 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
View 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

View File

@ -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);

View File

@ -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) { }

View File

@ -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;

View File

@ -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
View 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
View 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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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())
{

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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 {

View File

@ -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) {

View File

@ -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
View 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

View File

@ -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!)

View File

@ -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;

View File

@ -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