diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-04-01 18:00:00 +0200 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-04-01 18:00:00 +0200 |
commit | 610c5600df98b35226536ffe92b1fd231128c7d4 (patch) | |
tree | f0df8ce83dd3e4829be7def61126871f425e2f23 | |
parent | f2937af95ceaf3a52c327e96571367ef5475b3a1 (diff) | |
download | vdr-patch-lnbsharing-610c5600df98b35226536ffe92b1fd231128c7d4.tar.gz vdr-patch-lnbsharing-610c5600df98b35226536ffe92b1fd231128c7d4.tar.bz2 |
Version 0.72vdr-0.72
- Fixed SVDRP commands LSTC and LSTT to make them return an error message if
no channels or timers are defined.
- Enhanced 'channels.conf.cable' (thanks to Hans-Peter Raschke).
- Fixed switching to another channel via the EPG while a recording is being
replayed.
- Fixed a memory leak in the EIT processor that happened when the system time
was set.
- Removed some redundant code from the cListBase destructor.
- Fixed internationalization of some Main menu texts.
- Updated 'channels.conf' after the recent changes of Premiere World (thanks
to Axel Gruber).
- Redesigned the ring buffer to make it work with two separate threads for
input and output (also prepared for using a remultiplexer).
- Fixed setting system time from transponders.
- Fixed a segfault in the Schedule menu in case there is no EPG information.
- The 'runvdr' script now kills any leftover vdr threads before restarting it.
- Fixed a problem with Daylight Saving Time when displaying the times of
recordings.
- Added Dutch language texts (thanks to Arnold Niessen).
- The new command line option -t can be used to set the controlling terminal
(thanks to Jürgen Sauer). This is especially useful when starting VDR through
an entry in /etc/inittab (see INSTALL).
- Since the CAM module only works if it is installed in the "highest" DVB card,
recordings now search for a free DVB card from lowest to highest index (as
opposed to the previous "highest to lowest" search) in order to not use the
CAM card for FTA recordings unless necessary. This is only important for
systems with three or more DVB cards.
- Added the "statdvb2vdr" tool from Hans-Peter Raschke.
- Fixed a segfault that sometimes happened when killing VDR.
- VDR now returns an exit status of '2' in case of an error at startup, instead
of terminating with 'abort()' (which caused a core dump).
- SVDRP now also works with clients that don't do line buffering (like the
Windows 'telnet').
- Empty lines in config files no longer cause error messages.
- New SVDRP command LSTE to list the EPG data.
- The SVDRP HELP command now prints the topics in several columns.
-rw-r--r-- | CONTRIBUTORS | 10 | ||||
-rw-r--r-- | HISTORY | 39 | ||||
-rw-r--r-- | INSTALL | 5 | ||||
-rw-r--r-- | Makefile | 41 | ||||
-rw-r--r-- | Tools/statdvb2vdr/ch.pl | 250 | ||||
-rw-r--r-- | channels.conf | 63 | ||||
-rw-r--r-- | channels.conf.cable | 301 | ||||
-rw-r--r-- | config.c | 66 | ||||
-rw-r--r-- | config.h | 22 | ||||
-rw-r--r-- | dvbapi.c | 321 | ||||
-rw-r--r-- | eit.c | 1452 | ||||
-rw-r--r-- | eit.h | 17 | ||||
-rw-r--r-- | i18n.c | 143 | ||||
-rw-r--r-- | menu.c | 42 | ||||
-rw-r--r-- | recording.c | 3 | ||||
-rw-r--r-- | remux.c | 173 | ||||
-rw-r--r-- | remux.h | 51 | ||||
-rw-r--r-- | ringbuffer.c | 170 | ||||
-rw-r--r-- | ringbuffer.h | 55 | ||||
-rwxr-xr-x | runvdr | 13 | ||||
-rw-r--r-- | svdrp.c | 114 | ||||
-rw-r--r-- | svdrp.h | 7 | ||||
-rw-r--r-- | tools.c | 28 | ||||
-rw-r--r-- | tools.h | 3 | ||||
-rw-r--r-- | vdr.c | 36 |
25 files changed, 2151 insertions, 1274 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7a93b33..8a67f37 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -57,6 +57,16 @@ Dave Chapman <dave@dchapman.com> Hans-Peter Raschke <Hans-Peter.Raschke@Wintermann-DatenService.de> for his support in adapting VDR to DVB-C + for adding the 'statdvb2vdr' tool (see Tools/statdvb2vdr) Peter Hofmann <software@pxh.de> for his support in adapting VDR to DVB-C + +Axel Gruber <axel@agm.de> + for his support in keeping the Premiere World channels up to date in 'channels.conf' + +Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com> + for translating the OSD texts to the Dutch language + +Jürgen Sauer <jojo@automatix.de> + for implementing the -t option to set the controlling terminal @@ -413,3 +413,42 @@ Video Disk Recorder Revision History 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. + +2001-04-01: Version 0.72 + +- Fixed SVDRP commands LSTC and LSTT to make them return an error message if + no channels or timers are defined. +- Enhanced 'channels.conf.cable' (thanks to Hans-Peter Raschke). +- Fixed switching to another channel via the EPG while a recording is being + replayed. +- Fixed a memory leak in the EIT processor that happened when the system time + was set. +- Removed some redundant code from the cListBase destructor. +- Fixed internationalization of some Main menu texts. +- Updated 'channels.conf' after the recent changes of Premiere World (thanks + to Axel Gruber). +- Redesigned the ring buffer to make it work with two separate threads for + input and output (also prepared for using a remultiplexer). +- Fixed setting system time from transponders. +- Fixed a segfault in the Schedule menu in case there is no EPG information. +- The 'runvdr' script now kills any leftover vdr threads before restarting it. +- Fixed a problem with Daylight Saving Time when displaying the times of + recordings. +- Added Dutch language texts (thanks to Arnold Niessen). +- The new command line option -t can be used to set the controlling terminal + (thanks to Jürgen Sauer). This is especially useful when starting VDR through + an entry in /etc/inittab (see INSTALL). +- Since the CAM module only works if it is installed in the "highest" DVB card, + recordings now search for a free DVB card from lowest to highest index (as + opposed to the previous "highest to lowest" search) in order to not use the + CAM card for FTA recordings unless necessary. This is only important for + systems with three or more DVB cards. +- Added the "statdvb2vdr" tool from Hans-Peter Raschke. +- Fixed a segfault that sometimes happened when killing VDR. +- VDR now returns an exit status of '2' in case of an error at startup, instead + of terminating with 'abort()' (which caused a core dump). +- SVDRP now also works with clients that don't do line buffering (like the + Windows 'telnet'). +- Empty lines in config files no longer cause error messages. +- New SVDRP command LSTE to list the EPG data. +- The SVDRP HELP command now prints the topics in several columns. @@ -71,6 +71,11 @@ 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. +When starting the program through an entry in /etc/inittab, use the --terminal +option to set the controlling terminal, as in + +vdr:123:respawn:/usr/local/bin/vdr --terminal=/dev/tty8 -w 60 + Automatic restart in case of hangups: ------------------------------------- @@ -4,13 +4,14 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.20 2001/02/24 15:52:58 kls Exp $ +# $Id: Makefile 1.21 2001/03/11 11:36:15 kls Exp $ DVBDIR = ../DVB INCLUDES = -I$(DVBDIR)/driver OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\ - recording.o remote.o svdrp.o thread.o tools.o vdr.o videodir.o + recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o tools.o vdr.o\ + videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1 @@ -37,26 +38,28 @@ font: genfontfile fontfix.c fontosd.c # Implicit rules: %.o: %.c - g++ -g -O2 -Wall -m486 -c $(DEFINES) $(INCLUDES) $< + g++ -g -O2 -Wall -Woverloaded-virtual -m486 -c $(DEFINES) $(INCLUDES) $< # Dependencies: -config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -dvbosd.o : dvbosd.c dvbosd.h font.h tools.h -eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h -font.o : font.c font.h fontfix.c fontosd.c tools.h -i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h -interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h -osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h -recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h -svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h -thread.o : thread.c thread.h tools.h -tools.o : tools.c tools.h -vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -videodir.o : videodir.c tools.h videodir.h +config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h remux.h ringbuffer.h svdrp.h thread.h tools.h videodir.h +dvbosd.o : dvbosd.c dvbosd.h font.h tools.h +eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h +font.o : font.c font.h fontfix.c fontosd.c tools.h +i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h +interface.o : interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h +menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h +osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h +recording.o : recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h +remux.o : remux.c remux.h tools.h +ringbuffer.o: ringbuffer.c ringbuffer.h thread.h tools.h +svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h +thread.o : thread.c thread.h tools.h +tools.o : tools.c tools.h +vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +videodir.o : videodir.c tools.h videodir.h # The main program: diff --git a/Tools/statdvb2vdr/ch.pl b/Tools/statdvb2vdr/ch.pl new file mode 100644 index 0000000..91e918d --- /dev/null +++ b/Tools/statdvb2vdr/ch.pl @@ -0,0 +1,250 @@ +#!/usr/bin/perl + +# Reads the file statdvb.dat produced by the Siemens windows +# software (1.50), which contains the scanned channels of an +# DVB-C (-S). The file ist located in the windows directory. +# +# Output is suitable for VDR (channels.conf). Only tested for +# the cable version. Should work with slight modifications for +# the sat version. +# +# 8. März 2001 - Hans-Peter Raschke + + +# file structure derived from "DvbGlobalDef.h" of the Siemens +# DVB kit. + +# typedef int TABLETYPE; +# enum TunStandard +# { +# PAL_BG, //B/G stereo or mono +# PAL_I, //I mono (with Nicam stereo) +# PAL_DK, //D/K mono +# SECAM_L, //L mono (with Nicam stereo) +# SECAM_LI, //Secam L’ (with Nicam stereo) +# SECAM_DK, +# SECAM_BG, +# NTSC_M, +# DVB_C, +# DVB_S, +# DVB_T +# }; +# +# typedef struct TunProgDataTag //xx bytes+1string +# { +# int nNumber; //logical number of the program +# DWORD dwFrequency; //frequency in khz +# CString csName; //name of the program +# TunStandard eStandard; //standard of the program +# DWORD dwExtraInfo; //specific info, like teletext,reserved data +# //0x8 == external input 1-CVBS +# //0x10 == external input 2-Y/C +# //0x20 == scrambled Program stream +# //0x40 == ASTRA Sattable +# //0x80 == Eutelsat Sattable +# //0xC0 == Sattable from File +# //0x100 == Pulsed switch to other satellite dish +# //0x1000-0xF000 = Other Satellite Nr(if Sattable from File) +# //Digital only params beginning from here +# WORD ProgNr; //DVB Nr for the prog (PAS related) +# WORD wTS_ID; //Transport-Stream ID orig. +# WORD wNW_ID; //Network ID orig. +# WORD wService_ID; //Service /Programm Id +# BYTE nModulation; //Modulation-Type QAM,QPSK,other +# BYTE nFEC_outerinner; //outer(high nibble) and inner(low n.) +# DWORD dwSymbolrate; //in symbol/s +# BOOL b22kHz; //east or west(TRUE) position in Sat +# BOOL bVertical_pos; //horizontal or vertical(TRUE) position in SAT +# BYTE nProgtype; //type of service (e.g. tv, radio) +# WORD wVideo_PID; //video-pid of the channel +# WORD wAudio_PID; //audio-pid of the channel +# WORD wPMT_PID; //PID of the associated PMT +# WORD wTxt_PID; //teletext PID for the program +# WORD wSubtitling_PID; //subtitling PID for the program +# WORD wData_PID; //PID for data broadcast +# BYTE nIPFilter; //filter for different ip's +# DWORD dwReserved1; //Shows some extended Information LOWORD=DataBroadcast_Id, +# //MSB showing Databroadcast, (HIWORD & 0xFF)=ComponentTag from the stream ident desc +# DWORD dwReserved2; //reserved dword +# }DVBTunProgData; +# + +use strict; +use FileHandle; + +# for a full dump +my @varNames = ("nNumber", # logical number of the program + "dwFrequency", # frequency in khz + "csName", # name of the program + "eStandard", # standard of the program + "dwExtraInfo", # specific info, like teletext,reserved data + # 0x8 == external input 1-CVBS + # 0x10 == external input 2-Y/C + # 0x20 == scrambled Program stream + # 0x40 == ASTRA Sattable + # 0x80 == Eutelsat Sattable + # 0xC0 == Sattable from File + # 0x100 == Pulsed switch to other satellite dish + # 0x1000-0xF000 = Other Satellite Nr(if Sattable from File) + "ProgNr", # DVB Nr for the prog (PAS related) + "wTS_ID", # Transport-Stream ID orig. + "wNW_ID", # Network ID orig. + "wService_ID", # Service /Programm Id + "nModulation", # Modulation-Type QAM,QPSK,other + "nFEC_outerinner", # outer(high nibble) and inner(low n.) + "dwSymbolrate", # in symbol/s + "b22kHz", # east or west(TRUE) position in Sat + "bVertical_pos", # horizontal or vertical(TRUE) position in SAT + "nProgtype", # type of service (e.g. tv, radio) + "wVideo_PID", # video-pid of the channel + "wAudio_PID", # audio-pid of the channel + "wPMT_PID", # PID of the associated PMT + "wTxt_PID", # teletext PID for the program + "wSubtitling_PID", # subtitling PID for the program + "wData_PID"); # PID for data broadcast + +my @outVar = ("csName", + "dwFrequency", + "bVertical_pos", + "b22kHz", + "dwSymbolrate", + "wVideo_PID", + "wAudio_PID", + "wTxt_PID", + "dwExtraInfo", + "ProgNr"); + +# channels that need a valid smartcard +my @addCrypted = ("Extreme Sport", + "Bloomberg", + "Fashion TV", + "BET ON JAZZ", + "LANDSCAPE", + "Einstein", + "Single TV"); + +my @chNames = (); # list of scanned channels +my $camNo = 1; # number of CI/CAM to use +my %chData; # all channel data +my $buff; # input buffer +my $fh = new FileHandle("$ARGV[0]") or die "Datei $ARGV[0] nicht gefunden!"; + +binmode($fh); # could be run on windows +$fh->seek(4, 0); # skip id + +my $chCnt = 0; +while (!$fh->eof()) { + $chCnt++; + + last if ($fh->read($buff, 7) != 7); + my ($nNumber, + $dwFrequency, + $sLen + ) = unpack("SLC", $buff); + + last if ($fh->read($buff, $sLen) != $sLen); + my ($csName) = unpack("A$sLen", $buff); + $csName =~ s/:/./g; + $csName =~ s/^\s+//; + $csName =~ s/\s+$//; + + last if ($fh->read($buff, 54) != 54); + my ($eStandard, + $dwExtraInfo, + $ProgNr, + $wTS_ID, + $wNW_ID, + $wService_ID, + $nModulation, + $nFEC_outerinner, + $dwSymbolrate, + $b22kHz, + $bVertical_pos, + $nProgtype, + $wVideo_PID, + $wAudio_PID, + $wPMT_PID, + $wTxt_PID, + $wSubtitling_PID, + $wData_PID + ) = unpack("LLSSSSCCLLLCSSSSSS", $buff); + + # some modifications for VDR + $dwFrequency /= 1000; + $bVertical_pos = $bVertical_pos ? "v" : "h"; + $dwSymbolrate /= 1000; + $dwExtraInfo = ($dwExtraInfo == 32 || grep(($_ cmp $csName) == 0, @addCrypted)) ? $camNo : 0; + + my $x = 1; + my $orgName = $csName; + while (exists($chData{$csName})) { + $csName = "$orgName" . "_$x"; + $x++; + } + push(@chNames, $csName); + + my %tmp = ("nNumber" => $nNumber, + "dwFrequency" => $dwFrequency, + "csName" => $orgName, + "eStandard" => $eStandard, + "dwExtraInfo" => $dwExtraInfo, + "ProgNr" => $ProgNr, + "wTS_ID" => $wTS_ID, + "wNW_ID" => $wNW_ID, + "wService_ID" => $wService_ID, + "nModulation" => $nModulation, + "nFEC_outerinner" => $nFEC_outerinner, + "dwSymbolrate" => $dwSymbolrate, + "b22kHz" => $b22kHz, + "bVertical_pos" => $bVertical_pos, + "nProgtype" => $nProgtype, + "wVideo_PID" => $wVideo_PID, + "wAudio_PID" => $wAudio_PID, + "wPMT_PID" => $wPMT_PID, + "wTxt_PID" => $wTxt_PID, + "wSubtitling_PID" => $wSubtitling_PID, + "wData_PID" => $wData_PID); + $chData{$csName} = {%tmp}; +} + +print STDERR "$chCnt channels found!\n"; + +# now we print the channels.conf +# crypted TV +print ":verschlüsselte Fernsehprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 1 && $tmp{"dwExtraInfo"}); +} + +# TV +print ":Fernsehprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 1 && !$tmp{"dwExtraInfo"}); +} + +# crypted radio +print ":verschlüsselte Radioprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 2 && $tmp{"dwExtraInfo"}); +} + +# radio +print ":Radioprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 2 && !$tmp{"dwExtraInfo"}); +} + +sub printChannel { + my $p = shift; + my @tmp = (); + + for my $n (@outVar) { + push(@tmp, ${$p}{$n}); + } + + print join(":", @tmp), "\n"; +} diff --git a/channels.conf b/channels.conf index 4947f82..36b5b28 100644 --- a/channels.conf +++ b/channels.conf @@ -1,4 +1,4 @@ -RTL:12188:h:0:27500:163:104:32:0:12003 +RTL:12188:h:0:27500:163:104:105: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 @@ -54,53 +54,54 @@ 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 +Romantic Movies:11797:h:0:27500:1791:1792:0:3:11 +Studio Universal:12090:v:0:27500:255:256:0:3:36 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 +Disney Channel:12090:v:0:27500:767:768:0:3:34 +Fox Kids:11797:h:0:27500:2559:2560:0:3:22 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 +Planet:12090:v:0:27500:1279:1280: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 +Filmpalast:11758:h:0:27500:2559:2560:0:3:516 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 +Classica:12031:h:0:27500:767:768:0:3:15 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 +Sport 1:11720:h:0:27500:255:256:0:3:17 +Sport 2:12070:h:0:27500:2047:2048:0:3:27 +Sport 3:12070:h:0:27500:2303:2304:0:3:18 +Sport 4:12070:h:0:27500:2559:2560:0:3:24 +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 +Cinedom Deluxe:12070:h:0:27500:1279:1280:0:3:188 +Cinedom 1A de:11758:h:0:27500:511:512:0:3:178 +Cinedom 1A en:11758:h:0:27500:511:513:0:3:178 +Cinedom 1B:12070:h:0:27500:767:768:0:3:185 +Cinedom 1C:12070:h:0:27500:1791:1792:0:3:191 +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 2B:11758:h:0:27500:767:768:0:3:179 +Cinedom 2C:11758:h:0:27500:1023:1024:0:3:193 +Cinedom 2D??:12070:h:0:27500:511:512:0:3:184 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 3C??:12090:v:0:27500:1279:1280:17689:3:192 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 +Cinedom 4B:12070:h:0:27500:1023:1025:0:3:186 +Cinedom 4C??:11720:h:0:27500:767:768:0:3:181 +Cinedom 5A:12032:h:0:27500:2559:2560:0:3:187 +Beate Uhse_TV:11797:h:0:27500:2047:2048:0:3:21 +Blue Channel:11758:h:0:27500:2559:2560:0:3:516 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:0:20601 Mosaico:11934:v:0:27500:165:100:0:0:29010 diff --git a/channels.conf.cable b/channels.conf.cable index 93fc376..c60fb8f 100644 --- a/channels.conf.cable +++ b/channels.conf.cable @@ -1,134 +1,167 @@ -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 +:verschlüsselte Fernsehprogramme +Extreme Sport:346:h:0:6900:801:802:0:1:50700 +Bloomberg:346:h:0:6900:811:812:0:1:50701 +Fashion TV:346:h:0:6900:821:822:0:1:50702 +BET ON JAZZ:346:h:0:6900:841:842:0:1:50704 +LANDSCAPE:346:h:0:6900:831:832:0:1:50703 +Einstein:346:h:0:6900:623:624:0:1:50719 +Single TV:346:h:0:6900:621:622:0:1:50706 +Einstein:346:h:0:6900:255:256:0:1:40100 +GOLDSTAR TV:354:h:0:6900:3839:3840:0:1:518 +HEIMATKANAL:354:h:0:6900:2815:2816:0:1:517 +FILMPALAST:354:h:0:6900:2559:2560:0:1:516 +FILMPALAST:354:h:0:6900:1535:1536:0:1:195 +FILMPALAST:354:h:0:6900:1279:1280:0:1:194 +FILMPALAST:354:h:0:6900:255:256:0:1:177 +FILMPALAST:354:h:0:6900:767:768:0:1:179 +FILMPALAST:354:h:0:6900:511:513:0:1:178 +FILMPALAST:354:h:0:6900:1023:1024:0:1:193 +BLUE MOVIE 1:354:h:0:6900:255:256:0:1:513 +BLUE MOVIE 2:354:h:0:6900:255:256:0:1:514 +BLUE MOVIE 3:354:h:0:6900:255:256:0:1:515 +SPORT 1:362:h:0:6900:255:256:0:1:17 +F1 Boxenstrasse:362:h:0:6900:2815:2816:0:1:240 +F1 Cockpit:362:h:0:6900:2559:2560:0:1:242 +F1 Multikanal:362:h:0:6900:2047:2048:0:1:243 +SPORT 1:362:h:0:6900:255:256:0:1:180 +SPORT 1:362:h:0:6900:255:256:0:1:181 +SPORT 1:362:h:0:6900:255:256:0:1:182 +SPORT 1:362:h:0:6900:255:256:0:1:183 +SPORT 1:362:h:0:6900:255:256:0:1:176 +SPORT 1:362:h:0:6900:255:256:0:1:190 +PREMIERE:370:h:0:6900:511:512:0:1:10 +STAR KINO:370:h:0:6900:767:768:0:1:9 +CINE ACTION:370:h:0:6900:1023:1024:0:1:20 +CINE COMEDY:370:h:0:6900:1279:1280:0:1:29 +SCI-FANTASY:370:h:0:6900:1535:1536:0:1:41 +ROMANTIC MOVIES:370:h:0:6900:1791:1792:0:1:11 +BEATE-UHSE.TV:370:h:0:6900:2047:2048:0:1:21 +13 TH STREET:370:h:0:6900:2303:2304:0:1:43 +FOX KIDS:370:h:0:6900:255:256:0:1:22 +SUNSET:378:h:0:6900:1023:1024:0:1:16 +COMEDY:378:h:0:6900:1279:1280:0:1:28 +KRIMI &CO:378:h:0:6900:1535:1536:0:1:23 +DISCOVERY CHANNEL:378:h:0:6900:1791:1792:0:1:14 +CLASSICA:378:h:0:6900:767:768:0:1:15 +SUPERDOM:378:h:0:6900:2303:2304:0:1:42 +K-TOON:378:h:0:6900:511:512:0:1:12 +SUPERDOM:378:h:0:6900:2047:2048:0:1:192 +SUPERDOM:378:h:0:6900:2559:2560:0:1:187 +JUNIOR:378:h:0:6900:255:256:0:1:19 +SUPERDOM 5:378:h:0:6900:2815:2816:0:1:213 +KICK 1:386:h:0:6900:255:257:0:1:26 +KICK 4:386:h:0:6900:1279:1281:0:1:188 +KICK 4:386:h:0:6900:1535:1536:0:1:189 +SPORT 2:386:h:0:6900:2047:2048:0:1:27 +KICK 4:386:h:0:6900:1023:1024:0:1:186 +KICK 2:386:h:0:6900:2559:2560:0:1:300 +KICK 4:386:h:0:6900:767:769:0:1:185 +SPORT 3:386:h:0:6900:2303:2304:0:1:18 +SUPERDOM 3:386:h:0:6900:3583:3584:0:1:211 +SPORT 4:386:h:0:6900:255:256:0:1:24 +KICK 3:386:h:0:6900:255:256:0:1:301 +KICK 4:386:h:0:6900:255:256:0:1:302 +KICK 4:386:h:0:6900:255:256:0:1:184 +KICK 4:386:h:0:6900:255:256:0:1:191 +EuroNews:394:h:0:6900:255:256:0:1:65039 +SEASONS:402:h:0:6900:1040:1044:0:1:33 +DISNEY CHANNEL:402:h:0:6900:1030:1034:0:1:34 +STUDIO UNIVERSAL:402:h:0:6900:1050:1054:0:1:36 +PLANET:402:h:0:6900:1100:1104:0:1:13 +BBC PRIME:402:h:0:6900:255:256:0:1:32 +ATV:402:h:0:6900:255:256:0:1:39 +:Fernsehprogramme +Leitseite:346:h:0:6900:2254:0:0:0:5004 +Via 1 - Schöner Reisen:346:h:0:6900:611:612:0:0:50705 +PREMIERE WORLD:370:h:0:6900:255:256:32:0:8 +ZDF:394:h:0:6900:110:120:130:0:28006 +3sat:394:h:0:6900:210:220:230:0:28007 +KiKa:394:h:0:6900:255:256:0:0:28008 +Eurosport:394:h:0:6900:410:420:430:0:28009 +ZDF.info:394:h:0:6900:610:620:0:0:28011 +EuroNews:394:h:0:6900:2221:2233:768:0:28015 +ZDF Theaterkanal:394:h:0:6900:1110:1120:0:0:28016 +ZDF.doku:394:h:0:6900:660:670:0:0:28014 +Test-R:410:h:0:6900:901:902:104:0:28130 +Bayerisches FS:410:h:0:6900:201:202:204:0:28107 +WDR FERNSEHEN:410:h:0:6900:601:602:604:0:28111 +arte:410:h:0:6900:401:402:404:0:28109 +SR Fernsehen Suedwest:410:h:0:6900:501:502:504:0:28110 +Das Erste:410:h:0:6900:101:102:104:0:28106 +hessen fernsehen:410:h:0:6900:301:302:304:0:28108 +BR-alpha:410:h:0:6900:701:702:704:0:28112 +SWR Fernsehen:410:h:0:6900:801:802:804:0:28113 +Phoenix:410:h:0:6900:255:256:0:0:28114 +Phoenix:410:h:0:6900:255:256:0:0:61225 +ARD-Online-Kanal:426:h:0:6900:0:1801:0:0:28218 +EinsExtra:426:h:0:6900:101:102:0:0:28201 +EinsFestival:426:h:0:6900:201:202:0:0:28202 +EinsMuXx:426:h:0:6900:301:302:0:0:28203 +MDR FERNSEHEN:426:h:0:6900:401:402:404:0:28204 +ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205 +B1 Berlin:426:h:0:6900:601:602:604:0:28206 +N3:426:h:0:6900:2401:2402:2404:0:28224 +TV Polonia:434:h:0:6900:641:642:0:0:53204 +Kanal D:434:h:0:6900:651:652:0:0:53205 +RTP international:434:h:0:6900:661:662:0:0:53206 +ATV:434:h:0:6900:631:632:0:0:53203 +ERT-Sat:434:h:0:6900:691:692:0:0:53209 +CNE:434:h:0:6900:255:256:0:0:53208 +ERT-Sat:434:h:0:6900:255:256:0:0:48587 +ZEE TV:442:h:0:6900:517:773:0:0:53301 +NTV i:442:h:0:6900:514:515:0:0:53302 +:verschlüsselte Radioprogramme +LOVE SONGS:362:h:0:6900:0:320:0:1:163 +MUSICALS:362:h:0:6900:0:336:0:1:164 +EASY LISTENING:362:h:0:6900:0:304:0:1:162 +HITLISTE:362:h:0:6900:0:784:0:1:150 +ALTERNATIVE ROCK:362:h:0:6900:0:800:0:1:151 +DANCE:362:h:0:6900:0:816:0:1:152 +COUNTRY:362:h:0:6900:0:352:0:1:153 +CLASSIC ROCK:362:h:0:6900:0:544:0:1:154 +FILMMUSIK:362:h:0:6900:0:368:0:1:155 +DEUTSCHE HITS:362:h:0:6900:0:384:0:1:156 +SOUL CLASSICS:362:h:0:6900:0:400:0:1:157 +TÜRK MÜZIGI:362:h:0:6900:0:560:0:1:158 +GOLD:362:h:0:6900:0:576:0:1:159 +KLASSIK POPULÄR:362:h:0:6900:0:592:0:1:145 +KLASS. SYMPHONIEN:362:h:0:6900:0:608:0:1:146 +OPER & VOKALMUSIK:362:h:0:6900:0:624:0:1:147 +BAROCKMUSIK:362:h:0:6900:0:640:0:1:148 +SCHLAGER:378:h:0:6900:0:320:0:1:166 +VOLKSMUSIK:378:h:0:6900:0:336:0:1:167 +OLD GOLD:378:h:0:6900:0:304:0:1:165 +:Radioprogramme +100,6:354:h:0:6900:0:1312:0:0:161 +DLR-Berlin:394:h:0:6900:0:710:0:0:28012 +DLF-Köln:394:h:0:6900:0:810:0:0:28013 +Österreich 1:394:h:0:6900:0:169:0:0:28017 +Bayern 4 Klassik:410:h:0:6900:0:3001:0:0:28120 +B5 aktuell:410:h:0:6900:0:3101:0:0:28121 +Bremen 2:410:h:0:6900:0:3801:0:0:28128 +Bayern 1:410:h:0:6900:0:3601:0:0:28126 +NDR 4 Info:410:h:0:6900:0:3701:0:0:28127 +SR 1:410:h:0:6900:0:3901:0:0:28129 +HR2 plus:410:h:0:6900:0:3401:0:0:28124 +HR2:410:h:0:6900:0:3301:0:0:28123 +hr-chronos:410:h:0:6900:0:3201:0:0:28122 +HR XXL:410:h:0:6900:0:3501:0:0:28125 +Radio 3:426:h:0:6900:0:701:0:0:28207 +MDR KULTUR:426:h:0:6900:0:801:0:0:28208 +Fritz:426:h:0:6900:0:901:0:0:28209 +JUMP:426:h:0:6900:0:1001:0:0:28210 +MDR info:426:h:0:6900:0:1101:0:0:28211 +SPUTNIK:426:h:0:6900:0:1201:0:0:28212 +SFB4 Multikulti:426:h:0:6900:0:1301:0:0:28213 +SWR-2:426:h:0:6900:0:1401:0:0:28214 +WDR3:426:h:0:6900:0:1501:0:0:28215 +WDR Radio 5:426:h:0:6900:0:1601:0:0:28216 +All Jazz:442:h:0:6900:0:535:0:0:53350 +Cristal New Age:442:h:0:6900:0:536:0:0:53351 +Movie Sounds:442:h:0:6900:0:537:0:0:53352 +Sinfonica:442:h:0:6900:0:538:0:0:53353 +Opernfestival:442:h:0:6900:0:539:0:0:53354 +Barock Fantasie:442:h:0:6900:0:540:0:0:53355 +Musica Camerata:442:h:0:6900:0:541:0:0:53356 +Musica Antica:442:h:0:6900:0:542:0:0:53357 +Adagio:442:h:0:6900:0:543:0:0:53358 @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.43 2001/02/24 13:20:18 kls Exp $ + * $Id: config.c 1.44 2001/04/01 14:32:22 kls Exp $ */ #include "config.h" @@ -75,37 +75,39 @@ bool cKeys::Load(const char *FileName) result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; - char *Name = buffer; - char *p = strpbrk(Name, " \t"); - if (p) { - *p = 0; // terminates 'Name' - while (*++p && isspace(*p)) - ; - if (*p) { - if (strcasecmp(Name, "Code") == 0) - code = *p; - else if (strcasecmp(Name, "Address") == 0) - address = strtol(p, NULL, 16); - else { - for (tKey *k = keys; k->type != kNone; k++) { - if (strcasecmp(Name, k->name) == 0) { - k->code = strtol(p, NULL, 16); - Name = NULL; // to indicate that we found it + if (!isempty(buffer)) { + char *Name = buffer; + char *p = strpbrk(Name, " \t"); + if (p) { + *p = 0; // terminates 'Name' + while (*++p && isspace(*p)) + ; + if (*p) { + if (strcasecmp(Name, "Code") == 0) + code = *p; + else if (strcasecmp(Name, "Address") == 0) + address = strtol(p, NULL, 16); + else { + for (tKey *k = keys; k->type != kNone; k++) { + if (strcasecmp(Name, k->name) == 0) { + k->code = strtol(p, NULL, 16); + Name = NULL; // to indicate that we found it + break; + } + } + if (Name) { + esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line); + result = false; break; } } - if (Name) { - esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line); - result = false; - break; - } - } + } + continue; } - continue; + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + result = false; + break; } - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - result = false; - break; } fclose(f); } @@ -782,10 +784,12 @@ bool cSetup::Load(const char *FileName) bool result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; - if (*buffer != '#' && !Parse(buffer)) { - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - result = false; - break; + if (!isempty(buffer)) { + if (*buffer != '#' && !Parse(buffer)) { + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + result = false; + break; + } } } fclose(f); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.42 2001/02/24 13:19:39 kls Exp $ + * $Id: config.h 1.44 2001/04/01 14:44:40 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.71" +#define VDRVERSION "0.72" #define MaxBuffer 10000 @@ -184,14 +184,16 @@ public: result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; - T *l = new T; - if (l->Parse(buffer)) - Add(l); - else { - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - delete l; - result = false; - break; + if (!isempty(buffer)) { + T *l = new T; + if (l->Parse(buffer)) + Add(l); + else { + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + delete l; + result = false; + break; + } } } fclose(f); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.61 2001/02/24 13:13:19 kls Exp $ + * $Id: dvbapi.c 1.66 2001/03/31 15:01:57 kls Exp $ */ #include "dvbapi.h" @@ -22,6 +22,8 @@ extern "C" { #include "config.h" #include "interface.h" #include "recording.h" +#include "remux.h" +#include "ringbuffer.h" #include "tools.h" #include "videodir.h" @@ -29,29 +31,9 @@ extern "C" { #define VBIDEVICE "/dev/vbi" // The size of the array used to buffer video data: +// (must be larger than MINVIDEODATA - see remux.h) #define VIDEOBUFSIZE (1024*1024) -// The minimum amount of video data necessary to identify frames -// (must be smaller than VIDEOBUFSIZE!): -#define MINVIDEODATA (256*1024) // just a safe guess (max. size of any frame block, plus some safety) - -// The maximum time the buffer is allowed to write data to disk when recording: -#define MAXRECORDWRITETIME 50 // ms - -// Picture types: -#define NO_PICTURE 0 -#define I_FRAME 1 -#define P_FRAME 2 -#define B_FRAME 3 - -// Start codes: -#define SC_PICTURE 0x00 // "picture header" -#define SC_SEQU 0xB3 // "sequence header" -#define SC_PHEAD 0xBA // "pack header" -#define SC_SHEAD 0xBB // "system header" -#define SC_AUDIO 0xC0 -#define SC_VIDEO 0xE0 - #define FRAMESPERSEC 25 // The maximum file size is limited by the range that can be covered @@ -333,7 +315,7 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) return -1; } -// --- cRingBuffer ----------------------------------------------------------- +// --- cRingBuffer_ ----------------------------------------------------------- /* cRingBuffer reads data from an input file, stores it in a buffer and writes it to an output file upon request. The Read() and Write() functions should @@ -344,7 +326,7 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) will be made. */ -class cRingBuffer { +class cRingBuffer_ { private: uchar *buffer; int size, head, tail, freeLimit, availLimit; @@ -367,8 +349,8 @@ protected: int FindStartCode(uchar Code, int Offset = 0); int GetPacketLength(int Offset = 0); public: - cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); - virtual ~cRingBuffer(); + cRingBuffer_(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); + virtual ~cRingBuffer_(); virtual int Read(int Max = -1); virtual int Write(int Max = -1); bool EndOfFile(void) { return eof; } @@ -377,7 +359,7 @@ public: void Skip(int n); }; -cRingBuffer::cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit, int AvailLimit) +cRingBuffer_::cRingBuffer_(int *InFile, int *OutFile, int Size, int FreeLimit, int AvailLimit) { inFile = InFile; outFile = OutFile; @@ -393,13 +375,13 @@ cRingBuffer::cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit, int esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); } -cRingBuffer::~cRingBuffer() +cRingBuffer_::~cRingBuffer_() { dsyslog(LOG_INFO, "buffer stats: %d free, %d overflows, limit exceeded %d times", minFree, countOverflow, countLimit); delete buffer; } -int cRingBuffer::Byte(int Offset) +int cRingBuffer_::Byte(int Offset) { if (buffer && Offset < Available()) { Offset += head; @@ -410,7 +392,7 @@ int cRingBuffer::Byte(int Offset) return -1; } -bool cRingBuffer::Set(int Offset, int Length, int Value) +bool cRingBuffer_::Set(int Offset, int Length, int Value) { if (buffer && Offset + Length <= Available() ) { Offset += head; @@ -425,7 +407,7 @@ bool cRingBuffer::Set(int Offset, int Length, int Value) return false; } -void cRingBuffer::Skip(int n) +void cRingBuffer_::Skip(int n) { if (n > 0) { if (head < tail) { @@ -443,7 +425,7 @@ void cRingBuffer::Skip(int n) } } -int cRingBuffer::Read(int Max) +int cRingBuffer_::Read(int Max) { if (buffer) { eof = false; @@ -501,7 +483,7 @@ int cRingBuffer::Read(int Max) return -1; } -int cRingBuffer::Write(int Max) +int cRingBuffer_::Write(int Max) { if (buffer) { int avail = Available(); @@ -540,7 +522,7 @@ int cRingBuffer::Write(int Max) return -1; } -int cRingBuffer::FindStartCode(uchar Code, int Offset) +int cRingBuffer_::FindStartCode(uchar Code, int Offset) { // Searches for a start code (beginning at Offset) and returns the number // of bytes from Offset to the start code. @@ -557,7 +539,7 @@ int cRingBuffer::FindStartCode(uchar Code, int Offset) return -1; } -int cRingBuffer::GetPacketLength(int Offset) +int cRingBuffer_::GetPacketLength(int Offset) { // Returns the entire length of the packet starting at offset. return (Byte(Offset + 4) << 8) + Byte(Offset + 5) + 6; @@ -671,31 +653,29 @@ int cFileName::NextFile(void) // --- cRecordBuffer --------------------------------------------------------- -class cRecordBuffer : public cRingBuffer, public cThread { +class cRecordBuffer : public cRingBuffer { private: cFileName fileName; cIndexFile *index; + cRemux remux; uchar pictureType; int fileSize; int videoDev; int recordFile; - bool ok, synced, stop; + bool recording; time_t lastDiskSpaceCheck; bool RunningLowOnDiskSpace(void); - int ScanVideoPacket(int *PictureType, int Offset); - int Synchronize(void); bool NextFile(void); - virtual int Write(int Max = -1); - bool WriteWithTimeout(void); protected: - virtual void Action(void); + virtual void Input(void); + virtual void Output(void); public: cRecordBuffer(int *InFile, const char *FileName); virtual ~cRecordBuffer(); }; cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) -:cRingBuffer(InFile, &recordFile, VIDEOBUFSIZE, VIDEOBUFSIZE / 10, 0) +:cRingBuffer(VIDEOBUFSIZE) ,fileName(FileName, true) { index = NULL; @@ -703,7 +683,7 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) fileSize = 0; videoDev = *InFile; recordFile = fileName.Open(); - ok = synced = stop = false; + recording = false; lastDiskSpaceCheck = time(NULL); if (!fileName.Name()) return; @@ -712,44 +692,15 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) if (!index) esyslog(LOG_ERR, "ERROR: can't allocate index"); // let's continue without index, so we'll at least have the recording - ok = true; Start(); } cRecordBuffer::~cRecordBuffer() { - stop = true; - Cancel(3); + Stop(); delete index; } -void cRecordBuffer::Action(void) -{ - dsyslog(LOG_INFO, "recording thread started (pid=%d)", getpid()); - - time_t t = time(NULL); - for (;;) { - usleep(1); // this keeps the CPU load low - - LOCK_THREAD; - - int r = Read(); - if (r >= 0) { - if (r > 0) - t = time(NULL); - if (!WriteWithTimeout()) - break; - } - if (r < 0 || (r == 0 && time(NULL) - t > 5)) { - esyslog(LOG_ERR, "ERROR: video data stream broken"); - t = time(NULL); - } - } - SetPlayMode(videoDev, VID_PLAY_RESET); - - dsyslog(LOG_INFO, "end recording thread"); -} - bool cRecordBuffer::RunningLowOnDiskSpace(void) { if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { @@ -763,88 +714,6 @@ bool cRecordBuffer::RunningLowOnDiskSpace(void) return false; } -int cRecordBuffer::ScanVideoPacket(int *PictureType, int Offset) -{ - // Scans the video packet starting at Offset and returns its length. - // If the return value is -1 the packet was not completely in the buffer. - - int Length = GetPacketLength(Offset); - if (Length <= Available()) { - 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); - return Length; - } - } - } - *PictureType = NO_PICTURE; - return Length; - } - return -1; -} - -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. - - pictureType = NO_PICTURE; - - //XXX remove this once the buffer is handled with two separate threads: - if (!synced && Free() < 100000) { - dsyslog(LOG_INFO, "unable to synchronize, dropped %d bytes", Available()); - Clear(); - return 0; - } - 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_VIDEO: { - int pt = NO_PICTURE; - int l = ScanVideoPacket(&pt, i); - if (l < 0) - 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); - } - else if (pictureType == NO_PICTURE) { - if (!synced) { - if (pt == I_FRAME) { - Skip(i); - synced = true; - } - else { - Skip(i + l); - i = 0; - break; - } - } - if (synced) - pictureType = pt; - } - else - return i; - } - else if (!synced) { - Skip(i + l); - i = 0; - break; - } - i += l - 1; // -1 to compensate for i++ in the loop! - } - break; - case SC_AUDIO: i += GetPacketLength(i) - 1; // -1 to compensate for i++ in the loop! - break; - } - } - } - return 0; // no useful data found, wait for more -} - bool cRecordBuffer::NextFile(void) { if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME @@ -856,56 +725,93 @@ bool cRecordBuffer::NextFile(void) return recordFile >= 0; } -int cRecordBuffer::Write(int Max) +void cRecordBuffer::Input(void) { - // This function ignores the incoming 'Max'! - // It tries to write out exactly *one* frame block. - if (!ok) - return -1; - int n = Synchronize(); - if (n) { - if (stop && pictureType == I_FRAME) { - ok = false; - return -1; // finish the recording before the next 'I' frame - } - if (NextFile()) { - if (index && pictureType != NO_PICTURE) - index->Write(pictureType, fileName.Number(), fileSize); - int written = 0; - for (;;) { - int w = cRingBuffer::Write(n); - if (w >= 0) { - fileSize += w; - written += w; - n -= w; - if (n == 0) - return written; + dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); + + uchar b[MINVIDEODATA]; + time_t t = time(NULL); + recording = true; + for (;;) { + int r = read(videoDev, b, sizeof(b)); + if (r > 0) { + uchar *p = b; + while (r > 0) { + int w = Put(p, r); + p += w; + r -= w; } - else - return w; + t = time(NULL); + } + else if (r < 0) { + if (errno != EAGAIN) { + LOG_ERROR; + break; } - } - return -1; - } - return 0; + } + else if (time(NULL) - t > 5) { + esyslog(LOG_ERR, "ERROR: video data stream broken"); + t = time(NULL); + } + cFile::FileReady(videoDev, 100); + if (!recording) + break; + } + SetPlayMode(videoDev, VID_PLAY_RESET); + + dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); } -bool cRecordBuffer::WriteWithTimeout(void) +void cRecordBuffer::Output(void) { - int t0 = time_ms(); - do { - int w = Write(); - if (w < 0) - return false; - if (w == 0) - break; - } while (time_ms() - t0 < MAXRECORDWRITETIME); - return true; + dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); + + uchar b[MINVIDEODATA * 2]; + int r = 0; + for (;;) { + usleep(1); // this keeps the CPU load low + r += Get(b + r, sizeof(b) - r); + if (r > 0) { + //XXX buffer full??? + int Count = r, Result; + const uchar *p = remux.Process(b, Count, Result, pictureType); + if (p) { + if (!Busy() && pictureType == I_FRAME) // finish the recording before the next 'I' frame + break; + if (NextFile()) { + if (index && pictureType != NO_PICTURE) + index->Write(pictureType, fileName.Number(), fileSize); + while (Result > 0) { + int w = write(recordFile, p, Result); + if (w < 0) { + LOG_ERROR_STR(fileName.Name()); + recording = false; + return; + } + p += w; + Result -= w; + fileSize += w; + } + } + else + break; + } + if (Count > 0) { + r -= Count; + memmove(b, b + Count, r); + } + if (!recording) + break; + } + } + recording = false; + + dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); } // --- cReplayBuffer --------------------------------------------------------- -class cReplayBuffer : public cRingBuffer, public cThread { +class cReplayBuffer : public cRingBuffer_, public cThread { private: enum eReplayCmd { rcNone, rcStill, rcPause, rcPlay, rcForward, rcBackward }; enum eReplayMode { rmStill, rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; @@ -944,7 +850,7 @@ public: }; cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) -:cRingBuffer(&replayFile, OutFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +:cRingBuffer_(&replayFile, OutFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) ,fileName(FileName, false) { index = NULL; @@ -1271,7 +1177,7 @@ int cReplayBuffer::Read(int Max = -1) int readin = 0; do { // If Max is > 0 here we need to make sure we read in the entire block! - int r = cRingBuffer::Read(Max); + int r = cRingBuffer_::Read(Max); if (r >= 0) readin += r; else @@ -1300,7 +1206,7 @@ int cReplayBuffer::Write(int Max) if (Max) { int w; do { - w = cRingBuffer::Write(Max); + w = cRingBuffer_::Write(Max); if (w >= 0) { fileOffset += w; Written += w; @@ -1348,7 +1254,7 @@ void cTransferBuffer::Action(void) { dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid()); - cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); + cRingBuffer_ Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); active = true; while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start Buffer.Read(); // initializes fromDevice for reading @@ -1364,7 +1270,7 @@ void cTransferBuffer::Action(void) // --- cCuttingBuffer -------------------------------------------------------- -class cCuttingBuffer : public cRingBuffer, public cThread { +class cCuttingBuffer : public cRingBuffer_, public cThread { private: bool active; int fromFile, toFile; @@ -1379,7 +1285,7 @@ public: }; cCuttingBuffer::cCuttingBuffer(const char *FromFileName, const char *ToFileName) -:cRingBuffer(&fromFile, &toFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +:cRingBuffer_(&fromFile, &toFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) { active = false; fromFile = toFile = -1; @@ -1438,7 +1344,7 @@ void cCuttingBuffer::Action(void) CurrentFileNumber = FileNumber; } if (fromFile >= 0) - Length = cRingBuffer::Read(Length); + Length = cRingBuffer_::Read(Length); else break; } @@ -1456,7 +1362,7 @@ void cCuttingBuffer::Action(void) } LastIFrame = 0; } - cRingBuffer::Write(Length); + cRingBuffer_::Write(Length); toIndex->Write(PictureType, toFileName->Number(), FileSize); FileSize += Length; if (!LastIFrame) @@ -1535,7 +1441,7 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK); if (videoDev >= 0) { siProcessor = new cSIProcessor(VbiFileName); - if (!NumDvbApis) // only the first one shall set the system time + if (!dvbApi[0]) // only the first one shall set the system time siProcessor->SetUseTSTime(Setup.SetSystemTime); siProcessor->AddFilter(0x14, 0x70); // TDT siProcessor->AddFilter(0x14, 0x73); // TOT @@ -1582,7 +1488,7 @@ cDvbApi::~cDvbApi() StopTransfer(); OvlO(false); //Overlay off! //XXX the following call sometimes causes a segfault - driver problem? - close(videoDev); + //XXX close(videoDev); } #if defined(DEBUG_OSD) || defined(REMOTE_KBD) endwin(); @@ -1611,7 +1517,7 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) { cDvbApi *d = NULL, *dMinPriority = NULL; int index = Ca - 1; - for (int i = MAXDVBAPI; --i >= 0; ) { + for (int i = 0; i < MAXDVBAPI; i++) { if (dvbApi[i]) { if (i == index) { // means we need exactly _this_ device d = dvbApi[i]; @@ -2136,6 +2042,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, if (videoDev >= 0) { cThreadLock ThreadLock(siProcessor); // makes sure the siProcessor won't access the vbi-device while switching StopTransfer(); + StopReplay(); SetPlayMode(videoDev, VID_PLAY_RESET); struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); @@ -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.12 2001/02/24 12:12:58 kls Exp $ + * $Id: eit.c 1.15 2001/04/01 15:36:09 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -39,11 +39,11 @@ // --- cMJD ------------------------------------------------------------------ class cMJD { -public: - cMJD(); - cMJD(u_char date_hi, u_char date_lo); - cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese); - ~cMJD(); +public: + cMJD(); + cMJD(u_char date_hi, u_char date_lo); + cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese); + ~cMJD(); /** */ void ConvertToTime(); /** */ @@ -73,18 +73,18 @@ cMJD::cMJD() cMJD::cMJD(u_char date_hi, u_char date_lo) { - mjd = date_hi << 8 | date_lo; - time_hour = time_minute = time_second = 0; - ConvertToTime(); + mjd = date_hi << 8 | date_lo; + time_hour = time_minute = time_second = 0; + ConvertToTime(); } cMJD::cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese) { - mjd = date_hi << 8 | date_lo; - time_hour = timehr; - time_minute = timemi; - time_second = timese; - ConvertToTime(); + mjd = date_hi << 8 | date_lo; + time_hour = timehr; + time_minute = timemi; + time_second = timese; + ConvertToTime(); } cMJD::~cMJD() @@ -94,103 +94,102 @@ cMJD::~cMJD() /** */ void cMJD::ConvertToTime() { - struct tm t; - - t.tm_sec = time_second; - t.tm_min = time_minute; - t.tm_hour = time_hour; - int k; - - t.tm_year = (int) ((mjd - 15078.2) / 365.25); - t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001); - t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001)); - k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0; - t.tm_year = t.tm_year + k; - t.tm_mon = t.tm_mon - 1 - k * 12; - t.tm_mon--; - - t.tm_isdst = -1; - t.tm_gmtoff = 0; - - mjdtime = timegm(&t); - - //isyslog(LOG_INFO, "Time parsed = %s\n", ctime(&mjdtime)); + struct tm t; + + t.tm_sec = time_second; + t.tm_min = time_minute; + t.tm_hour = time_hour; + int k; + + t.tm_year = (int) ((mjd - 15078.2) / 365.25); + t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001); + t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001)); + k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0; + t.tm_year = t.tm_year + k; + t.tm_mon = t.tm_mon - 1 - k * 12; + t.tm_mon--; + + t.tm_isdst = -1; + t.tm_gmtoff = 0; + + mjdtime = timegm(&t); + + //isyslog(LOG_INFO, "Time parsed = %s\n", ctime(&mjdtime)); } /** */ bool cMJD::SetSystemTime() { - struct tm *ptm; - time_t loctim; - - ptm = localtime(&mjdtime); - loctim = time(NULL); - - if (abs(mjdtime - loctim) > 2) - { - isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim); - isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime); - if (stime(&mjdtime) < 0) + struct tm *ptm; + time_t loctim; + + ptm = localtime(&mjdtime); + loctim = time(NULL); + + if (abs(mjdtime - loctim) > 2) + { + isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim); + isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime); + if (stime(&mjdtime) < 0) esyslog(LOG_ERR, "ERROR while setting system time: %m"); - return true; - } - - return false; + return true; + } + + return false; } /** */ time_t cMJD::GetTime_t() { - return mjdtime; + return mjdtime; } // --- cTDT ------------------------------------------------------------------ typedef struct { - u_char table_id : 8; + u_char table_id : 8; #if BYTE_ORDER == BIG_ENDIAN - u_char section_syntax_indicator : 1; - u_char : 3; - u_char section_length_hi : 4; + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; #else - u_char section_length_hi : 4; - u_char : 3; - u_char section_syntax_indicator : 1; + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; #endif - u_char section_length_lo : 8; + u_char section_length_lo : 8; - u_char utc_date_hi : 8; - u_char utc_date_lo : 8; - u_char utc_hour : 4; - u_char utc_hour_ten : 4; - u_char utc_min : 4; - u_char utc_min_ten : 4; - u_char utc_sec : 4; - u_char utc_sec_ten : 4; + u_char utc_date_hi : 8; + u_char utc_date_lo : 8; + u_char utc_hour : 4; + u_char utc_hour_ten : 4; + u_char utc_min : 4; + u_char utc_min_ten : 4; + u_char utc_sec : 4; + u_char utc_sec_ten : 4; } tdt_t; class cTDT { -public: - cTDT(tdt_t *ptdt); - ~cTDT(); +public: + cTDT(tdt_t *ptdt); + ~cTDT(); /** */ bool SetSystemTime(); protected: // Protected attributes /** */ tdt_t tdt; /** */ - cMJD * mjd; + cMJD mjd; // kls 2001-03-02: made this a member instead of a pointer (it wasn't deleted in the destructor!) }; cTDT::cTDT(tdt_t *ptdt) +:tdt(*ptdt) +,mjd(tdt.utc_date_hi, tdt.utc_date_lo, tdt.utc_hour_ten * 10 + tdt.utc_hour, + tdt.utc_min_ten * 10 + tdt.utc_min, + tdt.utc_sec_ten * 10 + tdt.utc_sec) { - tdt = *ptdt; - mjd = new cMJD(tdt.utc_date_hi, tdt.utc_date_lo, - tdt.utc_hour_ten * 10 + tdt.utc_hour, - tdt.utc_min_ten * 10 + tdt.utc_min, - tdt.utc_sec_ten * 10 + tdt.utc_sec); } cTDT::~cTDT() @@ -199,22 +198,22 @@ cTDT::~cTDT() /** */ bool cTDT::SetSystemTime() { - return mjd->SetSystemTime(); + return mjd.SetSystemTime(); } // --- cEventInfo ------------------------------------------------------------ cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid) { - pTitle = NULL; - pSubtitle = NULL; - pExtendedDescription = NULL; - bIsPresent = bIsFollowing = false; - lDuration = 0; - tTime = 0; - uEventID = eventid; - uServiceID = serviceid; - cExtendedDescriptorNumber = 0; + pTitle = NULL; + pSubtitle = NULL; + pExtendedDescription = NULL; + bIsPresent = bIsFollowing = false; + lDuration = 0; + tTime = 0; + uEventID = eventid; + uServiceID = serviceid; + cExtendedDescriptorNumber = 0; nChannelNumber = 0; } @@ -228,165 +227,165 @@ cEventInfo::~cEventInfo() /** */ const char * cEventInfo::GetTitle() const { - return pTitle; + return pTitle; } /** */ const char * cEventInfo::GetSubtitle() const { - return pSubtitle; + return pSubtitle; } /** */ const char * cEventInfo::GetExtendedDescription() const { - return pExtendedDescription; + return pExtendedDescription; } /** */ bool cEventInfo::IsPresent() const { - return bIsPresent; + return bIsPresent; } /** */ void cEventInfo::SetPresent(bool pres) { - bIsPresent = pres; + bIsPresent = pres; } /** */ bool cEventInfo::IsFollowing() const { - return bIsFollowing; + return bIsFollowing; } /** */ void cEventInfo::SetFollowing(bool foll) { - bIsFollowing = foll; + bIsFollowing = foll; } /** */ const char * cEventInfo::GetDate() const { - static char szDate[25]; + static char szDate[25]; - strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime(&tTime)); + strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime(&tTime)); - return szDate; + return szDate; } /** */ const char * cEventInfo::GetTimeString() const { - static char szTime[25]; - - strftime(szTime, sizeof(szTime), "%R", localtime(&tTime)); - - return szTime; + static char szTime[25]; + + strftime(szTime, sizeof(szTime), "%R", localtime(&tTime)); + + return szTime; } /** */ const char * cEventInfo::GetEndTimeString() const { - static char szEndTime[25]; + static char szEndTime[25]; time_t tEndTime = tTime + lDuration; - - strftime(szEndTime, sizeof(szEndTime), "%R", localtime(&tEndTime)); - - return szEndTime; + + strftime(szEndTime, sizeof(szEndTime), "%R", localtime(&tEndTime)); + + return szEndTime; } /** */ time_t cEventInfo::GetTime() const { - return tTime; + return tTime; } /** */ long cEventInfo::GetDuration() const { - return lDuration; + return lDuration; } /** */ unsigned short cEventInfo::GetEventID() const { - return uEventID; + return uEventID; } /** */ bool cEventInfo::SetTitle(char *string) { - if (string == NULL) - return false; - - pTitle = strdup(string); - if (pTitle == NULL) - return false; - - return true; + if (string == NULL) + return false; + + pTitle = strdup(string); + if (pTitle == NULL) + return false; + + return true; } /** */ bool cEventInfo::SetSubtitle(char *string) { - if (string == NULL) - return false; - - pSubtitle = strdup(string); - if (pSubtitle == NULL) - return false; - - return true; + if (string == NULL) + return false; + + pSubtitle = strdup(string); + if (pSubtitle == NULL) + return false; + + return true; } /** */ bool cEventInfo::AddExtendedDescription(char *string) { - int size = 0; - bool first = true; - char *p; - - if (string == NULL) - return false; - - if (pExtendedDescription) - { - first = false; - size += strlen(pExtendedDescription); - } - - size += (strlen(string) + 1); - - p = (char *)realloc(pExtendedDescription, size); - if (p == NULL) - return false; - - if (first) - *p = 0; - - strcat(p, string); - - pExtendedDescription = p; - - return true; + int size = 0; + bool first = true; + char *p; + + if (string == NULL) + return false; + + if (pExtendedDescription) + { + first = false; + size += strlen(pExtendedDescription); + } + + size += (strlen(string) + 1); + + p = (char *)realloc(pExtendedDescription, size); + if (p == NULL) + return false; + + if (first) + *p = 0; + + strcat(p, string); + + pExtendedDescription = p; + + return true; } /** */ void cEventInfo::SetTime(time_t t) { - tTime = t; + tTime = t; } /** */ void cEventInfo::SetDuration(long l) { - lDuration = l; + lDuration = l; } /** */ void cEventInfo::SetEventID(unsigned short evid) { - uEventID = evid; + uEventID = evid; } /** */ void cEventInfo::SetServiceID(unsigned short servid) { - uServiceID = servid; + uServiceID = servid; } /** */ u_char cEventInfo::GetExtendedDescriptorNumber() const { - return cExtendedDescriptorNumber; + return cExtendedDescriptorNumber; } /** */ void cEventInfo::IncreaseExtendedDescriptorNumber() { - cExtendedDescriptorNumber++; + cExtendedDescriptorNumber++; } /** */ @@ -396,17 +395,17 @@ unsigned short cEventInfo::GetServiceID() const } /** */ -void cEventInfo::Dump(FILE *f) const +void cEventInfo::Dump(FILE *f, const char *Prefix) const { if (tTime + lDuration >= time(NULL)) { - fprintf(f, "E %u %ld %ld\n", uEventID, tTime, lDuration); + fprintf(f, "%sE %u %ld %ld\n", Prefix, uEventID, tTime, lDuration); if (!isempty(pTitle)) - fprintf(f, "T %s\n", pTitle); + fprintf(f, "%sT %s\n", Prefix, pTitle); if (!isempty(pSubtitle)) - fprintf(f, "S %s\n", pSubtitle); + fprintf(f, "%sS %s\n", Prefix, pSubtitle); if (!isempty(pExtendedDescription)) - fprintf(f, "D %s\n", pExtendedDescription); - fprintf(f, "e\n"); + fprintf(f, "%sD %s\n", Prefix, pExtendedDescription); + fprintf(f, "%se\n", Prefix); } } @@ -414,8 +413,8 @@ void cEventInfo::Dump(FILE *f) const cSchedule::cSchedule(unsigned short servid) { - pPresent = pFollowing = NULL; - uServiceID = servid; + pPresent = pFollowing = NULL; + uServiceID = servid; } @@ -429,15 +428,15 @@ const cEventInfo * cSchedule::GetPresentEvent() const time_t now = time(NULL); if (pPresent && !(pPresent->GetTime() <= now && now <= pPresent->GetTime() + pPresent->GetDuration())) { - cEventInfo *pe = Events.First(); - while (pe != NULL) - { - if (pe->GetTime() <= now && now <= pe->GetTime() + pe->GetDuration()) + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetTime() <= now && now <= pe->GetTime() + pe->GetDuration()) return pe; pe = Events.Next(pe); - } + } } - return pPresent; + return pPresent; } /** */ const cEventInfo * cSchedule::GetFollowingEvent() const @@ -451,111 +450,111 @@ const cEventInfo * cSchedule::GetFollowingEvent() const cEventInfo *pe = Events.First(), *pf = NULL; while (pe != NULL) { - int dt = pe->GetTime() - now; - if (dt > 0 && dt < minDt) + int dt = pe->GetTime() - now; + if (dt > 0 && dt < minDt) { minDt = dt; pf = pe; } - pe = Events.Next(pe); + pe = Events.Next(pe); } return pf; } - return pFollowing; + return pFollowing; } /** */ void cSchedule::SetServiceID(unsigned short servid) { - uServiceID = servid; + uServiceID = servid; } /** */ unsigned short cSchedule::GetServiceID() const { - return uServiceID; + return uServiceID; } /** */ const cEventInfo * cSchedule::GetEvent(unsigned short uEventID) const { - cEventInfo *pe = Events.First(); - while (pe != NULL) - { - if (pe->GetEventID() == uEventID) - return pe; - - pe = Events.Next(pe); - } - - return NULL; + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetEventID() == uEventID) + return pe; + + pe = Events.Next(pe); + } + + return NULL; } /** */ const cEventInfo * cSchedule::GetEvent(time_t tTime) const { - cEventInfo *pe = Events.First(); - while (pe != NULL) - { - if (pe->GetTime() == tTime) - return pe; - - pe = Events.Next(pe); - } - - return NULL; + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetTime() == tTime) + return pe; + + pe = Events.Next(pe); + } + + return NULL; } /** */ bool cSchedule::SetPresentEvent(cEventInfo *pEvent) { - if (pPresent != NULL) - pPresent->SetPresent(false); - pPresent = pEvent; - pPresent->SetPresent(true); - - return true; + if (pPresent != NULL) + pPresent->SetPresent(false); + pPresent = pEvent; + pPresent->SetPresent(true); + + return true; } /** */ bool cSchedule::SetFollowingEvent(cEventInfo *pEvent) { - if (pFollowing != NULL) - pFollowing->SetFollowing(false); - pFollowing = pEvent; - pFollowing->SetFollowing(true); - - return true; + if (pFollowing != NULL) + pFollowing->SetFollowing(false); + pFollowing = pEvent; + pFollowing->SetFollowing(true); + + return true; } /** */ void cSchedule::Cleanup() { - Cleanup(time(NULL)); + Cleanup(time(NULL)); } /** */ void cSchedule::Cleanup(time_t tTime) { - cEventInfo *pEvent; - for (int a = 0; true ; a++) - { - pEvent = Events.Get(a); - if (pEvent == NULL) - break; - if (pEvent->GetTime() + pEvent->GetDuration() < tTime) - { - Events.Del(pEvent); - a--; - } - } + cEventInfo *pEvent; + for (int a = 0; true ; a++) + { + pEvent = Events.Get(a); + if (pEvent == NULL) + break; + if (pEvent->GetTime() + pEvent->GetDuration() < tTime) + { + Events.Del(pEvent); + a--; + } + } } /** */ -void cSchedule::Dump(FILE *f) const +void cSchedule::Dump(FILE *f, const char *Prefix) const { cChannel *channel = Channels.GetByServiceID(uServiceID); if (channel) { - fprintf(f, "C %u %s\n", uServiceID, channel->name); + fprintf(f, "%sC %u %s\n", Prefix, uServiceID, channel->name); for (cEventInfo *p = Events.First(); p; p = Events.Next(p)) - p->Dump(f); - fprintf(f, "c\n"); + p->Dump(f, Prefix); + fprintf(f, "%sc\n", Prefix); } } @@ -563,8 +562,8 @@ void cSchedule::Dump(FILE *f) const cSchedules::cSchedules() { - pCurrentSchedule = NULL; - uCurrentServiceID = 0; + pCurrentSchedule = NULL; + uCurrentServiceID = 0; } cSchedules::~cSchedules() @@ -573,58 +572,58 @@ cSchedules::~cSchedules() /** */ bool cSchedules::SetCurrentServiceID(unsigned short servid) { - pCurrentSchedule = GetSchedule(servid); - if (pCurrentSchedule == NULL) - { - Add(new cSchedule(servid)); - pCurrentSchedule = GetSchedule(servid); - if (pCurrentSchedule == NULL) - return false; - } - - uCurrentServiceID = servid; - - return true; + pCurrentSchedule = GetSchedule(servid); + if (pCurrentSchedule == NULL) + { + Add(new cSchedule(servid)); + pCurrentSchedule = GetSchedule(servid); + if (pCurrentSchedule == NULL) + return false; + } + + uCurrentServiceID = servid; + + return true; } /** */ const cSchedule * cSchedules::GetSchedule() const { - return pCurrentSchedule; + return pCurrentSchedule; } /** */ const cSchedule * cSchedules::GetSchedule(unsigned short servid) const { - cSchedule *p; - - p = First(); - while (p != NULL) - { - if (p->GetServiceID() == servid) - return p; - p = Next(p); - } - - return NULL; + cSchedule *p; + + p = First(); + while (p != NULL) + { + if (p->GetServiceID() == servid) + return p; + p = Next(p); + } + + return NULL; } /** */ void cSchedules::Cleanup() { - cSchedule *p; - - p = First(); - while (p != NULL) - { - p->Cleanup(time(NULL)); - p = Next(p); - } + cSchedule *p; + + p = First(); + while (p != NULL) + { + p->Cleanup(time(NULL)); + p = Next(p); + } } /** */ -void cSchedules::Dump(FILE *f) const +void cSchedules::Dump(FILE *f, const char *Prefix) const { for (cSchedule *p = First(); p; p = Next(p)) - p->Dump(f); + p->Dump(f, Prefix); } // --- cEIT ------------------------------------------------------------------ @@ -632,136 +631,136 @@ void cSchedules::Dump(FILE *f) const #define DEC(N) dec << setw(N) << setfill(int('0')) #define HEX(N) hex << setw(N) << setfill(int('0')) -#define EIT_STUFFING_DESCRIPTOR 0x42 -#define EIT_LINKAGE_DESCRIPTOR 0x4a -#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d -#define EIT_EXTENDED_EVENT_DESCRIPTOR 0x4e -#define EIT_TIME_SHIFTED_EVENT_DESCRIPTOR 0x4f -#define EIT_COMPONENT_DESCRIPTOR 0x50 -#define EIT_CA_IDENTIFIER_DESCRIPTOR 0x53 -#define EIT_CONTENT_DESCRIPTOR 0x54 -#define EIT_PARENTAL_RATING_DESCRIPTOR 0x55 -#define EIT_TELEPHONE_DESCRIPTOR 0x57 -#define EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR 0x5e -#define EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR 0x5f -#define EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 0x61 -#define EIT_DATA_BROADCAST_DESCRIPTOR 0x64 -#define EIT_PDC_DESCRIPTOR 0x69 +#define EIT_STUFFING_DESCRIPTOR 0x42 +#define EIT_LINKAGE_DESCRIPTOR 0x4a +#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d +#define EIT_EXTENDED_EVENT_DESCRIPTOR 0x4e +#define EIT_TIME_SHIFTED_EVENT_DESCRIPTOR 0x4f +#define EIT_COMPONENT_DESCRIPTOR 0x50 +#define EIT_CA_IDENTIFIER_DESCRIPTOR 0x53 +#define EIT_CONTENT_DESCRIPTOR 0x54 +#define EIT_PARENTAL_RATING_DESCRIPTOR 0x55 +#define EIT_TELEPHONE_DESCRIPTOR 0x57 +#define EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR 0x5e +#define EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR 0x5f +#define EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 0x61 +#define EIT_DATA_BROADCAST_DESCRIPTOR 0x64 +#define EIT_PDC_DESCRIPTOR 0x69 typedef struct eit_struct { - u_char table_id : 8; + u_char table_id : 8; #if BYTE_ORDER == BIG_ENDIAN - u_char section_syntax_indicator : 1; - u_char : 3; - u_char section_length_hi : 4; + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; #else - u_char section_length_hi : 4; - u_char : 3; - u_char section_syntax_indicator : 1; + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; #endif - u_char section_length_lo : 8; + u_char section_length_lo : 8; - u_char service_id_hi : 8; - u_char service_id_lo : 8; + u_char service_id_hi : 8; + u_char service_id_lo : 8; #if BYTE_ORDER == BIG_ENDIAN - u_char : 2; - u_char version_number : 5; - u_char current_next_indicator : 1; + u_char : 2; + u_char version_number : 5; + u_char current_next_indicator : 1; #else - u_char current_next_indicator : 1; - u_char version_number : 5; - u_char : 2; + u_char current_next_indicator : 1; + u_char version_number : 5; + u_char : 2; #endif - u_char section_number : 8; - u_char last_section_number : 8; - u_char transport_stream_id_hi : 8; - u_char transport_stream_id_lo : 8; - u_char original_network_id_hi : 8; - u_char original_network_id_lo : 8; - u_char segment_last_section_number : 8; - u_char segment_last_table_id : 8; + u_char section_number : 8; + u_char last_section_number : 8; + u_char transport_stream_id_hi : 8; + u_char transport_stream_id_lo : 8; + u_char original_network_id_hi : 8; + u_char original_network_id_lo : 8; + u_char segment_last_section_number : 8; + u_char segment_last_table_id : 8; } eit_t; typedef struct eit_loop_struct { - u_char event_id_hi : 8; - u_char event_id_lo : 8; - - u_char date_hi : 8; - u_char date_lo : 8; - u_char time_hour : 4; - u_char time_hour_ten : 4; - u_char time_minute : 4; - u_char time_minute_ten : 4; - u_char time_second : 4; - u_char time_second_ten : 4; - - u_char dur_hour : 4; - u_char dur_hour_ten : 4; - u_char dur_minute : 4; - u_char dur_minute_ten : 4; - u_char dur_second : 4; - u_char dur_second_ten : 4; + u_char event_id_hi : 8; + u_char event_id_lo : 8; + + u_char date_hi : 8; + u_char date_lo : 8; + u_char time_hour : 4; + u_char time_hour_ten : 4; + u_char time_minute : 4; + u_char time_minute_ten : 4; + u_char time_second : 4; + u_char time_second_ten : 4; + + u_char dur_hour : 4; + u_char dur_hour_ten : 4; + u_char dur_minute : 4; + u_char dur_minute_ten : 4; + u_char dur_second : 4; + u_char dur_second_ten : 4; #if BYTE_ORDER == BIG_ENDIAN - u_char running_status : 3; - u_char free_ca_mode : 1; - u_char descriptors_loop_length_hi : 4; + u_char running_status : 3; + u_char free_ca_mode : 1; + u_char descriptors_loop_length_hi : 4; #else - u_char descriptors_loop_length_hi : 4; - u_char free_ca_mode : 1; - u_char running_status : 3; + u_char descriptors_loop_length_hi : 4; + u_char free_ca_mode : 1; + u_char running_status : 3; #endif - u_char descriptors_loop_length_lo : 8; + u_char descriptors_loop_length_lo : 8; } eit_loop_t; typedef struct eit_short_event_struct { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; + u_char descriptor_tag : 8; + u_char descriptor_length : 8; - u_char language_code_1 : 8; - u_char language_code_2 : 8; - u_char language_code_3 : 8; + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; - u_char event_name_length : 8; + u_char event_name_length : 8; } eit_short_event_t; typedef struct eit_extended_event_struct { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; + u_char descriptor_tag : 8; + u_char descriptor_length : 8; - u_char last_descriptor_number : 4; - u_char descriptor_number : 4; + u_char last_descriptor_number : 4; + u_char descriptor_number : 4; - u_char language_code_1 : 8; - u_char language_code_2 : 8; - u_char language_code_3 : 8; + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; - u_char length_of_items : 8; + u_char length_of_items : 8; } eit_extended_event_t; typedef struct eit_content_descriptor { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; + u_char descriptor_tag : 8; + u_char descriptor_length : 8; } eit_content_descriptor_t; typedef struct eit_content_loop { - u_char content_nibble_level_2 : 4; - u_char content_nibble_level_1 : 4; - u_char user_nibble_2 : 4; - u_char user_nibble_1 : 4; + u_char content_nibble_level_2 : 4; + u_char content_nibble_level_1 : 4; + u_char user_nibble_2 : 4; + u_char user_nibble_1 : 4; } eit_content_loop_t; class cEIT { private: cSchedules *schedules; -public: - cEIT(void *buf, int length, cSchedules *Schedules); - ~cEIT(); +public: + cEIT(void *buf, int length, cSchedules *Schedules); + ~cEIT(); /** */ int ProcessEIT(); @@ -789,10 +788,10 @@ protected: // Protected attributes cEIT::cEIT(void * buf, int length, cSchedules *Schedules) { - buflen = length < int(sizeof(buffer)) ? length : sizeof(buffer); - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, buf, buflen); - tid = buffer[0]; + buflen = length < int(sizeof(buffer)) ? length : sizeof(buffer); + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, buf, buflen); + tid = buffer[0]; schedules = Schedules; } @@ -803,114 +802,114 @@ cEIT::~cEIT() /** */ int cEIT::ProcessEIT() { - int bufact = 0; - eit_t *eit; - eit_loop_t *eitloop; - u_char tmp[256]; - - if (bufact + (int)sizeof(eit_t) > buflen) - return 0; - eit = (eit_t *)buffer; - bufact += sizeof(eit_t); - - unsigned int service = (eit->service_id_hi << 8) | eit->service_id_lo; - - while(bufact + (int)sizeof(eit_loop_t) <= buflen) - { - eitloop = (eit_loop_t *)&buffer[bufact]; - bufact += sizeof(eit_loop_t); - - int descdatalen = (eitloop->descriptors_loop_length_hi << 8) + eitloop->descriptors_loop_length_lo; - int descdataact = 0; - - while (descdataact < descdatalen && bufact < buflen) - { - switch (buffer[bufact]) - { - eit_content_descriptor_t *cont; - eit_content_loop_t *contloop; - - case EIT_STUFFING_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_STUFFING_DESCRIPTOR"); - break; - - case EIT_LINKAGE_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_LINKAGE_DESCRIPTOR"); - break; - - case EIT_SHORT_EVENT_DESCRIPTOR: - WriteShortEventDescriptor(service, eitloop, &buffer[bufact]); - break; - - case EIT_EXTENDED_EVENT_DESCRIPTOR: - WriteExtEventDescriptor(service, eitloop, &buffer[bufact]); - break; - - case EIT_TIME_SHIFTED_EVENT_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_TIME_SHIFTED_EVENT_DESCRIPTOR"); - break; - - case EIT_COMPONENT_DESCRIPTOR : + int bufact = 0; + eit_t *eit; + eit_loop_t *eitloop; + u_char tmp[256]; + + if (bufact + (int)sizeof(eit_t) > buflen) + return 0; + eit = (eit_t *)buffer; + bufact += sizeof(eit_t); + + unsigned int service = (eit->service_id_hi << 8) | eit->service_id_lo; + + while(bufact + (int)sizeof(eit_loop_t) <= buflen) + { + eitloop = (eit_loop_t *)&buffer[bufact]; + bufact += sizeof(eit_loop_t); + + int descdatalen = (eitloop->descriptors_loop_length_hi << 8) + eitloop->descriptors_loop_length_lo; + int descdataact = 0; + + while (descdataact < descdatalen && bufact < buflen) + { + switch (buffer[bufact]) + { + eit_content_descriptor_t *cont; + eit_content_loop_t *contloop; + + case EIT_STUFFING_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_STUFFING_DESCRIPTOR"); + break; + + case EIT_LINKAGE_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_LINKAGE_DESCRIPTOR"); + break; + + case EIT_SHORT_EVENT_DESCRIPTOR: + WriteShortEventDescriptor(service, eitloop, &buffer[bufact]); + break; + + case EIT_EXTENDED_EVENT_DESCRIPTOR: + WriteExtEventDescriptor(service, eitloop, &buffer[bufact]); + break; + + case EIT_TIME_SHIFTED_EVENT_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_TIME_SHIFTED_EVENT_DESCRIPTOR"); + break; + + case EIT_COMPONENT_DESCRIPTOR : 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; - - case EIT_CA_IDENTIFIER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_CA_IDENTIFIER_DESCRIPTOR"); - break; - - case EIT_CONTENT_DESCRIPTOR : - cont = (eit_content_descriptor_t *)buffer; - contloop = (eit_content_loop_t *)&buffer[sizeof(eit_content_descriptor_t)]; - //dsyslog(LOG_INFO, "Found EIT_CONTENT_DESCRIPTOR 0x%02x/0x%02x\n", contloop->content_nibble_level_1, contloop->content_nibble_level_2); - break; - - case EIT_PARENTAL_RATING_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PARENTAL_RATING_DESCRIPTOR"); - break; - - case EIT_TELEPHONE_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_TELEPHONE_DESCRIPTOR"); - break; - - case EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR"); - break; - - case EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR"); - break; - - case EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR"); - break; - - case EIT_DATA_BROADCAST_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_DATA_BROADCAST_DESCRIPTOR"); - break; - - case EIT_PDC_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PDC_DESCRIPTOR"); - break; - - default: - //dsyslog(LOG_INFO, "Found unhandled descriptor 0x%02x with length of %04d\n", (int)buffer[bufact], (int)buffer[bufact + 1]); - break; - } - descdataact += (buffer[bufact + 1] + 2); - bufact += (buffer[bufact + 1] + 2); - } - } - - return 0; + 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; + + case EIT_CA_IDENTIFIER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_CA_IDENTIFIER_DESCRIPTOR"); + break; + + case EIT_CONTENT_DESCRIPTOR : + cont = (eit_content_descriptor_t *)buffer; + contloop = (eit_content_loop_t *)&buffer[sizeof(eit_content_descriptor_t)]; + //dsyslog(LOG_INFO, "Found EIT_CONTENT_DESCRIPTOR 0x%02x/0x%02x\n", contloop->content_nibble_level_1, contloop->content_nibble_level_2); + break; + + case EIT_PARENTAL_RATING_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PARENTAL_RATING_DESCRIPTOR"); + break; + + case EIT_TELEPHONE_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_TELEPHONE_DESCRIPTOR"); + break; + + case EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR"); + break; + + case EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR"); + break; + + case EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR"); + break; + + case EIT_DATA_BROADCAST_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_DATA_BROADCAST_DESCRIPTOR"); + break; + + case EIT_PDC_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PDC_DESCRIPTOR"); + break; + + default: + //dsyslog(LOG_INFO, "Found unhandled descriptor 0x%02x with length of %04d\n", (int)buffer[bufact], (int)buffer[bufact + 1]); + break; + } + descdataact += (buffer[bufact + 1] + 2); + bufact += (buffer[bufact + 1] + 2); + } + } + + return 0; } /** */ int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) { - int a = 0; - + 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) @@ -919,42 +918,42 @@ int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) return 0; } - if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff)) - { - for (a = 0; a < max; a++) - { - if (*src == 0) - break; - - if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) - *dst++ = *src++; - else - { - // if ((*src > '~' && *src < 0xa0) || *src == 0xff) - // cerr << "found special character 0x" << HEX(2) << (int)*src << endl; - src++; - } - } - *dst = 0; - } - else - { - const char *ret; - - switch (*src) - { - case 0x01: ret = "Coding according to character table 1"; break; - case 0x02: ret = "Coding according to character table 2"; break; - case 0x03: ret = "Coding according to character table 3"; break; - case 0x04: ret = "Coding according to character table 4"; break; - case 0x10: ret = "Coding according to ISO/IEC 8859"; break; - case 0x11: ret = "Coding according to ISO/IEC 10646"; break; - case 0x12: ret = "Coding according to KSC 5601"; break; - default: ret = "Unknown coding"; break; - } - strncpy((char *)dst, ret, max); - } - return a; + if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff)) + { + for (a = 0; a < max; a++) + { + if (*src == 0) + break; + + if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) + *dst++ = *src++; + else + { + // if ((*src > '~' && *src < 0xa0) || *src == 0xff) + // cerr << "found special character 0x" << HEX(2) << (int)*src << endl; + src++; + } + } + *dst = 0; + } + else + { + const char *ret; + + switch (*src) + { + case 0x01: ret = "Coding according to character table 1"; break; + case 0x02: ret = "Coding according to character table 2"; break; + case 0x03: ret = "Coding according to character table 3"; break; + case 0x04: ret = "Coding according to character table 4"; break; + case 0x10: ret = "Coding according to ISO/IEC 8859"; break; + case 0x11: ret = "Coding according to ISO/IEC 10646"; break; + case 0x12: ret = "Coding according to KSC 5601"; break; + default: ret = "Unknown coding"; break; + } + strncpy((char *)dst, ret, max); + } + return a; } /** returns true if this EIT covers a @@ -962,140 +961,140 @@ present/following information, false if it's schedule information */ bool cEIT::IsPresentFollowing() { - if (tid == 0x4e || tid == 0x4f) - return true; + if (tid == 0x4e || tid == 0x4f) + return true; - return false; + return false; } /** */ bool cEIT::WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) { - u_char tmp[256]; - eit_short_event_t *evt = (eit_short_event_t *)buf; - unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); - cEventInfo *pEvent; - - //isyslog(LOG_INFO, "Found Short Event Descriptor"); - - cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - { - schedules->Add(new cSchedule(service)); - pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - return false; - } + u_char tmp[256]; + eit_short_event_t *evt = (eit_short_event_t *)buf; + unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); + cEventInfo *pEvent; + + //isyslog(LOG_INFO, "Found Short Event Descriptor"); + + cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + { + schedules->Add(new cSchedule(service)); + pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + return false; + } /* cSchedule::GetPresentEvent() and cSchedule::GetFollowingEvent() verify the temporal sanity of these events, so calling them here appears to be a bad idea... (kls 2000-11-01) - // - // if we are working on a present/following info, let's see whether - // we already have present/following info for this service and if yes - // check whether it's the same eventid, if yes, just return, nothing - // left to do. - // - if (IsPresentFollowing()) - { - if (eitloop->running_status == 4 || eitloop->running_status == 3) - pEvent = (cEventInfo *)pSchedule->GetPresentEvent(); - else - pEvent = (cEventInfo *)pSchedule->GetFollowingEvent(); - - if (pEvent != NULL) - if (pEvent->GetEventID() == eventid) - return true; - } + // + // if we are working on a present/following info, let's see whether + // we already have present/following info for this service and if yes + // check whether it's the same eventid, if yes, just return, nothing + // left to do. + // + if (IsPresentFollowing()) + { + if (eitloop->running_status == 4 || eitloop->running_status == 3) + pEvent = (cEventInfo *)pSchedule->GetPresentEvent(); + else + pEvent = (cEventInfo *)pSchedule->GetFollowingEvent(); + + if (pEvent != NULL) + if (pEvent->GetEventID() == eventid) + return true; + } */ - // - // let's see whether we have that eventid already - // in case not, we have to create a new cEventInfo for it - // - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - { - pSchedule->Events.Add(new cEventInfo(service, eventid)); - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - return false; - - strdvbcpy(tmp, &buf[sizeof(eit_short_event_t)], evt->event_name_length); - pEvent->SetTitle((char *)tmp); - strdvbcpy(tmp, &buf[sizeof(eit_short_event_t) + evt->event_name_length + 1], - (int)buf[sizeof(eit_short_event_t) + evt->event_name_length]); - pEvent->SetSubtitle((char *)tmp); - cMJD mjd(eitloop->date_hi, eitloop->date_lo, - eitloop->time_hour_ten * 10 + eitloop->time_hour, - eitloop->time_minute_ten * 10 + eitloop->time_minute, - eitloop->time_second_ten * 10 + eitloop->time_second); - pEvent->SetTime(mjd.GetTime_t()); - pEvent->SetDuration((long)((long)((eitloop->dur_hour_ten * 10 + eitloop->dur_hour) * 60l * 60l) + - (long)((eitloop->dur_minute_ten * 10 + eitloop->dur_minute) * 60l) + - (long)(eitloop->dur_second_ten * 10 + eitloop->dur_second))); - } - - if (IsPresentFollowing()) - { - if (eitloop->running_status == 4 || eitloop->running_status == 3) - pSchedule->SetPresentEvent(pEvent); - else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) - pSchedule->SetFollowingEvent(pEvent); - } - - return true; + // + // let's see whether we have that eventid already + // in case not, we have to create a new cEventInfo for it + // + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + { + pSchedule->Events.Add(new cEventInfo(service, eventid)); + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + return false; + + strdvbcpy(tmp, &buf[sizeof(eit_short_event_t)], evt->event_name_length); + pEvent->SetTitle((char *)tmp); + strdvbcpy(tmp, &buf[sizeof(eit_short_event_t) + evt->event_name_length + 1], + (int)buf[sizeof(eit_short_event_t) + evt->event_name_length]); + pEvent->SetSubtitle((char *)tmp); + cMJD mjd(eitloop->date_hi, eitloop->date_lo, + eitloop->time_hour_ten * 10 + eitloop->time_hour, + eitloop->time_minute_ten * 10 + eitloop->time_minute, + eitloop->time_second_ten * 10 + eitloop->time_second); + pEvent->SetTime(mjd.GetTime_t()); + pEvent->SetDuration((long)((long)((eitloop->dur_hour_ten * 10 + eitloop->dur_hour) * 60l * 60l) + + (long)((eitloop->dur_minute_ten * 10 + eitloop->dur_minute) * 60l) + + (long)(eitloop->dur_second_ten * 10 + eitloop->dur_second))); + } + + if (IsPresentFollowing()) + { + if (eitloop->running_status == 4 || eitloop->running_status == 3) + pSchedule->SetPresentEvent(pEvent); + else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) + pSchedule->SetFollowingEvent(pEvent); + } + + return true; } /** */ bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) { - u_char tmp[256]; - eit_extended_event_t *evt = (eit_extended_event_t *)buf; - int bufact, buflen; - unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); - cEventInfo *pEvent; - - //isyslog(LOG_INFO, "Found Extended Event Descriptor"); - - cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - { - schedules->Add(new cSchedule(service)); - pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - return false; - } - - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - return false; - - if (evt->descriptor_number != pEvent->GetExtendedDescriptorNumber()) - return false; - - bufact = sizeof(eit_extended_event_t); - buflen = buf[1] + 2; - - if (evt->length_of_items > 0) - { - while (bufact - sizeof(eit_extended_event_t) < evt->length_of_items) - { - strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); - // could use value in tmp now to do something, - // haven't seen any items as of yet transmitted from satellite - bufact += (buf[bufact] + 1); - } - } - - strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); - if (pEvent->AddExtendedDescription((char *)tmp)) - { - pEvent->IncreaseExtendedDescriptorNumber(); - return true; - } - - return false; + u_char tmp[256]; + eit_extended_event_t *evt = (eit_extended_event_t *)buf; + int bufact, buflen; + unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); + cEventInfo *pEvent; + + //isyslog(LOG_INFO, "Found Extended Event Descriptor"); + + cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + { + schedules->Add(new cSchedule(service)); + pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + return false; + } + + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + return false; + + if (evt->descriptor_number != pEvent->GetExtendedDescriptorNumber()) + return false; + + bufact = sizeof(eit_extended_event_t); + buflen = buf[1] + 2; + + if (evt->length_of_items > 0) + { + while (bufact - sizeof(eit_extended_event_t) < evt->length_of_items) + { + strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); + // could use value in tmp now to do something, + // haven't seen any items as of yet transmitted from satellite + bufact += (buf[bufact] + 1); + } + } + + strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); + if (pEvent->AddExtendedDescription((char *)tmp)) + { + pEvent->IncreaseExtendedDescriptorNumber(); + return true; + } + + return false; } // --- cSIProcessor ---------------------------------------------------------- @@ -1110,13 +1109,13 @@ cMutex cSIProcessor::schedulesMutex; cSIProcessor::cSIProcessor(const char *FileName) { masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master' - useTStime = false; + useTStime = false; filters = NULL; if ((fsvbi = open(FileName, O_RDONLY)) >= 0) { if (!numSIProcessors++) // the first one creates it schedules = new cSchedules; - filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); + filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); } else LOG_ERROR_STR(FileName); @@ -1126,8 +1125,9 @@ cSIProcessor::~cSIProcessor() { if (fsvbi >= 0) { - Cancel(); - ShutDownFilters(); + active = false; + Cancel(3); + ShutDownFilters(); delete filters; if (!--numSIProcessors) // the last one deletes it delete schedules; @@ -1146,16 +1146,18 @@ void cSIProcessor::Action() } dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : ""); - + unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) - unsigned int seclen; - unsigned int pid; + unsigned int seclen; + unsigned int pid; time_t lastCleanup = time(NULL); time_t lastDump = time(NULL); - struct pollfd pfd; - - while(true) - { + struct pollfd pfd; + + active = true; + + while(active) + { if (masterSIProcessor) { time_t now = time(NULL); @@ -1185,65 +1187,65 @@ void cSIProcessor::Action() } } - /* wait data become ready from the bitfilter */ - pfd.fd = fsvbi; - pfd.events = POLLIN; - if(poll(&pfd, 1, 1000) != 0) /* timeout is 5 secs */ - { - // fprintf(stderr, "<data>\n"); - /* read section */ - read(fsvbi, buf, 8); - seclen = (buf[6] << 8) | buf[7]; - pid = (buf[4] << 8) | buf[5]; - read(fsvbi, buf, seclen); - - //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen); - - switch (pid) - { - case 0x14: - if (buf[0] == 0x70) - { - if (useTStime) + /* wait data become ready from the bitfilter */ + pfd.fd = fsvbi; + pfd.events = POLLIN; + if(poll(&pfd, 1, 1000) != 0) /* timeout is 5 secs */ + { + // fprintf(stderr, "<data>\n"); + /* read section */ + read(fsvbi, buf, 8); + seclen = (buf[6] << 8) | buf[7]; + pid = (buf[4] << 8) | buf[5]; + read(fsvbi, buf, seclen); + + //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen); + + switch (pid) + { + case 0x14: + if (buf[0] == 0x70) + { + if (useTStime) { cTDT ctdt((tdt_t *)buf); - ctdt.SetSystemTime(); + ctdt.SetSystemTime(); } - } + } /*XXX this comes pretty often: - else - dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]); + else + dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]); XXX*/ - break; - - case 0x12: - if (buf[0] != 0x72) - { + break; + + case 0x12: + if (buf[0] != 0x72) + { LOCK_THREAD; schedulesMutex.Lock(); - cEIT ceit(buf, seclen, schedules); - ceit.ProcessEIT(); + cEIT ceit(buf, seclen, schedules); + ceit.ProcessEIT(); schedulesMutex.Unlock(); - } - else - dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); - break; - - default: - break; - } - } - else - { + } + else + dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); + break; + + default: + break; + } + } + else + { LOCK_THREAD; //XXX this comes pretty often - //isyslog(LOG_INFO, "Received timeout from poll, refreshing filters\n"); - RefreshFilters(); - } -// WakeUp(); - } + //isyslog(LOG_INFO, "Received timeout from poll, refreshing filters\n"); + RefreshFilters(); + } +// WakeUp(); + } } /** Add a filter with packet identifier pid and @@ -1253,42 +1255,42 @@ bool cSIProcessor::AddFilter(u_char pid, u_char tid) if (fsvbi < 0) return false; - int section = ((int)tid << 8) | 0x00ff; - - struct bitfilter filt = { - pid, - { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - SECTION_CONTINUOS, 0, - FILTER_MEM, - {}, - }; - - if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) - return false; - - for (int a = 0; a < MAX_FILTERS; a++) - { - if (filters[a].inuse == false) - { - filters[a].pid = pid; - filters[a].tid = tid; - filters[a].handle = filt.handle; - filters[a].inuse = true; - // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); - return true; - } - } - - return false; + int section = ((int)tid << 8) | 0x00ff; + + struct bitfilter filt = { + pid, + { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + SECTION_CONTINUOS, 0, + FILTER_MEM, + {}, + }; + + if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) + return false; + + for (int a = 0; a < MAX_FILTERS; a++) + { + if (filters[a].inuse == false) + { + filters[a].pid = pid; + filters[a].tid = tid; + filters[a].handle = filt.handle; + filters[a].inuse = true; + // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); + return true; + } + } + + return false; } /** set whether local systems time should be set by the received TDT or TOT packets */ bool cSIProcessor::SetUseTSTime(bool use) { - useTStime = use; - return useTStime; + useTStime = use; + return useTStime; } /** */ @@ -1297,22 +1299,22 @@ bool cSIProcessor::ShutDownFilters() if (fsvbi < 0) return false; - bool ret = true; - - for (int a = 0; a < MAX_FILTERS; a++) - { - if (filters[a].inuse == true) - { - if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &filters[a].handle) < 0) - ret = false; + bool ret = true; + + for (int a = 0; a < MAX_FILTERS; a++) + { + if (filters[a].inuse == true) + { + if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &filters[a].handle) < 0) + ret = false; + + // dsyslog(LOG_INFO, "Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); - // dsyslog(LOG_INFO, "Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); - - filters[a].inuse = false; - } - } + filters[a].inuse = false; + } + } - return ret; + return ret; } /** */ @@ -1328,18 +1330,18 @@ bool cSIProcessor::RefreshFilters() if (fsvbi < 0) return false; - bool ret = true; - - ret = ShutDownFilters(); - - for (int a = 0; a < MAX_FILTERS; a++) - { - if (filters[a].inuse == false && filters[a].pid != 0 && filters[a].tid != 0) - { - if (!AddFilter(filters[a].pid, filters[a].tid)) - ret = false; - } - } - - return ret; + bool ret = true; + + ret = ShutDownFilters(); + + for (int a = 0; a < MAX_FILTERS; a++) + { + if (filters[a].inuse == false && filters[a].pid != 0 && filters[a].tid != 0) + { + if (!AddFilter(filters[a].pid, filters[a].tid)) + ret = false; + } + } + + return ret; } @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.4 2000/11/24 14:35:22 kls Exp $ + * $Id: eit.h 1.6 2001/04/01 15:14:12 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -49,7 +49,7 @@ protected: bool SetSubtitle(char *string); void IncreaseExtendedDescriptorNumber(void); cEventInfo(unsigned short serviceid, unsigned short eventid); -public: +public: ~cEventInfo(); const char *GetTimeString(void) const; const char *GetEndTimeString(void) const; @@ -66,7 +66,7 @@ public: unsigned short GetServiceID(void) const; int GetChannelNumber(void) const { return nChannelNumber; } void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' - void Dump(FILE *f) const; + void Dump(FILE *f, const char *Prefix = "") const; }; class cSchedule : public cListObject { @@ -84,7 +84,7 @@ protected: void Cleanup(time_t tTime); void Cleanup(void); cSchedule(unsigned short servid = 0); -public: +public: ~cSchedule(); const cEventInfo *GetPresentEvent(void) const; const cEventInfo *GetFollowingEvent(void) const; @@ -93,7 +93,7 @@ public: const cEventInfo *GetEvent(time_t tTime) const; const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } int NumEvents(void) const { return Events.Count(); } - void Dump(FILE *f) const; + void Dump(FILE *f, const char *Prefix = "") const; }; class cSchedules : public cList<cSchedule> { @@ -104,12 +104,12 @@ private: protected: bool SetCurrentServiceID(unsigned short servid); void Cleanup(); -public: +public: cSchedules(void); ~cSchedules(); const cSchedule *GetSchedule(unsigned short servid) const; const cSchedule *GetSchedule(void) const; - void Dump(FILE *f) const; + void Dump(FILE *f, const char *Prefix = "") const; }; typedef struct sip_filter { @@ -130,9 +130,10 @@ private: bool useTStime; SIP_FILTER *filters; int fsvbi; + bool active; bool RefreshFilters(void); void Action(void); -public: +public: cSIProcessor(const char *FileName); ~cSIProcessor(); bool SetUseTSTime(bool use); @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.14 2001/02/24 13:57:14 kls Exp $ + * $Id: i18n.c 1.16 2001/03/31 09:58:14 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> + * Dutch translations provided by Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com> * */ @@ -48,7 +49,7 @@ #include "config.h" #include "tools.h" -const int NumLanguages = 4; +const int NumLanguages = 5; typedef const char *tPhrase[NumLanguages]; @@ -58,542 +59,648 @@ const tPhrase Phrases[] = { "Deutsch", "Slovenski", "Italiano", + "Nederlands", }, // Menu titles: { "Main", "Hauptmenü", "Glavni meni", "Principale", + "Hoofdmenu", }, { "Schedule", "Programm", "Urnik", "Programmi", + "Gids", }, { "Channels", "Kanäle", "Kanali", "Canali", + "Kanalen", }, { "Timers", "Timer", "Termini", "Timer", + "Timers", }, { "Recordings", "Aufzeichnungen", "Posnetki", "Registrazioni", + "Opnames", }, { "Setup", "Einstellungen", "Nastavitve", "Opzioni", + "Instellingen", }, { "Commands", "Befehle", "Ukazi", "Comandi", + "Commando's", }, { "Edit Channel", "Kanal Editieren", "Uredi kanal", "Modifica canale", + "Kanaal aanpassen", }, { "Edit Timer", "Timer Editieren", "Uredi termin", "Modifica Timer", + "Timer veranderen", }, { "Event", "Sendung", "Oddaja", "Eventi", + "Uitzending", }, { "Summary", "Inhalt", "Vsebina", "Sommario", + "Inhoud", }, { "Schedule - %s", "Programm - %s", "Urnik - %s", "Programma - %s", + "Programma - %s", }, { "What's on now?", "Was läuft jetzt?", "Kaj je na sporedu?", "In programmazione", + "Wat is er nu?", }, { "What's on next?", "Was läuft als nächstes?", "Kaj sledi?", "Prossimi programmi", + "Wat komt er hierna?", }, // Button texts (must not be more than 10 characters!): { "Edit", "Editieren", "Uredi", "Modifica", + "Verander", }, { "New", "Neu", "Novo", "Nuovo", + "Nieuw", }, { "Delete", "Löschen", "Odstrani", "Cancella", + "Verwijder", }, { "Mark", "Markieren", "Oznaci", "Marca", + "Verplaats", }, { "Record", "Aufnehmen", "Posnemi", "Registra", + "Opnemen", }, { "Play", "Wiedergabe", "Predavajaj", "Riproduci", + "Afspelen", }, { "Rewind", "Anfang", "Zacetek", "Da inizio", + "Spoel terug", }, { "Resume", "Weiter", "Nadaljuj", "Riprendi", + "Verder", }, { "Summary", "Inhalt", "Vsebina", "Sommario", + "Inhoud", }, { "Switch", "Umschalten", "Preklopi", "Cambia", + "Selecteer", }, { "Now", "Jetzt", "Sedaj", "Adesso", + "Nu", }, { "Next", "Nächste", "Naslednji", "Prossimo", + "Hierna", }, { "Schedule", "Programm", "Urnik", "Programma", + "Programma", }, // Confirmations: { "Delete channel?", "Kanal löschen?", "Odstrani kanal?", "Cancello il canale?", + "Kanaal verwijderen?", }, { "Delete timer?", "Timer löschen?", "Odstani termin?", "Cancello il timer?", + "Timer verwijderen?", }, { "Delete recording?", "Aufzeichnung löschen?", "Odstrani posnetek?", "Cancello la registrazione?", + "Opname verwijderen?", }, { "Stop recording?", "Aufzeichnung beenden?", "Koncaj snemanje?", "Fermo la registrazione?", + "Opname stoppen?", }, { "Cancel editing?", "Schneiden abbrechen?", "Zelite prekiniti urejanje?", "Annullo la modifica?", + "Bewerken afbreken?", }, // Channel parameters: { "Name", "Name", "Naziv", "Nome", + "Naam", }, { "Frequency", "Frequenz", "Frekvenca", "Frequenza", + "Frequentie", }, { "Polarization", "Polarisation", "Polarizacija", "Polarizzazione", + "Polarisatie", }, { "Diseqc", "Diseqc", "Diseqc", "Diseqc", + "Diseqc", }, { "Srate", "Srate", "Srate", "Srate", + "Srate", }, { "Vpid", "Vpid", "Vpid", "Vpid", + "Vpid", }, { "Apid", "Apid", "Apid", "Apid", + "Apid", }, { "Tpid", "Tpid", "Tpid", "Tpid", + "Tpid", }, { "CA", "CA", "CA", "CA", + "CA", }, { "Pnr", "Pnr", "Pnr", "Pnr", + "Pnr", }, // Timer parameters: { "Active", "Aktiv", "Aktivno", "Attivo", + "Actief", }, { "Channel", "Kanal", "Kanal", "Canale", + "Kanaal", }, { "Day", "Tag", "Dan", "Giorno", + "Dag", }, { "Start", "Anfang", "Zacetek", "Inizio", + "Begin", }, { "Stop", "Ende", "Konec", "Fine", + "Einde", }, { "Priority", "Priorität", "Prioriteta", "Priorita", + "Prioriteit", }, { "Lifetime", "Lebensdauer", "Veljavnost", "Durata", + "Bewaarduur", }, { "File", "Datei", "Datoteka", "Nome", + "Filenaam", }, // Error messages: { "Channel is being used by a timer!", "Kanal wird von einem Timer benutzt!", "Urnik zaseda kanal!", "Canale occupato da un timer!", + "Kanaal wordt gebruikt door een timer!", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", "Ne morem preklopiti kanala!", "Impossibile cambiare canale!", + "Kan geen kanaal wisselen!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", "Snemanje po urniku!", "Registrazione di un timer in corso!", + "Timer is aan het opnemen!", }, { "Error while deleting recording!", "Fehler beim Löschen der Aufzeichnung!", "Napaka pri odstranjevanju posnetka!", "Errore durante la canc del filmato!", + "Fout bij verwijderen opname!", }, { "*** Invalid Channel ***", "*** Ungültiger Kanal ***", "*** Neznan kanal ***", "*** CANALE INVALIDO ***", + "*** Ongeldig kanaal ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", "Ni proste DVB naprave za snemanje!", "Nessuna card DVB disp per registrare!", + "Geen vrije DVB kaart om op te nemen!", }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", "Zaklenjen kanal (snemanje)!", "Canale bloccato (in registrazione)!", + "Kanaal geblokkeerd (neemt op)!", }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", "Ne morem zaceti urejanja!", "Imposs iniziare processo di modifica", + "Kan niet beginnen met bewerken!", }, { "Editing process already active!", "Schnitt bereits aktiv!", "Urejanje je ze aktivno!", "Processo di modifica gia` attivo", + "Bewerken is al actief!", }, // Setup parameters: { "OSD-Language", "OSD-Sprache", "OSD-jezik", "Linguaggio OSD", + "OSD-taal", }, { "PrimaryDVB", "Primäres Interface", "Primarna naprava", "Scheda DVB primaria", + "Eerste DVB kaart", }, { "ShowInfoOnChSwitch", "Info zeigen", "Pokazi naziv kanala", "Vis info nel cambio canale", + "Kanaal info tonen", }, { "MenuScrollPage", "Seitenweise scrollen", "Drsni meni", "Scrolla pagina nel menu", + "Scrollen per pagina", }, { "MarkInstantRecord", "Direktaufz. markieren", "Oznaci direktno snemanje", "Marca la registrazione", + "Direkte opnamen markeren", }, { "LnbFrequLo", "Untere LNB-Frequenz", "Spodnja LNB-frek.", "Freq LO LNB", + "Laagste LNB frequentie", }, { "LnbFrequHi", "Obere LNB-Frequenz", "Zgornja LNB-frek.", "Freq HI LNB", + "Hoogste LNB frequentie", }, { "SetSystemTime", "Systemzeit stellen", "Sistemski cas", "Setta orario auto", + "Systeem klok instellen", }, { "MarginStart", "Zeitpuffer bei Anfang", "Premor pred zacetkom", "Min margine inizio", + "Tijd marge (begin)", }, { "MarginStop", "Zeitpuffer bei Ende", "Premor za koncem", "Min margine fine", + "Tijd marge (eind)", }, { "EPGScanTimeout", "Zeit bis EPG Scan", "Cas do EPG pregleda", "Timeout EPG", + "EPG-scan Timeout", }, { "SVDRPTimeout", "SVDRP Timeout", "", // TODO "Timeout SVDRP", + "SVDRP Timeout", }, { "PrimaryLimit", "Primär-Limit", "", // TODO "", // TODO + "", // TODO }, // The days of the week: { "MTWTFSS", "MDMDFSS", "PTSCPSN", "DLMMGVS", + "MDWDVZZ", }, // Learning keys: { "Learning Remote Control Keys", "Fernbedienungs-Codes lernen", "Ucim se kod upravljalca", "Apprendimento tasti unita` remota", + "Leren toetsen afstandsbediening", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", "Faza 1: Sprejemanje IR kode", "Fase 1: tipo ricevitore RC", + "Fase 1: detecteren type afstandsbediening", }, { "Press any key on the RC unit", "Eine Taste auf der FB drücken", "Pritisnite tipko na upravljalcu", "Premere un tasto nell'unita` RC", + "Druk op een willekeurige knop", }, { "RC code detected!", "FB Code erkannt!", "IR koda sprejeta!", "Codice RC rilevato!", + "Afstandsbediening code herkend!", }, { "Do not press any key...", "Keine Taste drücken...", "Ne pritiskajte tipk...", "Non premere alcun tasto...", + "Druk niet op een knop...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", "Faza 2: Ucenje posebnih kod", "Fase 2: Codici specifici dei tasti", + "Fase 2: Leren specifieke toets-codes", }, { "Press key for '%s'", "Taste für '%s' drücken", "Pritisnite tipko za '%s'", "Premere il tasto per '%s'", + "Druk knop voor '%s'", }, { "Press 'Up' to confirm", "'Auf' drücken zum Bestätigen", "Pritisnite tipko 'Gor' za potrditev", "Premere 'Su' per confermare", + "Druk 'Omhoog' om te bevestigen", }, { "Press 'Down' to continue", "'Ab' drücken zum Weitermachen", "Pritisnite tipko 'Dol' za nadaljevanje", "Premere 'Giu' per confermare", + "Druk 'Omlaag' om verder te gaan", }, { "(press 'Up' to go back)", "('Auf' drücken um zurückzugehen)", "(pritisnite 'Gor' za nazaj)", "(premere 'Su' per tornare indietro)", + "(druk 'Omhoog' om terug te gaan)", }, { "(press 'Down' to end key definition)", - "('Ab' drücken zum Beenden", + "('Ab' drücken zum Beenden)", "(pritisnite 'Dol' za konec)", "('Giu' per finire la definiz tasti)", + "(Druk 'Omlaag' om te beeindigen)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", "Faza 3: Shranjujem kodo", "Fase 3: Salvataggio key codes", + "Fase 3: Opslaan toets codes", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", "'Gor' za potrditev, 'Dol' za prekinitev", "'Su' per salvare, 'Giu' per annullare", + "'Omhoog' te bewaren, 'Omlaag' voor annuleren", }, // Key names: { "Up", "Auf", "Gor", "Su", + "Omhoog", }, { "Down", "Ab", "Dol", "Giu", + "Omlaag", }, { "Menu", "Menü", "Meni", "Menu", + "Menu", }, { "Ok", "Ok", "Ok", "Ok", + "Ok", }, { "Back", "Zurück", "Nazaj", "Indietro", + "Terug", }, { "Left", "Links", "Levo", "Sinistra", + "Links", }, { "Right", "Rechts", "Desno", "Destra", + "Rechts", }, { "Red", "Rot", "Rdeca", "Rosso", + "Rood", }, { "Green", "Grün", "Zelena", "Verde", + "Groen", }, { "Yellow", "Gelb", "Rumena", "Giallo", + "Geel", }, { "Blue", "Blau", "Modra", "Blu", + "Blauw", }, // Miscellaneous: { "yes", "ja", "da", "si", + "ja", }, { "no", "nein", "ne", "no", - }, - { "Stop replaying", - "Wiedergabe beenden", - "Prekini ponavljanje", - "Interrompi riproduzione", - }, - { "Stop recording ", // note the trailing blank! - "Aufzeichnung beenden ", - "Prekini shranjevanje ", - "Interrompi registrazione ", - }, - { "Cancel editing", - "Schneiden abbrechen", - "Prekini urejanje", - "Annulla modifiche", + "nee", + }, + { " Stop replaying", // note the leading blank! + " Wiedergabe beenden", + " Prekini ponavljanje", + " Interrompi riproduzione", + " Stop afspelen", + }, + { " Stop recording ", // note the leading and trailing blanks! + " Aufzeichnung beenden ", + " Prekini shranjevanje ", + " Interrompi registrazione ", + " Stop opnemen ", + }, + { " Cancel editing", // note the leading blank! + " Schneiden abbrechen", + " Prekini urejanje", + " Annulla modifiche", + " Bewerken afbreken", }, { "Switching primary DVB...", "Primäres Interface wird umgeschaltet...", "Preklapljanje primarne naprave...", "Cambio su card DVB primaria...", + "Eerste DVB-kaart wordt omgeschakeld...", }, { "Up/Dn for new location - OK to move", "Auf/Ab für neue Position - dann OK", "Gor/Dol za novo poz. - Ok za premik", "Su/Giu per nuova posizione - OK per muovere", + "Gebruik Omhoog/Omlaag - daarna Ok", }, { "Editing process started", "Schnitt gestartet", "Urejanje se je zacelo", "Processo di modifica iniziato", + "Bewerken is gestart", }, { NULL } }; @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.68 2001/02/24 14:53:40 kls Exp $ + * $Id: menu.c 1.70 2001/03/18 10:16:56 kls Exp $ */ #include "menu.h" @@ -1425,23 +1425,27 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { case kRed: return Record(); - 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 kGreen: if (schedules) { + 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: if (schedules) + return AddSubMenu(new cMenuWhatsOn(schedules, false, cMenuWhatsOn::CurrentChannel())); + break; + case kBlue: if (Count()) + return Switch(); + break; case kOk: if (Count()) return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo, otherChannel)); break; @@ -1688,7 +1692,7 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) // --- cMenuMain ------------------------------------------------------------- -#define STOP_RECORDING tr("Stop recording ") +#define STOP_RECORDING tr(" Stop recording ") static const char *hk(int n, const char *s) { diff --git a/recording.c b/recording.c index d6e5a33..fc0daa5 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.28 2001/02/18 16:14:05 kls Exp $ + * $Id: recording.c 1.29 2001/03/31 09:38:30 kls Exp $ */ #define _GNU_SOURCE @@ -206,6 +206,7 @@ cRecording::cRecording(const char *FileName) if (p) { time_t now = time(NULL); struct tm t = *localtime(&now); // this initializes the time zone in 't' + t.tm_isdst = -1; // makes sure mktime() will determine the correct dst setting if (7 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &priority, &lifetime)) { t.tm_year -= 1900; t.tm_mon--; @@ -0,0 +1,173 @@ +/* + * remux.c: A streaming MPEG2 remultiplexer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: remux.c 1.1 2001/03/31 08:42:17 kls Exp $ + */ + +/* The calling interface of the 'cRemux::Process()' function is defined + as follows: + + 'Data' points to a chunk of data that consists of 'Count' bytes. + The 'Process' function shall try to remultiplex as much of the + data as possible and return a pointer to the resulting buffer. + That buffer typically is different from the incoming 'Data', + but in the simplest case (when 'Process' does nothing) might + as well point to the original 'Data'. When returning, 'Count' + shall be set to the number of bytes that have been processed + (i.e. have been taken from 'Data'), while 'Result' indicates + how many bytes the returned buffer contains. 'PictureType' shall + be set to NO_PICTURE if the returned data does not start a new + picture, or one of I_FRAME, P_FRAME or B_FRAME if a new picture + starting point has been found. This also means that the returned + data buffer may contain at most one entire video frame, because + the next frame must be returned with its own value for 'PictureType'. + + 'Process' shall do it's best to keep the latency time as short + as possible in order to allow a quick start of VDR's "Transfer + mode" (displaying the signal of one DVB card on another card). + In order to do that, this function may decide to first pass + through the incoming data (almost) unprocessed, and make + actual processing kick in after a few seconds (if that is at + all possible for the algorithm). This may result in a non- + optimal stream at the beginning, which won't matter for normal + recordings but may make switching through encrypted channels + in "Transfer mode" faster. + + In the resulting data stream, a new packet shall always be started + when a frame border is encountered. VDR needs this in order to + be able to detect and store the frame indexes, and to easily + display single frames in fast forward/back mode. The very first + data block returned shall be the starting point of an I_FRAME. + Everything before that shall be silently dropped. + + If the incoming data is not enough to do remultiplexing, a value + of NULL shall be returned ('Result' has no meaning then). This + will tell the caller to wait for more data to be presented in + the next call. If NULL is returned and 'Count' is not 0, the + caller shall remove 'Count' bytes from the beginning of 'Data' + before the next call. This is the way 'Process' indicates that + it must skip that data. + + Any data that is not used during this call will appear at the + beginning of the incoming 'Data' buffer at the next call, plus + any new data that has become available. + + It is guaranteed that the caller will completely process any + returned data before the next call to 'Process'. That way, 'Process' + can dynamically allocate its return buffer and be sure the caller + doesn't keep any pointers into that buffer. +*/ + +#include "remux.h" +#include "tools.h" + +#if defined(REMUX_NONE) + +cRemux::cRemux(void) +{ + synced = false; +} + +cRemux::~cRemux() +{ +} + +int cRemux::GetPacketLength(const uchar *Data, int Count, int Offset) +{ + // Returns the entire length of the packet starting at offset, or -1 in case of error. + return (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1; +} + +int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType) +{ + // Scans the video packet starting at Offset and returns its length. + // If the return value is -1 the packet was not completely in the buffer. + + int Length = GetPacketLength(Data, Count, Offset); + if (Length > 0 && Offset + Length <= Count) { + int i = Offset + 8; // the minimum length of the video packet header + i += Data[i] + 1; // possible additional header bytes + for (; i < Offset + Length; i++) { + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { + switch (Data[i + 3]) { + case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07; + return Length; + } + } + } + PictureType = NO_PICTURE; + return Length; + } + return -1; +} + +const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar &PictureType) +{ + int Skip = 0; + + PictureType = NO_PICTURE; + + if (Count >= MINVIDEODATA) { + for (int i = 0; i < Count; i++) { + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { + switch (Data[i + 3]) { + case SC_VIDEO: + { + uchar pt = NO_PICTURE; + int l = ScanVideoPacket(Data, Count, i, pt); + if (l < 0) { + if (Skip < Count) + Count = Skip; + return NULL; // 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); + } + else if (PictureType == NO_PICTURE) { + if (!synced) { + if (pt == I_FRAME) { + Skip = i; + synced = true; + } + else { + i += l; + Skip = i; + break; + } + } + if (synced) + PictureType = pt; + } + else { + Count = i; + Result = i - Skip; + return Data + Skip; + } + } + else if (!synced) { + i += l; + Skip = i; + break; + } + i += l - 1; // -1 to compensate for i++ in the loop! + } + break; + case SC_AUDIO: + i += GetPacketLength(Data, Count, i) - 1; // -1 to compensate for i++ in the loop! + break; + } + } + } + } + if (Skip < Count) + Count = Skip; + return NULL; // no useful data found, wait for more +} + +#elif defined(REMUX_TEST) +#endif + @@ -0,0 +1,51 @@ +/* + * remux.h: A streaming MPEG2 remultiplexer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: remux.h 1.1 2001/03/31 08:42:27 kls Exp $ + */ + +#ifndef __REMUX_H +#define __REMUX_H + +// There are various experiments with different types of remultiplexers +// going on at the moment. Select the remultiplexer here: +#define REMUX_NONE 1 +//#define REMUX_TEST 1 + +// Picture types: +#define NO_PICTURE 0 +#define I_FRAME 1 +#define P_FRAME 2 +#define B_FRAME 3 + +// Start codes: +#define SC_PICTURE 0x00 // "picture header" +#define SC_SEQU 0xB3 // "sequence header" +#define SC_PHEAD 0xBA // "pack header" +#define SC_SHEAD 0xBB // "system header" +#define SC_AUDIO 0xC0 +#define SC_VIDEO 0xE0 + +// The minimum amount of video data necessary to identify frames: +#define MINVIDEODATA (256*1024) // just a safe guess (max. size of any frame block, plus some safety) + +typedef unsigned char uchar; + +class cRemux { +private: +#if defined(REMUX_NONE) + bool synced; + int GetPacketLength(const uchar *Data, int Count, int Offset); + int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); +#elif defined(REMUX_TEST) +#endif +public: + cRemux(void); + ~cRemux(); + const uchar *Process(const uchar *Data, int &Count, int &Result, uchar &PictureType); + }; + +#endif // __REMUX_H diff --git a/ringbuffer.c b/ringbuffer.c new file mode 100644 index 0000000..4870713 --- /dev/null +++ b/ringbuffer.c @@ -0,0 +1,170 @@ +/* + * ringbuffer.c: A threaded ring buffer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * Parts of this file were inspired by the 'ringbuffy.c' from the + * LinuxDVB driver (see linuxtv.org). + * + * $Id: ringbuffer.c 1.1 2001/03/10 17:11:34 kls Exp $ + */ + +#include "ringbuffer.h" +#include "tools.h" + +// --- cRingBufferInputThread ------------------------------------------------- + +class cRingBufferInputThread : public cThread { +private: + cRingBuffer *ringBuffer; +protected: + virtual void Action(void) { ringBuffer->Input(); } +public: + cRingBufferInputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; } + }; + +// --- cRingBufferOutputThread ------------------------------------------------ + +class cRingBufferOutputThread : public cThread { +private: + cRingBuffer *ringBuffer; +protected: + virtual void Action(void) { ringBuffer->Output(); } +public: + cRingBufferOutputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; } + }; + +// --- cRingBuffer ------------------------------------------------------------ + +cRingBuffer::cRingBuffer(int Size) +{ + size = Size; + buffer = NULL; + inputThread = NULL; + outputThread = NULL; + maxFill = 0; + busy = false; + if (size > 1) { // 'size - 1' must not be 0! + buffer = new uchar[size]; + if (!buffer) + esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); + Clear(); + } + else + esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", size); +} + +cRingBuffer::~cRingBuffer() +{ + delete inputThread; + delete outputThread; + delete buffer; + dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); +} + +void cRingBuffer::Clear(void) +{ + mutex.Lock(); + head = tail = 0; + mutex.Unlock(); +} + +int cRingBuffer::Put(const uchar *Data, int Count) +{ + if (Count > 0) { + mutex.Lock(); + int rest = size - head; + int diff = tail - head; + mutex.Unlock(); + int free = (diff > 0) ? diff - 1 : size + diff - 1; + // Statistics: + int fill = size - free - 1 + Count; + if (fill >= size) + fill = size - 1; + if (fill > maxFill) { + maxFill = fill; + int percent = maxFill * 100 / (size - 1); + if (percent > 75) + dsyslog(LOG_INFO, "buffer usage: %d%%", percent); + } + // + if (free <= 0) + return 0; + if (free < Count) + Count = free; + if (Count > maxFill) + maxFill = Count; + if (Count >= rest) { + memcpy(buffer + head, Data, rest); + if (Count - rest) + memcpy(buffer, Data + rest, Count - rest); + head = Count - rest; + } + else { + memcpy(buffer + head, Data, Count); + head += Count; + } + } + return Count; +} + +int cRingBuffer::Get(uchar *Data, int Count) +{ + if (Count > 0) { + mutex.Lock(); + int rest = size - tail; + int diff = head - tail; + mutex.Unlock(); + int cont = (diff >= 0) ? diff : size + diff; + if (rest <= 0) + return 0; + if (cont < Count) + Count = cont; + if (Count >= rest) { + memcpy(Data, buffer + tail, rest); + if (Count - rest) + memcpy(Data + rest, buffer, Count - rest); + tail = Count - rest; + } + else { + memcpy(Data, buffer + tail, Count); + tail += Count; + } + } + return Count; +} + +bool cRingBuffer::Start(void) +{ + if (!busy) { + busy = true; + outputThread = new cRingBufferOutputThread(this); + if (!outputThread->Start()) + DELETENULL(outputThread); + inputThread = new cRingBufferInputThread(this); + if (!inputThread->Start()) { + DELETENULL(inputThread); + DELETENULL(outputThread); + } + busy = outputThread && inputThread; + } + return busy; +} + +bool cRingBuffer::Active(void) +{ + return outputThread && outputThread->Active() && inputThread && inputThread->Active(); +} + +void cRingBuffer::Stop(void) +{ + busy = false; + for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) { + if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active()))) + break; + } + DELETENULL(inputThread); + DELETENULL(outputThread); +} + diff --git a/ringbuffer.h b/ringbuffer.h new file mode 100644 index 0000000..1669a49 --- /dev/null +++ b/ringbuffer.h @@ -0,0 +1,55 @@ +/* + * ringbuffer.h: A threaded ring buffer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: ringbuffer.h 1.1 2001/03/10 14:00:59 kls Exp $ + */ + +#ifndef __RINGBUFFER_H +#define __RINGBUFFER_H + +#include "thread.h" + +typedef unsigned char uchar; + +class cRingBufferInputThread; +class cRingBufferOutputThread; + +class cRingBuffer { + friend class cRingBufferInputThread; + friend class cRingBufferOutputThread; +private: + cRingBufferInputThread *inputThread; + cRingBufferOutputThread *outputThread; + cMutex mutex; + int size, head, tail; + uchar *buffer; + int maxFill; + bool busy; +protected: + bool Busy(void) { return busy; } + void Clear(void); + // Immediately clears the ring buffer. + int Put(const uchar *Data, int Count); + // Puts at most Count bytes of Data into the ring buffer. + // Returns the number of bytes actually stored. + int Get(uchar *Data, int Count); + // Gets at most Count bytes of Data from the ring buffer. + // Returns the number of bytes actually retrieved. + virtual void Input(void) = 0; + // Runs as a separate thread and shall continuously read data from + // a source and call Put() to store the data in the ring buffer. + virtual void Output(void) = 0; + // Runs as a separate thread and shall continuously call Get() to + // retrieve data from the ring buffer and write it to a destination. +public: + cRingBuffer(int Size); + virtual ~cRingBuffer(); + bool Start(void); + bool Active(void); + void Stop(void); + }; + +#endif // __RINGBUFFER_H @@ -1,13 +1,18 @@ #!/bin/sh -DVBDIR='../DVB/driver' -VDRCMD='./vdr -w 60' +DVBDIR="../DVB/driver" +VDRPRG="./vdr" +VDRCMD="$VDRPRG -w 60" -while test 1; do +KILLPROC="/sbin/killproc -TERM" + +while (true) do # (cd $DVBDIR; make reload) # sleep 3 - if $VDRCMD; then exit; fi + $VDRCMD + if test $? -ne 1; then exit; fi date echo "restarting VDR" + $KILLPROC $VDRPRG sleep 10 done @@ -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.14 2001/02/18 14:18:13 kls Exp $ + * $Id: svdrp.c 1.18 2001/04/01 16:06:54 kls Exp $ */ #define _GNU_SOURCE @@ -113,7 +113,6 @@ int cSocket::Accept(void) // --- cSVDRP ---------------------------------------------------------------- -#define MAXCMDBUFFER 10000 #define MAXHELPTOPIC 10 const char *HelpPages[] = { @@ -138,6 +137,8 @@ const char *HelpPages[] = { " List channels. Without option, all channels are listed. Otherwise\n" " only the given channel is listed. If a name is given, all channels\n" " containing the given string as part of their name are listed.", + "LSTE\n" + " List EPG data.", "LSTT [ <number> ]\n" " List timers. Without option, all timers are listed. Otherwise\n" " only the given timer is listed.", @@ -188,6 +189,7 @@ const char *HelpPages[] = { /* SVDRP Reply Codes: 214 Help message + 215 EPG data record 220 VDR service ready 221 VDR service closing transmission channel 250 Requested VDR action okay, completed @@ -234,6 +236,7 @@ const char *GetHelpPage(const char *Cmd) cSVDRP::cSVDRP(int Port) :socket(Port) { + numChars = 0; message = NULL; lastActivity = 0; isyslog(LOG_INFO, "SVDRP listening on port %d", Port); @@ -470,13 +473,24 @@ void cSVDRP::CmdHELP(const char *Option) Reply(-214, "This is VDR version %s", VDRVERSION); Reply(-214, "Topics:"); const char **hp = HelpPages; + int NumPages = 0; while (*hp) { - //TODO multi-column??? - const char *topic = GetHelpTopic(*hp); - if (topic) - Reply(-214, " %s", topic); + NumPages++; hp++; } + const int TopicsPerLine = 5; + int x = 0; + for (int y = 0; (y * TopicsPerLine + x) < NumPages; y++) { + char buffer[TopicsPerLine * (MAXHELPTOPIC + 5)]; + char *q = buffer; + for (x = 0; x < TopicsPerLine && (y * TopicsPerLine + x) < NumPages; x++) { + const char *topic = GetHelpTopic(HelpPages[(y * TopicsPerLine + x)]); + if (topic) + q += sprintf(q, " %s", topic); + } + x = 0; + Reply(-214, buffer); + } Reply(-214, "To report bugs in the implementation send email to"); Reply(-214, " vdr-bugs@cadsoft.de"); } @@ -535,7 +549,7 @@ void cSVDRP::CmdLSTC(const char *Option) Reply(250, "%d %s", next->number, next->ToText()); } } - else { + else if (Channels.MaxNumber() >= 1) { for (int i = 1; i <= Channels.MaxNumber(); i++) { cChannel *channel = Channels.GetByNumber(i); if (channel) @@ -544,6 +558,27 @@ void cSVDRP::CmdLSTC(const char *Option) Reply(501, "Channel \"%d\" not found", i); } } + else + Reply(550, "No channels defined"); +} + +void cSVDRP::CmdLSTE(const char *Option) +{ + cThreadLock ThreadLock; + const cSchedules *Schedules = cDvbApi::PrimaryDvbApi->Schedules(&ThreadLock); + if (Schedules) { + FILE *f = fdopen(file, "w"); + if (f) { + Schedules->Dump(f, "215-"); + fflush(f); + Reply(215, "End of EPG data"); + // don't 'fclose(f)' here! + } + else + Reply(451, "Can't open file connection"); + } + else + Reply(451, "Can't get EPG data"); } void cSVDRP::CmdLSTT(const char *Option) @@ -559,7 +594,7 @@ void cSVDRP::CmdLSTT(const char *Option) else Reply(501, "Error in timer number \"%s\"", Option); } - else { + else if (Timers.Count()) { for (int i = 0; i < Timers.Count(); i++) { cTimer *timer = Timers.Get(i); if (timer) @@ -568,6 +603,8 @@ void cSVDRP::CmdLSTT(const char *Option) Reply(501, "Timer \"%d\" not found", i + 1); } } + else + Reply(550, "No timers defined"); } void cSVDRP::CmdMESG(const char *Option) @@ -838,7 +875,8 @@ void cSVDRP::Execute(char *Cmd) char *s = Cmd; while (*s && !isspace(*s)) s++; - *s++ = 0; + if (*s) + *s++ = 0; if (CMD("CHAN")) CmdCHAN(s); else if (CMD("DELC")) CmdDELC(s); else if (CMD("DELT")) CmdDELT(s); @@ -846,6 +884,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("HELP")) CmdHELP(s); else if (CMD("HITK")) CmdHITK(s); else if (CMD("LSTC")) CmdLSTC(s); + else if (CMD("LSTE")) CmdLSTE(s); else if (CMD("LSTT")) CmdLSTT(s); else if (CMD("MESG")) CmdMESG(s); else if (CMD("MODC")) CmdMODC(s); @@ -860,8 +899,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("OVLP")) CmdOVLP(s); else if (CMD("OVLO")) CmdOVLO(s); else if (CMD("UPDT")) CmdUPDT(s); - else if (CMD("QUIT") - || CMD("\x04")) Close(); + else if (CMD("QUIT")) Close(); else Reply(500, "Command unrecognized: \"%s\"", Cmd); } @@ -871,29 +909,55 @@ void cSVDRP::Process(void) bool SendGreeting = NewConnection; if (file.IsOpen() || file.Open(socket.Accept())) { - char buffer[MAXCMDBUFFER]; if (SendGreeting) { //TODO how can we get the *full* hostname? + char buffer[MAXCMDBUFFER]; gethostname(buffer, sizeof(buffer)); 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??? - // strip trailing whitespace: - while (rbytes > 0 && strchr(" \t\r\n", buffer[rbytes - 1])) - buffer[--rbytes] = 0; - // make sure the string is terminated: - buffer[rbytes] = 0; - // showtime! - Execute(buffer); - lastActivity = time(NULL); + if (file.Ready(false)) { + unsigned char c; + int r = read(file, &c, 1); + if (r > 0) { + if (c == '\n' || c == 0x00) { + // strip trailing whitespace: + while (numChars > 0 && strchr(" \t\r\n", cmdLine[numChars - 1])) + cmdLine[--numChars] = 0; + // make sure the string is terminated: + cmdLine[numChars] = 0; + // showtime! + Execute(cmdLine); + numChars = 0; + } + else if (c == 0x04 && numChars == 0) { + // end of file (only at beginning of line) + Close(); + } + else if (c == 0x08 || c == 0x7F) { + // backspace or delete (last character) + if (numChars > 0) + numChars--; + } + else if (c <= 0x03 || c == 0x0D || 0xF0 <= c) { + // ignore control characters + } + else if (numChars < sizeof(cmdLine) - 1) { + cmdLine[numChars++] = c; + cmdLine[numChars] = 0; + } + else { + Reply(501, "Command line too long"); + esyslog(LOG_ERR, "SVDRP: command line too long: '%s'", cmdLine); + numChars = 0; + } + lastActivity = time(NULL); + } + else if (r < 0) + Close(); } - else if (rbytes < 0) - Close(); else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) { isyslog(LOG_INFO, "timeout on SVDRP connection"); Close(true); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.7 2001/02/18 13:36:47 kls Exp $ + * $Id: svdrp.h 1.9 2001/04/01 15:05:38 kls Exp $ */ #ifndef __SVDRP_H @@ -26,11 +26,15 @@ public: int Accept(void); }; +#define MAXCMDBUFFER 1024 + class cSVDRP { private: cSocket socket; cFile file; CRect ovlClipRects[MAXCLIPRECTS]; + uint numChars; + char cmdLine[MAXCMDBUFFER]; char *message; time_t lastActivity; void Close(bool Timeout = false); @@ -43,6 +47,7 @@ private: void CmdHELP(const char *Option); void CmdHITK(const char *Option); void CmdLSTC(const char *Option); + void CmdLSTE(const char *Option); void CmdLSTT(const char *Option); void CmdMESG(const char *Option); void CmdMODC(const char *Option); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.30 2001/02/11 14:44:22 kls Exp $ + * $Id: tools.c 1.32 2001/04/01 14:13:36 kls Exp $ */ #define _GNU_SOURCE @@ -369,27 +369,6 @@ void cFile::Close(void) } } -int cFile::ReadString(char *Buffer, int Size) -{ - int rbytes = 0; - bool wait = true; - - while (Ready(wait)) { - int n = read(f, Buffer + rbytes, 1); - if (n == 0) - break; // EOF - if (n < 0) { - LOG_ERROR; - return -1; - } - rbytes += n; - if (rbytes == Size || Buffer[rbytes - 1] == '\n') - break; - wait = false; - } - return rbytes; -} - bool cFile::Ready(bool Wait) { return f >= 0 && AnyFileReady(f, Wait ? 1000 : 0); @@ -519,11 +498,6 @@ cListBase::cListBase(void) cListBase::~cListBase() { Clear(); - while (objects) { - cListObject *object = objects->Next(); - delete objects; - objects = object; - } } void cListBase::Add(cListObject *Object) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.24 2001/02/11 13:39:40 kls Exp $ + * $Id: tools.h 1.25 2001/04/01 14:13:42 kls Exp $ */ #ifndef __TOOLS_H @@ -64,7 +64,6 @@ public: bool Open(int FileDes); void Close(void); bool IsOpen(void) { return f >= 0; } - int ReadString(char *Buffer, int Size); bool Ready(bool Wait = true); static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000); static bool FileReady(int FileDes, int TimeoutMs = 1000); @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.54 2001/02/24 16:18:43 kls Exp $ + * $Id: vdr.c 1.56 2001/04/01 11:16:54 kls Exp $ */ #include <getopt.h> @@ -74,6 +74,7 @@ int main(int argc, char *argv[]) const char *ConfigDirectory = NULL; bool DaemonMode = false; int WatchdogTimeout = DEFAULTWATCHDOG; + char *Terminal = NULL; static struct option long_options[] = { { "config", required_argument, NULL, 'c' }, @@ -84,12 +85,13 @@ int main(int argc, char *argv[]) { "port", required_argument, NULL, 'p' }, { "video", required_argument, NULL, 'v' }, { "watchdog", required_argument, NULL, 'w' }, + { "terminal", required_argument, NULL, 't' }, { 0 } }; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:t:", long_options, &option_index)) != -1) { switch (c) { case 'c': ConfigDirectory = optarg; break; @@ -102,7 +104,7 @@ int main(int argc, char *argv[]) } } fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg); - abort(); + return 2; 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" @@ -117,9 +119,10 @@ int main(int argc, char *argv[]) " 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" + " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" " seconds (default: %d); '0' disables the watchdog\n" + " -t TTY, --terminal=TTY controlling tty\n" "\n" "Report bugs to <vdr-bugs@cadsoft.de>\n", DEFAULTSVDRPPORT, @@ -136,15 +139,17 @@ int main(int argc, char *argv[]) } } fprintf(stderr, "vdr: invalid log level: %s\n", optarg); - abort(); + return 2; break; case 'p': if (isnumber(optarg)) SVDRPport = atoi(optarg); else { fprintf(stderr, "vdr: invalid port number: %s\n", optarg); - abort(); + return 2; } break; + case 't': Terminal = optarg; + break; case 'v': VideoDirectory = optarg; while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') optarg[strlen(optarg) - 1] = 0; @@ -157,9 +162,9 @@ int main(int argc, char *argv[]) } } fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg); - abort(); + return 2; break; - default: abort(); + default: return 2; } } @@ -172,7 +177,7 @@ int main(int argc, char *argv[]) if (!DirectoryOk(VideoDirectory, true)) { fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory); - abort(); + return 2; } // Daemon mode: @@ -183,7 +188,7 @@ int main(int argc, char *argv[]) if (pid < 0) { fprintf(stderr, "%m\n"); esyslog(LOG_ERR, "ERROR: %m"); - abort(); + return 2; } if (pid != 0) return 0; // initial program immediately returns @@ -192,9 +197,16 @@ int main(int argc, char *argv[]) fclose(stderr); #else fprintf(stderr, "vdr: can't run in daemon mode with DEBUG_OSD or REMOTE_KBD on!\n"); - abort(); + return 2; #endif } + else if (Terminal) { + // Claim new controlling terminal + stdin = freopen(Terminal, "r", stdin); + stdout = freopen(Terminal, "w", stdout); + stderr = freopen(Terminal, "w", stderr); + } + isyslog(LOG_INFO, "VDR version %s started", VDRVERSION); // Configuration data: @@ -215,7 +227,7 @@ int main(int argc, char *argv[]) // DVB interfaces: if (!cDvbApi::Init()) - abort(); + return 2; cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); |