summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS8
-rw-r--r--CONTRIBUTORS19
-rw-r--r--FORMATS31
-rw-r--r--HISTORY64
-rw-r--r--INSTALL32
-rw-r--r--MANUAL28
-rw-r--r--Makefile9
-rw-r--r--TODO7
-rw-r--r--Tools/schnitt/README84
-rwxr-xr-xTools/schnitt/cut.pl40
-rwxr-xr-xTools/schnitt/cut22
-rwxr-xr-xTools/schnitt/cutall4
-rwxr-xr-xTools/schnitt/cutall25
-rwxr-xr-xTools/schnitt/cutt85
-rwxr-xr-xTools/schnitt/getpreviframe.pl31
-rw-r--r--Tools/schnitt/index.php215
-rwxr-xr-xTools/schnitt/lmplex51
-rwxr-xr-xTools/schnitt/mv223
-rwxr-xr-xTools/schnitt/schnitt.pl26
-rwxr-xr-xTools/schnitt/schnitt2.pl91
-rwxr-xr-xTools/schnitt/schnitt3.pl64
-rwxr-xr-xTools/schnitt/schnitt3.pl.new77
-rwxr-xr-xTools/schnitt/schnitt4.pl13
-rwxr-xr-xTools/schnitt/schnitt5.pl16
-rwxr-xr-xTools/schnitt/schnitt6.pl30
-rwxr-xr-xTools/schnitt/schnittcommon.pli64
-rwxr-xr-xTools/schnitt/show11
-rwxr-xr-xTools/schnitt/unsort25
-rwxr-xr-xTools/schnitt/vdr-remote.pl40
-rwxr-xr-xTools/schnitt/vdr22
-rwxr-xr-xTools/schnitt/vmount18
-rw-r--r--channels.conf318
-rw-r--r--channels.conf.cable134
-rw-r--r--config.c30
-rw-r--r--config.h7
-rw-r--r--dvbapi.c208
-rw-r--r--dvbapi.h26
-rw-r--r--eit.c13
-rwxr-xr-x[-rw-r--r--]epg2html.pl0
-rw-r--r--i18n.c22
-rw-r--r--interface.c20
-rw-r--r--menu.c115
-rw-r--r--menu.h4
-rw-r--r--osd.c50
-rw-r--r--osd.h7
-rw-r--r--recording.c97
-rw-r--r--recording.h14
-rw-r--r--remote.c12
-rw-r--r--remote.h10
-rwxr-xr-xrunvdr13
-rw-r--r--svdrp.c54
-rw-r--r--svdrp.h8
-rwxr-xr-xsvdrpsend.pl57
-rw-r--r--tools.c52
-rw-r--r--tools.h3
-rw-r--r--vdr.c111
-rw-r--r--videodir.c12
-rw-r--r--videodir.h3
58 files changed, 2214 insertions, 401 deletions
diff --git a/BUGS b/BUGS
deleted file mode 100644
index 506316a..0000000
--- a/BUGS
+++ /dev/null
@@ -1,8 +0,0 @@
-Video Disk Recorder - Known Bugs
---------------------------------
-
-* Sometimes the picture "jumps" as if a frame is skipped.
- Presumably this is a problem in the card driver or firmware?
-
-* The pictures captured with the GRAB command in SVDRP
- appear to be too dark.
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index ee44ada..7a93b33 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -34,18 +34,29 @@ Niels de Carpentier <niels@casema.net>
Martin Hammerschmid <martin@hammerschmid.com>
for suggesting to display the direct channel select input on the OSD
for suggesting to use the "Blue" button in the main menu to resume replay
+ for implementing pege up/down with the "Left" and "Right" keys
Bastian Guse <bastian@nocopy.de>
for writing the FORMATS entry for timers.conf
Matthias Schniedermeyer <ms@citd.de>
- for implementing the 'MarkInstantRecord' setup option.
+ for implementing the 'MarkInstantRecord' setup option
+ for his "schnitt" tools
Miha Setina <mihasetina@softhome.net>
- for translating the OSD texts to the Slovenian language.
+ for translating the OSD texts to the Slovenian language
Alberto Carraro <bertocar@tin.it>
- for translating the OSD texts to the Italian language.
+ for translating the OSD texts to the Italian language
Deti Fliegl <deti@fliegl.de>
- for implementing the 'CurrentChannel' setup parameter.
+ for implementing the 'CurrentChannel' setup parameter
+
+Dave Chapman <dave@dchapman.com>
+ for implementing support for the teletext PID
+
+Hans-Peter Raschke <Hans-Peter.Raschke@Wintermann-DatenService.de>
+ for his support in adapting VDR to DVB-C
+
+Peter Hofmann <software@pxh.de>
+ for his support in adapting VDR to DVB-C
diff --git a/FORMATS b/FORMATS
index ed52518..2a357a3 100644
--- a/FORMATS
+++ b/FORMATS
@@ -13,7 +13,7 @@ Video Disk Recorder File Formats
A "channel definition" is a line with channel data, where the fields
are separated by ':' characters:
- Example: "RTL:12188:h:1:27500:163:104:0:12003"
+ Example: "RTL:12188:h:1:27500:163:104:0:0:12003"
The fields in a channel definition have the following meaning (from left
to right):
@@ -21,15 +21,19 @@ Video Disk Recorder File Formats
- Name: the channel's name (if the name originally contains a ':' character
it has to be replaced by '|')
- Frequency in MHz (as an integer)
- - Polarization (one of 'h', 'H', 'v', 'V')
- - Diseqc number
+ - Polarization (one of 'h', 'H', 'v', 'V') **
+ - Diseqc number **
- Symbol rate
- Video PID
- Audio PID
+ - Teletext PID
- Conditional Access (0 = Free To Air, 1 = can be decrypted by the first
DVB card, 2 = can be decrypted by the second DVB card)
- Program Number
+ Fields marked with ** are only meaningful for DVB-S (satellite) receivers.
+ DVB-C receivers simply ignore these.
+
* timers.conf
This file contains the timer setup.
@@ -37,7 +41,10 @@ Video Disk Recorder File Formats
The fields in a timer definition have the following meaning (from left
to right):
- - Timer active (0 = inaactive, 1 = active)
+ - Timer active (0 = inactive, 1 = active)
+ Values larger than '1' can be used by external programs to mark active timers
+ and recognize if the user has modified them. When a user modifes an active
+ timer the 'active' field will be explicitly set to '1'.
- Program number of the channel to record
- Day of recording, either one or more of
M------ = Monday
@@ -55,8 +62,10 @@ Video Disk Recorder File Formats
- End time (first two digits for the hour, second two digits for the minutes)
- Priority (from 00 to 99, 00 = lowest prioity, 99 = highest priority)
- Guaranteed lifetime of recording (in days)
- - Name of timer (will be used to name the recording)
- - Summary
+ - Name of timer (will be used to name the recording); if the name contains
+ any ':' characters, these have to be replaced with '|'
+ - Summary (any newline characters in the summary have to be replaced with '|';
+ the summary may contain ':' characters)
* setup.conf
@@ -86,9 +95,13 @@ Video Disk Recorder File Formats
Examples:
- Check for new mail: /usr/local/bin/checkmail 2>&1
- CPU status : /usr/loval/bin/cpustatus 2>&1
- Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }'
+ 1 Check for new mail: /usr/local/bin/checkmail 2>&1
+ 2 CPU status : /usr/loval/bin/cpustatus 2>&1
+ 3 Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }'
+
+ If the first non-blank character of the 'title' is a digit in the range
+ 1..9, the command can be selected directly by pressing the respective numerical
+ key on the remote control.
* marks.vdr
diff --git a/HISTORY b/HISTORY
index 8d5e884..684d2b6 100644
--- a/HISTORY
+++ b/HISTORY
@@ -349,3 +349,67 @@ Video Disk Recorder Revision History
- The EIT scanning thread is now locked when switching channels to avoid problems.
- Encrypted channels can now be selected even without knowing the PNR (however, it
is still necessary for the EPG info).
+
+2001-02-24: Version 0.71
+
+- Fixed 'Transfer Mode' in cases where a non-primary interface was switched to
+ a channel that only the primary interface can receive (which could happen in
+ the EPG scanner).
+- The EPG scanner now starts with the first channel (it used to start with the
+ second channel).
+- Reacitvated setting the PNR.
+- Adapted the frame scanning to the new muxing of the driver.
+- The new compile time option REMOTE=NONE can be used to compile VDR without
+ any remote control support (for applications where it shall be controlled
+ exclusively via SVDRP).
+- The new command line option -D can be used to define which DVB interfaces
+ a certain instance of VDR shall use.
+- The "Left" and "Right" keys are now used to page up and down in lists (thanks
+ to Martin Hammerschmid). Since the "Timers" menu already uses these keys to
+ (de)activate timers, this functionality is not available there.
+- The "Main" and "Commands" menu now support "hotkeys", which means that if the
+ first non-blank character of a menu item is a digit in the range 1..9, that
+ item can be selected by pressing the respective numeric key on the remote
+ control.
+- The channel data in 'channels.conf' now contains the teletext PID (thanks to
+ Dave Chapman). Existing files will be read normally (and the teletext PID set
+ to 0), but once they are written back (due to some channel editing) the file
+ will have the new format.
+- The EPG scanner now scans each transponder only once per cycle.
+- Deleted recordings are now automatically removed from disk after a while (not
+ only when disk space is being needed for a new recording).
+- Fixed repeat function in LIRC remote control.
+- Changed the MAXDVBAPI macro in dvbapi.c to 4 in order to directly support the
+ maximum possible number of DVB cards.
+- The 'Ca' parameter in the default 'channels.conf' has been changed from '2'
+ to '3' because the VDR prototype now has 3 DVB cards (and currently the CAM
+ module only works if it is inserted into the last DVB card).
+- The "Now", "Next" and "Schedule" menus now remember the current channel and
+ restore the list when switching between them.
+- The "Green" button in the "Recordings" menu can now be used to rewind a
+ recording and play it from the very beginning.
+- Fixed handling ':' in timer filenames and '\n' in timer summaries (see FORMATS).
+- When removing recordings empty directories are now removed from the video
+ directory.
+- Added the "schnitt" tools from Matthias Schniedermeyer.
+- New SVDRP command MESG to display a short message on the OSD.
+- The Perl script 'svdrpsend.pl' can be used to send SVDRP commands to VDR.
+- SVDRP can now immediately reuse the same port if VDR is restarted.
+- SVDRP now has a timeout after which the connection is automatically closed
+ (default is 300 seconds, can be changed in "Setup").
+- The compile time switch VFAT can be used to make VDR avoid the ':' character
+ in file names (VFAT can't handle them). Do 'make VFAT=1' to enable this.
+- Support for DVB-C (thanks to Hans-Peter Raschke and Peter Hofmann).
+ See the INSTALL file for more information about the use of VDR with cable.
+- Fixed an occasional segfault in the EIT processor.
+- A value of '0' for the EPGScanTimeout setup parameter now completely turns off
+ scanning for EPG data on both single and multiple card systems.
+- New setup parameter "PrimaryLimit" that allows to prevent timers from using the
+ primary DVB interface in multi card systems. Default value is 0, which means
+ that every timer may use the primary interface.
+- The 'active' field of a timer will now be explicitly set to '1' if the user
+ modifies an active timer (see FORMATS for details).
+- The new command line option -w can be used to activate a watchdog that makes
+ VDR exit in case the main program loop does not respond for more than the
+ given number of seconds. This is mainly useful in combination with the new
+ 'runvdr' script that restarts VDR in case is has exited.
diff --git a/INSTALL b/INSTALL
index e2a67a0..c334ed6 100644
--- a/INSTALL
+++ b/INSTALL
@@ -15,7 +15,7 @@ If you have the DVB driver source in a different location
you will have to change the definition of DVBDIR in the
Makefile.
-This program requires the card driver version 0.8.1 or higher
+This program requires the card driver version 0.8.2 or higher
to work properly. You need to load the dvb.o module *without* option
'outstream=0' (previous versions of VDR required this option to have
the driver supply the data in AV_PES format; as of version 0.70 VDR
@@ -38,6 +38,7 @@ following values 'make' call to activate the respective control mode:
(see http://www.cadsoft.de/people/kls/vdr/remote.htm)
REMOTE=LIRC control via the "Linux Infrared Remote Control"
(see http://www.lirc.org)
+ REMOTE=NONE no remote control (in case only SVDRP shall be used)
Adding "DEBUG_OSD=1" will use the PC screen (or current window)
to display texts instead of the DVB card's on-screen display
@@ -45,6 +46,13 @@ interface. These modes are useful when testing new menus if you
only have a remote connection to the VDR (which, in my case, is
located in the living room and has neither a monitor nor a keyboard).
+If your video directory will be on a VFAT partition, add the compile
+time switch
+
+ VFAT=1
+
+to the 'make' command.
+
When running, the 'vdr' program writes status information into the
system log file (/var/log/messages). You may want to watch these
messages (tail -f /var/log/mesages) to see if there are any problems.
@@ -63,6 +71,13 @@ If the program shall run as a daemon, use the --daemon option. This
will completely detach it from the terminal and will continue as a
background process.
+Automatic restart in case of hangups:
+-------------------------------------
+
+If you run VDR using the 'runvdr' shell script it will use the built-in
+watchdog timer to restart the program in case something happens that
+causes a program hangup.
+
Command line options:
---------------------
@@ -132,6 +147,21 @@ that the channels defined in 'channels.conf' are correct before attempting
to record anything. Channel parameters may vary and not all of the channels
listed in the default 'channels.conf' file have been verified by the author.
+As a starting point you can copy the 'channels.conf' file that comes with the
+VDR archive into your video directory (or into your config directory,
+respectively, in case you have redirected it with the -c option).
+
+Running VDR with DVB-C (cable):
+-------------------------------
+
+VDR automatically recognizes if the DVB card in use is a cable card.
+The only things that needs to be different when using digital cable
+is the 'channels.conf' file. The distribution archive contains a default
+'channels.conf.cable', which cable users can rename or copy to 'channels.conf'
+in order to receive cable channels. The format of this file is exactly the
+same as for satellite channels (the fields containing "Polarization" and
+"Diseqc" data are ignored in case of DVB-C).
+
Learning the remote control keys:
---------------------------------
diff --git a/MANUAL b/MANUAL
index b0e9abe..f77bd27 100644
--- a/MANUAL
+++ b/MANUAL
@@ -12,16 +12,16 @@ Video Disk Recorder User's Manual
Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play
Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause
- Left Prev group - - Disable Decrement - Search back
- Right Next group - - Enable Increment - Search forward
+ Left Prev group - Page up Disable Decrement Page up Search back
+ Right Next group - Page down Enable Increment Page down Search forward
Ok Ch display Select Switch Edit Accept Play Progress disp.
Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on
Back - Menu off Main menu Main menu Discard Main menu Recordings menu
Red - Record Edit Edit - Play -
- Green - - New New - - Skip -60s
+ Green - - New New - Rewind Skip -60s
Yellow - - Delete Delete - Delete Skip +60s
- Blue - Resume Mark Mark - - Stop
- 0..9 Ch select - - - Numeric inp. - -
+ Blue - Resume Mark Mark - Summary Stop
+ 0..9 Ch select - - - Numeric inp. - Editing
* Navigating through the On Screen Menus
@@ -310,7 +310,7 @@ Video Disk Recorder User's Manual
1 = instant recordings will be marked.
LnbFrequLo = 9750 The low and high LNB frequencies (in MHz)
- LnbFrequHi = 10600
+ LnbFrequHi = 10600 (these have no meaning for DVB-C receivers)
SetSystemTime = 0 Defines whether the system time will be set according to
the time received from the DVB data stream.
@@ -326,7 +326,21 @@ Video Disk Recorder User's Manual
EPGScanTimeout = 5 The time (in hours) of user inactivity after which the
DVB card in a single card system starts scanning channels
to keep the EPG up-to-date.
- A value of '0' turns off scanning on a single card system.
+ A value of '0' completely turns off scanning on both single
+ and multiple card systems.
+
+ SVDRPTimeout = 300 The time (in seconds) of inactivity on an open SVDRP
+ connection after which the connection is automatically
+ closed. Default is 300, a value of 0 means no timeout.
+
+ PrimaryLimit = 0 The minimum priority a timer must have to be allowed to
+ use the primary DVB interface, or to force another timer
+ with higher priority to use the primary DVB interface.
+ This is mainly useful for recordings that should take
+ place only when there is nothing else to do, but should
+ never keep the user from viewing stuff on the primary
+ interface. On systems with only one DVB card, timers
+ with a priority below PrimaryLimit will never execute.
* Executing system commands
diff --git a/Makefile b/Makefile
index 4505c7b..c1cfabe 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 1.18 2001/01/13 12:26:43 kls Exp $
+# $Id: Makefile 1.20 2001/02/24 15:52:58 kls Exp $
DVBDIR = ../DVB
@@ -25,6 +25,11 @@ ifdef DEBUG_OSD
DEFINES += -DDEBUG_OSD
endif
+ifdef VFAT
+# for people who want their video directory on a VFAT partition
+DEFINES += -DVFAT
+endif
+
all: vdr
font: genfontfile fontfix.c fontosd.c
@echo "font files created."
@@ -75,6 +80,6 @@ genfontfile: genfontfile.o
# Housekeeping:
clean:
- -rm -f $(OBJS) vdr genfontfile genfontfile.o
+ -rm -f $(OBJS) vdr genfontfile genfontfile.o core
CLEAN: clean
-rm -f fontfix.c fontosd.c
diff --git a/TODO b/TODO
deleted file mode 100644
index 1ae7d71..0000000
--- a/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-TODO list for the Video Disk Recorder project
----------------------------------------------
-
-* Implement simultaneous record/replay with a single DVB card once
- the card driver/firmware allows this.
-* Implement channel scanning.
-* Implement remaining commands in SVDRP.
diff --git a/Tools/schnitt/README b/Tools/schnitt/README
new file mode 100644
index 0000000..29953e0
--- /dev/null
+++ b/Tools/schnitt/README
@@ -0,0 +1,84 @@
+ Sammlung von "Hilfs"-Scripten
+
+Diese Sammlung an "Hilfs"-Scripten habe ich mir zum scheiden und anderen
+Zwecken zusammengeschrieben.
+
+Das ganze unterliegt natuerlich der GPL.
+
+Ich bin nicht sonderlich gut im "Dokumentieren". Also gilt die Devise
+"Hilf dir selbst".
+
+Ein paar Worte zu den "Hart"-Codierten Pfaden.
+
+/yele/video (/video/video0)
+/yelg/video (/video/video1)
+
+Sind die 2 Pfade auf meinem DVB-Rechner
+
+/x1/video
+
+Ist das Verzeichniss in das die Video zum schneiden verschoben werden.
+
+/x1/temp
+/x2/temp
+
+Sind die beim schneiden verwendeten Temporaer-Verzeichnisse
+
+
+Enthalten sind folgende Scripte:
+
+cutall -> "Master"-Script zum starten des Scheide vorgangs.
+ Ist ein "find" nach "cut" -Dateien
+cutt -> Das "eigentliche" Schnitt-Script
+ Scheidet die Stuecke aus, demultipext, remultipext,
+ splitted die Dateien und macht am Ende ein
+ ISO-Image daraus
+index.php -> PHP-Script zum finden der Schnitt-Punkte, mit
+ Testmoeglichkeit ob erfolgreich an diesem Punkt
+ geschnitten werden kann
+mv2 -> Zum Moven der Aufnahmen von meinem DVB-Rechner
+ auf mein "Arbeitsrechner"
+schnitt.pl -> Extraiert ein einzelnes Bild um es anzuzeigen
+ (Fuer index.php)
+schnitt2.pl -> Gibt alles zwischen 2 Schnittpunkten auf STDOUT aus
+schnitt3.pl -> Testet ob erfolgreich geschnitten werden kann.
+schnitt3.pl.new -> Version fuer PES-Datenstroeme
+schnitt4.pl -> "Beschleunigtes" Schnitt-Programm fuer VIVA
+ aufnahmen. 1 "VIDEO" pro Zeile erzeugt
+ "a", "b" ... Dateien
+schnitt5.pl -> Gibt Datei-Nummern von einer Schnittmarke
+ +- 15000 Frames aus
+schnitt6.pl -> Loescht alle Dateien die nicht von in einer von
+ schnitt5.pl abgedeckt ist. (Damit mv2 nicht so
+ lange braucht)
+show -> Wird auf einem X-Display gestartet und zeigt das
+ aktuelle Bild von "schnitt.pl" an
+vdr-remote.pl -> "Skeleton" um ueber SVDR-Kommandos zu schicken
+vdr2 -> Start-Script
+vmount -> Mounten aller zusammengehoeriger ISO-Images zum
+ abspielen
+
+Hilsscripte:
+------------
+cut.pl -> Entspricht weitestgehend "split" aber mit
+ "Nummer" anstatt Buchstaben
+cut2 -> Entfernt escapende Backslashes
+cutall2 -> Springt ins Schnitt-Verzeichniss und ruft das
+ "eigentliche" Schnitt-Script auf
+lmplex -> Multiplexed Datenstrome unter Zurhilfename
+ saemtlicher CPUs
+schnittcommon.pli -> Das "Common" Script fuer schnitt?.pl
+getpreviframe.pl -> Findet das vorherige I-Frame.
+unsort -> Macht das Gegenteil von sort.
+
+
+Die ganze "Schnittloesung" ist leider etwas "unbrauchbar", weil ich aus
+Unachtsamkeit leider die gepatchten Sourcen von 2 wichtigen Programm
+geloescht habe.
+
+dumpfrage -> Extraiert das erste Frage in eine Datei zum
+ anzeigen (gepatchtes dump aus "libmpeg3"
+pvademux -> gepatcht um eine Pfad-Angabe
+
+Entweder macht jemand/ich patchen "nochmal" oder ich kann auch die
+Binaries zur Verfuegung stellen.
diff --git a/Tools/schnitt/cut.pl b/Tools/schnitt/cut.pl
new file mode 100755
index 0000000..dd62c18
--- /dev/null
+++ b/Tools/schnitt/cut.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my $maxsize = 660 * 1024 * 1024;
+
+my $read = 1024*1024;
+my $size = 1024*1024;
+
+my $filenum = "1";
+my $count = 0;
+
+my ($fi,$data);
+
+$fi = sprintf ("part%d",$filenum);
+open (FI,">$fi");
+
+while ($read == $size)
+ {
+ if ($count < $maxsize)
+ {
+ $read = read (STDIN,$data,$size);
+ print FI $data;
+ $count += $size;
+ $a = $count /1024/1024;
+ if ($a % 10 == 0) {
+ print STDERR "File: $filenum Size: ${a}MB\n";
+ }
+ }
+ else
+ {
+ close (FI);
+ $filenum++;
+ $fi = sprintf ("part%d",$filenum);
+ open (FI,">$fi");
+ $count = 0;
+ }
+ }
+
+close FI;
diff --git a/Tools/schnitt/cut2 b/Tools/schnitt/cut2
new file mode 100755
index 0000000..0193ac0
--- /dev/null
+++ b/Tools/schnitt/cut2
@@ -0,0 +1,2 @@
+#!/bin/sh
+cat cut | head -n 1 | tr -d [\\\\]
diff --git a/Tools/schnitt/cutall b/Tools/schnitt/cutall
new file mode 100755
index 0000000..355935f
--- /dev/null
+++ b/Tools/schnitt/cutall
@@ -0,0 +1,4 @@
+#!/bin/sh
+cutdir=/x1/video/
+
+find $cutdir -name "cut" -exec cutall2 {} \;
diff --git a/Tools/schnitt/cutall2 b/Tools/schnitt/cutall2
new file mode 100755
index 0000000..90b0f46
--- /dev/null
+++ b/Tools/schnitt/cutall2
@@ -0,0 +1,5 @@
+#!/bin/sh
+a=`echo $1 | cut -d / -f1-5`
+cd $a
+cutt
+mv cut cut.bak
diff --git a/Tools/schnitt/cutt b/Tools/schnitt/cutt
new file mode 100755
index 0000000..4e89b7a
--- /dev/null
+++ b/Tools/schnitt/cutt
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+DIRA=/x2/temp
+DIRB=/x1/temp
+
+if [ -f cut ]; then
+ name="`cut2`"
+ echo $name
+ count=`cat cut | wc -l`
+ let count=count-1
+ let test=count%2
+ if [ "$test" == "1" ]; then
+ echo Ungerade Anzahl von Markierungen
+ exit 1
+ fi
+
+ file=1
+
+ while [ "$count" != "0" ]
+ do
+ start=`cat cut | tail -n $count | head -n 1`
+ let count=count-1
+ end=`cat cut | tail -n $count | head -n 1`
+ let count=count-1
+ echo Cutting\&Demuxing from $start to $end
+ schnitt2.pl $start $end | pvademux $DIRA teil$file
+# schnitt2.pl $start $end | pes2av_pes | pvademux $DIRA teil$file
+ let file=file+1
+ done
+else
+ echo Keine Beschreibungsdatei
+ exit 1
+fi
+
+# Ab hier mkimg
+
+sync
+
+lmplex $DIRA $DIRB `ls -la $DIRA/teil*.m2v | cut -b 30- | sort -n -r | cut -d / -f4`
+
+echo Multiplexing DONE
+
+rm -f $DIRA/teil*.m2v $DIRA/teil*.mp2
+
+sync
+
+if [ -f $DIRB/teil1.mpg ]; then
+ echo Splitting
+ cd $DIRA
+# cat $DIRB/teil*.mpg | split -b 723517440
+ cat $DIRB/teil*.mpg | cut.pl
+ rm $DIRB/teil*
+fi
+
+sync
+
+cd $DIRA
+
+if [ -f part2 ]; then
+ count=1
+ cond=0
+
+ while [ "$cond" != "1" ]
+ do
+ mkdir a
+ mv "part$count" "a/${name} Teil $count"
+ echo mkisofs Teil $count
+ mkisofs -r -o $DIRB/image1.raw a
+ rm -rf a
+ mv -- $DIRB/image1.raw "$DIRB/${name} Teil $count"
+ sync
+
+ let count=count+1
+ if [ ! -f "part$count" ]; then
+ cond=1
+ fi
+ done
+else
+ mkdir a
+ mv part1 "a/${name}"
+ echo mkisofs
+ mkisofs -r -o $DIRB/image1.raw a
+ rm -rf a
+ mv -- $DIRB/image1.raw "$DIRB/${name}"
+fi
diff --git a/Tools/schnitt/getpreviframe.pl b/Tools/schnitt/getpreviframe.pl
new file mode 100755
index 0000000..6774f31
--- /dev/null
+++ b/Tools/schnitt/getpreviframe.pl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+use strict;
+
+my ($index, $oindex);
+
+require "/usr/local/bin/my/schnittcommon.pli";
+
+if (!open (INDEX,"index.vdr"))
+ {
+ exit 1;
+ }
+
+$index = $oindex = $ARGV[0];
+
+if ($index > 0)
+{
+ &prevI;
+ if ($oindex != $index)
+ {
+ print "$index\n";
+ }
+ else
+ {
+ print "$oindex\n";
+ }
+}
+else
+{
+ print "0\n";
+}
diff --git a/Tools/schnitt/index.php b/Tools/schnitt/index.php
new file mode 100644
index 0000000..58a288f
--- /dev/null
+++ b/Tools/schnitt/index.php
@@ -0,0 +1,215 @@
+<html>
+<head>
+ <title>Schneiden</title>
+</head>
+<body bgcolor=#C0C0C0>
+<?
+if ($level == 0)
+ {
+ $dircount=0;
+ $handle=opendir('/x1/video');
+ while ($file = readdir($handle)) {
+ if ($file != "." && $file != ".." && $file != "epg.data") {
+ $dir=$file;
+ $dircount++;
+ }
+ }
+ if ($dircount == 1) {
+ $level=1;
+ }
+ else
+ {
+?>
+<center><h1>Sender</h1></center>
+<form action="index.php" method="post">
+<input type=hidden name=level value="1">
+<?
+ $handle=opendir('/x1/video');
+ while ($file = readdir($handle)) {
+ if ($file != "." && $file != ".." && $file != "epg.data") {
+ echo "<input type=submit name=dir value=\"$file\">\n";
+ }
+ }
+ closedir($handle);
+?>
+</form>
+<?
+ }
+ }
+if ($level == 1)
+ {
+ $dircount=0;
+ $handle=opendir("/x1/video/$dir");
+ while ($file = readdir($handle)) {
+ if ($file != "." && $file != "..") {
+ $dira="$dir/$file";
+ $dircount++;
+ }
+ }
+ if ($dircount == 1) {
+ $dir = $dira;
+ $level = 2;
+ }
+ else
+ {
+?>
+<form action="index.php" method="post">
+<input type=hidden name=level value="2">
+<?
+ echo "<center><h1>Filme/Serien fuer den Sender $dir</h1></center>";
+ $handle=opendir("/x1/video/$dir");
+ while ($file = readdir($handle)) {
+ if ($file != "." && $file != "..") {
+ echo "<input type=submit name=dir value=\"$dir/$file\"><br>\n";
+ }
+ }
+ closedir($handle);
+?>
+</form>
+<?
+ }
+ }
+if ($level == 2)
+ {
+if ($aindex)
+ $index = $aindex;
+else if (!$index)
+ $index = 0;
+
+if ($dir)
+ chdir ("/x1/video/$dir");
+
+switch ($cindex) {
+ case "-10000":
+ if ($index >=10000)
+ $index -= 10000;
+ break;
+ case "-4000":
+ if ($index >=4000)
+ $index -= 4000;
+ break;
+ case "-2000":
+ if ($index >=2000)
+ $index -= 2000;
+ break;
+ case "-1000":
+ if ($index >=1000)
+ $index -= 1000;
+ break;
+ case "-500":
+ if ($index >=500)
+ $index -= 500;
+ break;
+ case "-100":
+ if ($index >=100)
+ $index -= 100;
+ break;
+ case "Vorheriges I-Frame":
+ $pindex = $index - 1;
+ $fp = popen ("/usr/local/bin/my/getpreviframe.pl $pindex","r");
+ $i = fgets($fp,1000);
+ $index = chop ($i);
+ pclose ($fp);
+ break;
+ case "Naechstes I-Frame":
+ $index ++;
+ break;
+ case "+100":
+ $index += 100;
+ break;
+ case "+500":
+ $index += 500;
+ break;
+ case "+1000":
+ $index += 1000;
+ break;
+ case "+2000":
+ $index += 2000;
+ break;
+ case "+4000":
+ $index += 4000;
+ break;
+ case "+10000":
+ $index += 10000;
+ break;
+ }
+
+if ($test)
+ {
+ $fp = popen ("/usr/local/bin/my/schnitt3.pl $index","r");
+ $i = fgets($fp,1000);
+ pclose ($fp);
+ $index = chop ($i);
+ }
+
+if ($name)
+ {
+ $fp = fopen ("cut","w");
+ fputs ($fp,"$name\n");
+ fclose ($fp);
+ }
+
+if ($cut)
+ {
+ $fp = fopen ("cut","a");
+ fputs ($fp,"$index\n");
+ fclose ($fp);
+ }
+
+$fp = popen ("/usr/local/bin/my/schnitt.pl $index","r");
+$i = fgets($fp,1000);
+pclose ($fp);
+$index = chop ($i);
+
+system ("/usr/local/bin/my/dumpframe /x2/temp/bild.m2v");
+system ("mv output.ppm /x2/temp");
+system ("touch /x2/temp/newpic");
+system ("killall sleep");
+?>
+<form action="index.php" method="post">
+<input type=hidden name=level value="2">
+<input type=hidden name=dir value="<?=$dir?>">
+<input type=hidden name=index value=<?=$index?>>
+<table width=90% align=center>
+<tr>
+<td><h1>Index <?=$index?></h1></td>
+<td><h1>Dir: <?=$dir?></h1></td>
+</tr>
+</table>
+<table width=80% align=center>
+<tr>
+<td><input type=submit name=cindex value="-10000"></td>
+<td><input type=submit name=cindex value="-4000"></td>
+<td><input type=submit name=cindex value="-2000"></td>
+<td><input type=submit name=cindex value="-1000"></td>
+<td><input type=submit name=cindex value="-500"></td>
+<td><input type=submit name=cindex value="-100"></td>
+<td><input type=submit name=cindex value="Vorheriges I-Frame"></td>
+<td><input type=submit name=cindex value="Naechstes I-Frame"</td>
+<td><input type=submit name=cindex value="+100"></td>
+<td><input type=submit name=cindex value="+500"></td>
+<td><input type=submit name=cindex value="+1000"></td>
+<td><input type=submit name=cindex value="+2000"></td>
+<td><input type=submit name=cindex value="+4000"></td>
+<td><input type=submit name=cindex value="+10000"></td>
+</tr>
+</table>
+<table>
+<tr>
+<td>Absoluter Index: <input type=text name=aindex size=6></td>
+<td><input type=submit name=test value="Schnitt-Test"></td>
+<td><input type=submit name=cut value="Mark"></td>
+</form>
+<form action="index.php" method="post">
+<input type=hidden name=level value="2">
+<input type=hidden name=dir value="<?=$dir?>">
+<input type=hidden name=index value=<?=$index?>>
+<td>Titel: <input type=text name=name size=50 maxlength=255></td>
+</form>
+</tr>
+</table>
+<?
+}
+?>
+</body>
+</html>
diff --git a/Tools/schnitt/lmplex b/Tools/schnitt/lmplex
new file mode 100755
index 0000000..8cbb50f
--- /dev/null
+++ b/Tools/schnitt/lmplex
@@ -0,0 +1,51 @@
+#! /usr/bin/perl
+
+### Calculate the number of CPUs we want to keep busy
+open IN, "/proc/cpuinfo";
+$cpus = grep /processor.*:/, <IN>;
+close IN;
+
+### This is a list of files to encode
+@names = @ARGV;
+
+$dira = shift @names;
+$dirb = shift @names;
+
+### This is the name of the encoder to use.
+$coder = "/usr/local/bin/mplex ";
+###
+
+###
+###
+###
+
+# Encode a single file
+sub do_one {
+ my($m2v) = shift;
+ # Make mp3 from wav
+ $m2v =~ s/\.m2v$//;
+
+ # In a subprocess, encode the file
+ printf "Multiplexing ${m2v}\n";
+ unless($pid = fork) {
+ system ("$coder ${dira}/${m2v}.m2v ${dira}/${m2v}.mp2 ${dirb}/${m2v}.mpg");
+ exit;
+ }
+}
+
+# Go ahead and prefork $cpus encoders
+foreach $i (0 .. $cpus-1) {
+ &do_one($names[0]) if ($names[0] ne "");
+ shift @names;
+}
+
+# Wait for the end of each encoder, start a new one...
+foreach $i (@names) {
+ wait;
+ &do_one($i);
+}
+
+# Wait for everything to close down.
+while(wait > 0) {
+ ;
+}
diff --git a/Tools/schnitt/mv2 b/Tools/schnitt/mv2
new file mode 100755
index 0000000..a0cefba
--- /dev/null
+++ b/Tools/schnitt/mv2
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+DIR = /x1/video
+
+if [ ! "$UID" = 0 ]; then
+ if [ -d "$1" ]; then
+ cd $DIR
+ a=`echo "$1" | cut -d / -f4-`
+ mkdir -p "$a"
+ cd "$a"
+ (echo cd "$1"; echo mget \*)| ftp -i dvb
+ cd $DIR
+ ls -Ls $1 > /tmp/yele
+ ls -Ls $a > /tmp/x1
+ a=`echo "$1" | cut -d \/ -f3-`
+ diff -u /tmp/yele /tmp/x1 &> /dev/null && rm -rfv /yel?/$a
+ rm /tmp/yele
+ rm /tmp/x1
+ rmdir /yel?/video/*
+ fi
+else
+ echo Not as root
+fi
diff --git a/Tools/schnitt/schnitt.pl b/Tools/schnitt/schnitt.pl
new file mode 100755
index 0000000..d5521eb
--- /dev/null
+++ b/Tools/schnitt/schnitt.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+
+require "/usr/local/bin/my/schnittcommon.pli";
+
+if (!open (INDEX,"index.vdr"))
+ {
+ exit 1;
+ }
+$index = $ARGV[0];
+&nextI;
+$offset1 = $offset;
+&readnext;
+$off = $offset - $offset1;
+close (FI);
+$fi = sprintf ("%03d.vdr",$file);
+open (FI,$fi);
+open (FO,">bild");
+sysseek (FI,$offset1,0);
+sysread (FI,$temp,200000);
+syswrite (FO,$temp,200000);
+close (FI);
+close (FO);
+
+`/usr/local/bin/pvademux.old /x2/temp bild`;
+#`/usr/local/bin/pes2av_pes bild | /usr/local/bin/pvademux /x2/temp bild`;
+print "$index\n";
diff --git a/Tools/schnitt/schnitt2.pl b/Tools/schnitt/schnitt2.pl
new file mode 100755
index 0000000..e52b245
--- /dev/null
+++ b/Tools/schnitt/schnitt2.pl
@@ -0,0 +1,91 @@
+#!/usr/bin/perl
+
+require "/usr/local/bin/my/schnittcommon.pli";
+
+if (!open (INDEX,"index.vdr"))
+ {
+ print "Error opening index.vdr";
+ exit 1;
+ }
+
+$index = $ARGV[0];
+&nextI;
+$file1 = $file;
+$offset1 = $offset;
+$index = $ARGV[1];
+&nextI;
+$file2 = $file;
+$offset2 = $offset;
+
+if ($file1 == $file2)
+ {
+ $count = $offset2 - $offset1;
+ $cond = 0;
+ $size = 1024*1024;
+ $fi = sprintf ("%03d.vdr",$file);
+ open (FI,$fi);
+ sysseek (FI,$offset1,0);
+ while ($cond == 0)
+ {
+ if ($count > $size)
+ {
+ $read = sysread (FI,$data,$size);
+ print $data;
+ $count -= $size;
+ }
+ else
+ {
+ $read = sysread (FI,$data,$count);
+ print $data;
+ $cond = 1;
+ }
+ }
+ }
+else
+ {
+ $count = $offset2;
+ $cond = 0;
+ $read = $size = 1024*1024;
+ $fi = sprintf ("%03d.vdr",$file1);
+ open (FI,$fi);
+ sysseek (FI,$offset1,0);
+ while ($read == $size)
+ {
+ $read = sysread (FI,$data,$size);
+ print $data;
+ }
+ close (FI);
+
+ $file1++;
+ while ($file1 != $file2)
+ {
+ $fi = sprintf ("%03d.vdr",$file1);
+ open (FI,$fi);
+ $read = 1024*1024;
+ while ($read == $size)
+ {
+ $read = sysread (FI,$data,$size);
+ print $data;
+ }
+ close (FI);
+ $file1++;
+ }
+
+ $fi = sprintf ("%03d.vdr",$file2);
+ open (FI,$fi);
+ while ($cond == 0)
+ {
+ if ($count > $size)
+ {
+ $read = sysread (FI,$data,$size);
+ print $data;
+ $count -= $size;
+ }
+ else
+ {
+ $read = sysread (FI,$data,$count);
+ print $data;
+ $cond = 1;
+ }
+ }
+ }
diff --git a/Tools/schnitt/schnitt3.pl b/Tools/schnitt/schnitt3.pl
new file mode 100755
index 0000000..7cc0f7f
--- /dev/null
+++ b/Tools/schnitt/schnitt3.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+
+require "/usr/local/bin/my/schnittcommon.pli";
+
+open (INDEX,"index.vdr");
+$index = $ARGV[0];
+&nextI;
+
+$oldindex = $index;
+$tempindex = $index;
+
+$add = -1;
+
+$fi = sprintf ("%03d.vdr",$file);
+open (FI2,$fi);
+open (FO,">test");
+sysseek (FI2,$offset,0);
+sysread (FI2,$temp,3000000);
+syswrite (FO,$temp,3000000);
+close (FI2);
+close (FO);
+`/usr/local/bin/pvademux.old . test`;
+if ( -s "test.mp2")
+ {
+ `rm test*`;
+ print "$index\n";
+ exit 0;
+ }
+
+while (1)
+ {
+ if ($index == 0)
+ {
+ $add = 1;
+ }
+ if ($add = -1)
+ {
+ $index--;
+ &prevI;
+ }
+ else
+ {
+ nextI;
+ }
+ $fi = sprintf ("%03d.vdr",$file);
+ open (FI2,$fi);
+ open (FO,">test");
+ sysseek (FI2,$offset,0);
+ sysread (FI2,$temp,3000000);
+ syswrite (FO,$temp,3000000);
+ close (FI2);
+ close (FO);
+ `/usr/local/bin/pvademux.old . test`;
+ if ( -s "test.mp2")
+ {
+ `rm test*`;
+ if ($index < 0)
+ {
+ $index *= -1;
+ }
+ print "$index\n";
+ exit 0;
+ }
+ }
diff --git a/Tools/schnitt/schnitt3.pl.new b/Tools/schnitt/schnitt3.pl.new
new file mode 100755
index 0000000..04a6239
--- /dev/null
+++ b/Tools/schnitt/schnitt3.pl.new
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+
+require "/usr/local/bin/my/schnittcommon.pli";
+
+open (INDEX,"index.vdr");
+
+$index = $ARGV[0];
+&nextI;
+
+$oldindex = $index;
+$tempindex = $index;
+
+$add = -1;
+
+$fi = sprintf ("%03d.vdr",$file);
+open (FI2,$fi);
+open (FO,">test2");
+sysseek (FI2,$offset,0);
+sysread (FI2,$temp,3000000);
+syswrite (FO,$temp,3000000);
+close (FI2);
+close (FO);
+
+system ("pes2av_pes test2 > test 2>/dev/null");
+open (PVA,"/usr/local/bin/pvademux.old . test 2>&1 |");
+
+@a=<PVA>; close PVA;
+@b=split (/\s/,$a[2]);
+
+if (!($b[4] =~ /\-/) && $b[4] < 2000)
+ {
+ unlink <test*>;
+ print "$index\n";
+ exit 0;
+ }
+
+while (1)
+ {
+ if ($index == 0)
+ {
+ $add = 1;
+ }
+ if ($add = -1)
+ {
+ $index--;
+ &prevI;
+ }
+ else
+ {
+ nextI;
+ }
+ $fi = sprintf ("%03d.vdr",$file);
+ open (FI2,$fi);
+ open (FO,">test2");
+ sysseek (FI2,$offset,0);
+ sysread (FI2,$temp,3000000);
+ syswrite (FO,$temp,3000000);
+ close (FI2);
+ close (FO);
+
+system ("/usr/local/bin/pes2av_pes test2 > test 2>/dev/null");
+open (PVA,"/usr/local/bin/pvademux.old . test 2>&1 |");
+
+@a=<PVA>; close PVA;
+@b=split (/\s/,$a[2]);
+
+if (!($b[4] =~ /\-/) && $b[4] < 2000)
+ {
+ unlink <test*>;
+ if ($index < 0)
+ {
+ $index *= -1;
+ }
+ print "$index\n";
+ exit 0;
+ }
+}
diff --git a/Tools/schnitt/schnitt4.pl b/Tools/schnitt/schnitt4.pl
new file mode 100755
index 0000000..75f2ad1
--- /dev/null
+++ b/Tools/schnitt/schnitt4.pl
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+
+open (FI,$ARGV[0]) or die "Kann Input-Datei nicht oeffnen";
+$count = 1;
+
+while (<FI>)
+ {
+ chomp;
+ $char = sprintf ("%c",$count + 96);
+ print "Cutting from/to $_ into /x2/clips/$char\n";
+ system ("/usr/local/bin/my/schnitt2.pl $_ > /x2/clips/$char");
+ $count++;
+ }
diff --git a/Tools/schnitt/schnitt5.pl b/Tools/schnitt/schnitt5.pl
new file mode 100755
index 0000000..7626ab5
--- /dev/null
+++ b/Tools/schnitt/schnitt5.pl
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+require "/usr/local/bin/my/schnittcommon.pli";
+
+open (INDEX,"index.vdr");
+$index = $ARGV[0] - 15000;
+&nextI;
+
+$file1 = $file;
+
+$index += 30000;
+&nextI;
+
+$file2 = $file;
+
+print "$file1 $file2\n";
+
diff --git a/Tools/schnitt/schnitt6.pl b/Tools/schnitt/schnitt6.pl
new file mode 100755
index 0000000..92d9eb4
--- /dev/null
+++ b/Tools/schnitt/schnitt6.pl
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+open (FI,"a");
+
+while (<FI>)
+{
+ open (SCH,"/usr/local/bin/my/schnitt5.pl $_|");
+ $files = <SCH>;
+ chomp $files;
+ ($a,$b) = split (/\s/,$files);
+ $files[$a] = 1;
+ $files[$b] = 1;
+ close (SCH);
+}
+
+while (<0*.vdr>)
+{
+ $_ =~ /\d(\d\d)\.vdr/;
+ if ($files[$1])
+ {
+ print "Keeping $1\n";
+ }
+ else
+ {
+ print "Deleting $_\n";
+ unlink $_;
+ }
+}
+
+close (FI);
diff --git a/Tools/schnitt/schnittcommon.pli b/Tools/schnitt/schnittcommon.pli
new file mode 100755
index 0000000..f221f41
--- /dev/null
+++ b/Tools/schnitt/schnittcommon.pli
@@ -0,0 +1,64 @@
+sub nextI
+ {
+ if (!$size)
+ {
+ $size = -s INDEX;
+ }
+ local ($a,$b,$c,$dummy);
+ $cond = 0;
+ seek (INDEX,$index * 8,0);
+
+ while ($cond == 0)
+ {
+ &readnext;
+ if ($frame == 1)
+ {
+ $cond = 1;
+ }
+ else
+ {
+ $index++;
+ if ($index > ($size/8-1))
+ {
+ $index = $size/8-1;
+ &prevI;
+ print "$index\n";
+ exit 1;
+ }
+ }
+ }
+ }
+
+sub readnext
+ {
+ read (INDEX,$a,4);
+ read (INDEX,$b,1);
+ read (INDEX,$c,1);
+ read (INDEX,$dummy,2);
+ $offset = unpack ("L",$a);
+ $frame = unpack ("C",$b);
+ $file = unpack ("C",$c);
+ }
+
+sub prevI
+ {
+ local ($a,$b,$c,$dummy);
+ $cond = 0;
+ seek (INDEX,$index * 8,0);
+
+ while ($cond == 0)
+ {
+ &readnext;
+ if ($frame == 1)
+ {
+ $cond = 1;
+ }
+ else
+ {
+ $index--;
+ seek (INDEX,$index * 8,0);
+ }
+ }
+ }
+
+1;
diff --git a/Tools/schnitt/show b/Tools/schnitt/show
new file mode 100755
index 0000000..afed79b
--- /dev/null
+++ b/Tools/schnitt/show
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd /x2/temp
+while true
+do
+ if [ -f newpic ]; then
+ killall xli
+ rm -f newpic
+ xli output.ppm &
+ fi
+sleep 24h
+done
diff --git a/Tools/schnitt/unsort b/Tools/schnitt/unsort
new file mode 100755
index 0000000..83adfb6
--- /dev/null
+++ b/Tools/schnitt/unsort
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+
+while (<>)
+{
+ $h{$_}=1;
+}
+
+foreach $key (sort shuffle keys %h)
+{
+ print $key;
+}
+
+sub shuffle {
+ $ran = rand(1);
+
+ if ($ran > 0.5)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
diff --git a/Tools/schnitt/vdr-remote.pl b/Tools/schnitt/vdr-remote.pl
new file mode 100755
index 0000000..32d408e
--- /dev/null
+++ b/Tools/schnitt/vdr-remote.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Socket;
+
+my ($dest, $port, $iaddr, $paddr, $proto, $line);
+
+$dest = "localhost";
+$port = "2001";
+
+$iaddr = inet_aton($dest) || Error("no host: $dest");
+$paddr = sockaddr_in($port, $iaddr);
+
+$proto = getprotobyname('tcp');
+socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!");
+connect(SOCK, $paddr) || Error("connect: $!");
+select (SOCK); $| = 1;
+$a=<SOCK>;
+
+for (;;)
+ {
+ open (FI,"/tmp/vdr-keys");
+ while (<FI>)
+ {
+ chomp;
+ print "$_\r\n";
+ $a=<SOCK>;
+ }
+ close (FI);
+ }
+
+print "quit\r\n";
+$a=<SOCK>;
+close (SOCK) || Error("close: $!");
+
+sub Error
+{
+ print STDERR "@_\n";
+ exit 0;
+}
diff --git a/Tools/schnitt/vdr2 b/Tools/schnitt/vdr2
new file mode 100755
index 0000000..96557bf
--- /dev/null
+++ b/Tools/schnitt/vdr2
@@ -0,0 +1,2 @@
+#!/bin/sh
+irpty ~/.lircrc-vdr -- vdr -c /home/ms/.vdr -v /video/video0
diff --git a/Tools/schnitt/vmount b/Tools/schnitt/vmount
new file mode 100755
index 0000000..6b79064
--- /dev/null
+++ b/Tools/schnitt/vmount
@@ -0,0 +1,18 @@
+#!/bin/sh
+count=1
+cond=0
+
+if [ -f "$1" ]; then
+ mount "$1" /mnt/1 -o loop
+ $cond = 1
+else
+ while [ "$cond" != "1" ]
+ do
+ if [ -f "$1$count" ]; then
+ mount "$1$count" /mnt/$count -o loop
+ else
+ cond=1
+ fi
+ let count=count+1
+ done
+fi
diff --git a/channels.conf b/channels.conf
index 43e69cd..4947f82 100644
--- a/channels.conf
+++ b/channels.conf
@@ -1,148 +1,174 @@
-RTL:12188:h:0:27500:163:104:0:12003
-Sat.1:12480:v:0:27500:1791:1792:0:46
-Pro-7:12480:v:0:27500:255:256:0:898
-RTL2:12188:h:0:27500:166:128:0:12020
-ARD:11837:h:0:27500:101:102:0:28106
-BR3:11837:h:0:27500:201:202:0:28107
-Hessen-3:11837:h:0:27500:301:302:0:28108
-N3:12110:h:0:27500:2401:2402:0:28224
-SR3:11837:h:0:27500:501:502:0:28110
-WDR:11837:h:0:27500:601:602:0:28111
-BR-alpha:11837:h:0:27500:701:702:0:28112
-SWR BW:11837:h:0:27500:801:802:0:28113
-Phoenix:11837:h:0:27500:901:902:0:28114
-ZDF:11954:h:0:27500:110:120:0:28006
-3sat:11954:h:0:27500:210:220:0:28007
-KiKa:11954:h:0:27500:310:320:0:28008
-arte:11836:h:0:27500:401:402:0:28109
-ORF Sat:11954:h:0:27500:506:507:0:28010
-ZDF.info:11954:h:0:27500:610:620:0:28011
-CNN:12168:v:0:27500:165:100:0:28512
-Super RTL:12188:h:0:27500:165:120:0:12040
-VOX:12188:h:0:27500:167:136:0:12060
-DW TV:12363:v:0:27500:305:306:0:8905
-Kabel 1:12480:v:0:27500:511:512:0:899
-tm3:12480:v:0:27500:767:768:0:897
-DSF:12480:v:0:27500:1023:1024:0:900
-HOT:12480:v:0:27500:1279:1280:0:40
-Bloomberg TV Germany:12551:v:0:22000:162:99:0:12160
-BLOOMBERG TV:11817:v:0:27500:163:92:0:8004
-Bloomberg:12168:v:0:27500:167:112:0:12721
-Sky News:12552:v:0:22000:305:306:0:3995
-KinderNet:12574:h:0:22000:163:92:0:5020
-Alice:12610:v:0:22000:162:96:0:12200
-n-tv:12669:v:0:22000:162:96:0:12730
-Grand Tourisme:12670:v:0:22000:289:290:0:17300
-TW1:12692:h:0:22000:166:167:0:13013
-Eurosport:11954:h:0:27500:410:420:0:28009
-EinsExtra:12110:h:0:27500:101:102:0:28201
-EinsFestival:12110:h:0:27500:201:202:0:28202
-EinsMuXx:12110:h:0:27500:301:302:0:28203
-ZDF Theaterkanal:11954:h:0:27500:1110:1120:0:28016
-ZDF.doku:11954:h:0:27500:660:670:0:28014
-MDR:12110:h:0:27500:401:402:0:28204
-NICK-PARAMOUNT:12246:v:0:27500:167:108:0:29312
-ORB:12110:h:0:27500:501:502:0:28205
-B1:12110:h:0:27500:601:602:0:28206
-ARD Online-Kanal:12722:h:0:22000:8191:701:0:0
+RTL:12188:h:0:27500:163:104:32:0:12003
+Sat.1:12480:v:0:27500:1791:1792:34:0:46
+Pro-7:12480:v:0:27500:255:256:32:0:898
+RTL2:12188:h:0:27500:166:128:68:0:12020
+ARD:11837:h:0:27500:101:102:0:0:28106
+BR3:11837:h:0:27500:201:202:0:0:28107
+Hessen-3:11837:h:0:27500:301:302:0:0:28108
+N3:12110:h:0:27500:2401:2402:0:0:28224
+SR3:11837:h:0:27500:501:502:0:0:28110
+WDR:11837:h:0:27500:601:602:0:0:28111
+BR-alpha:11837:h:0:27500:701:702:0:0:28112
+SWR BW:11837:h:0:27500:801:802:0:0:28113
+Phoenix:11837:h:0:27500:901:902:0:0:28114
+ZDF:11954:h:0:27500:110:120:130:0:28006
+3sat:11954:h:0:27500:210:220:230:0:28007
+KiKa:11954:h:0:27500:310:320:0:0:28008
+arte:11836:h:0:27500:401:402:0:0:28109
+ORF1:12692:h:0:22000:160:161:165:3:13001
+ORF2:12692:h:0:22000:500:501:505:3:13007
+ORF Sat:11954:h:0:27500:506:507:0:0:28010
+ZDF.info:11954:h:0:27500:610:620:0:0:28011
+CNN:12168:v:0:27500:165:100:0:0:28512
+Super RTL:12188:h:0:27500:165:120:65:0:12040
+VOX:12188:h:0:27500:167:136:0:0:12060
+DW TV:12363:v:0:27500:305:306:0:0:8905
+Kabel 1:12480:v:0:27500:511:512:33:0:899
+tm3:12480:v:0:27500:767:768:0:0:897
+DSF:12480:v:0:27500:1023:1024:0:0:900
+HOT:12480:v:0:27500:1279:1280:0:0:40
+Bloomberg TV Germany:12551:v:0:22000:162:99:0:0:12160
+BLOOMBERG TV:11817:v:0:27500:163:92:0:0:8004
+Bloomberg:12168:v:0:27500:167:112:0:0:12721
+Sky News:12552:v:0:22000:305:306:0:0:3995
+KinderNet:12574:h:0:22000:163:92:0:0:5020
+Alice:12610:v:0:22000:162:96:0:0:12200
+n-tv:12669:v:0:22000:162:96:55:0:12730
+Grand Tourisme:12670:v:0:22000:289:290:0:0:17300
+TW1:12692:h:0:22000:166:167:0:0:13013
+Eurosport:11954:h:0:27500:410:420:0:0:28009
+EinsExtra:12110:h:0:27500:101:102:0:0:28201
+EinsFestival:12110:h:0:27500:201:202:0:0:28202
+EinsMuXx:12110:h:0:27500:301:302:0:0:28203
+ZDF Theaterkanal:11954:h:0:27500:1110:1120:0:0:28016
+ZDF.doku:11954:h:0:27500:660:670:0:0:28014
+MDR:12110:h:0:27500:401:402:0:0:28204
+NICK-PARAMOUNT:12246:v:0:27500:167:108:0:0:29312
+ORB:12110:h:0:27500:501:502:0:0:28205
+B1:12110:h:0:27500:601:602:0:0:28206
+ARD Online-Kanal:12722:h:0:22000:8191:701:0:0:0
:Premiere World
-Premiere World Promo:11798:h:0:27500:255:256:0:8
-Premiere:11798:h:0:27500:511:512:2:10
-Star Kino:11798:h:0:27500:767:768:2:9
-Cine Action:11798:h:0:27500:1023:1024:2:20
-Cine Comedy:11798:h:0:27500:1279:1280:2:29
-Sci Fantasy:11798:h:0:27500:1535:1536:2:41
-Romantic Movies:11798:h:0:27500:1791:1792:2:11
-Studio Universal:11798:h:0:27500:2047:2048:2:21
-13th Street:11797:h:0:27500:2303:2304:2:43
-Junior:12031:h:0:27500:255:256:2:19
-K-Toon:12032:h:0:27500:511:512:2:12
-Disney Channel:12031:h:0:27500:767:768:2:15
-Fox Kids:11798:h:0:27500:255:256:2:0
-Sunset:12031:h:0:27500:1023:1024:2:16
-Comedy:12031:h:0:27500:1279:1280:2:28
-Planet:12031:h:0:27500:2047:2048:2:13
-Discovery Channel:12031:h:0:27500:1791:1792:2:14
-Krimi&Co:12031:h:0:27500:1535:1536:2:23
-Filmpalast:12090:v:0:27500:255:256:2:36
-Heimatkanal:11758:h:0:27500:2815:2816:2:517
-Goldstar:11758:h:0:27500:3839:3840:2:518
-Classica:12090:v:0:27500:767:768:2:34
-Seasons:12090:v:0:27500:511:512:2:33
-Blue Channel:11758:h:0:27500:2559:2560:2:516
-Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:2:242
-Feed (F1 Data):11720:h:0:27500:3071:3072:2:244
-Feed (F1 Multi):11720:h:0:27500:2815:2816:2:243
-Feed (F1 On Board):11720:h:0:27500:2303:2304:2:241
-Feed (F1 Verfolger):11720:h:0:27500:2047:2048:2:240
+Premiere World Promo:11798:h:0:27500:255:256:0:0:8
+Premiere:11798:h:0:27500:511:512:0:3:10
+Star Kino:11798:h:0:27500:767:768:0:3:9
+Cine Action:11798:h:0:27500:1023:1024:0:3:20
+Cine Comedy:11798:h:0:27500:1279:1280:0:3:29
+Sci Fantasy:11798:h:0:27500:1535:1536:0:3:41
+Romantic Movies:11798:h:0:27500:1791:1792:0:3:11
+Studio Universal:11798:h:0:27500:2047:2048:0:3:21
+13th Street:11797:h:0:27500:2303:2304:0:3:43
+Junior:12031:h:0:27500:255:256:0:3:19
+K-Toon:12032:h:0:27500:511:512:0:3:12
+Disney Channel:12031:h:0:27500:767:768:0:3:15
+Fox Kids:11798:h:0:27500:255:256:0:3:0
+Sunset:12031:h:0:27500:1023:1024:0:3:16
+Comedy:12031:h:0:27500:1279:1280:0:3:28
+Planet:12031:h:0:27500:2047:2048:0:3:13
+Discovery Channel:12031:h:0:27500:1791:1792:0:3:14
+Krimi&Co:12031:h:0:27500:1535:1536:0:3:23
+Filmpalast:12090:v:0:27500:255:256:0:3:36
+Heimatkanal:11758:h:0:27500:2815:2816:0:3:517
+Goldstar:11758:h:0:27500:3839:3840:0:3:518
+Classica:12090:v:0:27500:767:768:0:3:34
+Seasons:12090:v:0:27500:511:512:0:3:33
+Blue Channel:11758:h:0:27500:2559:2560:0:3:516
+Cinedom 1A de:12070:h:0:27500:1279:1280:0:3:188
+Cinedom 1A en:12070:h:0:27500:1279:1281:0:3:188
+Cinedom 1B:12070:h:0:27500:1791:1792:0:3:191
+Cinedom 1C:12070:h:0:27500:767:768:0:3:185
+Cinedom 1D:11758:h:0:27500:511:512:0:3:178
+Cinedom 1E:11720:h:0:27500:1535:1537:0:3:176
+Cinedom 2A:12070:h:0:27500:1535:1536:0:3:189
+Cinedom 2B:12070:h:0:27500:511:512:0:3:184
+Cinedom 2C:11758:h:0:27500:767:768:0:3:179
+Cinedom 2D:11758:h:0:27500:1023:1024:0:3:193
+Cinedom 2E:11720:h:0:27500:1279:1280:0:3:183
+Cinedom 3A:11758:h:0:27500:255:256:0:3:177
+Cinedom 3B:11758:h:0:27500:1279:1280:0:3:194
+Cinedom 3C:12090:v:0:27500:1279:1280:17689:3:192
+Cinedom 3D:11720:h:0:27500:511:512:0:3:180
+Cinedom 3E:11720:h:0:27500:1023:1024:0:3:182
+Cinedom 4A:11758:h:0:27500:1535:1536:0:3:195
+Cinedom 4B:12032:h:0:27500:2559:2560:0:3:187
+Cinedom 4C:11720:h:0:27500:767:768:0:3:181
+Cinedom 4D:11720:h:0:27500:1791:1792:0:3:190
+Cinedom 4E:12070:h:0:27500:1023:1025:0:3:186
+Blue Movie 1:11758:h:0:27500:1791:1792:0:3:513
+Blue Movie 2:11758:h:0:27500:2047:2048:0:3:514
+Blue Movie 3:11758:h:0:27500:2303:2304:0:3:515
+Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:0:3:242
+Feed (F1 Data):11720:h:0:27500:3071:3072:0:3:244
+Feed (F1 Multi):11720:h:0:27500:2815:2816:0:3:243
+Feed (F1 On Board):11720:h:0:27500:2303:2304:0:3:241
+Feed (F1 Verfolger):11720:h:0:27500:2047:2048:0:3:240
:
-TV Niepokalanow:11876:h:0:27500:305:321:0:20601
-Mosaico:11934:v:0:27500:165:100:0:29010
-Andalucia TV:11934:v:0:27500:166:104:0:29011
-TVC Internacional:11934:v:0:27500:167:108:0:0
-Nasza TV:11992:h:0:27500:165:98:0:0
-WishLine test:12012:v:0:27500:163:90:0:0
-Pro 7 Austria:12051:v:0:27500:161:84:0:0
-Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0
-Kabel 1 Austria:12051:v:0:27500:166:167:0:0
-Pro 7 Schweiz:12051:v:0:27500:289:290:0:0
-Kiosque:12129:v:0:27500:160:80:0:0
-KTO:12129:v:0:27500:170:120:0:0
-TCM:12168:v:0:27500:160:80:0:0
-Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0
-TVBS Europe:12168:v:0:27500:162:88:0:0
-TVBS Europe:12168:v:0:27500:162:89:0:0
-Travel:12168:v:0:27500:163:92:0:0
-TCM Espania:12168:v:0:27500:164:96:0:0
-MTV Spain:12168:v:0:27500:167:112:0:0
-TCM France:12168:v:0:27500:169:64:0:0
-RTL2 CH:12188:h:0:27500:164:112:0:0
-La Cinquieme:12207:v:0:27500:160:80:0:0
-ARTE:12207:v:0:27500:165:100:0:0
-Post Filial TV:12226:h:0:27500:255:256:0:0
-Canal Canaris:12246:v:0:27500:160:80:0:0
-Canal Canaris:12246:v:0:27500:160:81:0:0
-Canal Canaris:12246:v:0:27500:160:82:0:0
-Canal Canaris:12246:v:0:27500:160:83:0:0
-AB Sat Passion promo:12266:h:0:27500:160:80:0:0
-AB Channel 1:12266:h:0:27500:161:84:0:0
-Taquilla 0:12285:v:0:27500:165:100:0:0
-CSAT:12324:v:0:27500:160:80:0:0
-Mosaique:12324:v:0:27500:162:88:0:0
-Mosaique 2:12324:v:0:27500:163:92:0:0
-Mosaique 3:12324:v:0:27500:164:96:0:0
-Le Sesame C+:12324:v:0:27500:165:1965:0:0
-FEED:12344:h:0:27500:163:92:0:0
-RTM 1:12363:v:0:27500:162:96:0:0
-ESC 1:12363:v:0:27500:163:104:0:0
-TV5 Europe:12363:v:0:27500:164:112:0:0
-TV7 Tunisia:12363:v:0:27500:166:128:0:0
-ARTE:12363:v:0:27500:167:137:0:0
-RAI Uno:12363:v:0:27500:289:290:0:8904
-RTP International:12363:v:0:27500:300:301:0:0
-Fashion TV:12402:v:0:27500:163:92:0:0
-VideoService:12422:h:0:27500:255:256:0:0
-Beta Research promo:12422:h:0:27500:1023:1024:0:0
-Canal Canarias:12441:v:0:27500:160:80:0:0
-TVC International:12441:v:0:27500:512:660:0:0
-Fitur:12441:v:0:27500:514:662:0:0
-Astra Info 1:12552:v:0:22000:164:112:0:0
-Astra Info 2:12552:v:0:22000:165:120:0:0
-Astra Vision 1:12552:v:0:22000:168:144:0:0
-Astra Vision 1:12552:v:0:22000:168:145:0:0
-Astra Vision 1:12552:v:0:22000:168:146:0:0
-Astra Vision 1:12552:v:0:22000:168:147:0:0
-Astra Vision 1:12552:v:0:22000:168:148:0:0
-Astra Vision 1:12552:v:0:22000:168:149:0:0
-Astra Vision 1:12552:v:0:22000:168:150:0:0
-RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0
-Astra Mosaic:12552:v:0:22000:175:176:0:0
-MHP test:12604:h:0:22000:5632:8191:0:0
-VERONICA:12574:h:0:22000:161:84:0:5010
-VH1 Classic:12699:v:0:22000:3071:3072:0:28647
-VH-1 Germany:12699:v:0:22000:3081:3082:0:28648
-Via 1 - Schöner Reisen:12148:h:0:27500:511:512:0:44
-Video Italia:12610:v:0:22000:121:122:0:12220
-AC 3 promo:12670:v:0:22000:308:256:0:0
-ORF/ZDF:12699:h:0:22000:506:507:0:13012
-VIVA:12670:v:0:22000:309:310:0:12732
+TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601
+Mosaico:11934:v:0:27500:165:100:0:0:29010
+Andalucia TV:11934:v:0:27500:166:104:0:0:29011
+TVC Internacional:11934:v:0:27500:167:108:0:0:0
+Nasza TV:11992:h:0:27500:165:98:0:0:0
+WishLine test:12012:v:0:27500:163:90:0:0:0
+Pro 7 Austria:12051:v:0:27500:161:84:0:0:0
+Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0:0
+Kabel 1 Austria:12051:v:0:27500:166:167:0:0:0
+Pro 7 Schweiz:12051:v:0:27500:289:290:0:0:0
+Kiosque:12129:v:0:27500:160:80:0:0:0
+KTO:12129:v:0:27500:170:120:0:0:0
+TCM:12168:v:0:27500:160:80:0:0:0
+Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0:0
+TVBS Europe:12168:v:0:27500:162:88:0:0:0
+TVBS Europe:12168:v:0:27500:162:89:0:0:0
+Travel:12168:v:0:27500:163:92:0:0:0
+TCM Espania:12168:v:0:27500:164:96:0:0:0
+MTV Spain:12168:v:0:27500:167:112:0:0:0
+TCM France:12168:v:0:27500:169:64:0:0:0
+RTL2 CH:12188:h:0:27500:164:112:0:0:0
+La Cinquieme:12207:v:0:27500:160:80:0:0:0
+ARTE:12207:v:0:27500:165:100:0:0:0
+Post Filial TV:12226:h:0:27500:255:256:0:0:0
+Canal Canaris:12246:v:0:27500:160:80:0:0:0
+Canal Canaris:12246:v:0:27500:160:81:0:0:0
+Canal Canaris:12246:v:0:27500:160:82:0:0:0
+Canal Canaris:12246:v:0:27500:160:83:0:0:0
+AB Sat Passion promo:12266:h:0:27500:160:80:0:0:0
+AB Channel 1:12266:h:0:27500:161:84:0:0:0
+Taquilla 0:12285:v:0:27500:165:100:0:0:0
+CSAT:12324:v:0:27500:160:80:0:0:0
+Mosaique:12324:v:0:27500:162:88:0:0:0
+Mosaique 2:12324:v:0:27500:163:92:0:0:0
+Mosaique 3:12324:v:0:27500:164:96:0:0:0
+Le Sesame C+:12324:v:0:27500:165:1965:0:0:0
+FEED:12344:h:0:27500:163:92:0:0:0
+RTM 1:12363:v:0:27500:162:96:0:0:0
+ESC 1:12363:v:0:27500:163:104:0:0:0
+TV5 Europe:12363:v:0:27500:164:112:0:0:0
+TV7 Tunisia:12363:v:0:27500:166:128:0:0:0
+ARTE:12363:v:0:27500:167:137:0:0:0
+RAI Uno:12363:v:0:27500:289:290:0:0:8904
+RTP International:12363:v:0:27500:300:301:0:0:0
+Fashion TV:12402:v:0:27500:163:92:0:0:0
+VideoService:12422:h:0:27500:255:256:0:0:0
+Beta Research promo:12422:h:0:27500:1023:1024:0:0:0
+Canal Canarias:12441:v:0:27500:160:80:0:0:0
+TVC International:12441:v:0:27500:512:660:0:0:0
+Fitur:12441:v:0:27500:514:662:0:0:0
+Astra Info 1:12552:v:0:22000:164:112:0:0:0
+Astra Info 2:12552:v:0:22000:165:120:0:0:0
+Astra Vision 1:12552:v:0:22000:168:144:0:0:0
+Astra Vision 1:12552:v:0:22000:168:145:0:0:0
+Astra Vision 1:12552:v:0:22000:168:146:0:0:0
+Astra Vision 1:12552:v:0:22000:168:147:0:0:0
+Astra Vision 1:12552:v:0:22000:168:148:0:0:0
+Astra Vision 1:12552:v:0:22000:168:149:0:0:0
+Astra Vision 1:12552:v:0:22000:168:150:0:0:0
+RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0:0
+Astra Mosaic:12552:v:0:22000:175:176:0:0:0
+MHP test:12604:h:0:22000:5632:8191:0:0:0
+VERONICA:12574:h:0:22000:161:84:0:0:5010
+VH1 Classic:12699:v:0:22000:3071:3072:0:0:28647
+VH-1 Germany:12699:v:0:22000:3081:3082:0:0:28648
+Via 1 - Schöner Reisen:12148:h:0:27500:511:512:0:0:44
+Video Italia:12610:v:0:22000:121:122:0:0:12220
+AC 3 promo:12670:v:0:22000:308:256:0:0:0
+ORF/ZDF:12699:h:0:22000:506:507:0:0:13012
+VIVA:12670:v:0:22000:309:310:0:0:12732
diff --git a/channels.conf.cable b/channels.conf.cable
new file mode 100644
index 0000000..93fc376
--- /dev/null
+++ b/channels.conf.cable
@@ -0,0 +1,134 @@
+Leitseite:346:h:0:6900:2254:0:0:5004
+Extreme Sport:346:h:0:6900:801:802:0:0
+Bloomberg:346:h:0:6900:811:812:0:0
+Fashion TV:346:h:0:6900:821:822:0:0
+LANDSCAPE:346:h:0:6900:831:832:0:0
+BET ON JAZZ:346:h:0:6900:841:842:0:0
+Via 1 - Schöner Reisen:346:h:0:6900:611:612:0:50705
+Single TV:346:h:0:6900:621:622:0:0
+HomeNet:346:h:0:6900:0:0:0:0
+Einstein:346:h:0:6900:623:624:0:0
+BLUE CHANNEL:354:h:0:6900:2559:2560:0:0
+GOLDSTAR TV:354:h:0:6900:3839:3840:1:0
+HEIMATKANAL:354:h:0:6900:2815:2816:1:0
+100,6:354:h:0:6900:0:1312:0:0
+SPORT 1:362:h:0:6900:255:256:1:0
+LOVE SONGS:362:h:0:6900:0:320:1:0
+MUSICALS:362:h:0:6900:0:336:1:0
+EASY LISTENING:362:h:0:6900:0:304:1:0
+HITLISTE:362:h:0:6900:0:784:1:0
+ALTERNATIVE ROCK:362:h:0:6900:0:800:1:0
+DANCE:362:h:0:6900:0:816:1:0
+COUNTRY:362:h:0:6900:0:352:1:0
+CLASSIC ROCK:362:h:0:6900:0:544:1:0
+FILMMUSIK:362:h:0:6900:3552:368:1:0
+DEUTSCHE HITS:362:h:0:6900:3552:384:1:0
+SOUL CLASSICS:362:h:0:6900:3439:400:1:0
+TÜRK MÜZIGI:362:h:0:6900:0:560:1:0
+GOLD:362:h:0:6900:0:576:1:0
+KLASSIK POPULÄR:362:h:0:6900:3552:592:1:0
+KLASS. SYMPHONIEN:362:h:0:6900:0:608:1:0
+OPER & VOKALMUSIK:362:h:0:6900:0:624:1:0
+BAROCKMUSIK:362:h:0:6900:0:640:1:0
+JAZZ:362:h:0:6900:0:656:1:0
+Videotext:362:h:0:6900:0:0:0:0
+PREMIERE WORLD:370:h:0:6900:255:256:0:10
+PREMIERE:370:h:0:6900:511:0:1:0
+STAR KINO:370:h:0:6900:767:768:1:0
+CINE ACTION:370:h:0:6900:1023:1024:1:0
+CINE COMEDY:370:h:0:6900:1279:1280:1:0
+SCI-FANTASY:370:h:0:6900:1535:1536:1:0
+ROMANTIC MOVIES:370:h:0:6900:1791:1792:1:0
+STUDIO UNIVERSAL:370:h:0:6900:2047:2048:1:0
+13 TH STREET:370:h:0:6900:2303:2304:1:0
+FOX KIDS:370:h:0:6900:2559:2560:1:0
+DISNEY CHANNEL:378:h:0:6900:767:768:1:0
+SUNSET:378:h:0:6900:1023:1024:1:0
+COMEDY:378:h:0:6900:1279:1280:1:0
+KRIMI &CO:378:h:0:6900:1535:1536:1:0
+DISCOVERY CHANNEL:378:h:0:6900:1791:1792:1:0
+PLANET:378:h:0:6900:2047:2048:1:0
+SUPERDOM:378:h:0:6900:2303:2304:1:0
+VCR-Setup:378:h:0:6900:0:0:0:0
+Modem-Setup:378:h:0:6900:0:0:0:0
+SCHLAGER:378:h:0:6900:0:320:1:0
+VOLKSMUSIK:378:h:0:6900:0:336:1:0
+OLD GOLD:378:h:0:6900:0:304:1:0
+TM V1.0:378:h:0:6900:0:0:1:0
+JUNIOR:378:h:0:6900:255:256:1:0
+KICK 1:386:h:0:6900:255:256:1:0
+KICK 2:386:h:0:6900:2559:2560:1:0
+ZDF.digitext:394:h:0:6900:0:0:0:0
+ZDF:394:h:0:6900:110:120:0:28006
+DLR-Berlin:394:h:0:6900:0:710:0:0
+DLF-Köln:394:h:0:6900:0:810:0:0
+3sat:394:h:0:6900:210:0:0:28007
+KiKa:394:h:0:6900:0:0:0:28008
+Eurosport:394:h:0:6900:410:0:0:28009
+ZDF.info:394:h:0:6900:610:620:0:28011
+EuroNews:394:h:0:6900:2221:2233:0:28015
+ZDF Theaterkanal:394:h:0:6900:1110:0:0:0
+ZDF.doku:394:h:0:6900:660:670:0:28014
+SEASONS:402:h:0:6900:1040:1044:1:0
+CLASSICA:402:h:0:6900:1030:1034:1:0
+FILMPALAST:402:h:0:6900:1050:1054:1:0
+Blockmaster:402:h:0:6900:0:0:1:0
+Test-R:410:h:0:6900:901:0:0:0
+Bayerisches FS:410:h:0:6900:201:202:0:0
+Bayern 4 Klassik:410:h:0:6900:0:3001:0:0
+B5 aktuell:410:h:0:6900:0:3101:0:0
+WDR FERNSEHEN:410:h:0:6900:601:602:0:28111
+Bremen 2:410:h:0:6900:0:3801:0:0
+arte:410:h:0:6900:401:402:0:28109
+Bayern 1:410:h:0:6900:0:3601:0:0
+NDR 4 Info:410:h:0:6900:0:3701:0:0
+SR Fernsehen Suedwest:410:h:0:6900:501:502:0:28110
+SR 1:410:h:0:6900:0:3901:0:0
+Das Erste:410:h:0:6900:101:102:0:28106
+HR2 plus:410:h:0:6900:0:3401:0:0
+HR2:410:h:0:6900:0:3301:0:0
+hessen fernsehen:410:h:0:6900:301:302:0:28108
+hr-chronos:410:h:0:6900:0:3201:0:0
+HR XXL:410:h:0:6900:0:3501:0:0
+hessen:10160:h:1:6900:301:302:0:28108
+BR:10160:h:1:6900:201:202:0:28107
+BR-alpha:410:h:0:6900:701:702:0:28112
+SWR Fernsehen:410:h:0:6900:801:802:0:28113
+Phoenix:410:h:0:6900:901:902:0:0
+ARD-Online-Kanal:426:h:0:6900:0:1805:0:0
+EinsExtra:426:h:0:6900:101:102:0:28201
+EinsFestival:426:h:0:6900:201:202:0:28202
+EinsMuXx:426:h:0:6900:301:302:0:28203
+MDR FERNSEHEN:426:h:0:6900:401:402:0:28204
+ORB-Fernsehen:426:h:0:6900:501:502:0:28205
+B1 Berlin:426:h:0:6900:601:602:0:28206
+Radio 3:426:h:0:6900:0:701:0:0
+MDR KULTUR:426:h:0:6900:0:801:0:0
+Fritz:426:h:0:6900:0:901:0:0
+JUMP:426:h:0:6900:0:1001:0:0
+MDR info:426:h:0:6900:0:1101:0:0
+SPUTNIK:426:h:0:6900:0:1201:0:0
+SFB4 Multikulti:426:h:0:6900:0:1301:0:0
+SWR-2:426:h:0:6900:0:1401:0:0
+WDR3:426:h:0:6900:0:1501:0:0
+WDR 5:426:h:0:6900:0:1601:0:0
+N3:426:h:0:6900:2401:2402:0:0
+ORF:394:h:1:6900:506:507:0:28010
+TV Polonia:434:h:0:6900:641:642:0:0
+Kanal D:434:h:0:6900:651:652:0:0
+RTP international:434:h:0:6900:661:662:0:0
+ATV:434:h:0:6900:631:632:0:0
+ERT-Sat:434:h:0:6900:691:692:0:0
+MV-Test:442:h:0:6900:0:0:0:0
+ZEE TV:442:h:0:6900:517:773:0:0
+NTV i:442:h:0:6900:514:515:0:0
+All Jazz:442:h:0:6900:0:535:0:0
+Cristal New Age:442:h:0:6900:0:536:0:0
+Movie Sounds:442:h:0:6900:0:537:0:0
+Sinfonica:442:h:0:6900:0:538:0:0
+Opernfestival:442:h:0:6900:0:539:0:0
+Barock Fantasie:442:h:0:6900:0:540:0:0
+Musica Camerata:442:h:0:6900:0:541:0:0
+Musica Antica:442:h:0:6900:0:542:0:0
+Adagio:442:h:0:6900:0:543:0:0
+Jazz Legends:442:h:0:6900:0:544:0:0
diff --git a/config.c b/config.c
index 5838c68..66eb178 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.c 1.39 2001/01/14 15:29:15 kls Exp $
+ * $Id: config.c 1.43 2001/02/24 13:20:18 kls Exp $
*/
#include "config.h"
@@ -199,6 +199,7 @@ cChannel::cChannel(const cChannel *Channel)
srate = Channel ? Channel->srate : 27500;
vpid = Channel ? Channel->vpid : 255;
apid = Channel ? Channel->apid : 256;
+ tpid = Channel ? Channel->tpid : 32;
ca = Channel ? Channel->ca : 0;
pnr = Channel ? Channel->pnr : 0;
groupSep = Channel ? Channel->groupSep : false;
@@ -216,7 +217,7 @@ const char *cChannel::ToText(cChannel *Channel)
if (Channel->groupSep)
asprintf(&buffer, ":%s\n", s);
else
- asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->ca, Channel->pnr);
+ asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->tpid, Channel->ca, Channel->pnr);
return buffer;
}
@@ -239,8 +240,15 @@ bool cChannel::Parse(const char *s)
}
else {
groupSep = false;
- int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr);
- if (fields == 9) {
+ //XXX
+ int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &tpid, &ca, &pnr);
+ if (fields >= 9) {
+ if (fields == 9) {
+ // allow reading of old format
+ pnr = ca;
+ ca = tpid;
+ tpid = 0;
+ }
strn0cpy(name, buffer, MaxChannelName);
delete buffer;
}
@@ -265,7 +273,7 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
isyslog(LOG_INFO, "switching to channel %d", number);
}
for (int i = 3; i--;) {
- if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr))
+ if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, tpid, ca, pnr))
return true;
esyslog(LOG_ERR, "retrying");
}
@@ -360,7 +368,11 @@ cTimer& cTimer::operator= (const cTimer &Timer)
const char *cTimer::ToText(cTimer *Timer)
{
delete buffer;
+ strreplace(Timer->file, ':', '|');
+ strreplace(Timer->summary, '\n', '|');
asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : "");
+ strreplace(Timer->summary, '|', '\n');
+ strreplace(Timer->file, '|', ':');
return buffer;
}
@@ -449,6 +461,8 @@ bool cTimer::Parse(const char *s)
//TODO add more plausibility checks
day = ParseDay(buffer1);
strn0cpy(file, buffer2, MaxFileName);
+ strreplace(file, '|', ':');
+ strreplace(summary, '|', '\n');
delete buffer1;
delete buffer2;
delete s2;
@@ -724,6 +738,8 @@ cSetup::cSetup(void)
MarginStart = 2;
MarginStop = 10;
EPGScanTimeout = 5;
+ SVDRPTimeout = 300;
+ PrimaryLimit = 0;
CurrentChannel = -1;
}
@@ -744,6 +760,8 @@ bool cSetup::Parse(char *s)
else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
+ else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value);
+ else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value);
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
else
return false;
@@ -797,6 +815,8 @@ bool cSetup::Save(const char *FileName)
fprintf(f, "MarginStart = %d\n", MarginStart);
fprintf(f, "MarginStop = %d\n", MarginStop);
fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout);
+ fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout);
+ fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit);
fprintf(f, "CurrentChannel = %d\n", CurrentChannel);
f.Close();
isyslog(LOG_INFO, "saved setup to %s", FileName);
diff --git a/config.h b/config.h
index 277e957..60a95c3 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 1.38 2001/01/14 15:29:27 kls Exp $
+ * $Id: config.h 1.42 2001/02/24 13:19:39 kls Exp $
*/
#ifndef __CONFIG_H
@@ -19,7 +19,7 @@
#include "eit.h"
#include "tools.h"
-#define VDRVERSION "0.70"
+#define VDRVERSION "0.71"
#define MaxBuffer 10000
@@ -93,6 +93,7 @@ public:
int srate;
int vpid;
int apid;
+ int tpid;
int ca;
int pnr;
int number; // Sequence number assigned on load
@@ -268,6 +269,8 @@ public:
int SetSystemTime;
int MarginStart, MarginStop;
int EPGScanTimeout;
+ int SVDRPTimeout;
+ int PrimaryLimit;
int CurrentChannel;
cSetup(void);
bool Load(const char *FileName);
diff --git a/dvbapi.c b/dvbapi.c
index e583baf..8518d7f 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbapi.c 1.50 2001/01/18 19:53:54 kls Exp $
+ * $Id: dvbapi.c 1.61 2001/02/24 13:13:19 kls Exp $
*/
#include "dvbapi.h"
@@ -67,7 +67,6 @@ extern "C" {
#define DISKCHECKINTERVAL 100 // seconds
#define INDEXFILESUFFIX "/index.vdr"
-#define RESUMEFILESUFFIX "/resume.vdr"
#define RECORDFILESUFFIX "/%03d.vdr"
#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety...
@@ -105,56 +104,6 @@ int HMSFToIndex(const char *HMSF)
return 0;
}
-// --- cResumeFile ------------------------------------------------------------
-
-cResumeFile::cResumeFile(const char *FileName)
-{
- fileName = new char[strlen(FileName) + strlen(RESUMEFILESUFFIX) + 1];
- if (fileName) {
- strcpy(fileName, FileName);
- strcat(fileName, RESUMEFILESUFFIX);
- }
- else
- esyslog(LOG_ERR, "ERROR: can't allocate memory for resume file name");
-}
-
-cResumeFile::~cResumeFile()
-{
- delete fileName;
-}
-
-int cResumeFile::Read(void)
-{
- int resume = -1;
- if (fileName) {
- int f = open(fileName, O_RDONLY);
- if (f >= 0) {
- if (read(f, &resume, sizeof(resume)) != sizeof(resume)) {
- resume = -1;
- LOG_ERROR_STR(fileName);
- }
- close(f);
- }
- else if (errno != ENOENT)
- LOG_ERROR_STR(fileName);
- }
- return resume;
-}
-
-bool cResumeFile::Save(int Index)
-{
- if (fileName) {
- int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
- if (f >= 0) {
- if (write(f, &Index, sizeof(Index)) != sizeof(Index))
- LOG_ERROR_STR(fileName);
- close(f);
- return true;
- }
- }
- return false;
-}
-
// --- cIndexFile ------------------------------------------------------------
class cIndexFile {
@@ -821,7 +770,9 @@ int cRecordBuffer::ScanVideoPacket(int *PictureType, int Offset)
int Length = GetPacketLength(Offset);
if (Length <= Available()) {
- for (int i = Offset; i < Offset + Length; i++) {
+ int i = Offset + 8; // the minimum length of the video packet header
+ i += Byte(i) + 1; // possible additional header bytes
+ for (; i < Offset + Length; i++) {
if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) {
switch (Byte(i + 3)) {
case SC_PICTURE: *PictureType = GetPictureType(i);
@@ -840,8 +791,6 @@ int cRecordBuffer::Synchronize(void)
// Positions to the start of a data block (skipping everything up to
// an I-frame if not synced) and returns the block length.
- int LastPackHeader = -1;
-
pictureType = NO_PICTURE;
//XXX remove this once the buffer is handled with two separate threads:
@@ -853,8 +802,6 @@ int cRecordBuffer::Synchronize(void)
for (int i = 0; Available() > MINVIDEODATA && i < MINVIDEODATA; i++) {
if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) {
switch (Byte(i + 3)) {
- case SC_PHEAD: LastPackHeader = i;
- break;
case SC_VIDEO: {
int pt = NO_PICTURE;
int l = ScanVideoPacket(&pt, i);
@@ -862,21 +809,15 @@ int cRecordBuffer::Synchronize(void)
return 0; // no useful data found, wait for more
if (pt != NO_PICTURE) {
if (pt < I_FRAME || B_FRAME < pt) {
- esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt);
- }
+ esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt);
+ }
else if (pictureType == NO_PICTURE) {
if (!synced) {
- if (LastPackHeader == 0) {
- if (pt == I_FRAME)
- synced = true;
- }
- else if (LastPackHeader > 0) {
- Skip(LastPackHeader);
- LastPackHeader = -1;
- i = 0;
- break;
+ if (pt == I_FRAME) {
+ Skip(i);
+ synced = true;
}
- else { // LastPackHeader < 0
+ else {
Skip(i + l);
i = 0;
break;
@@ -885,13 +826,15 @@ int cRecordBuffer::Synchronize(void)
if (synced)
pictureType = pt;
}
- else if (LastPackHeader > 0)
- return LastPackHeader;
else
return i;
}
+ else if (!synced) {
+ Skip(i + l);
+ i = 0;
+ break;
+ }
i += l - 1; // -1 to compensate for i++ in the loop!
- LastPackHeader = -1;
}
break;
case SC_AUDIO: i += GetPacketLength(i) - 1; // -1 to compensate for i++ in the loop!
@@ -1576,6 +1519,7 @@ bool cVideoCutter::Active(void)
// --- cDvbApi ---------------------------------------------------------------
int cDvbApi::NumDvbApis = 0;
+int cDvbApi::useDvbApi = 0;
cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL };
cDvbApi *cDvbApi::PrimaryDvbApi = NULL;
@@ -1645,6 +1589,12 @@ cDvbApi::~cDvbApi()
#endif
}
+void cDvbApi::SetUseDvbApi(int n)
+{
+ if (n < MAXDVBAPI)
+ useDvbApi |= (1 << n);
+}
+
bool cDvbApi::SetPrimaryDvbApi(int n)
{
n--;
@@ -1659,7 +1609,7 @@ bool cDvbApi::SetPrimaryDvbApi(int n)
cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority)
{
- cDvbApi *d = NULL;
+ cDvbApi *d = NULL, *dMinPriority = NULL;
int index = Ca - 1;
for (int i = MAXDVBAPI; --i >= 0; ) {
if (dvbApi[i]) {
@@ -1669,13 +1619,25 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority)
}
else if (Ca == 0) { // means any device would be acceptable
if (!d || !dvbApi[i]->Recording() || (d->Recording() && d->Priority() > dvbApi[i]->Priority()))
- d = dvbApi[i];
+ d = dvbApi[i]; // this is one that is either not currently recording or has the lowest priority
if (d && d != PrimaryDvbApi && !d->Recording()) // avoids the PrimaryDvbApi if possible
break;
+ if (d && d->Recording() && d->Priority() < Setup.PrimaryLimit && (!dMinPriority || d->Priority() < dMinPriority->Priority()))
+ dMinPriority = d; // this is the one with the lowest priority below Setup.PrimaryLimit
}
}
}
- return (d && (!d->Recording() || d->Priority() < Priority || (!d->Ca() && Ca))) ? d : NULL;
+ if (d == PrimaryDvbApi) { // the PrimaryDvbApi was the only one that was free
+ if (Priority < Setup.PrimaryLimit)
+ return NULL; // not enough priority to use the PrimaryDvbApi
+ if (dMinPriority) // there's one that must not use the PrimaryDvbApi...
+ d = dMinPriority; // ...so let's kick out that one
+ }
+ return (d // we found one...
+ && (!d->Recording() // ...that's either not currently recording...
+ || d->Priority() < Priority // ...or has a lower priority...
+ || (!d->Ca() && Ca))) // ...or doesn't need this card
+ ? d : NULL;
}
int cDvbApi::Index(void)
@@ -1691,33 +1653,34 @@ bool cDvbApi::Init(void)
{
NumDvbApis = 0;
for (int i = 0; i < MAXDVBAPI; i++) {
- char fileName[strlen(VIDEODEVICE) + 10];
- sprintf(fileName, "%s%d", VIDEODEVICE, i);
- if (access(fileName, F_OK | R_OK | W_OK) == 0) {
- dsyslog(LOG_INFO, "probing %s", fileName);
- int f = open(fileName, O_RDWR);
- if (f >= 0) {
- struct video_capability cap;
- int r = ioctl(f, VIDIOCGCAP, &cap);
- close(f);
- if (r == 0 && (cap.type & VID_TYPE_DVB)) {
- char vbiFileName[strlen(VBIDEVICE) + 10];
- sprintf(vbiFileName, "%s%d", VBIDEVICE, i);
- dvbApi[i] = new cDvbApi(fileName, vbiFileName);
- NumDvbApis++;
+ if (useDvbApi == 0 || (useDvbApi & (1 << i)) != 0) {
+ char fileName[strlen(VIDEODEVICE) + 10];
+ sprintf(fileName, "%s%d", VIDEODEVICE, i);
+ if (access(fileName, F_OK | R_OK | W_OK) == 0) {
+ dsyslog(LOG_INFO, "probing %s", fileName);
+ int f = open(fileName, O_RDWR);
+ if (f >= 0) {
+ struct video_capability cap;
+ int r = ioctl(f, VIDIOCGCAP, &cap);
+ close(f);
+ if (r == 0 && (cap.type & VID_TYPE_DVB)) {
+ char vbiFileName[strlen(VBIDEVICE) + 10];
+ sprintf(vbiFileName, "%s%d", VBIDEVICE, i);
+ dvbApi[NumDvbApis++] = new cDvbApi(fileName, vbiFileName);
+ }
+ }
+ else {
+ if (errno != ENODEV)
+ LOG_ERROR_STR(fileName);
+ break;
}
}
else {
- if (errno != ENODEV)
+ if (errno != ENOENT)
LOG_ERROR_STR(fileName);
break;
}
}
- else {
- if (errno != ENOENT)
- LOG_ERROR_STR(fileName);
- break;
- }
}
PrimaryDvbApi = dvbApi[0];
if (NumDvbApis > 0) {
@@ -2168,7 +2131,7 @@ void cDvbApi::Flush(void)
#endif
}
-bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr)
+bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr)
{
if (videoDev >= 0) {
cThreadLock ThreadLock(siProcessor); // makes sure the siProcessor won't access the vbi-device while switching
@@ -2177,20 +2140,29 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
struct frontend front;
ioctl(videoDev, VIDIOCGFRONTEND, &front);
unsigned int freq = FrequencyMHz;
- front.ttk = (freq < 11700UL) ? 0 : 1;
- if (freq < 11700UL)
- freq -= Setup.LnbFrequLo;
- else
- freq -= Setup.LnbFrequHi;
- front.pnr = 0;
+ if (front.type == FRONT_DVBS) {
+ front.ttk = (freq < 11700UL) ? 0 : 1;
+ if (freq < 11700UL) {
+ freq -= Setup.LnbFrequLo;
+ front.ttk = 0;
+ }
+ else {
+ freq -= Setup.LnbFrequHi;
+ front.ttk = 1;
+ }
+ }
+ front.channel_flags = Ca ? DVB_CHANNEL_CA : DVB_CHANNEL_FTA;
+ front.pnr = Pnr;
front.freq = freq * 1000000UL;
front.diseqc = Diseqc;
front.srate = Srate * 1000;
front.volt = (Polarization == 'v' || Polarization == 'V') ? 0 : 1;
front.video_pid = Vpid;
front.audio_pid = Apid;
+ front.tt_pid = Tpid;
front.fec = 8;
front.AFC = 1;
+ front.qam = 2;
ioctl(videoDev, VIDIOCSFRONTEND, &front);
if (front.sync & 0x1F == 0x1F) {
if (this == PrimaryDvbApi && siProcessor)
@@ -2198,11 +2170,11 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
currentChannel = ChannelNumber;
// If this DVB card can't receive this channel, let's see if we can
// use the card that actually can receive it and transfer data from there:
- if (Ca && Ca != Index() + 1) {
+ if (this == PrimaryDvbApi && Ca && Ca != Index() + 1) {
cDvbApi *CaDvbApi = GetDvbApi(Ca, 0);
if (CaDvbApi) {
if (!CaDvbApi->Recording()) {
- if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Ca, Pnr))
+ if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr))
transferringFromDvbApi = CaDvbApi->StartTransfer(videoDev);
}
}
@@ -2403,7 +2375,25 @@ cEITScanner::cEITScanner(void)
{
lastScan = lastActivity = time(NULL);
currentChannel = 0;
- lastChannel = 1;
+ lastChannel = 0;
+ numTransponders = 0;
+ transponders = NULL;
+}
+
+cEITScanner::~cEITScanner()
+{
+ delete transponders;
+}
+
+bool cEITScanner::TransponderScanned(cChannel *Channel)
+{
+ for (int i = 0; i < numTransponders; i++) {
+ if (transponders[i] == Channel->frequency)
+ return true;
+ }
+ transponders = (int *)realloc(transponders, ++numTransponders * sizeof(int));
+ transponders[numTransponders - 1] = Channel->frequency;
+ return false;
}
void cEITScanner::Activity(void)
@@ -2417,7 +2407,7 @@ void cEITScanner::Activity(void)
void cEITScanner::Process(void)
{
- if (Channels.MaxNumber() > 1) {
+ if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
time_t now = time(NULL);
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
for (int i = 0; i < cDvbApi::NumDvbApis; i++) {
@@ -2428,10 +2418,12 @@ void cEITScanner::Process(void)
int oldCh = lastChannel;
int ch = oldCh + 1;
while (ch != oldCh) {
- if (ch > Channels.MaxNumber())
+ if (ch > Channels.MaxNumber()) {
ch = 1;
+ numTransponders = 0;
+ }
cChannel *Channel = Channels.GetByNumber(ch);
- if (Channel && Channel->pnr) {
+ if (Channel && Channel->pnr && !TransponderScanned(Channel)) {
if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel)
currentChannel = DvbApi->Channel();
Channel->Switch(DvbApi, false);
diff --git a/dvbapi.h b/dvbapi.h
index cf0584f..de64612 100644
--- a/dvbapi.h
+++ b/dvbapi.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbapi.h 1.30 2001/01/07 15:56:10 kls Exp $
+ * $Id: dvbapi.h 1.35 2001/02/11 10:41:10 kls Exp $
*/
#ifndef __DVBAPI_H
@@ -33,21 +33,13 @@ typedef struct CRect {
#define MenuLines 15
#define MenuColumns 40
-class cResumeFile {
-private:
- char *fileName;
-public:
- cResumeFile(const char *FileName);
- ~cResumeFile();
- int Read(void);
- bool Save(int Index);
- };
-
const char *IndexToHMSF(int Index, bool WithFrame = false);
// Converts the given index to a string, optionally containing the frame number.
int HMSFToIndex(const char *HMSF);
// Converts the given string (format: "hh:mm:ss.ff") to an index.
+class cChannel;
+
class cRecordBuffer;
class cReplayBuffer;
class cTransferBuffer;
@@ -69,12 +61,17 @@ private:
public:
~cDvbApi();
-#define MAXDVBAPI 2
+#define MAXDVBAPI 4
static int NumDvbApis;
private:
static cDvbApi *dvbApi[MAXDVBAPI];
+ static int useDvbApi;
public:
static cDvbApi *PrimaryDvbApi;
+ static void SetUseDvbApi(int n);
+ // Sets the 'useDvbApi' flag of the given DVB device.
+ // If this function is not called before Init(), all DVB devices
+ // will be used.
static bool SetPrimaryDvbApi(int n);
// Sets the primary DVB device to 'n' (which must be in the range
// 1...NumDvbApis) and returns true if this was possible.
@@ -162,7 +159,7 @@ public:
private:
int currentChannel;
public:
- bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr);
+ bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr);
static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; }
int Channel(void) { return currentChannel; }
@@ -251,8 +248,11 @@ private:
};
time_t lastScan, lastActivity;
int currentChannel, lastChannel;
+ int numTransponders, *transponders;
+ bool TransponderScanned(cChannel *Channel);
public:
cEITScanner(void);
+ ~cEITScanner();
bool Active(void) { return currentChannel; }
void Activity(void);
void Process(void);
diff --git a/eit.c b/eit.c
index e7c60c1..08588b0 100644
--- a/eit.c
+++ b/eit.c
@@ -13,7 +13,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.c 1.11 2000/12/03 15:33:37 kls Exp $
+ * $Id: eit.c 1.12 2001/02/24 12:12:58 kls Exp $
***************************************************************************/
#include "eit.h"
@@ -851,7 +851,8 @@ int cEIT::ProcessEIT()
break;
case EIT_COMPONENT_DESCRIPTOR :
- strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6);
+ if (buffer[bufact + 1] > 6) // kls 2001-02-24: otherwise strncpy() causes a segfault in strdvbcpy()
+ strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6);
//dsyslog(LOG_INFO, "Found EIT_COMPONENT_DESCRIPTOR %c%c%c 0x%02x/0x%02x/0x%02x '%s'\n", buffer[bufact + 5], buffer[bufact + 6], buffer[bufact + 7], buffer[2], buffer[3], buffer[4], tmp);
break;
@@ -910,6 +911,14 @@ int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max)
{
int a = 0;
+ // kls 2001-02-24: if we come in with negative values, the caller must
+ // have done something wrong and the strncpy() below will cause a segfault
+ if (max <= 0)
+ {
+ *dst = 0;
+ return 0;
+ }
+
if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff))
{
for (a = 0; a < max; a++)
diff --git a/epg2html.pl b/epg2html.pl
index 215eb73..215eb73 100644..100755
--- a/epg2html.pl
+++ b/epg2html.pl
diff --git a/i18n.c b/i18n.c
index cf1785f..f81a202 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.8 2001/01/06 16:17:39 kls Exp $
+ * $Id: i18n.c 1.14 2001/02/24 13:57:14 kls Exp $
*
* Slovenian translations provided by Miha Setina <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@@ -161,6 +161,11 @@ const tPhrase Phrases[] = {
"Predavajaj",
"Riproduci",
},
+ { "Rewind",
+ "Anfang",
+ "Zacetek",
+ "Da inizio",
+ },
{ "Resume",
"Weiter",
"Nadaljuj",
@@ -253,6 +258,11 @@ const tPhrase Phrases[] = {
"Apid",
"Apid",
},
+ { "Tpid",
+ "Tpid",
+ "Tpid",
+ "Tpid",
+ },
{ "CA",
"CA",
"CA",
@@ -406,6 +416,16 @@ const tPhrase Phrases[] = {
"Cas do EPG pregleda",
"Timeout EPG",
},
+ { "SVDRPTimeout",
+ "SVDRP Timeout",
+ "", // TODO
+ "Timeout SVDRP",
+ },
+ { "PrimaryLimit",
+ "Primär-Limit",
+ "", // TODO
+ "", // TODO
+ },
// The days of the week:
{ "MTWTFSS",
"MDMDFSS",
diff --git a/interface.c b/interface.c
index ef8368a..55cdb0b 100644
--- a/interface.c
+++ b/interface.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: interface.c 1.33 2000/12/09 11:04:10 kls Exp $
+ * $Id: interface.c 1.35 2001/02/18 10:46:13 kls Exp $
*/
#include "interface.h"
@@ -26,8 +26,10 @@ cInterface::cInterface(int SVDRPport)
rcIo = new cRcIoRCU("/dev/ttyS1");
#elif defined(REMOTE_LIRC)
rcIo = new cRcIoLIRC("/dev/lircd");
-#else
+#elif defined(REMOTE_KBD)
rcIo = new cRcIoKBD;
+#else
+ rcIo = new cRcIoBase; // acts as a dummy device
#endif
rcIo->SetCode(Keys.code, Keys.address);
if (SVDRPport)
@@ -68,8 +70,16 @@ unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release)
eKeys cInterface::GetKey(bool Wait)
{
Flush();
- if (SVDRP)
+ if (SVDRP) {
SVDRP->Process();
+ if (!open) {
+ char *message = SVDRP->GetMessage();
+ if (message) {
+ Info(message);
+ delete message;
+ }
+ }
+ }
eKeys Key = keyFromWait;
if (Key == kNone) {
bool Repeat = false, Release = false;
@@ -279,7 +289,7 @@ void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor)
void cInterface::Info(const char *s)
{
Open();
- isyslog(LOG_INFO, s);
+ isyslog(LOG_INFO, "info: %s", s);
Status(s, clrWhite, clrGreen);
Wait();
Status(NULL);
@@ -289,7 +299,7 @@ void cInterface::Info(const char *s)
void cInterface::Error(const char *s)
{
Open();
- esyslog(LOG_ERR, s);
+ esyslog(LOG_ERR, "ERROR: %s", s);
Status(s, clrWhite, clrRed);
Wait();
Status(NULL);
diff --git a/menu.c b/menu.c
index 144233f..45be9eb 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.58 2001/01/13 13:07:43 kls Exp $
+ * $Id: menu.c 1.68 2001/02/24 14:53:40 kls Exp $
*/
#include "menu.h"
@@ -541,6 +541,7 @@ cMenuEditChannel::cMenuEditChannel(int Index)
Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 27500)); //TODO exact limits - toggle???
Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem( tr("Apid"), &data.apid, 0, 10000)); //TODO exact limits???
+ Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem( tr("CA"), &data.ca, 0, cDvbApi::NumDvbApis));
Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0));
}
@@ -924,6 +925,8 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
strcpy(data.file, Channels.GetChannelNameByNumber(data.channel));
if (timer && memcmp(timer, &data, sizeof(data)) != 0) {
*timer = data;
+ if (timer->active)
+ timer->active = 1; // allows external programs to mark active timers with values > 1 and recognize if the user has modified them
Timers.Save();
isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive");
}
@@ -1074,6 +1077,16 @@ eOSState cMenuTimers::Summary(void)
eOSState cMenuTimers::ProcessKey(eKeys Key)
{
+ // Must do these before calling cOsdMenu::ProcessKey() because cOsdMenu
+ // uses them to page up/down:
+ if (!HasSubMenu()) {
+ switch (Key) {
+ case kLeft:
+ case kRight: return Activate(Key == kRight);
+ default: break;
+ }
+ }
+
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
@@ -1181,13 +1194,17 @@ class cMenuWhatsOn : public cOsdMenu {
private:
eOSState Record(void);
eOSState Switch(void);
+ static int currentChannel;
static const cEventInfo *scheduleEventInfo;
public:
- cMenuWhatsOn(const cSchedules *Schedules, bool Now);
+ cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr);
+ static int CurrentChannel(void) { return currentChannel; }
+ static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; }
static const cEventInfo *ScheduleEventInfo(void);
virtual eOSState ProcessKey(eKeys Key);
};
+int cMenuWhatsOn::currentChannel = 0;
const cEventInfo *cMenuWhatsOn::scheduleEventInfo = NULL;
static int CompareEventChannel(const void *p1, const void *p2)
@@ -1195,7 +1212,7 @@ static int CompareEventChannel(const void *p1, const void *p2)
return (int)( (*(const cEventInfo **)p1)->GetChannelNumber() - (*(const cEventInfo **)p2)->GetChannelNumber());
}
-cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now)
+cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), 4, 7, 6)
{
const cSchedule *Schedule = Schedules->First();
@@ -1219,8 +1236,9 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now)
qsort(pArray, num, sizeof(cEventInfo *), CompareEventChannel);
for (int a = 0; a < num; a++)
- Add(new cMenuWhatsOnItem(pArray[a]));
+ Add(new cMenuWhatsOnItem(pArray[a]), pArray[a]->GetChannelNumber() == CurrentChannelNr);
+ currentChannel = CurrentChannelNr;
delete pArray;
SetHelp(tr("Record"), Now ? tr("Next") : tr("Now"), tr("Schedule"), tr("Switch"));
}
@@ -1271,12 +1289,16 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
if (state == osUnknown) {
switch (Key) {
case kRed: return Record();
- case kYellow: {
+ case kYellow: state = osBack;
+ // continue with kGreen
+ case kGreen: {
cMenuWhatsOnItem *mi = (cMenuWhatsOnItem *)Get(Current());
- if (mi)
+ if (mi) {
scheduleEventInfo = mi->eventInfo;
+ currentChannel = mi->eventInfo->GetChannelNumber();
+ }
}
- return osBack;
+ break;
case kBlue: return Switch();
case kOk: if (Count())
return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->eventInfo, true));
@@ -1314,7 +1336,6 @@ private:
eOSState Record(void);
eOSState Switch(void);
void PrepareSchedule(cChannel *Channel);
- void PrepareWhatsOnNext(bool On);
public:
cMenuSchedule(void);
virtual eOSState ProcessKey(eKeys Key);
@@ -1327,6 +1348,7 @@ cMenuSchedule::cMenuSchedule(void)
otherChannel = 0;
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
if (channel) {
+ cMenuWhatsOn::SetCurrentChannel(channel->number);
schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock);
PrepareSchedule(channel);
SetHelp(tr("Record"), tr("Now"), tr("Next"));
@@ -1403,14 +1425,22 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
if (state == osUnknown) {
switch (Key) {
case kRed: return Record();
- case kGreen: if (!now && !next) {
- now = true;
- return AddSubMenu(new cMenuWhatsOn(schedules, true));
- }
- now = !now;
- next = !next;
- return AddSubMenu(new cMenuWhatsOn(schedules, now));
- case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false));
+ case kGreen: {
+ if (!now && !next) {
+ int ChannelNr = 0;
+ if (Count()) {
+ cChannel *channel = Channels.GetByServiceID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetServiceID());
+ if (channel)
+ ChannelNr = channel->number;
+ }
+ now = true;
+ return AddSubMenu(new cMenuWhatsOn(schedules, true, ChannelNr));
+ }
+ now = !now;
+ next = !next;
+ return AddSubMenu(new cMenuWhatsOn(schedules, now, cMenuWhatsOn::CurrentChannel()));
+ }
+ case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false, cMenuWhatsOn::CurrentChannel()));
case kBlue: return Switch();
case kOk: if (Count())
return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo, otherChannel));
@@ -1469,7 +1499,7 @@ cMenuRecordings::cMenuRecordings(void)
recording = Recordings.Next(recording);
}
}
- SetHelp(tr("Play"), NULL, tr("Delete"), tr("Summary"));
+ SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), tr("Summary"));
Display();
}
@@ -1483,6 +1513,18 @@ eOSState cMenuRecordings::Play(void)
return osContinue;
}
+eOSState cMenuRecordings::Rewind(void)
+{
+ cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
+ if (ri) {
+ cDvbApi::PrimaryDvbApi->StopReplay(); // must do this first to be able to rewind the currently replayed recording
+ cResumeFile ResumeFile(ri->recording->FileName());
+ ResumeFile.Delete();
+ return Play();
+ }
+ return osContinue;
+}
+
eOSState cMenuRecordings::Del(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
@@ -1523,6 +1565,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
switch (Key) {
case kOk:
case kRed: return Play();
+ case kGreen: return Rewind();
case kYellow: return Del();
case kBlue: return Summary();
case kMenu: return osEnd;
@@ -1567,6 +1610,8 @@ void cMenuSetup::Set(void)
Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart));
Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop));
Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout));
+ Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout));
+ Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit));
}
eOSState cMenuSetup::ProcessKey(eKeys Key)
@@ -1614,6 +1659,7 @@ cMenuCommands::cMenuCommands(void)
Add(new cOsdItem(command->Title()));
i++;
}
+ SetHasHotkeys();
}
eOSState cMenuCommands::Execute(void)
@@ -1644,18 +1690,25 @@ eOSState cMenuCommands::ProcessKey(eKeys Key)
#define STOP_RECORDING tr("Stop recording ")
+static const char *hk(int n, const char *s)
+{
+ static char buffer[32];
+ snprintf(buffer, sizeof(buffer), " %d %s", n, s);
+ return buffer;
+}
+
cMenuMain::cMenuMain(bool Replaying)
:cOsdMenu(tr("Main"))
{
- Add(new cOsdItem(tr("Schedule"), osSchedule));
- Add(new cOsdItem(tr("Channels"), osChannels));
- Add(new cOsdItem(tr("Timers"), osTimers));
- Add(new cOsdItem(tr("Recordings"), osRecordings));
- Add(new cOsdItem(tr("Setup"), osSetup));
+ Add(new cOsdItem(hk(1, tr("Schedule")), osSchedule));
+ Add(new cOsdItem(hk(2, tr("Channels")), osChannels));
+ Add(new cOsdItem(hk(3, tr("Timers")), osTimers));
+ Add(new cOsdItem(hk(4, tr("Recordings")), osRecordings));
+ Add(new cOsdItem(hk(5, tr("Setup")), osSetup));
if (Commands.Count())
- Add(new cOsdItem(tr("Commands"), osCommands));
+ Add(new cOsdItem(hk(6, tr("Commands")), osCommands));
if (Replaying)
- Add(new cOsdItem(tr("Stop replaying"), osStopReplay));
+ Add(new cOsdItem(tr(" Stop replaying"), osStopReplay));
const char *s = NULL;
while ((s = cRecordControls::GetInstantId(s)) != NULL) {
char *buffer = NULL;
@@ -1664,10 +1717,11 @@ cMenuMain::cMenuMain(bool Replaying)
delete buffer;
}
if (cVideoCutter::Active())
- Add(new cOsdItem(tr("Cancel editing"), osCancelEdit));
+ Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit));
SetHelp(tr("Record"), NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL);
Display();
lastActivity = time(NULL);
+ SetHasHotkeys();
}
eOSState cMenuMain::ProcessKey(eKeys Key)
@@ -1945,7 +1999,7 @@ bool cRecordControls::Start(cTimer *Timer)
}
}
}
- else
+ else if (!Timer || Timer->priority >= Setup.PrimaryLimit)
esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch);
}
else
@@ -1999,6 +2053,15 @@ void cRecordControls::Process(void)
}
}
+bool cRecordControls::Active(void)
+{
+ for (int i = 0; i < MAXDVBAPI; i++) {
+ if (RecordControls[i])
+ return true;
+ }
+ return false;
+}
+
// --- cProgressBar ----------------------------------------------------------
class cProgressBar : public cBitmap {
diff --git a/menu.h b/menu.h
index 9232111..356122e 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 1.16 2000/12/25 14:25:29 kls Exp $
+ * $Id: menu.h 1.18 2001/02/11 10:30:35 kls Exp $
*/
#ifndef _MENU_H
@@ -43,6 +43,7 @@ class cMenuRecordings : public cOsdMenu {
private:
cRecordings Recordings;
eOSState Play(void);
+ eOSState Rewind(void);
eOSState Del(void);
eOSState Summary(void);
public:
@@ -74,6 +75,7 @@ public:
static void Stop(cDvbApi *DvbApi);
static const char *GetInstantId(const char *LastInstantId);
static void Process(void);
+ static bool Active(void);
};
class cReplayControl : public cOsdBase {
diff --git a/osd.c b/osd.c
index bc9c948..c29c983 100644
--- a/osd.c
+++ b/osd.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.c 1.13 2000/11/12 15:29:25 kls Exp $
+ * $Id: osd.c 1.16 2001/02/24 16:26:11 kls Exp $
*/
#include "osd.h"
@@ -77,6 +77,7 @@ eOSState cOsdItem::ProcessKey(eKeys Key)
cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
{
+ hasHotkeys = false;
visible = false;
title = strdup(Title);
cols[0] = c0;
@@ -252,6 +253,32 @@ void cOsdMenu::CursorDown(void)
}
}
+void cOsdMenu::PageUp(void)
+{
+ if (Count() <= MAXOSDITEMS)
+ return;
+ current -= MAXOSDITEMS;
+ first -= MAXOSDITEMS;
+ if (first < 0)
+ first = current = 0;
+ Display();
+ DisplayCurrent(true);
+}
+
+void cOsdMenu::PageDown(void)
+{
+ if (Count() <= MAXOSDITEMS)
+ return;
+ current += MAXOSDITEMS;
+ first += MAXOSDITEMS;
+ if (current > Count() - 1) {
+ current = Count() - 1;
+ first = Count() - MAXOSDITEMS;
+ }
+ Display();
+ DisplayCurrent(true);
+}
+
void cOsdMenu::Mark(void)
{
if (Count() && marked < 0) {
@@ -260,6 +287,20 @@ void cOsdMenu::Mark(void)
}
}
+eOSState cOsdMenu::HotKey(eKeys Key)
+{
+ for (cOsdItem *item = First(); item; item = Next(item)) {
+ const char *s = item->Text();
+ if (s && (s = skipspace(s)) != NULL) {
+ if (*s == Key - k1 + '1') {
+ current = item->Index();
+ return ProcessKey(kOk);
+ }
+ }
+ }
+ return osContinue;
+}
+
eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
{
delete subMenu;
@@ -289,10 +330,17 @@ eOSState cOsdMenu::ProcessKey(eKeys Key)
return state;
}
switch (Key) {
+ case k1...k9: if (hasHotkeys)
+ return HotKey(Key);
+ break;
case kUp|k_Repeat:
case kUp: CursorUp(); break;
case kDown|k_Repeat:
case kDown: CursorDown(); break;
+ case kLeft|k_Repeat:
+ case kLeft: PageUp(); break;
+ case kRight|k_Repeat:
+ case kRight: PageDown(); break;
case kBack: return osBack;
case kOk: if (marked >= 0) {
SetStatus(NULL);
diff --git a/osd.h b/osd.h
index 16d0ec2..c0fb1a1 100644
--- a/osd.h
+++ b/osd.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.h 1.18 2000/12/24 10:16:52 kls Exp $
+ * $Id: osd.h 1.20 2001/02/03 15:13:59 kls Exp $
*/
#ifndef __OSD_H
@@ -77,6 +77,7 @@ private:
cOsdMenu *subMenu;
const char *helpRed, *helpGreen, *helpYellow, *helpBlue;
const char *status;
+ bool hasHotkeys;
protected:
bool visible;
virtual void Clear(void);
@@ -85,7 +86,10 @@ protected:
void DisplayCurrent(bool Current);
void CursorUp(void);
void CursorDown(void);
+ void PageUp(void);
+ void PageDown(void);
void Mark(void);
+ eOSState HotKey(eKeys Key);
eOSState AddSubMenu(cOsdMenu *SubMenu);
bool HasSubMenu(void) { return subMenu; }
void SetStatus(const char *s);
@@ -95,6 +99,7 @@ protected:
public:
cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
virtual ~cOsdMenu();
+ void SetHasHotkeys(void) { hasHotkeys = true; }
int Current(void) { return current; }
void Add(cOsdItem *Item, bool Current = false);
void Display(void);
diff --git a/recording.c b/recording.c
index 064731d..d6e5a33 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.c 1.24 2001/01/13 12:17:15 kls Exp $
+ * $Id: recording.c 1.28 2001/02/18 16:14:05 kls Exp $
*/
#define _GNU_SOURCE
@@ -15,16 +15,20 @@
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
-#include "dvbapi.h"
#include "interface.h"
#include "tools.h"
#include "videodir.h"
#define RECEXT ".rec"
#define DELEXT ".del"
+#ifdef VFAT
+#define DATAFORMAT "%4d-%02d-%02d.%02d.%02d.%02d.%02d" RECEXT
+#else
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
+#endif
#define NAMEFORMAT "%s/%s/" DATAFORMAT
+#define RESUMEFILESUFFIX "/resume.vdr"
#define SUMMARYFILESUFFIX "/summary.vdr"
#define MARKSFILESUFFIX "/marks.vdr"
@@ -32,8 +36,35 @@
#define MINDISKSPACE 1024 // MB
-#define DISKCHECKDELTA 300 // seconds between checks for free disk space
-#define REMOVELATENCY 10 // seconds to wait until next check after removing a file
+#define DELETEDLIFETIME 1 // hours after which a deleted recording will be actually removed
+#define REMOVECHECKDELTA 3600 // seconds between checks for removing deleted files
+#define DISKCHECKDELTA 300 // seconds between checks for free disk space
+#define REMOVELATENCY 10 // seconds to wait until next check after removing a file
+
+void RemoveDeletedRecordings(void)
+{
+ static time_t LastRemoveCheck = 0;
+ if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) {
+ // Remove the oldest file that has been "deleted":
+ cRecordings Recordings;
+ if (Recordings.Load(true)) {
+ cRecording *r = Recordings.First();
+ cRecording *r0 = r;
+ while (r) {
+ if (r->start < r0->start)
+ r0 = r;
+ r = Recordings.Next(r);
+ }
+ if (r0 && time(NULL) - r0->start > DELETEDLIFETIME * 60) {
+ r0->Remove();
+ RemoveEmptyVideoDirectories();
+ LastRemoveCheck += REMOVELATENCY;
+ return;
+ }
+ }
+ LastRemoveCheck = time(NULL);
+ }
+}
void AssertFreeDiskSpace(void)
{
@@ -83,6 +114,64 @@ void AssertFreeDiskSpace(void)
}
}
+// --- cResumeFile ------------------------------------------------------------
+
+cResumeFile::cResumeFile(const char *FileName)
+{
+ fileName = new char[strlen(FileName) + strlen(RESUMEFILESUFFIX) + 1];
+ if (fileName) {
+ strcpy(fileName, FileName);
+ strcat(fileName, RESUMEFILESUFFIX);
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: can't allocate memory for resume file name");
+}
+
+cResumeFile::~cResumeFile()
+{
+ delete fileName;
+}
+
+int cResumeFile::Read(void)
+{
+ int resume = -1;
+ if (fileName) {
+ int f = open(fileName, O_RDONLY);
+ if (f >= 0) {
+ if (read(f, &resume, sizeof(resume)) != sizeof(resume)) {
+ resume = -1;
+ LOG_ERROR_STR(fileName);
+ }
+ close(f);
+ }
+ else if (errno != ENOENT)
+ LOG_ERROR_STR(fileName);
+ }
+ return resume;
+}
+
+bool cResumeFile::Save(int Index)
+{
+ if (fileName) {
+ int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
+ if (f >= 0) {
+ if (write(f, &Index, sizeof(Index)) != sizeof(Index))
+ LOG_ERROR_STR(fileName);
+ close(f);
+ return true;
+ }
+ }
+ return false;
+}
+
+void cResumeFile::Delete(void)
+{
+ if (fileName) {
+ if (remove(fileName) < 0 && errno != ENOENT)
+ LOG_ERROR_STR(fileName);
+ }
+}
+
// --- cRecording ------------------------------------------------------------
cRecording::cRecording(cTimer *Timer)
diff --git a/recording.h b/recording.h
index 454c356..b561fa2 100644
--- a/recording.h
+++ b/recording.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.h 1.11 2000/12/16 14:25:20 kls Exp $
+ * $Id: recording.h 1.13 2001/02/11 10:45:52 kls Exp $
*/
#ifndef __RECORDING_H
@@ -14,8 +14,20 @@
#include "config.h"
#include "tools.h"
+void RemoveDeletedRecordings(void);
void AssertFreeDiskSpace(void);
+class cResumeFile {
+private:
+ char *fileName;
+public:
+ cResumeFile(const char *FileName);
+ ~cResumeFile();
+ int Read(void);
+ bool Save(int Index);
+ void Delete(void);
+ };
+
class cRecording : public cListObject {
friend class cRecordings;
private:
diff --git a/remote.c b/remote.c
index 691b5e9..9402438 100644
--- a/remote.c
+++ b/remote.c
@@ -6,7 +6,7 @@
*
* Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16.
*
- * $Id: remote.c 1.20 2000/12/03 11:55:06 kls Exp $
+ * $Id: remote.c 1.21 2001/02/04 19:17:59 kls Exp $
*/
#include "remote.h"
@@ -428,6 +428,7 @@ void cRcIoLIRC::Action(void)
dsyslog(LOG_INFO, "LIRC remote control thread started (pid=%d)", getpid());
int FirstTime = 0;
+ int LastTime = 0;
char buf[LIRC_BUFFER_SIZE];
char LastKeyName[LIRC_KEY_BUF];
@@ -451,14 +452,17 @@ void cRcIoLIRC::Action(void)
continue; // repeat function kicks in after a short delay
receivedData = receivedRepeat = true;
}
+ LastTime = Now;
WakeUp();
}
}
else if (receivedData) { // the last data before releasing the key hasn't been fetched yet
if (receivedRepeat) { // it was a repeat, so let's make it a release
- receivedRepeat = false;
- receivedRelease = true;
- WakeUp();
+ if (time_ms() - LastTime > REPEATDELAY) {
+ receivedRepeat = false;
+ receivedRelease = true;
+ WakeUp();
+ }
}
}
else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release
diff --git a/remote.h b/remote.h
index 0ea4442..659de1a 100644
--- a/remote.h
+++ b/remote.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remote.h 1.13 2000/10/08 12:11:34 kls Exp $
+ * $Id: remote.h 1.14 2001/02/02 14:49:10 kls Exp $
*/
#ifndef __REMOTE_H
@@ -18,9 +18,9 @@
class cRcIoBase {
protected:
time_t t;
- cRcIoBase(void);
public:
enum { modeH = 'h', modeB = 'b', modeS = 's' };
+ cRcIoBase(void);
virtual ~cRcIoBase();
virtual bool SetCode(unsigned char Code, unsigned short Address) { return true; }
virtual bool SetMode(unsigned char Mode) { return true; }
@@ -29,8 +29,8 @@ public:
virtual bool String(char *s) { return true; }
virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; }
virtual void Flush(int WaitMs = 0) {}
- virtual bool InputAvailable(void) = 0;
- virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL) = 0;
+ virtual bool InputAvailable(void) { return false; }
+ virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL) { return false; }
};
#if defined REMOTE_KBD
@@ -93,7 +93,7 @@ public:
virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL);
};
-#else
+#elif !defined REMOTE_NONE
#error Please define a remote control mode!
diff --git a/runvdr b/runvdr
new file mode 100755
index 0000000..83b2ea6
--- /dev/null
+++ b/runvdr
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+DVBDIR='../DVB/driver'
+VDRCMD='./vdr -w 60'
+
+while test 1; do
+# (cd $DVBDIR; make reload)
+# sleep 3
+ if $VDRCMD; then exit; fi
+ date
+ echo "restarting VDR"
+ sleep 10
+ done
diff --git a/svdrp.c b/svdrp.c
index 0ce30db..ffdac28 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 1.13 2000/12/03 15:34:35 kls Exp $
+ * $Id: svdrp.c 1.14 2001/02/18 14:18:13 kls Exp $
*/
#define _GNU_SOURCE
@@ -63,6 +63,10 @@ bool cSocket::Open(void)
port = 0;
return false;
}
+ // allow it to always reuse the same port:
+ int ReUseAddr = 1;
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ReUseAddr, sizeof(ReUseAddr));
+ //
struct sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(port);
@@ -137,6 +141,12 @@ const char *HelpPages[] = {
"LSTT [ <number> ]\n"
" List timers. Without option, all timers are listed. Otherwise\n"
" only the given timer is listed.",
+ "MESG [ <message> ]\n"
+ " Displays the given message on the OSD. If message is omitted, the\n"
+ " currently pending message (if any) will be returned. The message\n"
+ " will be displayed for a few seconds as soon as the OSD has become\n"
+ " idle. If a new MESG command is entered while the previous message\n"
+ " has not yet been displayed, the old message will be overwritten.",
"MODC <number> <settings>\n"
" Modify a channel. Settings must be in the same format as returned\n"
" by the LSTC command.",
@@ -224,22 +234,25 @@ const char *GetHelpPage(const char *Cmd)
cSVDRP::cSVDRP(int Port)
:socket(Port)
{
+ message = NULL;
+ lastActivity = 0;
isyslog(LOG_INFO, "SVDRP listening on port %d", Port);
}
cSVDRP::~cSVDRP()
{
Close();
+ delete message;
}
-void cSVDRP::Close(void)
+void cSVDRP::Close(bool Timeout)
{
if (file.IsOpen()) {
//TODO how can we get the *full* hostname?
char buffer[MAXCMDBUFFER];
gethostname(buffer, sizeof(buffer));
- Reply(221, "%s closing connection", buffer);
- isyslog(LOG_INFO, "closing connection"); //TODO store IP#???
+ Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : "");
+ isyslog(LOG_INFO, "closing SVDRP connection"); //TODO store IP#???
file.Close();
}
}
@@ -557,6 +570,20 @@ void cSVDRP::CmdLSTT(const char *Option)
}
}
+void cSVDRP::CmdMESG(const char *Option)
+{
+ if (*Option) {
+ delete message;
+ message = strdup(Option);
+ isyslog(LOG_INFO, "SVDRP message: '%s'", message);
+ Reply(250, "Message stored");
+ }
+ else if (message)
+ Reply(250, "%s", message);
+ else
+ Reply(550, "No pending message");
+}
+
void cSVDRP::CmdMODC(const char *Option)
{
if (*Option) {
@@ -820,6 +847,7 @@ void cSVDRP::Execute(char *Cmd)
else if (CMD("HITK")) CmdHITK(s);
else if (CMD("LSTC")) CmdLSTC(s);
else if (CMD("LSTT")) CmdLSTT(s);
+ else if (CMD("MESG")) CmdMESG(s);
else if (CMD("MODC")) CmdMODC(s);
else if (CMD("MODT")) CmdMODT(s);
else if (CMD("MOVC")) CmdMOVC(s);
@@ -839,7 +867,8 @@ void cSVDRP::Execute(char *Cmd)
void cSVDRP::Process(void)
{
- bool SendGreeting = !file.IsOpen();
+ bool NewConnection = !file.IsOpen();
+ bool SendGreeting = NewConnection;
if (file.IsOpen() || file.Open(socket.Accept())) {
char buffer[MAXCMDBUFFER];
@@ -849,6 +878,8 @@ void cSVDRP::Process(void)
time_t now = time(NULL);
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now));
}
+ if (NewConnection)
+ lastActivity = time(NULL);
int rbytes = file.ReadString(buffer, sizeof(buffer) - 1);
if (rbytes > 0) {
//XXX overflow check???
@@ -859,11 +890,22 @@ void cSVDRP::Process(void)
buffer[rbytes] = 0;
// showtime!
Execute(buffer);
+ lastActivity = time(NULL);
}
else if (rbytes < 0)
Close();
+ else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) {
+ isyslog(LOG_INFO, "timeout on SVDRP connection");
+ Close(true);
+ }
}
}
-//TODO timeout???
+char *cSVDRP::GetMessage(void)
+{
+ char *s = message;
+ message = NULL;
+ return s;
+}
+
//TODO more than one connection???
diff --git a/svdrp.h b/svdrp.h
index 12eb11e..62c1e75 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: svdrp.h 1.6 2000/09/17 13:22:04 kls Exp $
+ * $Id: svdrp.h 1.7 2001/02/18 13:36:47 kls Exp $
*/
#ifndef __SVDRP_H
@@ -31,7 +31,9 @@ private:
cSocket socket;
cFile file;
CRect ovlClipRects[MAXCLIPRECTS];
- void Close(void);
+ char *message;
+ time_t lastActivity;
+ void Close(bool Timeout = false);
bool Send(const char *s, int length = -1);
void Reply(int Code, const char *fmt, ...);
void CmdCHAN(const char *Option);
@@ -42,6 +44,7 @@ private:
void CmdHITK(const char *Option);
void CmdLSTC(const char *Option);
void CmdLSTT(const char *Option);
+ void CmdMESG(const char *Option);
void CmdMODC(const char *Option);
void CmdMODT(const char *Option);
void CmdMOVC(const char *Option);
@@ -59,6 +62,7 @@ public:
cSVDRP(int Port);
~cSVDRP();
void Process(void);
+ char *GetMessage(void);
};
#endif //__SVDRP_H
diff --git a/svdrpsend.pl b/svdrpsend.pl
new file mode 100755
index 0000000..5efd504
--- /dev/null
+++ b/svdrpsend.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+
+use Socket;
+use Getopt::Std;
+
+$Usage = qq{
+Usage: $0 options command...
+
+Options: -d hostname destination hostname (default: localhost)
+ -p port SVDRP port number (default: 2001)
+};
+
+die $Usage if (!$ARGV[0] || !getopts("d:p:"));
+
+$Dest = $opt_d || "localhost";
+$Port = $opt_p || 2001;
+$Cmd = "@ARGV" || Error("missing command");
+
+$Timeout = 10; # max. seconds to wait for response
+
+$SIG{ALRM} = sub { Error("timeout"); };
+alarm($Timeout);
+
+$iaddr = inet_aton($Dest) || Error("no host: $Dest");
+$paddr = sockaddr_in($Port, $iaddr);
+
+$proto = getprotobyname('tcp');
+socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!");
+connect(SOCK, $paddr) || Error("connect: $!");
+select(SOCK); $| = 1;
+Receive();
+Send($Cmd);
+Send("quit");
+close(SOCK) || Error("close: $!");
+
+sub Send
+{
+ my $cmd = shift || Error("no command to send");
+ print SOCK "$cmd\r\n";
+ Receive();
+}
+
+sub Receive
+{
+ while (<SOCK>) {
+ print STDOUT $_;
+ last if substr($_, 3, 1) ne "-";
+ }
+}
+
+sub Error
+{
+ print STDERR "@_\n";
+ close(SOCK);
+ exit 0;
+}
+
diff --git a/tools.c b/tools.c
index cd2c60f..a3b27e5 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.27 2001/01/13 15:35:02 kls Exp $
+ * $Id: tools.c 1.30 2001/02/11 14:44:22 kls Exp $
*/
#define _GNU_SOURCE
@@ -51,7 +51,7 @@ char *strreplace(char *s, char c1, char c2)
{
char *p = s;
- while (*p) {
+ while (p && *p) {
if (*p == c1)
*p = c2;
p++;
@@ -237,8 +237,10 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
}
}
dsyslog(LOG_INFO, "removing %s", FileName);
- if (remove(FileName) == 0)
- return true;
+ if (remove(FileName) < 0) {
+ LOG_ERROR_STR(FileName);
+ return false;
+ }
}
else if (errno != ENOENT) {
LOG_ERROR_STR(FileName);
@@ -247,6 +249,48 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
return true;
}
+bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
+{
+ DIR *d = opendir(DirName);
+ if (d) {
+ bool empty = true;
+ struct dirent *e;
+ while ((e = readdir(d)) != NULL) {
+ if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..") && strcmp(e->d_name, "lost+found")) {
+ char *buffer;
+ asprintf(&buffer, "%s/%s", DirName, e->d_name);
+ struct stat st;
+ if (stat(buffer, &st) == 0) {
+ if (S_ISDIR(st.st_mode)) {
+ if (!RemoveEmptyDirectories(buffer, true))
+ empty = false;
+ }
+ else
+ empty = false;
+ }
+ else {
+ LOG_ERROR_STR(buffer);
+ delete buffer;
+ return false;
+ }
+ delete buffer;
+ }
+ }
+ closedir(d);
+ if (RemoveThis && empty) {
+ dsyslog(LOG_INFO, "removing %s", DirName);
+ if (remove(DirName) < 0) {
+ LOG_ERROR_STR(DirName);
+ return false;
+ }
+ }
+ return empty;
+ }
+ else
+ LOG_ERROR_STR(DirName);
+ return false;
+}
+
char *ReadLink(const char *FileName)
{
char RealName[_POSIX_PATH_MAX];
diff --git a/tools.h b/tools.h
index 539dba0..96d0982 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.h 1.23 2001/01/13 15:36:00 kls Exp $
+ * $Id: tools.h 1.24 2001/02/11 13:39:40 kls Exp $
*/
#ifndef __TOOLS_H
@@ -48,6 +48,7 @@ uint FreeDiskSpaceMB(const char *Directory);
bool DirectoryOk(const char *DirName, bool LogErrors = false);
bool MakeDirs(const char *FileName, bool IsDirectory = false);
bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);
+bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false);
char *ReadLink(const char *FileName);
class cFile {
diff --git a/vdr.c b/vdr.c
index 698cc7a..938afcf 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
- * $Id: vdr.c 1.49 2001/01/14 15:29:51 kls Exp $
+ * $Id: vdr.c 1.54 2001/02/24 16:18:43 kls Exp $
*/
#include <getopt.h>
@@ -44,6 +44,8 @@
#define KEYS_CONF "keys.conf"
#endif
+#define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
+
static int Interrupted = 0;
static void SignalHandler(int signum)
@@ -53,48 +55,76 @@ static void SignalHandler(int signum)
signal(signum, SignalHandler);
}
+static void Watchdog(int signum)
+{
+ // Something terrible must have happened that prevented the 'alarm()' from
+ // being called in time, so let's get out of here:
+ esyslog(LOG_ERR, "PANIC: watchdog timer expired - exiting!");
+ exit(1);
+}
+
int main(int argc, char *argv[])
{
// Command line options:
#define DEFAULTSVDRPPORT 2001
+#define DEFAULTWATCHDOG 0 // seconds
int SVDRPport = DEFAULTSVDRPPORT;
const char *ConfigDirectory = NULL;
bool DaemonMode = false;
+ int WatchdogTimeout = DEFAULTWATCHDOG;
static struct option long_options[] = {
- { "config", required_argument, NULL, 'c' },
- { "daemon", no_argument, NULL, 'd' },
- { "help", no_argument, NULL, 'h' },
- { "log", required_argument, NULL, 'l' },
- { "port", required_argument, NULL, 'p' },
- { "video", required_argument, NULL, 'v' },
+ { "config", required_argument, NULL, 'c' },
+ { "daemon", no_argument, NULL, 'd' },
+ { "device", required_argument, NULL, 'D' },
+ { "help", no_argument, NULL, 'h' },
+ { "log", required_argument, NULL, 'l' },
+ { "port", required_argument, NULL, 'p' },
+ { "video", required_argument, NULL, 'v' },
+ { "watchdog", required_argument, NULL, 'w' },
{ 0 }
};
int c;
int option_index = 0;
- while ((c = getopt_long(argc, argv, "c:dhl:p:v:", long_options, &option_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:", long_options, &option_index)) != -1) {
switch (c) {
case 'c': ConfigDirectory = optarg;
break;
case 'd': DaemonMode = true; break;
+ case 'D': if (isnumber(optarg)) {
+ int n = atoi(optarg);
+ if (0 <= n && n < MAXDVBAPI) {
+ cDvbApi::SetUseDvbApi(n);
+ break;
+ }
+ }
+ fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg);
+ abort();
+ break;
case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80|
- " -c DIR, --config=DIR read config files from DIR (default is to read them\n"
- " from the video directory)\n"
- " -h, --help display this help and exit\n"
- " -d, --daemon run in daemon mode\n"
- " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
- " 0 = no logging, 1 = errors only,\n"
- " 2 = errors and info, 3 = errors, info and debug\n"
- " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
- " 0 turns off SVDRP\n"
- " -v DIR, --video=DIR use DIR as video directory (default is %s)\n"
+ " -c DIR, --config=DIR read config files from DIR (default is to read them\n"
+ " from the video directory)\n"
+ " -h, --help display this help and exit\n"
+ " -d, --daemon run in daemon mode\n"
+ " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
+ " there may be several -D options (default: all DVB\n"
+ " devices will be used)\n"
+ " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
+ " 0 = no logging, 1 = errors only,\n"
+ " 2 = errors and info, 3 = errors, info and debug\n"
+ " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
+ " 0 turns off SVDRP\n"
+ " -v DIR, --video=DIR use DIR as video directory (default is %s)\n"
+ " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
+ " seconds (default: %d); '0' disables the watchdog\n"
"\n"
"Report bugs to <vdr-bugs@cadsoft.de>\n",
DEFAULTSVDRPPORT,
- VideoDirectory
+ VideoDirectory,
+ DEFAULTWATCHDOG
);
return 0;
break;
@@ -119,6 +149,16 @@ int main(int argc, char *argv[])
while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/')
optarg[strlen(optarg) - 1] = 0;
break;
+ case 'w': if (isnumber(optarg)) {
+ int t = atoi(optarg);
+ if (t >= 0) {
+ WatchdogTimeout = t;
+ break;
+ }
+ }
+ fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg);
+ abort();
+ break;
default: abort();
}
}
@@ -166,9 +206,9 @@ int main(int argc, char *argv[])
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"));
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
-#ifdef REMOTE_LIRC
+#if defined(REMOTE_LIRC)
Keys.SetDummyValues();
-#else
+#elif !defined(REMOTE_NONE)
bool KeysLoaded = Keys.Load(AddDirectory(ConfigDirectory, KEYS_CONF));
#endif
@@ -186,7 +226,7 @@ int main(int argc, char *argv[])
// User interface:
Interface = new cInterface(SVDRPport);
-#ifndef REMOTE_LIRC
+#if !defined(REMOTE_LIRC) && !defined(REMOTE_NONE)
if (!KeysLoaded)
Interface->LearnKeys();
#endif
@@ -197,6 +237,8 @@ int main(int argc, char *argv[])
if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN);
if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN);
+ if (WatchdogTimeout > 0)
+ if (signal(SIGALRM, Watchdog) == SIG_IGN) signal(SIGALRM, SIG_IGN);
// Main program loop:
@@ -204,8 +246,23 @@ int main(int argc, char *argv[])
cReplayControl *ReplayControl = NULL;
int LastChannel = -1;
int PreviousChannel = cDvbApi::CurrentChannel();
+ time_t LastActivity = time(NULL);
+ int MaxLatencyTime = 0;
+
+ if (WatchdogTimeout > 0) {
+ dsyslog(LOG_INFO, "setting watchdog timer to %d seconds", WatchdogTimeout);
+ alarm(WatchdogTimeout); // Initial watchdog timer start
+ }
while (!Interrupted) {
+ // Restart the Watchdog timer:
+ if (WatchdogTimeout > 0) {
+ int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout);
+ if (LatencyTime > MaxLatencyTime) {
+ MaxLatencyTime = LatencyTime;
+ dsyslog(LOG_INFO, "max. latency time %d seconds", MaxLatencyTime);
+ }
+ }
// Channel display:
if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) {
if (!Menu)
@@ -310,6 +367,14 @@ int main(int argc, char *argv[])
EITScanner.Process();
cVideoCutter::Active();
}
+ if (!*Interact && !cRecordControls::Active()) {
+ if (time(NULL) - LastActivity > ACTIVITYTIMEOUT) {
+ RemoveDeletedRecordings();
+ LastActivity = time(NULL);
+ }
+ }
+ else
+ LastActivity = time(NULL);
}
isyslog(LOG_INFO, "caught signal %d", Interrupted);
Setup.CurrentChannel = cDvbApi::CurrentChannel();
@@ -319,6 +384,8 @@ int main(int argc, char *argv[])
delete ReplayControl;
delete Interface;
cDvbApi::Cleanup();
+ if (WatchdogTimeout > 0)
+ dsyslog(LOG_INFO, "max. latency time %d seconds", MaxLatencyTime);
isyslog(LOG_INFO, "exiting");
if (SysLogLevel > 0)
closelog();
diff --git a/videodir.c b/videodir.c
index 4d5c257..2824d04 100644
--- a/videodir.c
+++ b/videodir.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: videodir.c 1.3 2000/12/24 12:51:41 kls Exp $
+ * $Id: videodir.c 1.4 2001/02/11 13:48:30 kls Exp $
*/
#include "videodir.h"
@@ -28,7 +28,7 @@ public:
cVideoDirectory(void);
~cVideoDirectory();
uint FreeMB(void);
- const char *Name(void) { return name; }
+ const char *Name(void) { return name ? name : VideoDirectory; }
const char *Stored(void) { return stored; }
int Length(void) { return length; }
bool IsDistributed(void) { return name != NULL; }
@@ -197,3 +197,11 @@ const char *PrefixVideoFileName(const char *FileName, char Prefix)
return PrefixedName;
}
+void RemoveEmptyVideoDirectories(void)
+{
+ cVideoDirectory Dir;
+ do {
+ RemoveEmptyDirectories(Dir.Name());
+ } while (Dir.Next());
+}
+
diff --git a/videodir.h b/videodir.h
index 0716a28..0197de3 100644
--- a/videodir.h
+++ b/videodir.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: videodir.h 1.2 2000/12/24 12:41:10 kls Exp $
+ * $Id: videodir.h 1.3 2001/02/11 13:12:50 kls Exp $
*/
#ifndef __VIDEODIR_H
@@ -18,5 +18,6 @@ bool RenameVideoFile(const char *OldName, const char *NewName);
bool RemoveVideoFile(const char *FileName);
bool VideoFileSpaceAvailable(unsigned int SizeMB);
const char *PrefixVideoFileName(const char *FileName, char Prefix);
+void RemoveEmptyVideoDirectories(void);
#endif //__VIDEODIR_H