diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 6f9c812..d7f8dbf 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -24,6 +24,12 @@ Rolf Ahrenberg for suggesting a fix of the Makefile's default target for a TS PAT repacker based on Petri Laine's VDR TS recording patch for making it possible to pass parameters to externremux.sh + for removing pre VDR 1.4 legacy code + for adding gettext support + for fixing output format of some debug messages + for replacing private members by cThread::Running()/Active() + for improving externremux script termination + for fixing PAT repacker version field Rantanen Teemu for providing vdr-incompletesections.diff @@ -42,6 +48,7 @@ Udo Richter for fixing streamdev-server shutdown for speeding up cPluginStreamdevServer::Active() for adapting to VDR 1.5.0 API + for adapting to VDR 1.7.1 greenman for reporting that the log could get flooded on connection failures. @@ -70,3 +77,37 @@ Olli Lammi Joerg Pulz for his FreeBSD compatibility patch + +tobi + for pointing to unused files in the libdvbmpeg directory + +Diego Pierotto + for providing italian language texts + +micky979 + for providing french language texts + +Tiroler + for reporting a problem when switching between encrypted channels + +Pixelpeter + for an initial fix to the "switching between ecncrypted channels" problem + +Anssi Hannula + for the vdr-1.6.0-ignore_missing_cam.diff patch + +wirbel + for pointing out that section filtering is optional for VDR devices + +Jori Hamalainen + for extensive testing while making stream compatible to Network Media Tank + for adding Network Media Tank browser support to HTML pages + +owagner + for pointing out a problem with the encrypted channel switching fix + +Joachim König-Baltes + for fixing Min/MaxPriority parsing + +Artem Makhutov + for suggesting and heavy testing IGMP based multicast streaming diff --git a/HISTORY b/HISTORY index 160994e..4f8aef1 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,59 @@ VDR Plugin 'streamdev' Revision History --------------------------------------- +- added missing call to StopSectionHandler which could cause crashes when + shutting down VDR +- added IGMP based multicast streaming +- ignore trailing blank lines in HTTP requests +- fixed parsing Min/MaxPriority from config (thanks to Joachim König-Baltes) +- updated Finnish translation (thanks to Rolf Ahrenberg) +- added Min/MaxPriority parameters. Can be used to keep client VDR from + using streamdev e.g. when recording +- disabled PES for VDR 1.7.3+ +- added Network Media Tank browser support to HTML pages (thanks to Jori + Hamalainen) +- minor fixes of PAT repacker +- repack and send every PAT packet we receive +- fixed null pointer in server.c when cConnection::Accept() failes +- consider Pids from channels.conf when HTTP TS streaming. Section filtering + is an optional feature for VDR devices, so we must not rely on the PMT + alone (pointed out by wirbel@vdrportal) +- improved externremux script termination (thanks to Rolf Ahrenberg) +- use cThread::Running()/Active() instead of private members (thanks to + Rolf Ahrenberg) +- fixed output format of some debug messages (thanks to Rolf Ahrenberg) +- added HTTP authentication +- compatibility for VDR 1.7.1 (thanks to Udo Richter) +- added vdr-1.6.0-intcamdevices.patch (thanks to Anssi Hannula) +- fixed problem when switching from one encrypted channel to an other + (reported by Tiroler@vdrportal, initial bugfix by pixelpeter@vdrportal, + another fix by owagner@vdrportal) +- added preprocessor directive for ancient gcc +- added Russian translation (thanks to Oleg Roitburd) +- fixed assignment of externremux.sh's default location (reported by plautze) +- added French translation (thanks to micky979) +- added Italian translation (thanks to Diego Pierotto) +- added gettext support (thanks to Rolf Ahrenberg) +- added vdr-1.6.0-ignore_missing_cam patch +- dropped obsolete respect_ca patch +- removed legacy code for < VDR 1.5.9 (thanks to Rolf Ahrenberg) + +2008-04-07: Branched v0_4 + +- changed location of streamdevhosts.conf to VDRCONFDIR/plugins/streamdev +- changed externremux.sh's default location to VDRCONFDIR/plugins/streamdev +- added sample externremux.sh from http://www.vdr-wiki.de/ +- stop providing channels after client has been disabled at runtime +- added logging of the client device's card index +- changed default suspend mode to "Always suspended" +- added "Hide Mainmenu Entry" setup option on client +- resurrected clients "Suspend Server" menu item as its mainmenu entry +- dropped unused code for remote timers/recordings on client side +- dropped unused files client/{assembler,menu,remote}.[hc] +- dropped unused files in libdvbmpeg (reported by tobi) +- dropped patches for pre VDR 1.4 +- removed legacy code for pre VDR 1.4 (thanks to Rolf Ahrenberg) + 2008-03-31: Version 0.3.4 - added possibility to pass parameter to externremux.sh (thanks to Rolf diff --git a/Makefile b/Makefile index e4a17c4..b737563 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # # Makefile for a Video Disk Recorder plugin # -# $Id: Makefile,v 1.12 2008/03/31 10:34:26 schmirl Exp $ +# $Id: Makefile,v 1.17 2009/02/13 10:39:20 schmirl Exp $ # The official name of this plugin. # This name will be used in the '-P...' option of VDR to load the plugin. @@ -16,11 +16,10 @@ VERSION = $(shell grep 'const char \*VERSION *=' common.c | awk '{ print $$5 }' ### The C++ compiler and options: CXX ?= g++ -CXXFLAGS ?= -fPIC -Wall -Woverloaded-virtual +CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses ### The directory environment: -DVBDIR = ../../../../DVB VDRDIR = ../../.. LIBDIR = ../../lib TMPDIR = /tmp @@ -40,55 +39,39 @@ PACKAGE = vdr-$(ARCHIVE) ### Includes and Defines (add further entries here): -INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -I. +INCLUDES += -I$(VDRDIR)/include -I. -DEFINES += -D_GNU_SOURCE +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ### The object files (add further files here): -COMMONOBJS = common.o i18n.o \ +COMMONOBJS = common.o \ \ tools/source.o tools/select.o tools/socket.o tools/tools.o CLIENTOBJS = $(PLUGIN)-client.o \ \ client/socket.o client/device.o client/setup.o \ - client/remote.o client/assembler.o client/filter.o + client/filter.o SERVEROBJS = $(PLUGIN)-server.o \ \ - server/server.o server/connectionVTP.o server/connectionHTTP.o \ - server/componentHTTP.o server/componentVTP.o server/connection.o \ - server/component.o server/suspend.o server/setup.o server/streamer.o \ - server/livestreamer.o server/livefilter.o server/menuHTTP.o \ - \ + server/server.o server/component.o server/connection.o \ + server/componentVTP.o server/componentHTTP.o server/componentIGMP.o \ + server/connectionVTP.o server/connectionHTTP.o server/connectionIGMP.o \ + server/streamer.o server/livestreamer.o server/livefilter.o \ + server/suspend.o server/setup.o server/menuHTTP.o \ remux/tsremux.o remux/ts2ps.o remux/ts2es.o remux/extern.o ifdef DEBUG DEFINES += -DDEBUG - CXXFLAGS += -g -else - CXXFLAGS += -O2 -endif - -ifeq ($(shell test -f $(VDRDIR)/fontsym.h ; echo $$?),0) - DEFINES += -DHAVE_BEAUTYPATCH -endif - -ifeq ($(shell test -f $(VDRDIR)/fontsym.c ; echo $$?),0) - DEFINES += -DHAVE_BEAUTYPATCH -endif - -# HAVE_AUTOPID only applies if VDRVERSNUM < 10300 -ifeq ($(shell test -f $(VDRDIR)/sections.c ; echo $$?),0) - DEFINES += -DHAVE_AUTOPID endif ### The main target: -.PHONY: all dist clean -all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so +.PHONY: all i18n dist clean +all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so i18n ### Implicit rules: @@ -97,7 +80,7 @@ all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so # Dependencies: -MAKEDEP = g++ -MM -MG +MAKEDEP = $(CXX) -MM -MG DEPFILE = .dependencies ifdef GCC3 $(DEPFILE): Makefile @@ -113,12 +96,35 @@ endif -include $(DEPFILE) +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(CLIENTOBJS:%.o=%.c) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='' -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 diff --git a/README b/README index 5a82acb..cd03c58 100644 --- a/README +++ b/README @@ -15,13 +15,18 @@ Contents: 1. Description 2. Installation -2.1 VDR 1.2.X -2.2 VDR 1.3.X and above +2.1 VDR 1.4.x and older +2.2 VDR 1.6.0 and above +2.3 Updating from streamdev 0.3.x 3. Usage 3.1 Usage HTTP server -3.2 Usage VDR-to-VDR server -3.3 Usage VDR-to-VDR client +3.2 Usage IGMP multicast server +3.3 Usage VDR-to-VDR server +3.4 Usage VDR-to-VDR client 4. Other useful Plugins +4.1 Plugins for VDR-to-VDR clients +4.2 Plugins for Server +4.3 Alternatives 5. Known Problems @@ -57,7 +62,7 @@ the PROTOCOL file. 2. Installation: ---------------- -Let's say streamdev's version is 0.3.1 and vdr's version is 1.X.X. If you +Let's say streamdev's version is 0.4.0 and vdr's version is 1.X.X. If you use anything else please exchange the version numbers appropriately (this way I don't have to update this section all the times;) ). @@ -68,48 +73,67 @@ command line. What's important is that the client requests a channel using its Unique Channel ID. So, in order to find the channel at the server, it must have the same ID that is used on the client. You can achieve this by putting the server's -channels.conf on the client, preferably after scanning (in case you use 1.2.X -with AutoPID or 1.3.X). +channels.conf on the client, preferably after scanning. If you want to drive additional Input-Devices (with different sources) on the client, you can merge the channels.conf files. VDR will detect if the local device or the network device can receive the channels. -Last, but not least you have to put the provided streamdevhosts.conf.example -into the "plugins" subfolder of your config-directory (which is equal to your -video-directory if not specified otherwise), rename it to streamdevhosts.conf -and adjust it to your needs. The syntax is the same as for svdrphosts.conf, so -please consult VDR's documentation on how to fill that file, if you can't do -it on-the-fly. For example, if you didn't specify a separate config-directory, -and specified your video directory as "/video0", the file has to be put to -/video0/plugins/streamdevhosts.conf. +Last, but not least you have to copy the streamdev folder into the +"plugins/streamdev" subfolder of VDR's config-directory (which is equal to your +video-directory if not specified otherwise). For example, if you didn't specify +a separate config-directory, and specified your video directory as "/video0", +the directory has to be copied to /video0/plugins/streamdev. + +The directory contains a file named streamdevhosts.conf which you must adjust +to your needs. The syntax is the same as for svdrphosts.conf, so please consult +VDR's documentation on how to fill that file, if you can't do it on-the-fly. + +There's also a sample externremux.sh script in this directory. It is used by +streamdev's external remux feature. The sample script uses mencoder. Please +check the script for further information. You can specify a different script +location with the -r parameter. The VDR commandline would then include a +"-P 'streamdev-server -r /usr/local/bin/remux.sh'". Note the additional quotes, +as otherwise -r will be passed to VDR and not to streamdev. -2.1 VDR 1.2.X: --------------- +2.1 VDR 1.4.x and older: +------------------------ -It is recommended that you apply a patch to VDR that improves thread -cancellation. You can work without it, but you _might_ have delays in switching -(especially when using VDR-to-VDR streaming) that are around three seconds. +This version is not compatible to VDR releases older than 1.5.9. Take one of +the streamdev-0.4.x releases if you are running at least VDR 1.4.x. For older +VDRs you will probably need one of the streamdev-0.3.x releases. -cd vdr-1.X.X/PLUGINS/src -tar xvfz vdr-streamdev-0.3.1.tgz -ln -s streamdev-0.3.1 streamdev -cd ../.. -patch -p1 -#include -#include - -#include - -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(); -} diff --git a/client/assembler.h b/client/assembler.h deleted file mode 100644 index be8f88c..0000000 --- a/client/assembler.h +++ /dev/null @@ -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 -#include - -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 - diff --git a/client/device.c b/client/device.c index da93d12..4b6c3c5 100644 --- a/client/device.c +++ b/client/device.c @@ -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; diff --git a/client/device.h b/client/device.h index 525c1d4..8263fa5 100644 --- a/client/device.h +++ b/client/device.h @@ -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 #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, diff --git a/client/filter.c b/client/filter.c index 91af8b7..c187e05 100644 --- a/client/filter.c +++ b/client/filter.c @@ -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 -#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 diff --git a/client/filter.h b/client/filter.h index e0a1575..889006a 100644 --- a/client/filter.h +++ b/client/filter.h @@ -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 - -# if VDRVERSNUM >= 10300 - #include #include @@ -33,5 +30,4 @@ public: int OpenFilter(u_short Pid, u_char Tid, u_char Mask); }; -# endif // VDRVERSNUM >= 10300 #endif // VDR_STREAMDEV_FILTER_H diff --git a/client/menu.c b/client/menu.c deleted file mode 100644 index 268b3b2..0000000 --- a/client/menu.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * $Id: menu.c,v 1.4 2005/03/12 12:54:19 lordjaxom Exp $ - */ - -#include -#include - -#include "client/menu.h" -#include "client/socket.h" -#include "i18n.h" - -#define CHNUMWIDTH (numdigits(Channels.MaxNumber()) + 1) - -// --- cMenuText ------------------------------------------------------------- - -class cMenuText : public cOsdMenu { -public: - cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd); - virtual eOSState ProcessKey(eKeys Key); - }; - -// --- cStreamdevMenu -------------------------------------------------------- - -cStreamdevMenu::cStreamdevMenu(void): - cOsdMenu(tr("Streaming Control")) { - SetHasHotkeys(); - Add(new cOsdItem(hk(tr("Remote Schedule")), (eOSState)subSchedule)); - Add(new cOsdItem(hk(tr("Remote Timers")), (eOSState)subTimers)); - Add(new cOsdItem(hk(tr("Remote Recordings")), (eOSState)subRecordings)); - Add(new cOsdItem(hk(tr("Suspend Server")), (eOSState)subSuspend)); - Add(new cOsdItem(hk(tr("Synchronize EPG")), (eOSState)subSyncEPG)); -} - -cStreamdevMenu::~cStreamdevMenu() { -} - -eOSState cStreamdevMenu::ProcessKey(eKeys Key) { - eOSState state = cOsdMenu::ProcessKey(Key); - switch (state) { - case subSchedule: return AddSubMenu(new cStreamdevMenuSchedule); - case subTimers: return AddSubMenu(new cStreamdevMenuTimers); - case subRecordings: return AddSubMenu(new cStreamdevMenuRecordings); - case subSuspend: SuspendServer(); return osEnd; - case subSyncEPG: ClientSocket.SynchronizeEPG(); return osEnd; - default: return state; - } -} - -void cStreamdevMenu::SuspendServer(void) { - if (ClientSocket.SuspendServer()) - INFO(tr("Server is suspended")); - else - ERROR(tr("Couldn't suspend Server!")); -} - -#if VDRVERSNUM < 10307 -// --- cMenuEditChanItem ----------------------------------------------------- - -class cMenuEditChanItem : public cMenuEditIntItem { -protected: - virtual void Set(void); -public: - cMenuEditChanItem(const char *Name, int *Value); - virtual eOSState ProcessKey(eKeys Key); - }; - -// --- cMenuEditDateItem ----------------------------------------------------- - -class cMenuEditDateItem : public cMenuEditItem { -protected: - time_t *value; - virtual void Set(void); -public: - cMenuEditDateItem(const char *Name, time_t *Value); - virtual eOSState ProcessKey(eKeys Key); - }; - -// --- cMenuEditDayItem ------------------------------------------------------ - -class cMenuEditDayItem : public cMenuEditIntItem { -protected: - static int days[]; - int d; - virtual void Set(void); -public: - cMenuEditDayItem(const char *Name, int *Value); - virtual eOSState ProcessKey(eKeys Key); - }; - -// --- cMenuEditTimeItem ----------------------------------------------------- - -class cMenuEditTimeItem : public cMenuEditItem { -protected: - int *value; - int hh, mm; - int pos; - virtual void Set(void); -public: - cMenuEditTimeItem(const char *Name, int *Value); - virtual eOSState ProcessKey(eKeys Key); - }; -#endif // VDRVERSNUM < 10307 - -// --- cStreamdevMenuEditTimer ----------------------------------------------- - -class cStreamdevMenuEditTimer : public cOsdMenu { -private: - int m_Channel; - bool m_AddIfConfirmed; - cRemoteTimer *m_Timer; - cRemoteTimer m_Data; - cMenuEditDateItem *m_FirstDay; - -protected: - void SetFirstDayItem(void); - -public: - cStreamdevMenuEditTimer(cRemoteTimer *Timer, bool New = false); - virtual ~cStreamdevMenuEditTimer(); - - virtual eOSState ProcessKey(eKeys Key); -}; - -cStreamdevMenuEditTimer::cStreamdevMenuEditTimer(cRemoteTimer *Timer, bool New): - cOsdMenu(tr("Edit remote timer"), 12) { - m_FirstDay = NULL; - m_Timer = Timer; - m_AddIfConfirmed = New; - - if (m_Timer) { - m_Data = *m_Timer; - if (New) - m_Data.m_Active = 1; - m_Channel = m_Data.Channel()->Number(); -#if VDRVERSNUM < 10300 - Add(new cMenuEditBoolItem(tr("Active"), &m_Data.m_Active)); -#else - Add(new cMenuEditBitItem( tr("Active"), &m_Data.m_Active, tfActive)); -#endif - Add(new cMenuEditChanItem(tr("Channel"), &m_Channel)); - Add(new cMenuEditDayItem( tr("Day"), &m_Data.m_Day)); - Add(new cMenuEditTimeItem(tr("Start"), &m_Data.m_Start)); - Add(new cMenuEditTimeItem(tr("Stop"), &m_Data.m_Stop)); -#if VDRVERSNUM >= 10300 - Add(new cMenuEditBitItem( tr("VPS"), &m_Data.m_Active, tfVps)); -#endif - Add(new cMenuEditIntItem( tr("Priority"), &m_Data.m_Priority, 0, - MAXPRIORITY)); - Add(new cMenuEditIntItem( tr("Lifetime"), &m_Data.m_Lifetime, 0, - MAXLIFETIME)); - Add(new cMenuEditStrItem( tr("File"), m_Data.m_File, - sizeof(m_Data.m_File), tr(FileNameChars))); - SetFirstDayItem(); - } -} - -cStreamdevMenuEditTimer::~cStreamdevMenuEditTimer() { - if (m_Timer && m_AddIfConfirmed) { - Dprintf("SOMETHING GETS DELETED\n"); - delete m_Timer; // apparently it wasn't confirmed - } -} - -void cStreamdevMenuEditTimer::SetFirstDayItem(void) { - if (!m_FirstDay && !m_Data.IsSingleEvent()) { - Add(m_FirstDay = new cMenuEditDateItem(tr("First day"),&m_Data.m_FirstDay)); - Display(); - } else if (m_FirstDay && m_Data.IsSingleEvent()) { - Del(m_FirstDay->Index()); - m_FirstDay = NULL; - m_Data.m_FirstDay = 0; - Display(); - } -} - -eOSState cStreamdevMenuEditTimer::ProcessKey(eKeys Key) { - eOSState state = cOsdMenu::ProcessKey(Key); - - if (state == osUnknown) { - switch (Key) { - case kOk: - { - cChannel *ch = Channels.GetByNumber(m_Channel); - if (ch) - m_Data.m_Channel = ch; - else { - ERROR(tr("*** Invalid Channel ***")); - break; - } - if (!*m_Data.m_File) - strcpy(m_Data.m_File, m_Data.Channel()->Name()); - if (m_Timer) { - bool success = true; - if (m_Data != *m_Timer) { - // Timer has changed - if ((success = ClientSocket.SaveTimer(m_Timer, m_Data))) { - *m_Timer = m_Data; - if (m_Timer->m_Active) - m_Timer->m_Active = 1; - // allows external programs to mark active timers with - // values > 1 and recognize if the user has modified them - } - } - if (success) { - if (m_AddIfConfirmed) - RemoteTimers.Add(m_Timer); - isyslog("timer %d %s (%s)", m_Timer->Index() + 1, - m_AddIfConfirmed ? "added" : "modified", - m_Timer->m_Active ? "active" : "inactive"); - m_AddIfConfirmed = false; - } - } - } - return osBack; - - case kRed: - case kGreen: - case kYellow: - case kBlue: return osContinue; - default: break; - } - } - if (Key != kNone) - SetFirstDayItem(); - return state; -} - -// --- cMenuWhatsOnItem ------------------------------------------------------ - -#if VDRVERSNUM < 10300 -class cMenuWhatsOnItem : public cOsdItem { -public: - const cEventInfo *eventInfo; -# ifdef HAVE_BEAUTYPATCH - cMenuWhatsOnItem(const cEventInfo *EventInfo, bool ShowProgressBar); - ~cMenuWhatsOnItem(); - virtual void Display(int Offset= -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); -protected: - cBitmap *progressBar; - bool showProgressBar; - float percent; -private: - void DrawProgressBar(eDvbColor FgColor, eDvbColor BgColor); -# else - cMenuWhatsOnItem(const cEventInfo *EventInfo); -# endif -}; -#else -class cMenuWhatsOnItem : public cOsdItem { -public: - const cEvent *event; - const cChannel *channel; - cMenuWhatsOnItem(const cEvent *Event, cChannel *Channel); //, bool Now = false); -}; -#endif - -// --- cMenuEvent ------------------------------------------------------------ - -#if VDRVERSNUM < 10300 -class cMenuEvent : public cOsdMenu { -private: - const cEventInfo *eventInfo; -public: - cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch = false); - cMenuEvent(bool Now); - virtual eOSState ProcessKey(eKeys Key); -}; -#elif VDRVERSNUM < 10307 -class cMenuEvent : public cOsdMenu { -private: - const cEvent *event; -public: - cMenuEvent(const cEvent *Event, bool CanSwitch = false); - cMenuEvent(bool Now); - virtual eOSState ProcessKey(eKeys Key); -}; -#else -class cMenuEvent : public cOsdMenu { -private: - const cEvent *event; -public: - cMenuEvent(const cEvent *Event, bool CanSwitch = false); - virtual void Display(void); - virtual eOSState ProcessKey(eKeys Key); -}; -#endif - -// --- cStreamdevMenuWhatsOn ------------------------------------------------- - -int cStreamdevMenuWhatsOn::m_CurrentChannel = 0; -#if VDRVERSNUM < 10300 -const cEventInfo *cStreamdevMenuWhatsOn::m_ScheduleEventInfo = NULL; -#else -const cEvent *cStreamdevMenuWhatsOn::m_ScheduleEventInfo = NULL; -#endif - -#if VDRVERSNUM < 10300 -static int CompareEventChannel(const void *p1, const void *p2) { - return (int)((*(const cEventInfo**)p1)->GetChannelNumber() - - (*(const cEventInfo**)p2)->GetChannelNumber()); -} -#endif - -cStreamdevMenuWhatsOn::cStreamdevMenuWhatsOn(const cSchedules *Schedules, - bool Now, int CurrentChannel): - cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, - 7, 6) { -#if VDRVERSNUM < 10300 - const cSchedule *Schedule = Schedules->First(); - const cEventInfo **pArray = NULL; - int num = 0; - - while (Schedule) { - pArray=(const cEventInfo**)realloc(pArray, (num + 1) * sizeof(cEventInfo*)); - pArray[num] = Now ? Schedule->GetPresentEvent() - : Schedule->GetFollowingEvent(); - if (pArray[num]) { - cChannel *channel - = Channels.GetByChannelID(pArray[num]->GetChannelID(), true); - if (channel) - pArray[num++]->SetChannelNumber(channel->Number()); - } - Schedule = Schedules->Next(Schedule); - } - - qsort(pArray, num, sizeof(cEventInfo*), CompareEventChannel); - for (int a = 0; a < num; ++a) { - int channelnr = pArray[a]->GetChannelNumber(); -# ifdef HAVE_BEAUTYPATCH - Add(new cMenuWhatsOnItem(pArray[a],Now), channelnr == CurrentChannel); -# else - Add(new cMenuWhatsOnItem(pArray[a]), channelnr == CurrentChannel); -# endif - } - - free(pArray); -#else - for (cChannel *Channel = Channels.First(); Channel; - Channel = Channels.Next(Channel)) { - if (!Channel->GroupSep()) { - const cSchedule *Schedule - = Schedules->GetSchedule(Channel->GetChannelID()); - if (Schedule) { - const cEvent *Event = Now ? Schedule->GetPresentEvent() - : Schedule->GetFollowingEvent(); - if (Event) - Add(new cMenuWhatsOnItem(Event, Channel), - Channel->Number() == CurrentChannel); - } - } - } -#endif - m_CurrentChannel = CurrentChannel; - SetHelp(Count() ? tr("Record") : NULL, Now ? tr("Next") : tr("Now"), - tr("Schedule"), tr("Switch")); -} - -#if VDRVERSNUM < 10300 -const cEventInfo *cStreamdevMenuWhatsOn::ScheduleEventInfo(void) { - const cEventInfo *ei = m_ScheduleEventInfo; - m_ScheduleEventInfo = NULL; - return ei; -} -#else -const cEvent *cStreamdevMenuWhatsOn::ScheduleEventInfo(void) { - const cEvent *ei = m_ScheduleEventInfo; - m_ScheduleEventInfo = NULL; - return ei; -} -#endif - -eOSState cStreamdevMenuWhatsOn::Switch(void) { - cMenuWhatsOnItem *item = (cMenuWhatsOnItem*)Get(Current()); - if (item) { - cChannel *channel -#if VDRVERSNUM < 10300 - = Channels.GetByChannelID(item->eventInfo->GetChannelID(), true); -#else - = Channels.GetByChannelID(item->event->ChannelID(), true); -#endif - if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true)) - return osEnd; - } - ERROR(tr("Can't switch channel!")); - return osContinue; -} - -eOSState cStreamdevMenuWhatsOn::Record(void) { - cMenuWhatsOnItem *item = (cMenuWhatsOnItem*)Get(Current()); - if (item) { - cRemoteTimer *timer -#if VDRVERSNUM < 10300 - = new cRemoteTimer(item->eventInfo); -#else - = new cRemoteTimer(item->event); -#endif - return AddSubMenu(new cStreamdevMenuEditTimer(timer)); - // Load remote timers and see if timer exists before editing - } - return osContinue; -} - -eOSState cStreamdevMenuWhatsOn::ProcessKey(eKeys Key) { - eOSState state = cOsdMenu::ProcessKey(Key); - if (state == osUnknown) { - switch (Key) { - case kRecord: - case kRed: - return Record(); - - case kYellow: - state = osBack; - case kGreen: - { - cMenuWhatsOnItem *mi = (cMenuWhatsOnItem*)Get(Current()); - if (mi) { -#if VDRVERSNUM < 10300 - m_ScheduleEventInfo = mi->eventInfo; - m_CurrentChannel = mi->eventInfo->GetChannelNumber(); -#else - m_ScheduleEventInfo = mi->event; - m_CurrentChannel = mi->channel->Number(); -#endif - } - } - break; - - case kBlue: - return Switch(); - - case kOk: - if (Count()) -#if VDRVERSNUM < 10300 - return AddSubMenu(new cMenuEvent( - ((cMenuWhatsOnItem*)Get(Current()))->eventInfo, true)); -#else - return AddSubMenu(new cMenuEvent( - ((cMenuWhatsOnItem*)Get(Current()))->event, true)); -#endif - break; - - default: - break; - } - } - return state; -} - -// --- cMenuScheduleItem ----------------------------------------------------- - -#if VDRVERSNUM < 10300 -class cMenuScheduleItem : public cOsdItem { -public: - const cEventInfo *eventInfo; - cMenuScheduleItem(const cEventInfo *EventInfo); -}; -#else -class cMenuScheduleItem : public cOsdItem { -public: - const cEvent *event; - cMenuScheduleItem(const cEvent *Event); -}; -#endif - -// --- cStreamdevMenuSchedule ------------------------------------------------ - -cStreamdevMenuSchedule::cStreamdevMenuSchedule(void): -#if VDRVERSNUM < 10300 - cOsdMenu("", 6, 6) -#else - cOsdMenu("", 7, 6, 4) -#endif -{ - m_Now = false; - m_Next = false; - m_OtherChannel = -1; - m_Schedules = NULL; - - cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel()); - if (channel) { -#if VDRVERSNUM < 10300 - m_Schedules = cSIProcessor::Schedules(m_Lock); -#else - m_Schedules = cSchedules::Schedules(m_Lock); -#endif - PrepareSchedule(channel); - SetHelp(Count() ? tr("Record") : NULL, tr("Now"), tr("Next")); - } -} - -cStreamdevMenuSchedule::~cStreamdevMenuSchedule() { -} - -#if VDRVERSNUM < 10307 -static int CompareEventTime(const void *p1, const void *p2) { -#if VDRVERSNUM < 10300 - return (int)((*(cEventInfo **)p1)->GetTime() - - (*(cEventInfo **)p2)->GetTime()); -#else - return (int)((*(cEvent**)p1)->StartTime() - - (*(cEvent**)p2)->StartTime()); -#endif -} -#endif - -void cStreamdevMenuSchedule::PrepareSchedule(cChannel *Channel) { -#if VDRVERSNUM < 10300 - cTBString buffer; - Clear(); - buffer.Format(tr("Schedule - %s"), Channel->Name()); - SetTitle(buffer); - if (m_Schedules) { - const cSchedule *Schedule=m_Schedules->GetSchedule(Channel->GetChannelID()); - if (Schedule) { - int num = Schedule->NumEvents(); - const cEventInfo **pArray = MALLOC(const cEventInfo*, num); - if (pArray) { - time_t now = time(NULL); - int numreal = 0; - for (int a = 0; a < num; ++a) { - const cEventInfo *EventInfo = Schedule->GetEventNumber(a); - if (EventInfo->GetTime() + EventInfo->GetDuration() > now) - pArray[numreal++] = EventInfo; - } - - qsort(pArray, numreal, sizeof(cEventInfo*), CompareEventTime); - for (int a = 0; a < numreal; ++a) - Add(new cMenuScheduleItem(pArray[a])); - free(pArray); - } - } - } -#else - Clear(); - char *buffer = NULL; - asprintf(&buffer, tr("Schedule - %s"), Channel->Name()); - SetTitle(buffer); - free(buffer); - if (m_Schedules) { - const cSchedule *Schedule = m_Schedules->GetSchedule(Channel->GetChannelID()); - if (Schedule) { - const cEvent *PresentEvent = Schedule->GetPresentEvent(Channel->Number() == cDevice::CurrentChannel()); - time_t now = time(NULL) - Setup.EPGLinger * 60; - for (const cEvent *Event = Schedule->Events()->First(); Event; Event = Schedule->Events()->Next(Event)) { - if (Event->EndTime() > now || Event == PresentEvent) - Add(new cMenuScheduleItem(Event), Event == PresentEvent); - } - } - } -#endif -} - -eOSState cStreamdevMenuSchedule::Switch(void) { - if (m_OtherChannel) { - if (Channels.SwitchTo(m_OtherChannel)) - return osEnd; - } - ERROR(tr("Can't switch channel!")); - return osContinue; -} - -eOSState cStreamdevMenuSchedule::Record(void) { - cMenuScheduleItem *item = (cMenuScheduleItem*)Get(Current()); - if (item) { - cRemoteTimer *timer -#if VDRVERSNUM < 10300 - = new cRemoteTimer(item->eventInfo); -#else - = new cRemoteTimer(item->event); -#endif - return AddSubMenu(new cStreamdevMenuEditTimer(timer)); - // Load remote timers and see if timer exists before editing - } - return osContinue; -} - -eOSState cStreamdevMenuSchedule::ProcessKey(eKeys Key) { - eOSState state = cOsdMenu::ProcessKey(Key); - if (state == osUnknown) { - switch (Key) { - case kRecord: - case kRed: - return Record(); - - case kGreen: - if (m_Schedules) { - if (!m_Now && !m_Next) { - int channelnr = 0; - if (Count()) { - cChannel *channel -#if VDRVERSNUM < 10300 - = Channels.GetByChannelID( - ((cMenuScheduleItem*)Get(Current()))->eventInfo->GetChannelID(), - true); -#else - = Channels.GetByChannelID( - ((cMenuScheduleItem*)Get(Current()))->event->ChannelID(), true); -#endif - if (channel) - channelnr = channel->Number(); - } - m_Now = true; - return AddSubMenu(new cStreamdevMenuWhatsOn(m_Schedules, true, - channelnr)); - } - m_Now = !m_Now; - m_Next = !m_Next; - return AddSubMenu(new cStreamdevMenuWhatsOn(m_Schedules, m_Now, - cStreamdevMenuWhatsOn::CurrentChannel())); - } - - case kYellow: - if (m_Schedules) - return AddSubMenu(new cStreamdevMenuWhatsOn(m_Schedules, false, - cStreamdevMenuWhatsOn::CurrentChannel())); - break; - - case kBlue: - if (Count()) - return Switch(); - break; - - case kOk: - if (Count()) -#if VDRVERSNUM < 10300 - return AddSubMenu(new cMenuEvent( - ((cMenuScheduleItem*)Get(Current()))->eventInfo, m_OtherChannel)); -#else - return AddSubMenu(new cMenuEvent( - ((cMenuScheduleItem*)Get(Current()))->event, m_OtherChannel)); -#endif - break; - - default: - break; - } - } else if (!HasSubMenu()) { - m_Now = false; - m_Next = false; -#if VDRVERSNUM < 10300 - const cEventInfo *ei -#else - const cEvent *ei -#endif - = cStreamdevMenuWhatsOn::ScheduleEventInfo(); - if (ei) { - cChannel *channel -#if VDRVERSNUM < 10300 - = Channels.GetByChannelID(ei->GetChannelID(), true); -#else - = Channels.GetByChannelID(ei->ChannelID(), true); -#endif - if (channel) { - PrepareSchedule(channel); - if (channel->Number() != cDevice::CurrentChannel()) { - m_OtherChannel = channel->Number(); - SetHelp(Count() ? tr("Record") : NULL, tr("Now"), tr("Next"), - tr("Switch")); - } - Display(); - } - } - } - return state; -} - -// --- cStreamdevMenuRecordingItem ------------------------------------------- - -class cStreamdevMenuRecordingItem: public cOsdItem { -private: - int m_Total; - int m_New; - char *m_FileName; - char *m_Name; - -public: - cStreamdevMenuRecordingItem(cRemoteRecording *Recording, int Level); - virtual ~cStreamdevMenuRecordingItem(); - - void IncrementCounter(bool New); - const char *Name(void) const { return m_Name; } - const char *FileName(void) const { return m_FileName; } - bool IsDirectory(void) const { return m_Name != NULL; } -}; - -cStreamdevMenuRecordingItem::cStreamdevMenuRecordingItem( - cRemoteRecording *Recording, int Level) { - m_FileName = strdup(Recording->Name()); - m_Name = NULL; - m_Total = m_New = 0; - SetText(Recording->Title('\t', true, Level)); - if (*Text() == '\t') - m_Name = strdup(Text() + 2); -} - -cStreamdevMenuRecordingItem::~cStreamdevMenuRecordingItem() { -} - -void cStreamdevMenuRecordingItem::IncrementCounter(bool New) { - ++m_Total; - if (New) ++m_New; - char *buffer = NULL; - asprintf(&buffer, "%d\t%d\t%s", m_Total, m_New, m_Name); - SetText(buffer, false); -} - -// --- cStreamdevMenuRecordings ---------------------------------------------- - -cRemoteRecordings cStreamdevMenuRecordings::Recordings; -int cStreamdevMenuRecordings::HelpKeys = -1; - -cStreamdevMenuRecordings::cStreamdevMenuRecordings(const char *Base, int Level, - bool OpenSubMenus): - cOsdMenu(Base ? Base : tr("Remote Recordings"), 6, 6) { - m_Base = Base ? strdup(Base) : NULL; - m_Level = Setup.RecordingDirs ? Level : -1; - - Display(); // this keeps the higher level menus from showing up briefly when - // pressing 'Back' during replay - - if (!Base) { - STATUS(tr("Fetching recordings...")); - FLUSH(); - } - - if (Base || Recordings.Load()) { - cStreamdevMenuRecordingItem *LastItem = NULL; - char *LastItemText = NULL; - for (cRemoteRecording *r = Recordings.First(); r; r = Recordings.Next(r)) { - if (!Base || (strstr(r->Name(), Base) == r->Name() - && r->Name()[strlen(Base)] == '~')) { - cStreamdevMenuRecordingItem *Item = new cStreamdevMenuRecordingItem(r, - m_Level); - if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) - != 0)) { - Add(Item); - LastItem = Item; - free(LastItemText); - LastItemText = strdup(LastItem->Text()); - } else - delete Item; - - if (LastItem) { - if (LastItem->IsDirectory()) - LastItem->IncrementCounter(r->IsNew()); - } - } - } - free(LastItemText); - if (Current() < 0) - SetCurrent(First()); - else if (OpenSubMenus && Open(true)) - return; - } - -#if VDRVERSNUM >= 10307 - STATUS(NULL); - FLUSH(); -#endif - - SetHelpKeys(); -} - -cStreamdevMenuRecordings::~cStreamdevMenuRecordings() { - if (m_Base != NULL) free(m_Base); - HelpKeys = -1; -} - -void cStreamdevMenuRecordings::SetHelpKeys(void) { - cStreamdevMenuRecordingItem *ri =(cStreamdevMenuRecordingItem*)Get(Current()); - int NewHelpKeys = HelpKeys; - if (ri) { - if (ri->IsDirectory()) - NewHelpKeys = 1; - else { - NewHelpKeys = 2; - cRemoteRecording *recording = GetRecording(ri); - if (recording && recording->Summary()) - NewHelpKeys = 3; - } - } - if (NewHelpKeys != HelpKeys) { - switch (NewHelpKeys) { - case 0: SetHelp(NULL); break; - case 1: SetHelp(tr("Open")); break; - case 2: - case 3: SetHelp(NULL, NULL, tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL); - //SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL); XXX - } - HelpKeys = NewHelpKeys; - } -} - -cRemoteRecording *cStreamdevMenuRecordings::GetRecording( - cStreamdevMenuRecordingItem *Item) { - Dprintf("looking for %s\n", Item->FileName()); - cRemoteRecording *recording = Recordings.GetByName(Item->FileName()); - if (!recording) - ERROR(tr("Error while accessing recording!")); - return recording; -} - -bool cStreamdevMenuRecordings::Open(bool OpenSubMenus) { - cStreamdevMenuRecordingItem *ri - = (cStreamdevMenuRecordingItem*)Get(Current()); - - if (ri && ri->IsDirectory()) { - const char *t = ri->Name(); - char *buffer = NULL; - if (m_Base) { - asprintf(&buffer, "%s~%s", m_Base, t); - t = buffer; - } - AddSubMenu(new cStreamdevMenuRecordings(t, m_Level + 1, OpenSubMenus)); - if (buffer != NULL) free(buffer); - return true; - } - return false; -} - -eOSState cStreamdevMenuRecordings::Select(void) { - cStreamdevMenuRecordingItem *ri - = (cStreamdevMenuRecordingItem*)Get(Current()); - - if (ri) { - if (ri->IsDirectory()) - Open(); - /*else { - cControl::Launch(new cStreamdevPlayerControl(ri->FileName())); - return osEnd; - } XXX */ - } - return osContinue; -} - -eOSState cStreamdevMenuRecordings::Delete(void) { - if (HasSubMenu() || Count() == 0) - return osContinue; - cStreamdevMenuRecordingItem *ri - = (cStreamdevMenuRecordingItem*)Get(Current()); - if (ri && !ri->IsDirectory()) { - if (Interface->Confirm(tr("Delete recording?"))) { - cRemoteRecording *recording = GetRecording(ri); - if (recording) { - if (ClientSocket.DeleteRecording(recording)) { - cOsdMenu::Del(Current()); - Recordings.Del(recording); - Display(); - if (!Count()) - return osBack; - } - } - } - } - return osContinue; -} - -eOSState cStreamdevMenuRecordings::Summary(void) { - if (HasSubMenu() || Count() == 0) - return osContinue; - cStreamdevMenuRecordingItem *ri=(cStreamdevMenuRecordingItem *)Get(Current()); - if (ri && !ri->IsDirectory()) { - cRemoteRecording *recording = GetRecording(ri); - if (recording && recording->Summary() && *recording->Summary()) - return AddSubMenu(new cMenuText(tr("Summary"), recording->Summary())); - } - return osContinue; -} - -eOSState cStreamdevMenuRecordings::ProcessKey(eKeys Key) { - bool HadSubMenu = HasSubMenu(); - eOSState state = cOsdMenu::ProcessKey(Key); - - if (state == osUnknown) { - switch (Key) { - case kOk: - case kRed: return Select(); - case kYellow: return Delete(); - case kBlue: return Summary(); - default: break; - } - } - - if (Key == kYellow && HadSubMenu && !HasSubMenu()) { - cOsdMenu::Del(Current()); - if (!Count()) - return osBack; - Display(); - } - - if (!HasSubMenu() && Key != kNone) - SetHelpKeys(); - return state; -} - -// --- cStreamdevMenuTimerItem ----------------------------------------------- - -class cStreamdevMenuTimerItem: public cOsdItem { -private: - cRemoteTimer *m_Timer; - -public: - cStreamdevMenuTimerItem(cRemoteTimer *Timer); - virtual ~cStreamdevMenuTimerItem(); - - virtual void Set(void); - - cRemoteTimer *Timer(void) const { return m_Timer; } -}; - -cStreamdevMenuTimerItem::cStreamdevMenuTimerItem(cRemoteTimer *Timer) { - m_Timer = Timer; - Set(); -} - -cStreamdevMenuTimerItem::~cStreamdevMenuTimerItem() { -} - -void cStreamdevMenuTimerItem::Set(void) { - char *buffer = NULL; - asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s", - !m_Timer->Active() ? ' ' : - m_Timer->FirstDay() ? '!' : - /*m_Timer->Recording() ? '#' :*/ '>', - m_Timer->Channel()->Number(), - m_Timer->PrintDay(m_Timer->Day()), - m_Timer->Start() / 100, - m_Timer->Start() % 100, - m_Timer->Stop() / 100, - m_Timer->Stop() % 100, - m_Timer->File()); - SetText(buffer, false); -} - -// --- cStreamdevMenuTimers -------------------------------------------------- - -cStreamdevMenuTimers::cStreamdevMenuTimers(void): - cOsdMenu(tr("Remote Timers"), 2, CHNUMWIDTH, 10, 6, 6) { - Refresh(); - SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("On/Off")); -} - -cStreamdevMenuTimers::~cStreamdevMenuTimers() { -} - -eOSState cStreamdevMenuTimers::ProcessKey(eKeys Key) { - int timerNum = HasSubMenu() ? Count() : -1; - eOSState state = cOsdMenu::ProcessKey(Key); - - if (state == osUnknown) { - switch (Key) { - case kOk: return Summary(); - case kRed: return Edit(); - case kGreen: return New(); - case kYellow: return Delete(); - case kBlue: OnOff(); break; - default: break; - } - } - - if (timerNum >= 0 && !HasSubMenu()) { - Refresh(); - Display(); - } - return state; -} - -eOSState cStreamdevMenuTimers::Edit(void) { - if (HasSubMenu() || Count() == 0) - return osContinue; - isyslog("Streamdev: Editing remote timer %d", CurrentTimer()->Index() + 1); - return AddSubMenu(new cStreamdevMenuEditTimer(CurrentTimer())); -} - -eOSState cStreamdevMenuTimers::New(void) { - if (HasSubMenu()) - return osContinue; - return AddSubMenu(new cStreamdevMenuEditTimer(new cRemoteTimer, true)); -} - -eOSState cStreamdevMenuTimers::Delete(void) { - cRemoteTimer *ti = CurrentTimer(); - if (ti) { - if (Interface->Confirm(tr("Delete timer?"))) { - int idx = ti->Index(); - if (ClientSocket.DeleteTimer(ti)) { - RemoteTimers.Del(ti); - cOsdMenu::Del(Current()); - isyslog("Streamdev: Remote timer %d deleted", idx + 1); - } - Refresh(); - Display(); - } - } - return osContinue; -} - -eOSState cStreamdevMenuTimers::OnOff(void) { - cRemoteTimer *timer = CurrentTimer(); - if (timer) { - cRemoteTimer data = *timer; - data.OnOff(); - if (data.FirstDay()) - isyslog("Streamdev: Remote timer %d first day set to %s", - data.Index() + 1, data.PrintFirstDay()); - else - isyslog("Streamdev: Remote timer %d %sactivated", data.Index() + 1, - data.Active() ? "" : "de"); - - if (ClientSocket.SaveTimer(timer, data)) { - *timer = data; - RefreshCurrent(); - DisplayCurrent(true); - } else { - Refresh(); - Display(); - } - } - return osContinue; -} - -eOSState cStreamdevMenuTimers::Summary(void) { - if (HasSubMenu() || Count() == 0) - return osContinue; - - cRemoteTimer *ti = CurrentTimer(); - if (ti && ti->Summary() != "") - return AddSubMenu(new cMenuText(tr("Summary"), ti->Summary().c_str())); - - return osContinue; -} - -cRemoteTimer *cStreamdevMenuTimers::CurrentTimer(void) { - cStreamdevMenuTimerItem *item = (cStreamdevMenuTimerItem*)Get(Current()); - return item ? item->Timer() : NULL; -} - -void cStreamdevMenuTimers::Refresh(void) { - Clear(); - if (RemoteTimers.Load()) { - for (cRemoteTimer *t = RemoteTimers.First(); t; t = RemoteTimers.Next(t)) { - Add(new cStreamdevMenuTimerItem(t)); - } - } -} diff --git a/client/menu.h b/client/menu.h deleted file mode 100644 index dc873d2..0000000 --- a/client/menu.h +++ /dev/null @@ -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 - -#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 - diff --git a/client/remote.c b/client/remote.c deleted file mode 100644 index d5b1380..0000000 --- a/client/remote.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * $Id: remote.c,v 1.4 2005/04/24 16:26:14 lordjaxom Exp $ - */ - -#include - -#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); -} - diff --git a/client/remote.h b/client/remote.h deleted file mode 100644 index 36a1b09..0000000 --- a/client/remote.h +++ /dev/null @@ -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 -#include - -#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 { -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 { -public: - bool Load(void); -}; - -extern cRemoteTimers RemoteTimers; - -#endif // VDR_STREAMDEV_REMOTE_H diff --git a/client/setup.c b/client/setup.c index 8d7b9cb..bf050b3 100644 --- a/client/setup.c +++ b/client/setup.c @@ -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 #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; diff --git a/client/setup.h b/client/setup.h index b0a1867..9f4d11b 100644 --- a/client/setup.h +++ b/client/setup.h @@ -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; diff --git a/client/socket.c b/client/socket.c index f349e71..02f501d 100644 --- a/client/socket.c +++ b/client/socket.c @@ -1,5 +1,5 @@ /* - * $Id: socket.c,v 1.9 2008/03/13 16:01:17 schmirl Exp $ + * $Id: socket.c,v 1.12 2008/04/08 14:18:16 schmirl Exp $ */ #include @@ -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; -} diff --git a/client/socket.h b/client/socket.h index e839223..a0400e6 100644 --- a/client/socket.h +++ b/client/socket.h @@ -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); diff --git a/common.c b/common.c index 4759515..c38c689 100644 --- a/common.c +++ b/common.c @@ -1,5 +1,5 @@ /* - * $Id: common.c,v 1.6 2008/03/31 10:34:26 schmirl Exp $ + * $Id: common.c,v 1.9 2009/01/16 11:35:43 schmirl Exp $ */ #include @@ -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 + item->SetSelectable(false); Add(item); } diff --git a/common.h b/common.h index 2565604..e920c79 100644 --- a/common.h +++ b/common.h @@ -1,5 +1,5 @@ /* - * $Id: common.h,v 1.9 2008/03/12 09:36:27 schmirl Exp $ + * $Id: common.h,v 1.12 2009/01/16 11:35:43 schmirl Exp $ */ #ifndef VDR_STREAMDEV_COMMON_H @@ -23,27 +23,9 @@ # define Dprintf(x...) #endif -#if VDRVERSNUM < 10300 -# define TRANSPONDER(c1, c2) (ISTRANSPONDER(c1->Frequency(), c2->Frequency())) -#else # define TRANSPONDER(c1, c2) (c1->Transponder() == c2->Transponder()) -#endif -#if VDRVERSNUM < 10307 -# define INFO(s) Interface->Info(s) -# define STATUS(s) Interface->Status(s) -# define ERROR(s) Interface->Status(s) -# define FLUSH() Interface->Flush() -#else -# define INFO(s) Skins.Message(mtInfo, s) -# define STATUS(s) Skins.Message(mtInfo, s) -# define ERROR(s) Skins.Message(mtStatus, s) -# define FLUSH() Skins.Flush() -#endif - -#if VDRVERSNUM >= 10336 # define MAXPARSEBUFFER KILOBYTE(16) -#endif /* Check if a channel is a radio station. */ #define ISRADIO(x) ((x)->Vpid()==0||(x)->Vpid()==1||(x)->Vpid()==0x1fff) @@ -69,7 +51,9 @@ const cChannel *ChannelFromString(const char *String, int *Apid = NULL); enum eStreamType { stTS, +#if APIVERSNUM < 10703 stPES, +#endif stPS, stES, stExtern, diff --git a/i18n.c b/i18n.c deleted file mode 100644 index 8864994..0000000 --- a/i18n.c +++ /dev/null @@ -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 } -}; diff --git a/i18n.h b/i18n.h deleted file mode 100644 index 9d90f97..0000000 --- a/i18n.h +++ /dev/null @@ -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 - -extern const char *i18n_name; -extern const tI18nPhrase Phrases[]; - -#undef tr -#define tr(s) I18nTranslate(s, i18n_name) - -#endif // VDR_STREAMDEV_I18N_H diff --git a/libdvbmpeg/DVB.hh b/libdvbmpeg/DVB.hh deleted file mode 100644 index e713bee..0000000 --- a/libdvbmpeg/DVB.hh +++ /dev/null @@ -1,446 +0,0 @@ -#ifndef _DVB_DEV_HH_ -#define _DVB_DEV_HH_ - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NEWSTRUCT -#include -} - -#include -#include -#include -using namespace std; - -#include -#include - -#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 diff --git a/libdvbmpeg/Makefile b/libdvbmpeg/Makefile index 60eba44..a586182 100644 --- a/libdvbmpeg/Makefile +++ b/libdvbmpeg/Makefile @@ -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 diff --git a/libdvbmpeg/OSD.h b/libdvbmpeg/OSD.h deleted file mode 100644 index 385ac78..0000000 --- a/libdvbmpeg/OSD.h +++ /dev/null @@ -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 diff --git a/libdvbmpeg/channel.h b/libdvbmpeg/channel.h deleted file mode 100644 index c4f62b4..0000000 --- a/libdvbmpeg/channel.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _CHANNEL_H -#define _CHANNEL_H - -#include - -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 -#include -#include -#include - -#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 -#include -#include -#include -#include - -#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 diff --git a/libdvbmpeg/ci.hh b/libdvbmpeg/ci.hh deleted file mode 100644 index 77e7684..0000000 --- a/libdvbmpeg/ci.hh +++ /dev/null @@ -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 -#include - -#include -#include -#include -#include -#include -#include -#include - -#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 diff --git a/libdvbmpeg/cpptools.cc b/libdvbmpeg/cpptools.cc deleted file mode 100644 index 0cf514c..0000000 --- a/libdvbmpeg/cpptools.cc +++ /dev/null @@ -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> ts; - int j; - int found = 0; - for (j=0;j> 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++; - } - } - } -} - - diff --git a/libdvbmpeg/cpptools.hh b/libdvbmpeg/cpptools.hh deleted file mode 100644 index 49ea5de..0000000 --- a/libdvbmpeg/cpptools.hh +++ /dev/null @@ -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 -#include -#include -#include -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_ - diff --git a/libdvbmpeg/devices.hh b/libdvbmpeg/devices.hh deleted file mode 100644 index 02c62cd..0000000 --- a/libdvbmpeg/devices.hh +++ /dev/null @@ -1,310 +0,0 @@ -#ifndef _channel_hh -#define _channel_hh - -using namespace std; -#include - -#include -#include -#include - -#include -#include -#include - -#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*/ diff --git a/libdvbmpeg/osd.hh b/libdvbmpeg/osd.hh deleted file mode 100644 index 9c6b530..0000000 --- a/libdvbmpeg/osd.hh +++ /dev/null @@ -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 diff --git a/patches/respect_ca.diff b/patches/respect_ca.diff deleted file mode 100644 index 8240b19..0000000 --- a/patches/respect_ca.diff +++ /dev/null @@ -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; - } diff --git a/patches/thread.c.diff b/patches/thread.c.diff deleted file mode 100644 index a03ffac..0000000 --- a/patches/thread.c.diff +++ /dev/null @@ -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; diff --git a/patches/vdr-1.3.11-localchannelprovide.diff b/patches/vdr-1.3.11-localchannelprovide.diff deleted file mode 100644 index 448d7fc..0000000 --- a/patches/vdr-1.3.11-localchannelprovide.diff +++ /dev/null @@ -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) diff --git a/patches/vdr-1.3.24.LocalChannelProvide.diff b/patches/vdr-1.3.24.LocalChannelProvide.diff deleted file mode 100644 index 830960a..0000000 --- a/patches/vdr-1.3.24.LocalChannelProvide.diff +++ /dev/null @@ -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(); - } diff --git a/patches/vdr-1.3.6-incompletesections.diff b/patches/vdr-1.3.6-incompletesections.diff deleted file mode 100644 index a58a121..0000000 --- a/patches/vdr-1.3.6-incompletesections.diff +++ /dev/null @@ -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; diff --git a/patches/vdr-1.6.0-ignore_missing_cam.diff b/patches/vdr-1.6.0-ignore_missing_cam.diff new file mode 100644 index 0000000..60d93bd --- /dev/null +++ b/patches/vdr-1.6.0-ignore_missing_cam.diff @@ -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; diff --git a/patches/vdr-1.6.0-intcamdevices.patch b/patches/vdr-1.6.0-intcamdevices.patch new file mode 100644 index 0000000..aab1fb4 --- /dev/null +++ b/patches/vdr-1.6.0-intcamdevices.patch @@ -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; } + diff --git a/patches/vdr-cap_net_raw.diff b/patches/vdr-cap_net_raw.diff new file mode 100644 index 0000000..2f714b1 --- /dev/null +++ b/patches/vdr-cap_net_raw.diff @@ -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; diff --git a/patches/vdr-pluginactivity.diff b/patches/vdr-pluginactivity.diff deleted file mode 100644 index 0b173ae..0000000 --- a/patches/vdr-pluginactivity.diff +++ /dev/null @@ -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: diff --git a/po/de_DE.po b/po/de_DE.po new file mode 100644 index 0000000..82fa808 --- /dev/null +++ b/po/de_DE.po @@ -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 , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"PO-Revision-Date: 2008-03-30 02:11+0200\n" +"Last-Translator: Frank Schmirler \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP Streaming Client" + +msgid "Suspend Server" +msgstr "Server pausieren" + +msgid "Server is suspended" +msgstr "Server ist pausiert" + +msgid "Couldn't suspend Server!" +msgstr "Konnte Server nicht pausieren!" + +msgid "Hide Mainmenu Entry" +msgstr "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" diff --git a/po/fi_FI.po b/po/fi_FI.po new file mode 100644 index 0000000..259ef05 --- /dev/null +++ b/po/fi_FI.po @@ -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 , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"PO-Revision-Date: 2008-03-30 02:11+0200\n" +"Last-Translator: Rolf Ahrenberg \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP-suoratoistoasiakas" + +msgid "Suspend Server" +msgstr "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" diff --git a/po/fi_FI.po.bak b/po/fi_FI.po.bak new file mode 100644 index 0000000..f96a406 --- /dev/null +++ b/po/fi_FI.po.bak @@ -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 , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-01-31 13:34+0200\n" +"PO-Revision-Date: 2008-03-30 02:11+0200\n" +"Last-Translator: Rolf Ahrenberg \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP-suoratoistoasiakas" + +msgid "Suspend Server" +msgstr "Pysäytä palvelin" + +msgid "Server is suspended" +msgstr "Palvelin on pysäytetty" + +msgid "Couldn't suspend Server!" +msgstr "Palvelinta ei onnistuttu pysäyttämään!" + +msgid "Hide Mainmenu Entry" +msgstr "Piilota valinta päävalikosta" + +msgid "Start Client" +msgstr "Käynnistä VDR-asiakas" + +msgid "Remote IP" +msgstr "Etäkoneen IP-osoite" + +msgid "Remote Port" +msgstr "Etäkoneen portti" + +msgid "Filter Streaming" +msgstr "Suodatetun tiedon suoratoisto" + +msgid "Synchronize EPG" +msgstr "Päivitä ohjelmaopas" + +msgid "Minimum Priority" +msgstr "Pienin prioriteetti" + +msgid "Maximum Priority" +msgstr "Suurin prioriteetti" + +msgid "VDR Streaming Server" +msgstr "VDR-suoratoistopalvelin" + +msgid "Streaming active" +msgstr "Suoratoistopalvelin aktiivinen" + +msgid "Suspend Live TV" +msgstr "Pysäytä suora TV-lähetys" + +msgid "Common Settings" +msgstr "Yleiset asetukset" + +msgid "Maximum Number of Clients" +msgstr "Suurin sallittu asiakkaiden määrä" + +msgid "Suspend behaviour" +msgstr "Pysäytystoiminto" + +msgid "Client may suspend" +msgstr "Asiakas saa pysäyttää palvelimen" + +msgid "VDR-to-VDR Server" +msgstr "VDR-palvelin" + +msgid "Start VDR-to-VDR Server" +msgstr "Käynnistä VDR-palvelin" + +msgid "VDR-to-VDR Server Port" +msgstr "VDR-palvelimen portti" + +msgid "Bind to IP" +msgstr "Sido osoitteeseen" + +msgid "HTTP Server" +msgstr "HTTP-palvelin" + +msgid "Start HTTP Server" +msgstr "Käynnistä HTTP-palvelin" + +msgid "HTTP Server Port" +msgstr "HTTP-palvelimen portti" + +msgid "HTTP Streamtype" +msgstr "HTTP-lähetysmuoto" + +msgid "Offer suspend mode" +msgstr "tyrkytä" + +msgid "Always suspended" +msgstr "aina" + +msgid "Never suspended" +msgstr "ei koskaan" diff --git a/po/fr_FR.po b/po/fr_FR.po new file mode 100644 index 0000000..3ba78c0 --- /dev/null +++ b/po/fr_FR.po @@ -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 , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"PO-Revision-Date: 2008-03-30 02:11+0200\n" +"Last-Translator: micky979 \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "Client de streaming VTP" + +msgid "Suspend Server" +msgstr "Suspendre le serveur" + +msgid "Server is suspended" +msgstr "Le serveur est suspendu" + +msgid "Couldn't suspend Server!" +msgstr "Impossible de suspendre le serveur!" + +msgid "Hide Mainmenu Entry" +msgstr "Masquer dans le menu principal" + +msgid "Start Client" +msgstr "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" diff --git a/po/it_IT.po b/po/it_IT.po new file mode 100755 index 0000000..4db80ed --- /dev/null +++ b/po/it_IT.po @@ -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 , 2001 +# Antonio Ospite , 2003 +# Sean Carlos , 2005 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"PO-Revision-Date: 2008-04-13 23:42+0100\n" +"Last-Translator: Diego Pierotto \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "Client trasmissione VTP" + +msgid "Suspend Server" +msgstr "Sospendi Server" + +msgid "Server is suspended" +msgstr "Server sospeso" + +msgid "Couldn't suspend Server!" +msgstr "Impossibile sospendere il server!" + +msgid "Hide Mainmenu Entry" +msgstr "Nascondi voce menu principale" + +msgid "Start Client" +msgstr "Avvia Client" + +msgid "Remote IP" +msgstr "Indirizzo IP del Server" + +msgid "Remote Port" +msgstr "Porta Server Remoto" + +msgid "Filter Streaming" +msgstr "Filtra trasmissione" + +msgid "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" diff --git a/po/ru_RU.po b/po/ru_RU.po new file mode 100644 index 0000000..b80fcd3 --- /dev/null +++ b/po/ru_RU.po @@ -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 , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: streamdev 0.5.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-02-13 11:53+0100\n" +"PO-Revision-Date: 2008-06-26 15:36+0100\n" +"Last-Translator: Oleg Roitburd \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-5\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "VTP Streaming Client" +msgstr "VTP Streaming ÚŰŘŐÝâ" + +msgid "Suspend Server" +msgstr "žáâĐÝŢŇŘâě áŐŕŇŐŕ" + +msgid "Server is suspended" +msgstr "ÁŐŕŇŐŕ ŢáâĐÝŢŇŰŐÝ" + +msgid "Couldn't suspend Server!" +msgstr "ÝŐ ÜŢÓă ŢáâĐÝŢŇŘâě áŐŕŇŐŕ" + +msgid "Hide Mainmenu Entry" +msgstr "ÁßŕďâĐâě Ň ÓŰĐŇÝŢÜ ÜŐÝî" + +msgid "Start Client" +msgstr "ÁâĐŕâ ÚŰŘŐÝâĐ" + +msgid "Remote IP" +msgstr "ĂÔĐŰŐÝÝëŮ IP" + +msgid "Remote Port" +msgstr "ĂÔĐŰŐÝÝëŮ ßŢŕâ" + +msgid "Filter Streaming" +msgstr "ÄŘŰěâŕ ßŢâŢÚĐ" + +msgid "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 "˝ŘÚŢÓÔĐ ÝŐ ŢáâĐÝŢŇŰŐÝ" diff --git a/remux/extern.c b/remux/extern.c index e137c4a..c5f35de 100644 --- a/remux/extern.c +++ b/remux/extern.c @@ -1,4 +1,5 @@ #include "remux/extern.h" +#include "server/server.h" #include "server/streamer.h" #include #include @@ -6,8 +7,6 @@ #include #include -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,9 +66,13 @@ 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); - _exit(-1); + 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]); @@ -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) { - esyslog("streamdev-server: externremux process won't stop - killing it"); - kill(m_Process, SIGKILL); - } - cCondWait::SleepMs(100); + // 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; } } diff --git a/remux/extern.h b/remux/extern.h index 7a44852..aa6acf7 100644 --- a/remux/extern.h +++ b/remux/extern.h @@ -5,8 +5,6 @@ #include #include -extern const char *g_ExternRemux; - class cTSExt; class cExternRemux: public cTSRemux { diff --git a/remux/ts2ps.h b/remux/ts2ps.h index 334215a..f31e025 100644 --- a/remux/ts2ps.h +++ b/remux/ts2ps.h @@ -5,6 +5,10 @@ #include #include +#ifndef MAXTRACKS +#define MAXTRACKS 64 +#endif + class cTS2PS; class cTS2PSRemux: public cTSRemux { diff --git a/remux/tsremux.c b/remux/tsremux.c index 6be5245..c73c2fe 100644 --- a/remux/tsremux.c +++ b/remux/tsremux.c @@ -1,6 +1,7 @@ #include "remux/tsremux.h" -#define SC_PICTURE 0x00 // "picture header" +#define SC_PICTURE 0x00 // "picture header" +#define PID_MASK_HI 0x1F void cTSRemux::SetBrokenLink(uchar *Data, int Length) { diff --git a/remux/tsremux.h b/remux/tsremux.h index f7e4e09..a7fe481 100644 --- a/remux/tsremux.h +++ b/remux/tsremux.h @@ -4,6 +4,10 @@ #include "libdvbmpeg/transform.h" #include +#ifndef NO_PICTURE +#define NO_PICTURE 0 +#endif + #define RESULTBUFFERSIZE KILOBYTE(256) class cTSRemux { diff --git a/server/component.c b/server/component.c index 1a584b5..70d861a 100644 --- a/server/component.c +++ b/server/component.c @@ -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) { diff --git a/server/component.h b/server/component.h index 8703348..7efd4ba 100644 --- a/server/component.h +++ b/server/component.h @@ -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 diff --git a/server/componentIGMP.c b/server/componentIGMP.c new file mode 100644 index 0000000..946c513 --- /dev/null +++ b/server/componentIGMP.c @@ -0,0 +1,447 @@ +/* + * $Id: componentIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $ + */ +#include +#include + +#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(); +} diff --git a/server/componentIGMP.h b/server/componentIGMP.h new file mode 100644 index 0000000..09d8fde --- /dev/null +++ b/server/componentIGMP.h @@ -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 +#include +#include +#include "server/component.h" + +class cConnectionIGMP; +class cMulticastGroup; + +class cComponentIGMP: public cServerComponent, public cThread { +private: + char m_ReadBuffer[2048]; + cList 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 diff --git a/server/connection.c b/server/connection.c index 629ed1d..74b2783 100644 --- a/server/connection.c +++ b/server/connection.c @@ -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 #include -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); diff --git a/server/connection.h b/server/connection.h index fe828d9..2c28a09 100644 --- a/server/connection.h +++ b/server/connection.h @@ -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) { } diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c index 38a82a3..fc10bfc 100644 --- a/server/connectionHTTP.c +++ b/server/connectionHTTP.c @@ -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 #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; diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h index a3558ad..0548959 100644 --- a/server/connectionHTTP.h +++ b/server/connectionHTTP.h @@ -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 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); diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c new file mode 100644 index 0000000..dc08798 --- /dev/null +++ b/server/connectionIGMP.c @@ -0,0 +1,64 @@ +/* + * $Id: connectionIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $ + */ + +#include + +#include "server/connectionIGMP.h" +#include "server/server.h" +#include "server/setup.h" +#include + +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); + } +} diff --git a/server/connectionIGMP.h b/server/connectionIGMP.h new file mode 100644 index 0000000..90abd58 --- /dev/null +++ b/server/connectionIGMP.h @@ -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 + +#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 diff --git a/server/connectionVTP.c b/server/connectionVTP.c index 2829c13..e0edb6e 100644 --- a/server/connectionVTP.c +++ b/server/connectionVTP.c @@ -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; diff --git a/server/connectionVTP.h b/server/connectionVTP.h index 3acb1a2..452f3ae 100644 --- a/server/connectionVTP.h +++ b/server/connectionVTP.h @@ -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; diff --git a/server/livefilter.c b/server/livefilter.c index e7d896c..67b0e37 100644 --- a/server/livefilter.c +++ b/server/livefilter.c @@ -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 diff --git a/server/livefilter.h b/server/livefilter.h index 99c69d4..13e8956 100644 --- a/server/livefilter.h +++ b/server/livefilter.h @@ -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 -# if VDRVERSNUM >= 10300 - #include class cStreamdevStreamer; @@ -31,5 +29,4 @@ public: } }; -# endif // VDRVERSNUM >= 10300 #endif // VDR_STREAMEV_LIVEFILTER_H diff --git a/server/livestreamer.c b/server/livestreamer.c index 5e19d2b..97dffd7 100644 --- a/server/livestreamer.c +++ b/server/livestreamer.c @@ -3,13 +3,14 @@ #include #include +#include "remux/ts2ps.h" +#include "remux/ts2es.h" +#include "remux/extern.h" + #include #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); - m_Streamer->SetPids(pmtPid); - Add(pmtPid, 0x02); - pmtVersion = -1; + 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 diff --git a/server/livestreamer.h b/server/livestreamer.h index 57c3a90..5c4ae8f 100644 --- a/server/livestreamer.h +++ b/server/livestreamer.h @@ -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 class cStreamdevLiveFilter; @@ -85,6 +87,4 @@ public: //virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); }; -# endif // if VDRVERSNUM >= 10300 - #endif // VDR_STREAMDEV_LIVESTREAMER_H diff --git a/server/menuHTTP.c b/server/menuHTTP.c index b5bb299..41b1f10 100644 --- a/server/menuHTTP.c +++ b/server/menuHTTP.c @@ -112,10 +112,10 @@ const cChannel* cChannelList::GetGroup(int Index) // ******************** cHtmlChannelList ****************** const char* cHtmlChannelList::menu = - "[Home (no script)] " - "[Tree View] " - "[Groups (Playlist)] " - "[Channels (Playlist)] "; + "[Home (no script)] " + "[Tree View] " + "[Groups (Playlist)] " + "[Channels (Playlist)] "; const char* cHtmlChannelList::css = "