Version 1.3.0

- Changed thread handling to make it work with NPTL ("Native Posix Thread Library").
  Thanks to Jon Burgess, Andreas Schultz, Werner Fink and Stefan Huelswitt.
- The cThread class now accepts a 'Description' parameter, which is used to log
  the beginning and end of the thread, together with its process and thread id.
  For descriptions that need additional parameters you can use the function
  cThread::SetDescription(), which accepts 'printf()' like arguments.
  Existing plugins that use threads should be changed to use this functionality
  instead of explicit 'dsyslog()' calls inside their Action() function in order
  to support logging the thread ids.
- Added "Slovak Link" and "Czech Link" to 'ca.conf' (thanks to Emil Petersky).
  However, 'ca.conf' is now pretty much obsolete due to the automatic CA handling.
- Mutexes are now created with PTHREAD_MUTEX_ERRORCHECK_NP, which makes the
  'lockingTid' stuff obsolete (thanks to Stefan Huelswitt).
- Changed font handling to allow language specific character sets.
- Adopted the small font character set from the "Elchi" patch (originally
  provided by Alessio Sangalli).
- Greek language texts now use iso8859-7 character set (thanks to Dimitrios
  Dimitrakos).
- Rearranged section data handling, so that the actual data handling can be done
  separately, even from within plugins.
- The EPG data structures have been moved from eit.[hc] to epg.[hc] and have been
  adapted to the general VDR coding style. Plugins that use these data structures
  may need to change some function names (which should be obvious).
  The name 'subtitle' has been changed to 'shortText' to avoid clashes with actual
  subtitles that are part of a movie. The name 'extendedDescription' has been
  shortened to 'description'.
- Replaced 'libdtv' with 'libsi' (thanks to Marcel Wiesweg), which is thread
  safe and can be used by multiple section filters simultaneously.
- Added 'cRwLock' to 'thread.[hc]'. Note that all plugin Makefiles need to
  define _GNU_SOURCE for this to work (see the example plugin Makefiles and
  'newplugin').
- Fixed a problem with crc32 in SI handling on 64bit systems (thanks to Pedro
  Miguel Sequeira de Justo Teixeira for reporting this one).
- Fixed an alignment problem in CAM access on 64bit systems  (thanks to Pedro
  Miguel Sequeira de Justo Teixeira for reporting this one).
- Added 'StreamType' setting to CAM communication, which is important for
  Aston/SECA CAMs (thanks to Antonino Sergi).
- Now the CA descriptors are sent to the CAM in the 'program' or 'ES level'
  sections, depending on where they are found in the PMT (thanks to Hans-Peter
  Raschke for reporting this one). This should make SkyCrypt CAMs work.
- Now using the 'version number' of EPG events to avoid unnecessary work.
- Channel data is now automatically derived from the DVB data stream (inspired
  by the 'autopid' patch from Andreas Schultz).
- The current channel is now automatically re-tuned if the PIDs or other settings
  change. If a recording is going on on a channel that has a change in its
  settings, the recording will be stopped and immediately restarted to use the
  new channel settings.
- EPG events now use the complete channel ID with NID, TID and SID.
- Channel names in 'channels.conf' can now have a short form, as provided
  by some tv stations (see man vdr(5)). Currently channels that provide short
  names in addition to long ones are listed in the OSD as "short,long name",
  as in "RTL,RTL Television". The short names will be used explicitly later.
- The Ca parameter in 'channels.conf' has been extended and now contains all the
  CA system ids for the given channel. When switching to a channel VDR now tests
  for a device that provides one of these CA system ids. The devices automatically
  get their supported ids from the CI handler.
- The values in 'ca.conf' are currently without any real meaning. Whether or not
  a channel with conditional access can be received is now determined automatically
  by evaluating its CA descriptors and comparing them to the CA system ids
  provided by the installed CAM. Only the special values 1-16 are used to assign
  a channel to a particular device.
- Increased the maximum number of possible OSD colors to 256.
- Limited the line length in the EPG bugfix report, which appears to fix a buffer
  overflow that caused a crash when cleaning up the EPG data (at 05:00 in the
  morning).
This commit is contained in:
Klaus Schmidinger 2004-01-04 18:00:00 +01:00
parent c432905dd6
commit 93a94b18b5
98 changed files with 30394 additions and 9643 deletions

View File

@ -83,6 +83,8 @@ 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)
for reporting that the CA descriptors need to be sent to the CAM in the 'program'
or 'ES level' sections to make SkyCrypt CAMs work
Peter Hofmann <software@pxh.de>
for his support in adapting VDR to DVB-C
@ -177,6 +179,9 @@ Stefan Huelswitt <huels@iname.com>
for fixing an uninitialized variable in cDisplayChannel
for fixing a possible access of invalid file handles in cSIProcessor::Action()
for fixing extracting the ES data in cDvbDevice::StillPicture()
for changing thread handling to make it work with NPTL ("Native Posix Thread Library")
for creating mutexes with PTHREAD_MUTEX_ERRORCHECK_NP, which made the 'lockingTid'
stuff obsolete
Ulrich Röder <roeder@efr-net.de>
for pointing out that there are channels that have a symbol rate higher than
@ -210,6 +215,9 @@ Andreas Schultz <aschultz@warp10.net>
for changing C++ style comments in libdtv into C style to avoid warnings in gcc 3.x
for implementing the TerrestrialDeliverySystemDescriptor in libdtv
for fixing setting the locking pid after a timed wait
for changing thread handling to make it work with NPTL ("Native Posix Thread Library")
for his 'autopid' patch which was helpful when implementing automatic
channel data gathering
Aaron Holtzman
for writing 'ac3dec'
@ -243,6 +251,7 @@ Werner Fink <werner@suse.de>
for replacing the 'for' loops in StripAudioPackets() with memset() calls
for modifying handling of audio packets in cDvbPlayer for better sync with external
AC3 replay
for changing thread handling to make it work with NPTL ("Native Posix Thread Library")
Rolf Hakenes <hakenes@hippomi.de>
for providing 'libdtv' and adapting the EIT mechanisms to it
@ -403,6 +412,7 @@ Simon Dean <linux-dvb@sickhack.com>
Dimitrios Dimitrakos <mail@dimitrios.de>
for translating OSD texts to the Greek language
for fixing handling the LOG_LOCALn parameters in the -l option
for providing the iso8859-7 fonts
Marcus Kuba <marcus@kuba4u.de>
for reporting a bug in the unit of the "SVDRP timeout" setup parameter
@ -636,6 +646,7 @@ Marcel Wiesweg <marcel.wiesweg@gmx.de>
for reporting a problem with cReceivers that want to receive from PIDs that are
currently not transmitting
for fixing volume display in case a plugin has its own OSD open
for providing 'libsi' and adapting the EIT mechanisms to it
Torsten Herz <torsten.herz@web.de>
for fixing a possible deadlock when using the "Blue" button in the "Schedules" menu
@ -762,6 +773,7 @@ Karim Afifi <karim.afifi@free.fr>
Jon Burgess <mplayer@jburgess.uklinux.net>
for pointing out a problem with NPTL ("Native Posix Thread Library")
for changing thread handling to make it work with NPTL ("Native Posix Thread Library")
Thomas Schmidt <thomas.schmidt@in.stud.tu-ilmenau.de>
for reporting a crash when cancelling a newly created timer
@ -862,3 +874,16 @@ Luke Jenkins <a@xmission.com>
Dirk Mueller <dmuell@gmx.net>
for fixing getting the list of recordings in case VDR is started from a directory
where it doesn't have access to
Emil Petersky <petersky@isr.uni-stuttgart.de>
for adding "Slovak Link" and "Czech Link" to 'ca.conf'
Alessio Sangalli <alesan@manoweb.com>
for providing the iso8859-1 small font
Pedro Miguel Sequeira de Justo Teixeira <pedro.miguel.teixeira@bigfoot.com>
for reporting a problem with crc32 in SI handling on 64bit systems
for reporting an alignment problem in CAM access on 64bit systems
Antonino Sergi <voyaser@tiscalinet.it>
for adding 'StreamType' setting to CAM communication

70
HISTORY
View File

@ -2393,7 +2393,7 @@ Video Disk Recorder Revision History
not loaded (suggested by Alexander Wetzel).
- Fixed checking for VIDEO_STREAM_S in cRemux::SetBrokenLink() (thanks to Oliver
Endriss).
- Added 'repeat' function keys '7' and '9' ("jump to mark") in replay mode
- Added 'repeat' function to keys '7' and '9' ("jump to mark") in replay mode
(suggested by Oliver Endriss).
- Made cOsdMenu::Display() virtual, which allows plugins to do some additional
processing after calling the base class function (suggested by Jan Rieger).
@ -2469,3 +2469,71 @@ Video Disk Recorder Revision History
2003-11-14: Version 1.2.6
- Final release of version 1.2.6.
2004-01-04: Version 1.3.0
- Changed thread handling to make it work with NPTL ("Native Posix Thread Library").
Thanks to Jon Burgess, Andreas Schultz, Werner Fink and Stefan Huelswitt.
- The cThread class now accepts a 'Description' parameter, which is used to log
the beginning and end of the thread, together with its process and thread id.
For descriptions that need additional parameters you can use the function
cThread::SetDescription(), which accepts 'printf()' like arguments.
Existing plugins that use threads should be changed to use this functionality
instead of explicit 'dsyslog()' calls inside their Action() function in order
to support logging the thread ids.
- Added "Slovak Link" and "Czech Link" to 'ca.conf' (thanks to Emil Petersky).
However, 'ca.conf' is now pretty much obsolete due to the automatic CA handling.
- Mutexes are now created with PTHREAD_MUTEX_ERRORCHECK_NP, which makes the
'lockingTid' stuff obsolete (thanks to Stefan Huelswitt).
- Changed font handling to allow language specific character sets.
- Adopted the small font character set from the "Elchi" patch (originally
provided by Alessio Sangalli).
- Greek language texts now use iso8859-7 character set (thanks to Dimitrios
Dimitrakos).
- Rearranged section data handling, so that the actual data handling can be done
separately, even from within plugins.
- The EPG data structures have been moved from eit.[hc] to epg.[hc] and have been
adapted to the general VDR coding style. Plugins that use these data structures
may need to change some function names (which should be obvious).
The name 'subtitle' has been changed to 'shortText' to avoid clashes with actual
subtitles that are part of a movie. The name 'extendedDescription' has been
shortened to 'description'.
- Replaced 'libdtv' with 'libsi' (thanks to Marcel Wiesweg), which is thread
safe and can be used by multiple section filters simultaneously.
- Added 'cRwLock' to 'thread.[hc]'. Note that all plugin Makefiles need to
define _GNU_SOURCE for this to work (see the example plugin Makefiles and
'newplugin').
- Fixed a problem with crc32 in SI handling on 64bit systems (thanks to Pedro
Miguel Sequeira de Justo Teixeira for reporting this one).
- Fixed an alignment problem in CAM access on 64bit systems (thanks to Pedro
Miguel Sequeira de Justo Teixeira for reporting this one).
- Added 'StreamType' setting to CAM communication, which is important for
Aston/SECA CAMs (thanks to Antonino Sergi).
- Now the CA descriptors are sent to the CAM in the 'program' or 'ES level'
sections, depending on where they are found in the PMT (thanks to Hans-Peter
Raschke for reporting this one). This should make SkyCrypt CAMs work.
- Now using the 'version number' of EPG events to avoid unnecessary work.
- Channel data is now automatically derived from the DVB data stream (inspired
by the 'autopid' patch from Andreas Schultz).
- The current channel is now automatically re-tuned if the PIDs or other settings
change. If a recording is going on on a channel that has a change in its
settings, the recording will be stopped and immediately restarted to use the
new channel settings.
- EPG events now use the complete channel ID with NID, TID and SID.
- Channel names in 'channels.conf' can now have a short form, as provided
by some tv stations (see man vdr(5)). Currently channels that provide short
names in addition to long ones are listed in the OSD as "short,long name",
as in "RTL,RTL Television". The short names will be used explicitly later.
- The Ca parameter in 'channels.conf' has been extended and now contains all the
CA system ids for the given channel. When switching to a channel VDR now tests
for a device that provides one of these CA system ids. The devices automatically
get their supported ids from the CI handler.
- The values in 'ca.conf' are currently without any real meaning. Whether or not
a channel with conditional access can be received is now determined automatically
by evaluating its CA descriptors and comparing them to the CA system ids
provided by the installed CAM. Only the special values 1-16 are used to assign
a channel to a particular device.
- Increased the maximum number of possible OSD colors to 256.
- Limited the line length in the EPG bugfix report, which appears to fix a buffer
overflow that caused a crash when cleaning up the EPG data (at 05:00 in the
morning).

12
INSTALL
View File

@ -1,19 +1,9 @@
Installation of the Video Disk Recorder
---------------------------------------
Version 1.2
Version 1.3
-----------
IMPORTANT NOTE:
---------------
VDR currently doesn't work with NPTL ("Native Posix Thread Library").
Either don't use NPTL, or set the environment variable
LD_ASSUME_KERNEL=2.4.1
before running VDR.
Compiling and running the program:
----------------------------------

View File

@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: Makefile 1.58 2003/08/09 11:09:45 kls Exp $
# $Id: Makefile 1.62 2003/12/25 13:38:56 kls Exp $
.DELETE_ON_ERROR:
@ -15,7 +15,7 @@ CXX ?= g++
CXXFLAGS ?= -g -O2 -Wall -Woverloaded-virtual
DVBDIR = ../DVB
DTVDIR = ./libdtv
LSIDIR = ./libsi
MANDIR = /usr/local/man
BINDIR = /usr/local/bin
@ -31,16 +31,20 @@ DOXYFILE = Doxyfile
INCLUDES = -I$(DVBDIR)/include
DTVLIB = $(DTVDIR)/libdtv.a
SILIB = $(LSIDIR)/libsi.a
OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\
lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\
dvbplayer.o dvbspu.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
lirc.o menu.o menuitems.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o sources.o\
spu.o status.o svdrp.o thread.o timers.o tools.o transfer.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
FIXFONT_ISO8859_1 = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
OSDFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
SMLFONT_ISO8859_1 = -adobe-helvetica-medium-r-normal--18-*-100-100-p-*-iso8859-1
FIXFONT_ISO8859_7 = --user-medium-r-normal--26-171-110-110-m-140-iso8859-7
OSDFONT_ISO8859_7 = --user-medium-r-normal--23-179-85-85-m-120-iso8859-7
SMLFONT_ISO8859_7 = --user-medium-r-normal--19-160-72-72-m-110-iso8859-7
ifndef NO_KBD
DEFINES += -DREMOTE_KBD
@ -64,7 +68,9 @@ DEFINES += -DVFAT
endif
all: vdr
font: genfontfile fontfix.c fontosd.c
font: genfontfile\
fontfix.c fontosd.c fontsml.c\
fontfix_iso8859_7.c fontosd_iso8859_7.c fontsml_iso8859_7.c
@echo "font files created."
# Implicit rules:
@ -83,25 +89,33 @@ $(DEPFILE): Makefile
# The main program:
vdr: $(OBJS) $(DTVLIB)
$(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr
vdr: $(OBJS) $(SILIB)
$(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(SILIB) -o vdr
# The font files:
fontfix.c:
./genfontfile "cFont::tPixelData FontFix" "$(FIXFONT)" > $@
./genfontfile "cFont::tPixelData FontFix_iso8859_1" "$(FIXFONT_ISO8859_1)" > $@
fontosd.c:
./genfontfile "cFont::tPixelData FontOsd" "$(OSDFONT)" > $@
./genfontfile "cFont::tPixelData FontOsd_iso8859_1" "$(OSDFONT_ISO8859_1)" > $@
fontsml.c:
./genfontfile "cFont::tPixelData FontSml_iso8859_1" "$(SMLFONT_ISO8859_1)" > $@
fontfix_iso8859_1.c:
./genfontfile "cFont::tPixelData FontFix_iso8859_7" "$(FIXFONT_ISO8859_7)" > $@
fontosd_iso8859_1.c:
./genfontfile "cFont::tPixelData FontOsd_iso8859_7" "$(OSDFONT_ISO8859_7)" > $@
fontsml_iso8859_1.c:
./genfontfile "cFont::tPixelData FontSml_iso8859_7" "$(SMLFONT_ISO8859_7)" > $@
# The font file generator:
genfontfile: genfontfile.c
$(CC) $(CFLAGS) -o $@ -L/usr/X11R6/lib $< -lX11
# The libdtv library:
# The libsi library:
$(DTVLIB) $(DTVDIR)/libdtv.h:
$(MAKE) -C $(DTVDIR) all
$(SILIB):
$(MAKE) -C $(LSIDIR) all
# The 'include' directory (for plugins):
@ -140,11 +154,11 @@ srcdoc:
# Housekeeping:
clean:
$(MAKE) -C $(DTVDIR) clean
$(MAKE) -C $(LSIDIR) clean
-rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~
-rm -rf include
-rm -rf srcdoc
fontclean:
-rm -f fontfix.c fontosd.c
-rm -f fontfix*.c fontosd*.c fontsml*.c
CLEAN: clean fontclean

View File

@ -6,7 +6,7 @@
<center><h1>The VDR Plugin System</h1></center>
<center><b>Version 1.2.6</b></center>
<center><b>Version 1.3</b></center>
<p>
<center>
Copyright &copy; 2003 Klaus Schmidinger<br>
@ -14,9 +14,12 @@ Copyright &copy; 2003 Klaus Schmidinger<br>
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
</center>
<p>
<!--X1.1.32--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<!--X1.2.6--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.2.6 are marked like this.
<!--X1.1.32--></td></tr></table>
<!--X1.2.6--></td></tr></table>
<!--X1.3.0--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.0 are marked like this.
<!--X1.3.0--></td></tr></table>
<p>
VDR provides an easy to use plugin interface that allows additional functionality
to be added to the program by implementing a dynamically loadable library file.
@ -64,6 +67,9 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#Status monitor">Status monitor</a>
<li><a href="#Players">Players</a>
<li><a href="#Receivers">Receivers</a>
<!--X1.3.0--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<li><a href="#Filters">Filters</a>
<!--X1.3.0--></td></tr></table>
<li><a href="#The On Screen Display">The On Screen Display</a>
<li><a href="#Devices">Devices</a>
<li><a href="#Dolby Digital">Dolby Digital</a>
@ -112,7 +118,7 @@ No other characters should be used here.
<p>
A plugin can access its name through the (non virtual) member function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
const char *Name(void);
</pre></td></tr></table><p>
@ -127,7 +133,7 @@ By default plugins are located in a directory named <tt>PLUGINS</tt> below the
VDR source directory. Inside this directory the following subdirectory structure
is used:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
VDR/PLUGINS/src
VDR/PLUGINS/src/hello
VDR/PLUGINS/lib
@ -172,7 +178,7 @@ To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>
you need to unpack such an archive into the <tt>VDR/PLUGINS/src</tt> directory and
create a symbolic link with the basic plugin name, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
ln -s hello-0.0.1 hello
</pre></td></tr></table><p>
@ -226,7 +232,7 @@ If your plugin shall not be accessible through VDR's main menu, simply remove
<p>
At the end of the plugin's source file you will find a line that looks like this:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
VDRPLUGINCREATOR(cPluginHello);
</pre></td></tr></table><p>
@ -239,7 +245,7 @@ source directory and adjust the <tt>Makefile</tt> accordingly.
Header files usually contain preprocessor statements that prevent the same
file (or rather its contents, to be precise) from being included more than once, like
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#ifndef __I18N_H
#define __I18N_H
@ -274,7 +280,7 @@ and two replacing the dot).
The constructor and destructor of a plugin are defined as
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
cPlugin(void);
virtual ~cPlugin();
</pre></td></tr></table><p>
@ -304,7 +310,7 @@ Every plugin must have a version number of its own, which does not necessarily
have to be in any way related to the VDR version number.
VDR requests a plugin's version number through a call to the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual const char *Version(void) = 0;
</pre></td></tr></table><p>
@ -315,7 +321,7 @@ information, like for instance "0.0.1pre2" or the like. The string should only
be as long as really necessary, and shall not contain the plugin's name itself.
Here's an example:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
static const char *VERSION = "0.0.1";
const char *cPluginHello::Version(void)
@ -347,13 +353,13 @@ would be acceptable.
In order to tell the user what exactly a plugin does, it must implement the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual const char *Description(void) = 0;
</pre></td></tr></table><p>
which returns a short, one line description of the plugin's purpose:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
static const char *DESCRIPTION = "A friendly greeting";
virtual const char *Description(void)
@ -373,7 +379,7 @@ A VDR plugin can have command line arguments just like any normal program.
If a plugin wants to react on command line arguments, it needs to implement
the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool ProcessArgs(int argc, char *argv[]);
</pre></td></tr></table><p>
@ -390,7 +396,7 @@ these arguments. As with any normal C program, the strings pointed to by <tt>arg
will survive the entire lifetime of the plugin, so it is safe to store pointers to
these values inside the plugin. Here's an example:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
bool cPluginHello::ProcessArgs(int argc, char *argv[])
{
// Implement command line argument processing here if applicable.
@ -425,7 +431,7 @@ to exit.
If a plugin accepts command line options, it should implement the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual const char *CommandLineHelp(void);
</pre></td></tr></table><p>
@ -433,7 +439,7 @@ which will be called if the user enters the <b><tt>-h</tt></b> option when start
The returned string should contain the command line help for this plugin, formatted
in the same way as done by VDR itself:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
const char *cPluginHello::CommandLineHelp(void)
{
// Return a string that describes all known command line options.
@ -456,7 +462,7 @@ If a plugin implements a function that runs in the background (presumably in a
thread of its own), or wants to make use of <a href="#Internationalization">internationalization</a>,
it needs to implement one of the functions
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool Initialize(void);
virtual bool Start(void);
</pre></td></tr></table><p>
@ -493,7 +499,7 @@ texts, it doesn't need to implement either of these functions.
If the plugin implements a feature that the user shall be able to access
from VDR's main menu, it needs to implement the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual const char *MainMenuEntry(void);
</pre></td></tr></table><p>
@ -501,7 +507,7 @@ The default implementation returns a <tt>NULL</tt> pointer, which means that
this plugin will not have an item in the main menu. Here's an example of a
plugin that will have a main menu item:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
static const char *MAINMENUENTRY = "Hello";
const char *cPluginHello::MainMenuEntry(void)
@ -520,7 +526,7 @@ in the call to VDR.
If the user selects the main menu entry of a plugin, VDR calls the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual cOsdObject *MainMenuAction(void);
</pre></td></tr></table><p>
@ -554,7 +560,7 @@ the plugin should launch a separate thread to do this.
From time to time a plugin may want to do some regular tasks, like cleaning
up some files or other things. In order to do this it can implement the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual void Housekeeping(void);
</pre></td></tr></table><p>
@ -579,7 +585,7 @@ the plugin should launch a separate thread to do this.
If a plugin requires its own setup parameters, it needs to implement the following
functions to handle these parameters:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
</pre></td></tr></table><p>
@ -594,7 +600,7 @@ an error. If <i>false</i> is returned, an error message will be written to
the log file (and program execution will continue).
A possible implementation of <tt>SetupParse()</tt> could look like this:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
bool cPluginHello::SetupParse(const char *Name, const char *Value)
{
// Parse your own setup parameters and store their values.
@ -620,7 +626,7 @@ plugins need not worry about this.
<p>
To store its values in the global setup, a plugin has to call the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
void SetupStore(const char *Name, <i>type</i> Value);
</pre></td></tr></table><p>
@ -653,7 +659,7 @@ To implement a <i>Setup</i> menu, a plugin needs to derive a class from
<tt>cMenuSetupPage</tt> and implement its constructor and the pure virtual
<tt>Store()</tt> member function:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
int GreetingTime = 3;
int UseAlternateGreeting = false;
@ -714,7 +720,7 @@ configuration file. While the plugin is free to store such files anywhere it
sees fit, it might be a good idea to put them in a common place, preferably
where other configuration data already exists. VDR provides the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
const char *ConfigDirectory(const char *PluginName = NULL);
</pre></td></tr></table><p>
@ -737,7 +743,7 @@ these in a subdirectory of its own, named after the plugin. To easily get such a
the <tt>ConfigDirectory()</tt> function can be given an additional string that will
be appended to the returned directory name, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
const char *MyConfigDir = ConfigDirectory(Name());
</pre></td></tr></table><p>
@ -754,7 +760,7 @@ The <tt>ConfigDirectory()</tt> function is a static member function of the <tt>c
class. This allows it to be called even from outside any member function of the derived
plugin class, by writing
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
const char *MyConfigDir = cPlugin::ConfigDirectory();
</pre></td></tr></table><p>
@ -765,7 +771,7 @@ const char *MyConfigDir = cPlugin::ConfigDirectory();
If a plugin displays texts to the user, it should implement internationalized
versions of these texts and call the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
void RegisterI18n(const tI18nPhrase * const Phrases);
</pre></td></tr></table><p>
@ -774,7 +780,7 @@ to register them with VDR's internationalization mechanism.
The call to this function must be done in the <a href="#Getting started"><tt>Initialize()</tt></a>
or <a href="#Getting started"><tt>Start()</tt></a> function of the plugin:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
const tI18nPhrase Phrases[] = {
{ "Hello world!",
"Hallo Welt!",
@ -815,7 +821,7 @@ you may want to contact the maintainers of these languages (listed in the file
The actual runtime selection of the texts corresponding to the selected language
is done by wrapping each internationalized text with the <tt>tr()</tt> macro:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
const char *s = tr("Hello world!");
</pre></td></tr></table><p>
@ -833,20 +839,20 @@ core VDR code.
Plugins are loaded into VDR using the command line option <b><tt>-P</tt></b>, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
vdr -Phello
</pre></td></tr></table><p>
If the plugin accepts command line options, they are given as part of the argument
to the <b><tt>-P</tt></b> option, which then has to be enclosed in quotes:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
vdr -P"hello -a abc -b"
</pre></td></tr></table><p>
Any number of plugins can be loaded this way, each with its own <b><tt>-P</tt></b> option:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
vdr -P"hello -a abc -b" -Pdvd -Pmp3
</pre></td></tr></table><p>
@ -854,7 +860,7 @@ If you are not starting VDR from the VDR source directory (and thus your plugins
cannot be found at their default location) you need to tell VDR the location of
the plugins through the <b><tt>-L</tt></b> option:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
vdr -L/usr/lib/vdr -Phello
</pre></td></tr></table><p>
@ -879,14 +885,14 @@ provides the target <tt>dist</tt>, which does this for you.
<p>
Simply change into your source directory and execute <tt>make dist</tt>:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
cd VDR/PLUGINS/src/hello
make dist
</pre></td></tr></table><p>
After this you should find a file named like
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
vdr-hello-0.0.1.tgz
</pre></td></tr></table><p>
@ -902,7 +908,7 @@ plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number.
If a plugin wants to get informed on various events in VDR, it can derive a class from
<tt>cStatus</tt>, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/status.h&gt;
class cMyStatusMonitor : public cStatus {
@ -922,7 +928,7 @@ void cMyStatusMonitor::ChannelSwitch(const cDevice *Device, int ChannelNumber)
An object of this class will be informed whenever the channel is switched on one of
the DVB devices. It could be used in a plugin like this:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/plugin.h&gt;
class cPluginStatus : public cPlugin {
@ -975,7 +981,7 @@ the functions you actually want to use.
Implementing a player is a two step process.
First you need the actual player class, which is derived from the abstract <tt>cPlayer</tt>:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/player.h&gt;
class cMyPlayer : public cPlayer {
@ -991,7 +997,7 @@ What exactly you do in this class is entirely up to you. If you want to run a se
thread which, e.g., reads data from a file, you can additionally derive your class from
<tt>cThread</tt> and implement the necessary functionality:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/player.h&gt;
class cMyPlayer : public cPlayer, cThread {
@ -1009,7 +1015,7 @@ its own player for the VDR recordings.
<p>
To play the video data, the player needs to call its member function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
int PlayVideo(const uchar *Data, int Length);
</pre></td></tr></table><p>
@ -1020,7 +1026,7 @@ desired video data stream, and it must be delivered fast enough so that the
DVB device doesn't run out of data.
To avoid busy loops the player should call its member function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
bool DevicePoll(cPoller &amp;Poller, int TimeoutMs = 0);
</pre></td></tr></table><p>
@ -1029,7 +1035,7 @@ to determine whether the device is ready for further data.
If the player can provide more than a single audio track, it can implement the
following functions to make them available:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual int NumAudioTracks(void) const;
virtual const char **GetAudioTracks(int *CurrentTrack = NULL);
virtual void SetAudioTrack(int Index);
@ -1039,7 +1045,7 @@ virtual void SetAudioTrack(int Index);
If there is an additional audio track that has to be replayed with external hardware,
the player shall call its member function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
void PlayAudio(const uchar *Data, int Length);
</pre></td></tr></table><p>
@ -1048,7 +1054,7 @@ where <tt>Data</tt> points to a complete audio PES packet of <tt>Length</tt> byt
The second part needed here is a control object that receives user input from the main
program loop and reacts on this by telling the player what to do:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/player.h&gt;
class cMyControl : public cControl {
@ -1066,7 +1072,7 @@ public:
hand over a pointer to it to the <tt>cControl</tt> base class, so that it
can be later attached to the primary DVB device:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
cMyControl::cMyControl(void)
:cControl(player = new cMyPlayer)
{
@ -1093,7 +1099,7 @@ Finally, to get things going, a plugin that implements a player (and the surroun
infrastructure like displaying a list of playable stuff etc) simply has to call the
static function <tt>cControl::Launch()</tt> with the player control object, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
cControl::Launch(new cMyControl);
</pre></td></tr></table><p>
@ -1104,7 +1110,7 @@ use the primary DVB device, or the user decides to start a different replay).
<p>
The <tt>cPlayer</tt> class has a member function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
void DeviceStillPicture(const uchar *Data, int Length);
</pre></td></tr></table><p>
@ -1149,7 +1155,7 @@ ahead - it's your show...
In order to receive any kind of data from a <tt>cDevice</tt>, a plugin must set up an
object derived from the <tt>cReceiver</tt> class:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/receiver.h&gt;
class cMyReceiver : public cReceiver, cThread {
@ -1187,7 +1193,7 @@ a <tt>cReceiver</tt> to be detached from its <tt>cDevice</tt> at any time.
Once a <tt>cReceiver</tt> has been created, it needs to be <i>attached</i> to
a <tt>cDevice</tt>:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
cMyReceiver *Receiver = new cMyReceiver(123);
cDevice::ActualDevice()-&gt;AttachReceiver(Receiver);
@ -1201,6 +1207,52 @@ Mode</i>).
If the <tt>cReceiver</tt> isn't needed any more, it may simply be <i>deleted</i>
and will automatically detach itself from the <tt>cDevice</tt>.
<!--X1.3.0--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<a name="Filters"><hr><h2>Filters</h2>
<center><i><b>A Fistful of Datas</b></i></center><p>
If you want to receive section data you have to implement a derived <tt>cFilter</tt>
class which at least implements the <tt>Process()</tt> function and a constructor
that sets the (initial) filter parameters:
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/filter.h&gt;
class cMyFilter : public cFilter {
protected:
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public:
cMyFilter(void);
...
};
cMyFilter::cMyFilter(void)
{
Set(0x14, 0x70); // TDT
}
void cMyFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
// do something with the data here
}
</pre></td></tr></table><p>
An instance of such a filter needs to be attached to the device from
which it shall receive data, as in
<p><table><tr><td bgcolor=#F0F0F0><pre>
cMyFilter Filter;
cDevice::ActualDevice()-&gt;AttachFilter(Filter);
</pre></td></tr></table><p>
If the <tt>cFilter</tt> isn't needed any more, it may simply be <i>deleted</i>
and will automatically detach itself from the <tt>cDevice</tt>.
<p>
See VDR/eit.c or VDR/pat.c to learn how to process filter data.
<!--X1.3.0--></td></tr></table>
<a name="The On Screen Display"><hr><h2>The On Screen Display</h2>
<center><i><b>Express yourself</b></i></center><p>
@ -1213,7 +1265,7 @@ windows and color depths.
If a plugin needs to have total control over the OSD, it can call the
static function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/osd.h&gt;
cOsdBase *MyOsd = cOsd::OpenRaw(x, y);
@ -1223,7 +1275,7 @@ where <tt>x</tt> and <tt>y</tt> are the coordinates of the upper left corner
of the OSD area on the screen. Such a "raw" OSD doesn't display anything
yet, so you need to at least call the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
MyOsd-&gt;Create(...);
</pre></td></tr></table><p>
@ -1247,7 +1299,7 @@ stream and displays it, for instance, on an existing graphics adapter.
<p>
To implement an additional device, a plugin must derive a class from cDevice:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/device.h&gt;
class cMyDevice : public cDevice {
@ -1266,7 +1318,7 @@ the <tt>cDvbDevice</tt>, which is used to access the DVB PCI cards.
If the new device can receive, it most likely needs to provide a way of
selecting which channel it shall tune to:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool ProvidesSource(int Source) const;
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL);
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
@ -1281,7 +1333,7 @@ repectively.
If the device can provide more than a single audio track, it can implement the
following functions to make them available:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual int NumAudioTracksDevice(void) const;
virtual const char **GetAudioTracksDevice(int *CurrentTrack = NULL) const;
virtual void SetAudioTrackDevice(int Index);
@ -1292,7 +1344,7 @@ virtual void SetAudioTrackDevice(int Index);
<p>
A device that can be used for recording must implement the functions
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
virtual bool OpenDvr(void);
virtual void CloseDvr(void);
@ -1308,7 +1360,7 @@ must deliver exactly one such packet (if one is currently available).
If this device allows receiving several different data streams, it can
implement
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool CanBeReUsed(int Frequency, int Vpid);
</pre></td></tr></table><p>
@ -1318,13 +1370,13 @@ to indicate this to VDR.
<p>
The functions to implement replaying capabilites are
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool HasDecoder(void) const;
virtual bool CanReplay(void) const;
virtual bool SetPlayMode(ePlayMode PlayMode);
<!--X1.1.32--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<!--X1.2.6--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
virtual int64_t GetSTC(void);
<!--X1.1.32--></td></tr></table>
<!--X1.2.6--></td></tr></table>
virtual void TrickSpeed(int Speed);
virtual void Clear(void);
virtual void Play(void);
@ -1338,12 +1390,39 @@ virtual int PlayVideo(const uchar *Data, int Length);
In addition, the following functions may be implemented to provide further
functionality:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int Si
virtual void SetVideoFormat(bool VideoFormat16_9);
virtual void SetVolumeDevice(int Volume);
</pre></td></tr></table><p>
<!--X1.3.0--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<p>
<b>Section Filtering</b>
<p>
If your device provides section filtering capabilities it can implement
the function
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
</pre></td></tr></table><p>
which must open a file handle that delivers section data for the given
filter parameters.
<p>
In order to actually start section handling, the
device also needs to call the function
<p><table><tr><td bgcolor=#F0F0F0><pre>
StartSectionHandler();
</pre></td></tr></table><p>
from its constructor.
<p>
See <a href="#Filters">Filters</a> on how to set up actual filters that can
handle section data.
<!--X1.3.0--></td></tr></table>
<p>
<b>On Screen Display</b>
<p>
@ -1351,7 +1430,7 @@ If your device provides On Screen Display (OSD) capabilities (which every device
that is supposed to be used as a primary device should do), it can implement
the function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual cOsdBase *NewOsd(int x, int y);
</pre></td></tr></table><p>
@ -1391,7 +1470,7 @@ audio replay facility.
To implement a new audio output facility, simply derive a class from <tt>cAudio</tt>,
as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/audio.h&gt;
#include &lt;vdr/thread.h&gt;
@ -1435,7 +1514,7 @@ remote control, so a plugin can use the <tt>cRemote</tt> class to do that.
The simplest method for a plugin to issue commands to VDR is to call the
static function <tt>cRemote::Put(eKeys Key)</tt>, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
cRemote::Put(kUp);
</pre></td></tr></table><p>
@ -1447,7 +1526,7 @@ In cases where the incoming codes are not known, or not all available keys may
be supported by the actual remote control in use, you may want to derive your
own remote control class from <tt>cRemote</tt>, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
#include &lt;vdr/remote.h&gt;
#include &lt;vdr/thread.h&gt;
@ -1472,7 +1551,7 @@ when the program ends).
<p>
The constructor of your remote control class should look like this
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
cMyRemote::cMyRemote(const char *Name)
:cRemote(Name)
{
@ -1492,7 +1571,7 @@ member variables, you should do so before calling <tt>Start()</tt>.
If your remote control for some reason can't work (maybe because it was unable to
open some file handle it requires) it can implement the virtual function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual bool Ready(void);
</pre></td></tr></table><p>
@ -1513,7 +1592,7 @@ If your remote control class needs some setup data that shall be
readily available next time VDR starts (without having to go through the initialization
procedure again) it can use the <tt>cRemote</tt> member functions
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
void PutSetup(const char *Setup);
const char *GetSetup(void);
</pre></td></tr></table><p>
@ -1527,7 +1606,7 @@ The <tt>cRemote</tt> class assumes that any incoming remote control code can be
expressed as a character string. So whatever data your remote control provides
needs to be given to the base class by calling
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
Put(const char *Code, bool Repeat = false, bool Release = false);
</pre></td></tr></table><p>
@ -1538,7 +1617,7 @@ Since a common case for remote control data is to be given as a numerical
value, there is another <tt>Put()</tt> function available for your convenience,
which takes a 64 bit unsigned integer value instead of a character string:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
<p><table><tr><td bgcolor=#F0F0F0><pre>
Put(uint64 Code, bool Repeat = false, bool Release = false);
</pre></td></tr></table><p>

View File

@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile 1.8 2002/12/13 14:54:14 kls Exp $
# $Id: Makefile 1.9 2003/12/21 15:47:22 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@ -42,7 +42,7 @@ PACKAGE = vdr-$(ARCHIVE)
INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):

View File

@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile 1.2 2002/12/13 14:54:29 kls Exp $
# $Id: Makefile 1.3 2003/12/21 15:47:26 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@ -42,7 +42,7 @@ PACKAGE = vdr-$(ARCHIVE)
INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):

View File

@ -12,3 +12,7 @@ VDR Plugin 'sky' Revision History
2003-05-09: Version 0.1.1
- Changed Start() to Initialize().
2004-01-04: Version 0.2.0
- Implemented automatic PID switching and channel detection

View File

@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile 1.2 2002/12/13 14:54:24 kls Exp $
# $Id: Makefile 1.3 2003/12/21 15:47:31 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@ -42,7 +42,7 @@ PACKAGE = vdr-$(ARCHIVE)
INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):

View File

@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: sky.c 1.3 2003/05/09 15:27:16 kls Exp $
* $Id: sky.c 1.4 2004/01/04 15:29:15 kls Exp $
*/
#include <sys/socket.h>
@ -14,7 +14,7 @@
#include <vdr/plugin.h>
#include <vdr/sources.h>
static const char *VERSION = "0.1.1";
static const char *VERSION = "0.2.0";
static const char *DESCRIPTION = "Sky Digibox interface";
// --- cDigiboxDevice --------------------------------------------------------
@ -37,6 +37,7 @@ public:
cDigiboxDevice(void);
virtual ~cDigiboxDevice();
virtual bool ProvidesSource(int Source) const;
virtual bool ProvidesTransponder(const cChannel *Channel) const;
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSetChannel = NULL) const;
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
};
@ -137,13 +138,18 @@ bool cDigiboxDevice::ProvidesSource(int Source) const
return source == Source;
}
bool cDigiboxDevice::ProvidesTransponder(const cChannel *Channel) const
{
return false; // can't provide any actual transponder
}
bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
{
bool result = false;
bool hasPriority = Priority < 0 || Priority > this->Priority();
bool needsDetachReceivers = true;
if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
if (ProvidesSource(Channel->Source()) && Channel->Ca() == 0x30) {//XXX
if (Receiving()) {
if (digiboxChannelNumber == Channel->Frequency()) {
needsDetachReceivers = false;

View File

@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile 1.6 2002/12/13 14:54:19 kls Exp $
# $Id: Makefile 1.7 2003/12/21 15:47:41 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@ -42,7 +42,7 @@ PACKAGE = vdr-$(ARCHIVE)
INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):

83
README.developer Normal file
View File

@ -0,0 +1,83 @@
Version 1.3.0 marks the beginning of a new developer version
of VDR, in which I am going to integrate functionality from
patches that have been written by various people for previous
versions of VDR.
IMPORTANT NOTE: Beginning with version 1.3.0, VDR will automatically
=============== modify the 'channels.conf' file. Please run this version
of VDR in a controlled environment only, and work with
copies of all your config files!
This version of VDR focuses on some improvements regarding
CAM support and, most important, the first step towards automatic
PID handling. Some things are still in a raw state, but at least
the program should now dynamically react on any changes in the
channel settings.
Here's a list of the highlights - and what _not_ to expect yet
(but don't worry, these things will come soon ;-):
- Automatic switching when PIDs are changed (e.g. for regional
programmes).
- There is no explicit transponder list yet, so you just
have to define one channel for a new transponder and VDR
will automatically detect all other channels on that transponder.
- New channels are added to the end of the channel list, so
it might be a good idea to add a line like
:@1000 New channels
to have them start at some high number.
- Improved CAM support. Channels with conditional access now automatically
use the device that contains the proper CAM.
- No NVOD or "linked services" support yet.
- No radio support yet.
- No transponder scan yet.
Note that this is currently work in progress, so there may be some
areas that don't work as smooth as expected, yet.
Known issues:
=============
- The Setup/CICAM menu is currently without much meaning.
CA detection is done automatically.
- The channel "EURO1080" on Astra 19.2E currently broadcasts HDTV
test signals. Unfortunately, the full featured DVB cards crash
pretty ugly when tuned to that channel, so it might be a good idea
to have the channel definition
EURO1080:12168:v:S19.2E:27500:308:256:0:FF:21100:1:1088:0
in your 'channels.conf' file. Note the Ca parameter 'F' (255 in hex),
which gives this channel a non-existent Ca mode, so that it won't
be tuned to at all. If you really want to tune to this channel for
tests, do it on your own risk.
- The 'sky' plugin now temporarily uses Ca value 30 (this will be changed
later).
- Since the CA detection is now done automatically, a timer that starts
immediately after VDR has been launched and wants to record a CA channel
may not work. This will be changed later to make this work safely.
What to test:
=============
Apart from the usual general functionality, special attention should
be given to the following matters:
- Does the automatic PID switching really work in all cases, especially
in conjunction with conditional access channels?
- Does CAM support work for all kinds of CAMs?
Known bugs:
===========
- Sometimes a new channel is created with the wrong 'source'
parameter. This presumably happens when the transponder and source
are switched, and there is still an SDT data packet being processed.
The call to device->HasLock() in sections.c should fix this (and it
apparently does for most cases), but there must still be soemthing
wrong in that area.
- Sometimes the current channel gets re-tuned even though the channel
data of this channel didn't change (but that of an other channel did
change).

View File

@ -18,6 +18,8 @@
# Cryptoworks
201 GOD-DIGITAL
202 Slovak Link
203 Czech Link
# Videoguard

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: channels.c 1.16 2003/10/17 15:42:40 kls Exp $
* $Id: channels.c 1.17 2004/01/04 12:28:49 kls Exp $
*/
#include "channels.h"
@ -159,6 +159,7 @@ char *cChannel::buffer = NULL;
cChannel::cChannel(void)
{
memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__);
strcpy(name, "Pro7");
frequency = 12480;
source = cSource::FromString("S19.2E");
@ -170,7 +171,7 @@ cChannel::cChannel(void)
dpid1 = 257;
dpid2 = 0;
tpid = 32;
ca = 0;
caids[0] = 0;
nid = 0;
tid = 0;
sid = 888;
@ -186,6 +187,28 @@ cChannel::cChannel(void)
transmission = TRANSMISSION_MODE_AUTO;
guard = GUARD_INTERVAL_AUTO;
hierarchy = HIERARCHY_AUTO;
modification = CHANNELMOD_NONE;
}
cChannel::cChannel(const cChannel *Channel)
{
*this = *Channel;
*name = 0;
vpid = 0;
ppid = 0;
apid1 = 0;
apid2 = 0;
dpid1 = 0;
dpid2 = 0;
tpid = 0;
caids[0] = 0;
nid = 0;
tid = 0;
sid = 0;
rid = 0;
number = 0;
groupSep = false;
modification = CHANNELMOD_NONE;
}
cChannel& cChannel::operator= (const cChannel &Channel)
@ -194,16 +217,117 @@ cChannel& cChannel::operator= (const cChannel &Channel)
return *this;
}
static int MHz(int frequency)
int cChannel::Transponder(void) const
{
while (frequency > 20000)
frequency /= 1000;
return frequency;
int tf = frequency;
while (tf > 20000)
tf /= 1000;
return tf;
}
tChannelID cChannel::GetChannelID(void) const
{
return tChannelID(source, nid, nid ? tid : MHz(frequency), sid, rid);
return tChannelID(source, nid, nid ? tid : Transponder(), sid, rid);
}
int cChannel::Modification(int Mask)
{
int Result = modification & Mask;
modification = CHANNELMOD_NONE;
return Result;
}
void cChannel::SetId(int Nid, int Tid, int Sid, int Rid, bool Log)
{
if (nid != Nid || tid != Tid || sid != Sid || rid != Rid) {
if (Log)
dsyslog("changing id of channel %d from %d-%d-%d-%d to %d-%d-%d-%d", Number(), nid, tid, sid, rid, Nid, Tid, Sid, Rid);
nid = Nid;
tid = Tid;
sid = Sid;
rid = Rid;
modification |= CHANNELMOD_ID;
Channels.SetModified();
}
}
void cChannel::SetName(const char *Name, bool Log)
{
if (!isempty(Name) && strcmp(name, Name) != 0) {
if (Log)
dsyslog("changing name of channel %d from '%s' to '%s'", Number(), name, Name);
strn0cpy(name, Name, MaxChannelName);
modification |= CHANNELMOD_NAME;
Channels.SetModified();
}
}
void cChannel::SetPids(int Vpid, int Ppid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid)
{
//XXX if (vpid != Vpid || ppid != Ppid || apid1 != Apid1 || apid2 != Apid2 || dpid1 != Dpid1 || dpid2 != Dpid2 || tpid != Tpid) {
if (vpid != Vpid || ppid != Ppid || apid1 != Apid1 || (Apid2 && apid2 != Apid2) || dpid1 != Dpid1 || dpid2 != Dpid2 || tpid != Tpid) {
dsyslog("changing pids of channel %d from %d+%d:%d,%d;%d,%d:%d to %d+%d:%d,%d;%d,%d:%d", Number(), vpid, ppid, apid1, apid2, dpid1, dpid2, tpid, Vpid, Ppid, Apid1, Apid2, Dpid1, Dpid2, Tpid);
vpid = Vpid;
ppid = Ppid;
apid1 = Apid1;
if (Apid2)//XXX should we actually react here?
apid2 = Apid2;
dpid1 = Dpid1;
dpid2 = Dpid2;
tpid = Tpid;
modification |= CHANNELMOD_PIDS;
Channels.SetModified();
}
}
void cChannel::SetCaIds(const int *CaIds)
{
if (caids[0] && caids[0] <= 0x00FF)
return; // special values will not be overwritten
bool modified = false;
for (int i = 0; i < MAXCAIDS; i++) {
if (caids[i] != CaIds[i]) {
modified = true;
break;
}
if (!caids[i] || !CaIds[i])
break;
}
if (modified) {
char OldCaIdsBuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
char NewCaIdsBuf[MAXCAIDS * 5 + 10];
char *qo = OldCaIdsBuf;
char *qn = NewCaIdsBuf;
int i;
for (i = 0; i < MAXCAIDS; i++) {
if (i == 0 || caids[i])
qo += snprintf(qo, sizeof(OldCaIdsBuf), "%s%X", i > 0 ? "," : "", caids[i]);
if (!caids[i])
break;
}
for (i = 0; i < MAXCAIDS; i++) {
if (i == 0 || CaIds[i])
qn += snprintf(qn, sizeof(NewCaIdsBuf), "%s%X", i > 0 ? "," : "", CaIds[i]);
caids[i] = CaIds[i];
if (!CaIds[i])
break;
}
caids[i] = 0;
*qo = *qn = 0;
dsyslog("changing caids of channel %d from %s to %s", Number(), OldCaIdsBuf, NewCaIdsBuf);
modification |= CHANNELMOD_CA;
Channels.SetModified();
}
}
void cChannel::SetCaDescriptors(int Level)
{
if (Level > 0) {
modification |= CHANNELMOD_CA;
Channels.SetModified();
if (Level > 1)
dsyslog("changing ca descriptors of channel %d", Number());
}
}
static int PrintParameter(char *p, char Name, int Value)
@ -290,10 +414,10 @@ const char *cChannel::ToText(cChannel *Channel)
char vpidbuf[32];
char *q = vpidbuf;
q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
if (Channel->ppid)
if (Channel->ppid && Channel->ppid != Channel->vpid)
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
*q = 0;
char apidbuf[32];
char apidbuf[MAXAPIDS * 2 * 6 + 10]; // 2: Apids and Dpids, 6: 5 digits plus delimiting ',' or ';', 10: paranoia
q = apidbuf;
q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1);
if (Channel->apid2)
@ -303,7 +427,16 @@ const char *cChannel::ToText(cChannel *Channel)
if (Channel->dpid2)
q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2);
*q = 0;
asprintf(&buffer, "%s:%d:%s:%s:%d:%s:%s:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->ParametersToString(), cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, Channel->tpid, Channel->ca, Channel->sid, Channel->nid, Channel->tid, Channel->rid);
char caidbuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
q = caidbuf;
for (int i = 0; i < MAXCAIDS; i++) {
if (i == 0 || Channel->caids[i])
q += snprintf(q, sizeof(caidbuf), "%s%X", i > 0 ? "," : "", Channel->caids[i]);
if (!Channel->caids[i])
break;
}
*q = 0;
asprintf(&buffer, "%s:%d:%s:%s:%d:%s:%s:%d:%s:%d:%d:%d:%d\n", s, Channel->frequency, Channel->ParametersToString(), cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, Channel->tpid, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid);
}
return buffer;
}
@ -336,12 +469,16 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
char *parambuf = NULL;
char *vpidbuf = NULL;
char *apidbuf = NULL;
int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%d :%d :%d :%d :%d ", &namebuf, &frequency, &parambuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpid, &ca, &sid, &nid, &tid, &rid);
char *caidbuf = NULL;
int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%a[^:]:%d :%d :%d :%d ", &namebuf, &frequency, &parambuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpid, &caidbuf, &sid, &nid, &tid, &rid);
if (fields >= 9) {
if (fields == 9) {
// allow reading of old format
sid = ca;
ca = tpid;
sid = atoi(caidbuf);
delete caidbuf;
caidbuf = NULL;
caids[0] = tpid;
caids[1] = 0;
tpid = 0;
}
vpid = ppid = 0;
@ -350,24 +487,46 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
ok = false;
if (parambuf && sourcebuf && vpidbuf && apidbuf) {
ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0;
char *p = strchr(vpidbuf, '+');
if (p)
*p++ = 0;
sscanf(vpidbuf, "%d", &vpid);
if (p)
sscanf(p, "%d", &ppid);
else
ppid = vpid;
p = strchr(apidbuf, ';');
if (p)
*p++ = 0;
sscanf(apidbuf, "%d ,%d ", &apid1, &apid2);
if (p)
sscanf(p, "%d ,%d ", &dpid1, &dpid2);
if (caidbuf) {
char *p = caidbuf;
char *q;
int NumCaIds = 0;
while ((q = strtok(p, ",")) != NULL) {
if (NumCaIds < MAXCAIDS) {
caids[NumCaIds++] = strtol(q, NULL, 16) & 0xFFFF;
if (NumCaIds == 1 && caids[0] <= 0x00FF)
break;
}
else
esyslog("ERROR: too many CA ids!"); // no need to set ok to 'false'
p = NULL;
}
caids[NumCaIds] = 0;
}
}
strn0cpy(name, namebuf, MaxChannelName);
free(parambuf);
free(sourcebuf);
free(vpidbuf);
free(apidbuf);
free(caidbuf);
free(namebuf);
if (!GetChannelID().Valid()) {
esyslog("ERROR: channel data results in invalid ID!");
@ -394,6 +553,12 @@ bool cChannel::Save(FILE *f)
cChannels Channels;
cChannels::cChannels(void)
{
maxNumber = 0;
modified = false;
}
bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist)
{
if (cConfig<cChannel>::Load(FileName, AllowComments, MustExist)) {
@ -457,10 +622,10 @@ cChannel *cChannels::GetByNumber(int Number, int SkipGap)
return NULL;
}
cChannel *cChannels::GetByServiceID(int Source, unsigned short ServiceID)
cChannel *cChannels::GetByServiceID(int Source, int Transponder, unsigned short ServiceID)
{
for (cChannel *channel = First(); channel; channel = Next(channel)) {
if (!channel->GroupSep() && channel->Source() == Source && channel->Sid() == ServiceID)
if (!channel->GroupSep() && channel->Source() == Source && ISTRANSPONDER(channel->Transponder(), Transponder) && channel->Sid() == ServiceID)
return channel;
}
return NULL;
@ -497,3 +662,31 @@ bool cChannels::SwitchTo(int Number)
cChannel *channel = GetByNumber(Number);
return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true);
}
void cChannels::SetModified(void)
{
modified = true;
}
bool cChannels::Modified(void)
{
bool Result = modified;
modified = false;
return Result;
}
cChannel *cChannels::NewChannel(int Source, int Transponder, const char *Name, int Nid, int Tid, int Sid, int Rid)
{
dsyslog("creating new channel '%s' on %s transponder %d with id %d-%d-%d-%d", Name, cSource::ToString(Source), Transponder, Nid, Tid, Sid, Rid);
for (cChannel *channel = First(); channel; channel = Next(channel)) {
if (!channel->GroupSep() && channel->Source() == Source && ISTRANSPONDER(channel->Transponder(), Transponder)) {
cChannel *NewChannel = new cChannel(channel);
Add(NewChannel);
ReNumber();
NewChannel->SetId(Nid, Tid, Sid, Rid, false);
NewChannel->SetName(Name, false);
return NewChannel;
}
}
return NULL;
}

View File

@ -1,162 +1,110 @@
RTL:12188:h:S19.2E:27500:163:104:105:0:12003:0:0:0
Sat.1:12480:v:S19.2E:27500:1791:1792:34:0:46:0:0:0
Pro-7:12480:v:S19.2E:27500:255:256;257:32:0:898:0:0:0
RTL2:12188:h:S19.2E:27500:166:128:68:0:12020:0:0:0
ARD:11837:h:S19.2E:27500:101:102:104:0:28106:0:0:0
BR3:11837:h:S19.2E:27500:201:202:204:0:28107:0:0:0
Hessen-3:11837:h:S19.2E:27500:301:302:304:0:28108:0:0:0
N3:12110:h:S19.2E:27500:2401:2402:2404:0:28224:0:0:0
SR3:11837:h:S19.2E:27500:501:502:504:0:28110:0:0:0
WDR:11837:h:S19.2E:27500:601:602:604:0:28111:0:0:0
BR-alpha:11837:h:S19.2E:27500:701:702:704:0:28112:0:0:0
SWR BW:11837:h:S19.2E:27500:801:802:804:0:28113:0:0:0
Phoenix:11837:h:S19.2E:27500:901:902:904:0:28114:0:0:0
ZDF:11954:h:S19.2E:27500:110:120:130:0:28006:0:0:0
3sat:11954:h:S19.2E:27500:210:220:230:0:28007:0:0:0
KiKa:11954:h:S19.2E:27500:310:320:330:0:28008:0:0:0
arte:11836:h:S19.2E:27500:401:402:404:0:28109:0:0:0
ORF1:12692:h:S19.2E:22000:160:161:165:102:13001:0:0:0
ORF2:12692:h:S19.2E:22000:500:501:505:102:13002:0:0:0
ZDF.info:11954:h:S19.2E:27500:610:620:0:0:28011:0:0:0
CNN:11778:v:S19.2E:27500:165:100:0:0:28522:0:0:0
Super RTL:12188:h:S19.2E:27500:165:120:65:0:12040:0:0:0
VOX:12188:h:S19.2E:27500:167:136:71:0:12060:0:0:0
:#DW TV:10788:v:S19.2E:22000:305:306:0:0:8905:0:0:0
Kabel 1:12480:v:S19.2E:27500:511:512:33:0:899:0:0:0
Neun Live:12480:v:S19.2E:27500:767:768:35:0:897:0:0:0
DSF:12480:v:S19.2E:27500:1023:1024:0:0:900:0:0:0
HOT:12480:v:S19.2E:27500:1279:1280:0:0:40:0:0:0
Bloomberg TV Germany:12552:v:S19.2E:22000:162:99:0:0:12160:0:0:0
Bloomberg TV France:11817:v:S19.2E:27500:163:92:0:0:8004:0:0:0
Bloomberg TV Spain:12168:v:S19.2E:27500:167:112:0:0:12721:0:0:0
Sky News:11597:v:S19.2E:22000:305:306:0:0:28707:0:0:0
Fox Kids Netherlands:12574:h:S19.2E:22000:163:92:0:0:5020:0:0:0
BVN:12574:h:S19.2E:22000:164+131:96:0:0:5025:0:0:0
Alice:12610:v:S19.2E:22000:162:96:0:0:12200:0:0:0
n-tv:12670:v:S19.2E:22000:162:96:55:0:12730:0:0:0
Al Jazeera:11568:v:S19.2E:22000:55:56:0:0:9021:0:0:0
Grand Tourisme:12670:v:S19.2E:22000:289:290:0:0:17300:0:0:0
TW1:12692:h:S19.2E:22000:166:167:0:0:13013:0:0:0
Eurosport:11954:h:S19.2E:27500:410:420:0:0:28009:0:0:0
EinsExtra:12110:h:S19.2E:27500:101:102:0:0:28201:0:0:0
EinsFestival:12110:h:S19.2E:27500:201:202:0:0:28202:0:0:0
EinsMuXx:12110:h:S19.2E:27500:301:302:0:0:28203:0:0:0
ZDF Theaterkanal:11954:h:S19.2E:27500:1110:1120:0:0:28016:0:0:0
ZDF.doku:11954:h:S19.2E:27500:660:670:0:0:28014:0:0:0
MDR:12110:h:S19.2E:27500:401:402:404:0:28204:0:0:0
RBB Brandenburg:12110:h:S19.2E:27500:501:502:504:0:28205:0:0:0
RBB Berlin:12110:h:S19.2E:27500:601:602:604:0:28206:0:0:0
RTL,RTL Television:12188:h:S19.2E:27500:163:104:105:0:12003:1:1089:0
SAT.1:12480:v:S19.2E:27500:1791:1792;1795:34:0:46:133:33:0
ProSieben:12480:v:S19.2E:27500:255:256;257:32:0:898:133:33:0
RTL2:12188:h:S19.2E:27500:166:128:68:0:12020:1:1089:0
Das Erste:11837:h:S19.2E:27500:101:102:104:0:28106:1:1101:0
Bayerisches FS:11837:h:S19.2E:27500:201:202:204:0:28107:1:1101:0
hessen fernsehen:11837:h:S19.2E:27500:301:302:304:0:28108:1:1101:0
NDR FS MV:12110:h:S19.2E:27500:2401:2402:2404:0:28224:1:1073:0
SR Fernsehen Suedwest:11837:h:S19.2E:27500:501:502:504:0:28110:1:1101:0
WDR FERNSEHEN:11837:h:S19.2E:27500:601:602:604:0:28111:1:1101:0
BR-alpha:11837:h:S19.2E:27500:701:702:704:0:28112:1:1101:0
SÜDWEST BW:11837:h:S19.2E:27500:801:802:804:0:28113:1:1101:0
Phoenix:11837:h:S19.2E:27500:901:902:904:0:28114:1:1101:0
ZDF:11954:h:S19.2E:27500:110:120;125:130:0:28006:1:1079:0
3sat:11954:h:S19.2E:27500:210:220:230:0:28007:1:1079:0
KiKa:11954:h:S19.2E:27500:310:320:330:0:28008:1:1079:0
arte:11836:h:S19.2E:27500:401:402,403:404:0:28109:1:1101:0
ORF 1:12692:h:S19.2E:22000:160:161;163:165:1762,D05,1702,1801:13001:1:1117:0
ORF 2:12692:h:S19.2E:22000:500:501;503:505:1762,D05,1702,1801:13002:1:1117:0
ZDFinfokanal:11954:h:S19.2E:27500:610:620:130:0:28011:1:1079:0
CNN Int.:11778:v:S19.2E:27500:165:100:47:0:28522:1:1068:0
S RTL,Super RTL:12188:h:S19.2E:27500:165:120:65:0:12040:1:1089:0
VOX:12188:h:S19.2E:27500:167:136:71:0:12060:1:1089:0
KABEL1:12480:v:S19.2E:27500:511:512:33:0:899:133:33:0
NEUN LIVE,NEUN LIVE Television:12480:v:S19.2E:27500:767:768:35:0:897:133:33:0
DSF:12480:v:S19.2E:27500:1023:1024:0:0:900:133:33:0
HSEurope,Home Shopping Europe:12480:v:S19.2E:27500:1279:1280:37:0:40:133:33:0
Bloomberg TV Germany:12552:v:S19.2E:22000:162:99:0:0:12160:1:1108:0
EURONEWS:11817:v:S19.2E:27500:163:92,93:0:500,100:8004:1:1070:0
Sky News:11597:v:S19.2E:22000:305:306:0:0:28707:1:1026:0
Veronica/FoxKids:12574:h:S19.2E:22000:518+8190:92:38:622,602,100:5020:53:1109:0
BVN:12574:h:S19.2E:22000:515+8190:96:36:0:5025:53:1109:0
CNBC Europe:12610:v:S19.2E:22000:944:945:0:0:12200:1:1112:0
n-tv:12670:v:S19.2E:22000:162:96:55:0:12730:1:1116:0
Al Jazeera:11568:v:S19.2E:22000:55:56:0:0:9021:1:1024:0
TW1:12692:h:S19.2E:22000:166:167:168:0:13013:1:1117:0
Eurosport:11954:h:S19.2E:27500:410:420:430:0:28009:1:1079:0
EinsExtra:12110:h:S19.2E:27500:101:102:0:0:28201:1:1073:0
EinsFestival:12110:h:S19.2E:27500:201:202:0:0:28202:1:1073:0
EinsMuXx:12110:h:S19.2E:27500:301:302:0:0:28203:1:1073:0
ZDFtheaterkanal:11954:h:S19.2E:27500:1110:1120:130:0:28016:1:1079:0
ZDFdokukanal:11954:h:S19.2E:27500:660:670:130:0:28014:1:1079:0
MDR FERNSEHEN:12110:h:S19.2E:27500:401:402:404:0:28204:1:1073:0
RBB Brandenburg:12110:h:S19.2E:27500:501:502:504:0:28205:1:1073:0
RBB Berlin:12110:h:S19.2E:27500:601:602:604:0:28206:1:1073:0
:Premiere World
Premiere Start:11797:h:S19.2E:27500:255:256:0:101:8:0:0:0
Premiere 1:11797:h:S19.2E:27500:511:512,513;515:0:101:10:0:0:0
Premiere 2:11797:h:S19.2E:27500:1791:1792,1793;1795:0:101:11:0:0:0
Premiere 3:11797:h:S19.2E:27500:2303:2304,2305:0:101:43:0:0:0
Premiere 4:11797:h:S19.2E:27500:767:768,769:0:101:9:0:0:0
Premiere 5:11797:h:S19.2E:27500:1279:1280,1281:0:101:29:0:0:0
Premiere 6:11797:h:S19.2E:27500:1535:1536:0:101:41:0:0:0
Premiere 7:11797:h:S19.2E:27500:1023:1024:0:101:20:0:0:0
13th Street:11758:h:S19.2E:27500:2303:2304:0:101:42:0:0:0
Sci-Fi:11758:h:S19.2E:27500:2047:2048:0:101:36:0:0:0
Premiere Serie:12031:h:S19.2E:27500:1023:1024:0:101:16:0:0:0
Disney Channel:11758:h:S19.2E:27500:2559:2560:0:101:34:0:0:0
Premiere Nostalgie:12031:h:S19.2E:27500:2559:2560:0:101:516:0:0:0
Discovery Channel:11758:h:S19.2E:27500:1023:1024:8181:101:14:0:0:0
Planet:12090:v:S19.2E:27500:1279:1280:0:101:13:0:0:0
Fox Kids:11758:h:S19.2E:27500:1279:1280:0:101:28:0:0:0
Junior:11758:h:S19.2E:27500:255:256:0:101:19:0:0:0
K-Toon:11758:h:S19.2E:27500:511:512:0:101:12:0:0:0
Krimi&Co:12031:h:S19.2E:27500:1535:1536:0:101:23:0:0:0
Goldstar TV:11758:h:S19.2E:27500:3839:3840:0:101:518:0:0:0
MGM:11758:h:S19.2E:27500:767:768:2:101:515:0:0:0
Sonnenklar TV:12090:v:S19.2E:27500:1023:1024:0:0:32:0:0:0
START,PREMIERE START:11797:h:S19.2E:27500:255:256:32:1702,1722,1801:8:133:2:0
PREM 1,PREMIERE 1:11797:h:S19.2E:27500:511:512,513;515:0:1702,1722,1801:10:133:2:0
PREM 2,PREMIERE 2:11797:h:S19.2E:27500:1791:1792,1793;1795:0:1702,1722,1801:11:133:2:0
PREM 3,PREMIERE 3:11797:h:S19.2E:27500:2303:2304,2305:0:1702,1722,1801:43:133:2:0
PREM 4,PREMIERE 4:11797:h:S19.2E:27500:767:768,769:0:1702,1722,1801:9:133:2:0
PREM 5,PREMIERE 5:11797:h:S19.2E:27500:1279:1280,1281:0:1702,1722,1801:29:133:2:0
PREM 6,PREMIERE 6:11797:h:S19.2E:27500:1535:1536:0:1702,1722,1801:41:133:2:0
PREM 7,PREMIERE 7:11797:h:S19.2E:27500:1023:1024:0:1702,1722,1801:20:133:2:0
DISNEY,DISNEY CHANNEL:11758:h:S19.2E:27500:2559:2560:0:1702,1722,1801:34:133:17:0
:Premiere Direkt
Premiere Direkt Portal:12031:h:S19.2E:27500:2815:2816:0:101:18:0:0:0
Premiere Direkt 1A:11719:h:S19.2E:27500:2047:2048:0:101:240:0:0:0
Premiere Direkt 1B:11719:h:S19.2E:27500:2303:2304:0:101:241:0:0:0
Premiere Direkt 1C:11719:h:S19.2E:27500:2559:2560:0:101:242:0:0:0
Premiere Direkt 2A:11719:h:S19.2E:27500:2815:2816:0:101:243:0:0:0
Premiere Direkt 2B:11719:h:S19.2E:27500:3071:3072:0:101:244:0:0:0
Premiere Direkt 2C:12031:h:S19.2E:27500:3071:3072:0:101:208:0:0:0
Premiere Direkt 2D:11719:h:S19.2E:27500:3327:3328:0:101:245:0:0:0
Premiere Direkt 3A:12031:h:S19.2E:27500:3327:3328:0:101:209:0:0:0
Premiere Direkt 3B:12031:h:S19.2E:27500:2303:2304:0:101:210:0:0:0
Premiere Direkt 3C:11758:h:S19.2E:27500:511:512:0:101:211:0:0:0
Premiere Direkt 3D:12070:h:S19.2E:27500:511:512:0:101:212:0:0:0
DIREKT,PREMIERE DIREKT:12031:h:S19.2E:27500:2815:2816,2817;2819:0:0:18:133:4:0
:PW Erotic
Beate-Uhse.TV:12071:h:S19.2E:27500:1023:1024:0:101:21:0:0:0
Premiere Erotik 1:12031:h:S19.2E:27500:1279:1280:2:101:513:0:0:0
Premiere Erotik 2:12070:h:S19.2E:27500:1535:1536:0:101:778:0:0:0
Premiere Erotik 3:12070:h:S19.2E:27500:1791:1792:0:101:779:0:0:0
Premiere Erotik 4:12070:h:S19.2E:27500:3583:3584:0:101:780:0:0:0
B-UHSE,BEATE-UHSE.TV:12071:h:S19.2E:27500:1023:1024:0:1702,1722,1801:21:133:1:0
EROTIK,PREMIERE EROTIK:12031:h:S19.2E:27500:1279:0:0:1702,1722,1801:513:133:4:0
:Sportsworld
Premiere Sport 1:11720:h:S19.2E:27500:255:256,257:0:101:17:0:0:0
Premiere Sport 2:12031:h:S19.2E:27500:3839:3840:0:101:27:0:0:0
:Formel 1
:#Supersignal:12070:h:S19.2E:27500:255:256:0:101:211:0:0:0
:#Cockpitkanal:12070:h:S19.2E:27500:511:512:0:101:212:0:0:0
:#Boxengasse:12070:h:S19.2E:27500:767:768:0:101:213:0:0:0
:#Verfolgerfeld:12070:h:S19.2E:27500:1023:1024:0:101:214:0:0:0
:#Infokanal:12070:h:S19.2E:27500:1279:1280:0:101:215:0:0:0
:#Multikanal:11720:h:S19.2E:27500:255:256:0:101:17:0:0:0
SPORT 1,PREMIERE SPORT 1:11720:h:S19.2E:27500:255:256,257:0:1702,1722,1801:17:133:3:0
SPORT 2,PREMIERE SPORT 2:12031:h:S19.2E:27500:3839:3840,3841:0:1702,1722,1801:27:133:4:0
:Beta Digital
N24:12480:v:S19.2E:27500:2047:2048:0:0:47:0:0:0
CNBC:11954:h:S19.2E:27500:510:520:0:0:28010:0:0:0
Liberty TV.com:12610:v:S19.2E:22000:941:943,942:0:0:12199:0:0:0
:Premiere Bundesliga
BL-Konferenz:12031:h:S19.2E:27500:2303:2304,2305:0:101:210:0:0:1
BuLi 1:11719:h:S19.2E:27500:255:256,257:0:101:17:0:0:1
BuLi 2:11719:h:S19.2E:27500:2047:2048,2049:0:101:240:0:0:1
BuLi 3:11719:h:S19.2E:27500:2303:2304,2305:0:101:241:0:0:1
BuLi 4:11719:h:S19.2E:27500:2559:2560,2561:0:101:242:0:0:1
BuLi 5:11719:h:S19.2E:27500:2815:2816,2817:0:101:243:0:0:1
BuLi 6:11719:h:S19.2E:27500:3071:3072,3073:0:101:244:0:0:1
BuLi 7:11719:h:S19.2E:27500:3327:3328,3329:0:101:245:0:0:1
BuLi 8:12031:h:S19.2E:27500:3071:3072,3073:0:101:208:0:0:1
BuLi 9:12031:h:S19.2E:27500:3327:3328,3329:0:101:209:0:0:1
N24:12480:v:S19.2E:27500:2047:2048:36:0:47:133:33:0
CNBC:11954:h:S19.2E:27500:510:520:530:0:28010:1:1079:0
Liberty TV.com:12610:v:S19.2E:22000:941:943:0:0:12199:1:1112:0
:-
Mosaico:11934:v:S19.2E:27500:165:100:0:0:29010:0:0:0
Andalucia TV:11934:v:S19.2E:27500:166:104:0:0:29011:0:0:0
Canal J:11934:v:S19.2E:27500:167:108:0:0:8157:0:0:0
Extreme Sports Channel:11992:h:S19.2E:27500:165:98,99:0:0:20365:0:0:0
Pro 7 Austria:12051:v:S19.2E:27500:161:84:0:0:20002:0:0:0
Kabel 1 Schweiz:12051:v:S19.2E:27500:162:163:0:0:20003:0:0:0
Kabel 1 Austria:12051:v:S19.2E:27500:166:167:0:0:20004:0:0:0
Pro 7 Schweiz:12051:v:S19.2E:27500:289:290:0:0:20001:0:0:0
:#KTO:11739:v:S19.2E:27500:163:90:0:0:8304:0:0:0
Cartoon Network France:12168:v:S19.2E:27500:161:84:0:0:28511:0:0:0
TVBS Europe:12168:v:S19.2E:27500:162:88,89:0:0:28631:0:0:0
travel channel:12168:v:S19.2E:27500:163:92,93:0:0:28001:0:0:0
TCM Espana:12168:v:S19.2E:27500:164:96,97:0:0:28516:0:0:0
TCM France:12168:v:S19.2E:27500:169:64,65:0:0:28515:0:0:0
La Cinquieme:12207:v:S19.2E:27500:160:80:0:0:8501:0:0:0
LCP:12207:v:S19.2E:27500:165:100:0:0:8506:0:0:0
:#AB Moteurs:12266:h:S19.2E:27500:160:80:0:0:17000:0:0:0
:#AB 1:12266:h:S19.2E:27500:161:84:0:0:17001:0:0:0
Escales:12285:v:S19.2E:27500:165:100:0:0:17025:0:0:0
Canal Club:12324:v:S19.2E:27500:160:80:0:0:8612:0:0:0
:#RAI Uno:10788:v:S19.2E:22000:289:290:0:0:9004:0:0:0
K13:12402:v:S19.2E:27500:163:92:0:0:8704:0:0:0
Astra Mosaic 1:12552:v:S19.2E:22000:175:176:0:0:3988:0:0:0
Astra Mosaic 2:12552:v:S19.2E:22000:179:120:0:0:3987:0:0:0
Astra Mosaic 3:12552:v:S19.2E:22000:182:169:0:0:3986:0:0:0
Astra Mosaic 4:12552:v:S19.2E:22000:185:170:0:0:3985:0:0:0
Astra Mosaic 5:12552:v:S19.2E:22000:163:170:0:0:3984:0:0:0
Chamber TV:12552:v:S19.2E:22000:55:56:0:0:12180:0:0:0
RTL Tele Letzebuerg:12552:v:S19.2E:22000:168:144,146:0:0:3994:0:0:0
VERONICA:12574:h:S19.2E:22000:161:84:0:0:5010:0:0:0
VH1 Classic:12670:v:S19.2E:22000:3071:3072:0:0:28647:0:0:0
MTV 2:12225:h:S19.2E:27500:513:661:577:0:28640:0:0:0
ProSieben Austria:12051:v:S19.2E:27500:161:84:36:0:20002:1:1082:0
Kabel 1 Schweiz:12051:v:S19.2E:27500:162:163:165:0:20003:1:1082:0
Kabel 1 Austria:12051:v:S19.2E:27500:166:167:169:0:20004:1:1082:0
ProSieben Schweiz:12051:v:S19.2E:27500:289:290:33:0:20001:1:1082:0
FRANCE 5:12207:v:S19.2E:27500:160:80:32:0:8501:1:1090:0
LCP:12207:v:S19.2E:27500:165:100:0:0:8506:1:1090:0
ESCALES:12285:v:S19.2E:27500:165:100:0:500,100:17025:1:1094:0
CANAL CLUB:12324:v:S19.2E:27500:160:80:0:0:8612:1:1096:0
ASTRA-Mosaic:12552:v:S19.2E:22000:175:176:0:0:3988:1:1108:0
ASTRA-Mosaic 2:12552:v:S19.2E:22000:179:120:0:0:3987:1:1108:0
ASTRA-Mosaic 3:12552:v:S19.2E:22000:182:169:0:0:3986:1:1108:0
ASTRA-Mosaic 4:12552:v:S19.2E:22000:185:170:0:0:3985:1:1108:0
ASTRA-Mosaic 5:12552:v:S19.2E:22000:163:164:0:0:3984:1:1108:0
Chamber TV:12552:v:S19.2E:22000:55:56:0:0:12180:1:1108:0
RTL TELE Letzebuerg:12552:v:S19.2E:22000:168:144,146:74:0:3994:1:1108:0
Yorin:12574:h:S19.2E:22000:512+8190:84:33:622,602,100:5010:53:1109:0
MTV2 Pop Channel:12225:h:S19.2E:27500:513:661:577:0:28640:1:1091:0
Via 1 - Schöner Reisen:12148:h:S19.2E:27500:511:512:0:0:44:0:0:0
Video Italia:12610:v:S19.2E:22000:121:122:0:0:12220:0:0:0
ORF/ZDF:12670:h:S19.2E:22000:506:507:0:0:13012:0:0:0
VIVA:12670:v:S19.2E:22000:309:310:311:0:12732:0:0:0
VIVA PLUS:12552:v:S19.2E:22000:171:172:179:0:12120:0:0:0
MTV Central:11739:v:S19.2E:27500:3031:3032:3034:0:28653:0:0:0
QVC Germany:12552:v:S19.2E:22000:165:166:0:0:12100:0:0:0
Tele 5:12480:v:S19.2E:27500:1535:1536:0:0:51:0:0:0
VIVA:12670:v:S19.2E:22000:309:310:311:0:12732:1:1116:0
VIVA PLUS:12552:v:S19.2E:22000:171:172:173:0:12120:1:1108:0
MTV Central:11739:v:S19.2E:27500:3031:3032:3034:0:28653:1:1066:0
QVC GERMANY:12552:v:S19.2E:22000:165:166:167:0:12100:1:1108:0
TELE 5:12480:v:S19.2E:27500:1535:1536:38:0:51:133:33:0
:@201 Sky
Sky One:106:h:S28.2E:0:160:80:0:301:222:0:0:0
Sky One Mix:107:h:S28.2E:0:160:80:0:301:919:0:0:0
itv2:226:h:S28.2E:0:160:80:0:301:451:0:0:0
sci-fi:130:h:S28.2E:0:160:80:0:301:161:0:0:0
Paramount Comedy:127:h:S28.2E:0:160:80:0:301:185:0:0:0
Sky One:106:h:S28.2E:0:160:80:0:30:222:0:0:0
Sky One Mix:107:h:S28.2E:0:160:80:0:30:919:0:0:0
itv2:226:h:S28.2E:0:160:80:0:30:451:0:0:0
sci-fi:130:h:S28.2E:0:160:80:0:30:161:0:0:0
Paramount Comedy:127:h:S28.2E:0:160:80:0:30:185:0:0:0
:@900 Some 'seed' channels
Chelsea TV:11778:v:S28.2E:27500:2308+2304:2309:0:960,961:9307:2:2004:0
Sky One:12285:v:S28.2E:27500:2311+2304:2312,2313:2307:960,961:4703:2:2030:0
WDR Münster:12421:h:S19.2E:27500:101:102:104:0:28310:1:1201:0
Going Places:10921:h:S28.2E:22000:2310+2304:2311:2312:0:5008:2:2055:0
Animal Plnt+:12070:h:S28.2E:27500:2315+2307:2316:0:960,961:50002:2:2019:0
S1T:11954:h:S28.2E:27500:0:0:0:0:4409:2:2030:0
CNN:12032:v:S28.2E:27500:2309:2311:2310:0:7140:2:2018:0
BBC PARL'MNT:12129:v:S28.2E:27500:2306:2308,2309:2307:0:7300:2:2022:0
AL HAYAT:11200:v:S13.0E:27500:413:414:0:0:4733:318:13400:0
EURO1080:12168:v:S19.2E:27500:308:256:0:FF:21100:1:1088:0
:@1000 New channels

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: channels.h 1.9 2003/10/26 13:21:59 kls Exp $
* $Id: channels.h 1.10 2004/01/04 12:26:37 kls Exp $
*/
#ifndef __CHANNELS_H
@ -12,10 +12,22 @@
#include "config.h"
#include "sources.h"
#include "thread.h"
#include "tools.h"
#define ISTRANSPONDER(f1, f2) (abs((f1) - (f2)) < 4) //XXX
#define CHANNELMOD_NONE 0x00
#define CHANNELMOD_ALL 0xFF
#define CHANNELMOD_NAME 0x01
#define CHANNELMOD_PIDS 0x02
#define CHANNELMOD_ID 0x04
#define CHANNELMOD_CA 0x10
#define CHANNELMOD_RETUNE (CHANNELMOD_PIDS | CHANNELMOD_CA)
#define MAXAPIDS 2
#define MAXCAIDS 8
struct tChannelParameterMap {
int userValue;
int driverValue;
@ -46,7 +58,7 @@ public:
tChannelID(void) { source = nid = tid = sid = rid = 0; }
tChannelID(int Source, int Nid, int Tid, int Sid, int Rid = 0) { source = Source; nid = Nid; tid = Tid; sid = Sid; rid = Rid; }
bool operator== (const tChannelID &arg) const;
bool Valid(void) { return tid && sid; } // nid and rid are optional and source may be 0
bool Valid(void) { return tid && sid; } // nid and rid are optional and source may be 0//XXX source may not be 0???
tChannelID &ClrRid(void) { rid = 0; return *this; }
static tChannelID FromString(const char *s);
const char *ToString(void);
@ -58,7 +70,7 @@ class cChannel : public cListObject {
private:
static char *buffer;
static const char *ToText(cChannel *Channel);
enum { MaxChannelName = 32 }; // 31 chars + terminating 0!
enum { MaxChannelName = 64 }; // 63 chars + terminating 0!
int __BeginData__;
char name[MaxChannelName];
int frequency; // MHz
@ -69,7 +81,7 @@ private:
int apid1, apid2;
int dpid1, dpid2;
int tpid;
int ca;
int caids[MAXCAIDS + 1]; // list is zero-terminated
int nid;
int tid;
int sid;
@ -86,16 +98,19 @@ private:
int guard;
int hierarchy;
int __EndData__;
int modification;
const char *ParametersToString(void);
bool StringToParameters(const char *s);
public:
cChannel(void);
cChannel(const cChannel *Channel);
cChannel& operator= (const cChannel &Channel);
const char *ToText(void);
bool Parse(const char *s, bool AllowNonUniqueID = false);
bool Save(FILE *f);
const char *Name(void) const { return name; }
int Frequency(void) const { return frequency; }
int Frequency(void) const { return frequency; } ///< Returns the actual frequency, as given in 'channels.conf'
int Transponder(void) const; ///< Returns the transponder frequency in MHz
int Source(void) const { return source; }
int Srate(void) const { return srate; }
int Vpid(void) const { return vpid; }
@ -105,8 +120,11 @@ public:
int Dpid1(void) const { return dpid1; }
int Dpid2(void) const { return dpid2; }
int Tpid(void) const { return tpid; }
int Ca(void) const { return ca; }
int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
int Nid(void) const { return nid; }
int Tid(void) const { return tid; }
int Sid(void) const { return sid; }
int Rid(void) const { return rid; }
int Number(void) const { return number; }
void SetNumber(int Number) { number = Number; }
bool GroupSep(void) const { return groupSep; }
@ -123,24 +141,38 @@ public:
bool IsSat(void) const { return (source & cSource::st_Mask) == cSource::stSat; }
bool IsTerr(void) const { return (source & cSource::st_Mask) == cSource::stTerr; }
tChannelID GetChannelID(void) const;
int Modification(int Mask = CHANNELMOD_ALL);
void SetId(int Nid, int Tid, int Sid, int Rid = 0, bool Log = true);
void SetName(const char *Name, bool Log = true);
void SetPids(int Vpid, int Ppid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid);
void SetCaIds(const int *CaIds); // list must be zero-terminated
void SetCaDescriptors(int Level);
};
class cChannels : public cConfig<cChannel> {
protected:
class cChannels : public cRwLock, public cConfig<cChannel> {
private:
int maxNumber;
bool modified;
int beingEdited;
public:
cChannels(void) { maxNumber = 0; }
cChannels(void);
virtual bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false);
int GetNextGroup(int Idx); // Get next channel group
int GetPrevGroup(int Idx); // Get previous channel group
int GetNextNormal(int Idx); // Get next normal channel (not group)
void ReNumber(void); // Recalculate 'number' based on channel type
cChannel *GetByNumber(int Number, int SkipGap = 0);
cChannel *GetByServiceID(int Source, unsigned short ServiceID);
cChannel *GetByServiceID(int Source, int Transponder, unsigned short ServiceID);
cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false);
int BeingEdited(void) { return beingEdited; }
void IncBeingEdited(void) { beingEdited++; }
void DecBeingEdited(void) { beingEdited--; }
bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel = NULL);
bool SwitchTo(int Number);
int MaxNumber(void) { return maxNumber; }
void SetModified(void);
bool Modified(void);
cChannel *NewChannel(int Source, int Transponder, const char *Name, int Nid, int Tid, int Sid, int Rid = 0);
};
extern cChannels Channels;

71
ci.c
View File

@ -4,14 +4,11 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ci.c 1.17 2003/10/26 13:04:23 kls Exp $
* $Id: ci.c 1.21 2004/01/02 15:07:36 kls Exp $
*/
/* XXX TODO
- update CA descriptors in case they change
XXX*/
#include "ci.h"
#include <asm/unaligned.h>
#include <ctype.h>
#include <linux/dvb/ca.h>
#include <malloc.h>
@ -21,6 +18,7 @@ XXX*/
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include "pat.h"
#include "tools.h"
/* these might come in handy in case you want to use this code without VDR's other files:
@ -793,10 +791,10 @@ bool cCiApplicationInformation::Process(int Length, const uint8_t *Data)
if ((l -= 1) < 0) break;
applicationType = *d++;
if ((l -= 2) < 0) break;
applicationManufacturer = ntohs(*(uint16_t *)d);
applicationManufacturer = ntohs(get_unaligned((uint16_t *)d));
d += 2;
if ((l -= 2) < 0) break;
manufacturerCode = ntohs(*(uint16_t *)d);
manufacturerCode = ntohs(get_unaligned((uint16_t *)d));
d += 2;
free(menuString);
menuString = GetString(l, &d);
@ -1265,8 +1263,9 @@ bool cCiEnquiry::Cancel(void)
#define CPCI_QUERY 0x03
#define CPCI_NOT_SELECTED 0x04
cCiCaPmt::cCiCaPmt(int ProgramNumber)
cCiCaPmt::cCiCaPmt(int Source, int Transponder, int ProgramNumber, const unsigned short *CaSystemIds)
{
caDescriptorsLength = GetCaDescriptors(Source, Transponder, ProgramNumber, CaSystemIds, sizeof(caDescriptors), caDescriptors, streamFlag);
length = 0;
capmt[length++] = CPLM_ONLY;
capmt[length++] = (ProgramNumber >> 8) & 0xFF;
@ -1275,20 +1274,31 @@ cCiCaPmt::cCiCaPmt(int ProgramNumber)
esInfoLengthPos = length;
capmt[length++] = 0x00; // program_info_length H (at program level)
capmt[length++] = 0x00; // program_info_length L
if (!streamFlag)
AddCaDescriptors(caDescriptorsLength, caDescriptors);
}
void cCiCaPmt::AddPid(int Pid)
bool cCiCaPmt::Valid(void)
{
//XXX buffer overflow check???
capmt[length++] = 0x00; //XXX stream_type (apparently doesn't matter)
capmt[length++] = (Pid >> 8) & 0xFF;
capmt[length++] = Pid & 0xFF;
esInfoLengthPos = length;
capmt[length++] = 0x00; // ES_info_length H (at ES level)
capmt[length++] = 0x00; // ES_info_length L
return caDescriptorsLength > 0;
}
void cCiCaPmt::AddCaDescriptor(int Length, uint8_t *Data)
void cCiCaPmt::AddPid(int Pid, uint8_t StreamType)
{
if (Pid) {
//XXX buffer overflow check???
capmt[length++] = StreamType;
capmt[length++] = (Pid >> 8) & 0xFF;
capmt[length++] = Pid & 0xFF;
esInfoLengthPos = length;
capmt[length++] = 0x00; // ES_info_length H (at ES level)
capmt[length++] = 0x00; // ES_info_length L
if (streamFlag)
AddCaDescriptors(caDescriptorsLength, caDescriptors);
}
}
void cCiCaPmt::AddCaDescriptors(int Length, const uint8_t *Data)
{
if (esInfoLengthPos) {
if (length + Length < int(sizeof(capmt))) {
@ -1355,7 +1365,7 @@ cCiHandler *cCiHandler::CreateCiHandler(const char *FileName)
int cCiHandler::ResourceIdToInt(const uint8_t *Data)
{
return (ntohl(*(int *)Data));
return (ntohl(get_unaligned((int32_t *)Data)));
}
bool cCiHandler::Send(uint8_t Tag, int SessionId, int ResourceId, int Status)
@ -1367,10 +1377,10 @@ bool cCiHandler::Send(uint8_t Tag, int SessionId, int ResourceId, int Status)
if (Status >= 0)
*p++ = Status;
if (ResourceId) {
*(int *)p = htonl(ResourceId);
put_unaligned(htonl(ResourceId), (int32_t *)p);
p += 4;
}
*(short *)p = htons(SessionId);
put_unaligned(htons(SessionId), (uint16_t *)p);
p += 2;
buffer[1] = p - buffer - 2; // length
return tc && tc->SendData(p - buffer, buffer) == OK;
@ -1481,7 +1491,7 @@ bool cCiHandler::Process(void)
if (Data && Length > 1) {
switch (*Data) {
case ST_SESSION_NUMBER: if (Length > 4) {
int SessionId = ntohs(*(short *)&Data[2]);
int SessionId = ntohs(get_unaligned((uint16_t *)&Data[2]));
cCiSession *Session = GetSessionBySessionId(SessionId);
if (Session)
Session->Process(Length - 4, Data + 4);
@ -1492,7 +1502,7 @@ bool cCiHandler::Process(void)
case ST_OPEN_SESSION_REQUEST: OpenSession(Length, Data);
break;
case ST_CLOSE_SESSION_REQUEST: if (Length == 4)
CloseSession(ntohs(*(short *)&Data[2]));
CloseSession(ntohs(get_unaligned((uint16_t *)&Data[2])));
break;
case ST_CREATE_SESSION_RESPONSE: //XXX fall through to default
case ST_CLOSE_SESSION_RESPONSE: //XXX fall through to default
@ -1556,6 +1566,23 @@ const unsigned short *cCiHandler::GetCaSystemIds(int Slot)
return cas ? cas->GetCaSystemIds() : NULL;
}
bool cCiHandler::ProvidesCa(const unsigned short *CaSystemIds)
{
cMutexLock MutexLock(&mutex);
for (int Slot = 0; Slot < numSlots; Slot++) {
cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
if (cas) {
for (const unsigned short *ids = cas->GetCaSystemIds(); ids && *ids; ids++) {
for (const unsigned short *id = CaSystemIds; *id; id++) {
if (*id == *ids)
return true;
}
}
}
}
return false;
}
bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot)
{
cMutexLock MutexLock(&mutex);

13
ci.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ci.h 1.9 2003/10/26 12:22:09 kls Exp $
* $Id: ci.h 1.12 2003/12/31 13:49:49 kls Exp $
*/
#ifndef __CI_H
@ -66,10 +66,14 @@ private:
int length;
int esInfoLengthPos;
uint8_t capmt[2048]; ///< XXX is there a specified maximum?
int caDescriptorsLength;
uint8_t caDescriptors[2048];
bool streamFlag;
void AddCaDescriptors(int Length, const uint8_t *Data);
public:
cCiCaPmt(int ProgramNumber);
void AddPid(int Pid);
void AddCaDescriptor(int Length, uint8_t *Data);
cCiCaPmt(int Source, int Transponder, int ProgramNumber, const unsigned short *CaSystemIds);
bool Valid(void);
void AddPid(int Pid, uint8_t StreamType);
};
#define MAX_CI_SESSION 16 //XXX
@ -107,6 +111,7 @@ public:
cCiMenu *GetMenu(void);
cCiEnquiry *GetEnquiry(void);
const unsigned short *GetCaSystemIds(int Slot);
bool ProvidesCa(const unsigned short *CaSystemIds); //XXX Slot???
bool SetCaPmt(cCiCaPmt &CaPmt, int Slot);
bool Reset(int Slot);
};

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.176.1.6 2003/11/14 13:29:13 kls Exp $
* $Id: config.h 1.178 2003/12/27 13:57:56 kls Exp $
*/
#ifndef __CONFIG_H
@ -19,8 +19,8 @@
#include "device.h"
#include "tools.h"
#define VDRVERSION "1.2.6"
#define VDRVERSNUM 10206 // Version * 10000 + Major * 100 + Minor
#define VDRVERSION "1.3.0"
#define VDRVERSNUM 10300 // Version * 10000 + Major * 100 + Minor
#define MAXPRIORITY 99
#define MAXLIFETIME 99
@ -87,7 +87,7 @@ public:
cConfig(void) { fileName = NULL; }
virtual ~cConfig() { free(fileName); }
const char *FileName(void) { return fileName; }
bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false)
virtual bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false)
{
Clear();
if (FileName) {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: cutter.c 1.5 2003/08/17 09:04:04 kls Exp $
* $Id: cutter.c 1.6 2003/10/18 11:29:37 kls Exp $
*/
#include "cutter.h"
@ -32,6 +32,7 @@ public:
};
cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
:cThread("video cutting")
{
error = NULL;
active = false;
@ -62,8 +63,6 @@ cCuttingThread::~cCuttingThread()
void cCuttingThread::Action(void)
{
dsyslog("video cutting thread started (pid=%d)", getpid());
cMark *Mark = fromMarks.First();
if (Mark) {
fromFile = fromFileName->Open();
@ -175,7 +174,6 @@ void cCuttingThread::Action(void)
}
else
esyslog("no editing marks found!");
dsyslog("end video cutting thread");
}
// --- cCutter ---------------------------------------------------------------

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.c 1.47.1.1 2003/11/07 13:16:12 kls Exp $
* $Id: device.c 1.51 2004/01/04 11:30:05 kls Exp $
*/
#include "device.h"
@ -13,7 +13,6 @@
#include <sys/mman.h>
#include "audio.h"
#include "channels.h"
#include "eit.h"
#include "i18n.h"
#include "player.h"
#include "receiver.h"
@ -36,6 +35,8 @@ cDevice::cDevice(void)
{
cardIndex = nextCardIndex++;
SetDescription("receiver on device %d", CardIndex() + 1);
SetVideoFormat(Setup.VideoFormat);
active = false;
@ -43,6 +44,11 @@ cDevice::cDevice(void)
mute = false;
volume = Setup.CurrentVolume;
sectionHandler = NULL;
eitFilter = NULL;
patFilter = NULL;
sdtFilter = NULL;
ciHandler = NULL;
player = NULL;
@ -63,6 +69,10 @@ cDevice::~cDevice()
for (int i = 0; i < MAXRECEIVERS; i++)
Detach(receiver[i]);
delete ciHandler;
delete sdtFilter;
delete patFilter;
delete eitFilter;
delete sectionHandler;
}
void cDevice::SetUseDevice(int n)
@ -149,7 +159,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDe
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
if (device[i]->Receiving() && !ndr)
pri = 0; // receiving and allows additional receivers
else if (d && !device[i]->Receiving() && device[i]->ProvidesCa(Channel->Ca()) < d->ProvidesCa(Channel->Ca()))
else if (d && !device[i]->Receiving() && device[i]->ProvidesCa(Channel) < d->ProvidesCa(Channel))
pri = 1; // free and fewer Ca's
else if (!device[i]->Receiving() && !device[i]->IsPrimaryDevice())
pri = 2; // free and not the primary device
@ -157,7 +167,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDe
pri = 3; // free
else if (d && device[i]->Priority() < d->Priority())
pri = 4; // receiving but priority is lower
else if (d && device[i]->Priority() == d->Priority() && device[i]->ProvidesCa(Channel->Ca()) < d->ProvidesCa(Channel->Ca()))
else if (d && device[i]->Priority() == d->Priority() && device[i]->ProvidesCa(Channel) < d->ProvidesCa(Channel))
pri = 5; // receiving with same priority but fewer Ca's
else
pri = 6; // all others
@ -311,11 +321,42 @@ bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
return false;
}
void cDevice::StartSectionHandler(void)
{
if (!sectionHandler) {
sectionHandler = new cSectionHandler(this);
AttachFilter(eitFilter = new cEitFilter);
AttachFilter(patFilter = new cPatFilter);
AttachFilter(sdtFilter = new cSdtFilter(patFilter));
sectionHandler->SetStatus(true);
}
}
int cDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
{
return -1;
}
void cDevice::AttachFilter(cFilter *Filter)
{
sectionHandler->Attach(Filter);
}
void cDevice::Detach(cFilter *Filter)
{
sectionHandler->Detach(Filter);
}
bool cDevice::ProvidesSource(int Source) const
{
return false;
}
bool cDevice::ProvidesTransponder(const cChannel *Channel) const
{
return false;
}
bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
{
return false;
@ -398,16 +439,28 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
Result = scrNotAvailable;
}
else {
Channels.Lock(false);
cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
if (!SetChannelDevice(Channel, LiveView))
// Stop section handling:
if (sectionHandler) {
sectionHandler->SetStatus(false);
sectionHandler->SetSource(0, 0);
}
if (SetChannelDevice(Channel, LiveView)) {
// Start section handling:
if (sectionHandler) {
sectionHandler->SetSource(Channel->Source(), Channel->Transponder());
sectionHandler->SetStatus(true);
}
}
else
Result = scrFailed;
Channels.Unlock();
}
if (Result == scrOk) {
if (LiveView && IsPrimaryDevice()) {
cSIProcessor::SetCurrentChannelID(Channel->GetChannelID());
if (LiveView && IsPrimaryDevice())
currentChannel = Channel->Number();
}
cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull
}
@ -419,6 +472,11 @@ bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
return false;
}
bool cDevice::HasLock(void)
{
return true;
}
bool cDevice::HasProgramme(void)
{
return Replaying() || pidHandles[ptAudio].pid || pidHandles[ptVideo].pid;
@ -608,6 +666,7 @@ int cDevice::Priority(void) const
int cDevice::CanShift(int Ca, int Priority, int UsedCards) const
{
return -1;//XXX+ too complex with multiple recordings per device
/*XXX
// Test whether a receiver on this device can be shifted to another one
// in order to perform a new receiving with the given Ca and Priority on this device:
int ShiftLevel = -1; // default means this device can't be shifted
@ -638,25 +697,17 @@ int cDevice::CanShift(int Ca, int Priority, int UsedCards) const
else if (Priority > this->Priority())
ShiftLevel = 0; // no shifting necessary, this device can do the job
return ShiftLevel;
XXX*/
}
int cDevice::ProvidesCa(int Ca) const
int cDevice::ProvidesCa(const cChannel *Channel) const
{
int Ca = Channel->Ca();
if (Ca == CardIndex() + 1)
return 1; // exactly _this_ card was requested
if (Ca && Ca <= MAXDEVICES)
return 0; // a specific card was requested, but not _this_ one
int result = Ca ? 0 : 1; // by default every card can provide FTA
int others = Ca ? 1 : 0;
for (int i = 0; i < MAXCACAPS; i++) {
if (caCaps[i]) {
if (caCaps[i] == Ca)
result = 1;
else
others++;
}
}
return result ? result + others : 0;
return !Ca; // by default every card can provide FTA
}
bool cDevice::Receiving(bool CheckAny) const
@ -670,8 +721,6 @@ bool cDevice::Receiving(bool CheckAny) const
void cDevice::Action(void)
{
dsyslog("receiver thread started on device %d (pid=%d)", CardIndex() + 1, getpid());
if (OpenDvr()) {
active = true;
for (; active;) {
@ -694,8 +743,6 @@ void cDevice::Action(void)
}
CloseDvr();
}
dsyslog("receiver thread ended on device %d (pid=%d)", CardIndex() + 1, getpid());
}
bool cDevice::OpenDvr(void)

View File

@ -4,13 +4,18 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.h 1.35 2003/11/07 13:15:45 kls Exp $
* $Id: device.h 1.37 2004/01/04 11:52:00 kls Exp $
*/
#ifndef __DEVICE_H
#define __DEVICE_H
#include "ci.h"
#include "eit.h"
#include "filter.h"
#include "pat.h"
#include "sdt.h"
#include "sections.h"
#include "thread.h"
#include "tools.h"
@ -127,7 +132,8 @@ public:
///< Returns the card index of this device (0 ... MAXDEVICES - 1).
int DeviceNumber(void) const;
///< Returns the number of this device (0 ... MAXDEVICES - 1).
int ProvidesCa(int Ca) const;
virtual int ProvidesCa(const cChannel *Channel) const;//XXX PLUGINS.html!!!
//XXX describe changed functionality!!!
///< Checks whether this device provides the given value in its
///< caCaps. Returns 0 if the value is not provided, 1 if only this
///< value is provided, and > 1 if this and other values are provided.
@ -157,6 +163,8 @@ protected:
public:
virtual bool ProvidesSource(int Source) const;
///< Returns true if this device can provide the given source.
virtual bool ProvidesTransponder(const cChannel *Channel) const;
///< XXX -> PLUGINS.html!
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
///< Returns true if this device can provide the given channel.
///< In case the device has cReceivers attached to it or it is the primary
@ -188,6 +196,10 @@ protected:
public:
static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; }
///< Returns the number of the current channel on the primary device.
virtual bool HasLock(void);//XXX PLUGINS.html
///< Returns true if the device has a lock on the requested transponder.
///< Default is true, a specific device implementation may return false
///< to indicate that it is not ready yet.
virtual bool HasProgramme(void);
///< Returns true if the device is currently showing any programme to
///< the user, either through replaying or live.
@ -222,6 +234,27 @@ protected:
///< Type indicates some special types of PIDs, which the device may
///< need to set in a specific way.
// Section filter facilities
private:
cSectionHandler *sectionHandler;
cEitFilter *eitFilter;
cPatFilter *patFilter;
cSdtFilter *sdtFilter;
protected:
void StartSectionHandler(void);
///< A derived device that provides section data must call
///< this function to actually set up the section handler.
public:
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
///< Opens a file handle for the given filter data.
///< A derived device that provides section data must
///< implement this function.
void AttachFilter(cFilter *Filter);
///< Attaches the given filter to this device.
void Detach(cFilter *Filter);
///< Detaches the given filter from this device.
// Common Interface facilities:
protected:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbdevice.c 1.67.1.4 2003/11/09 11:08:22 kls Exp $
* $Id: dvbdevice.c 1.76 2004/01/04 14:48:37 kls Exp $
*/
#include "dvbdevice.h"
@ -86,7 +86,7 @@ public:
virtual ~cDvbTuner();
bool IsTunedTo(const cChannel *Channel) const;
void Set(const cChannel *Channel, bool Tune, bool UseCa);
bool Locked(void) { return tunerStatus == tsLocked; }
bool Locked(void) { return tunerStatus >= tsLocked; }
};
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler)
@ -100,6 +100,7 @@ cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCi
useCa = false;
tunerStatus = tsIdle;
startTime = time(NULL);
SetDescription("tuner on device %d", cardIndex + 1);
Start();
}
@ -113,19 +114,18 @@ cDvbTuner::~cDvbTuner()
bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
{
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Frequency() == Channel->Frequency();
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Transponder() == Channel->Transponder();
}
void cDvbTuner::Set(const cChannel *Channel, bool Tune, bool UseCa)
{
cMutexLock MutexLock(&mutex);
bool CaChange = !(Channel->GetChannelID() == channel.GetChannelID());
if (Tune)
tunerStatus = tsSet;
else if (tunerStatus == tsCam && CaChange)
else if (tunerStatus == tsCam)
tunerStatus = tsTuned;
useCa = UseCa;
if (Channel->Ca() && CaChange)
if (Channel->Ca() && tunerStatus != tsCam)
startTime = time(NULL);
channel = *Channel;
newSet.Broadcast();
@ -247,7 +247,6 @@ bool cDvbTuner::SetFrontend(void)
void cDvbTuner::Action(void)
{
dsyslog("tuner thread started on device %d (pid=%d)", cardIndex + 1, getpid());
active = true;
while (active) {
cMutexLock MutexLock(&mutex);
@ -268,41 +267,31 @@ void cDvbTuner::Action(void)
continue;
}
}
if (tunerStatus >= tsLocked) {
if (ciHandler) {
if (ciHandler->Process() && useCa) {
if (tunerStatus != tsCam) {//XXX TODO update in case the CA descriptors have changed
for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
uchar buffer[2048];
int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot), sizeof(buffer), buffer);
if (length > 0) {
cCiCaPmt CaPmt(channel.Sid());
CaPmt.AddCaDescriptor(length, buffer);
if (channel.Vpid())
CaPmt.AddPid(channel.Vpid());
if (channel.Apid1())
CaPmt.AddPid(channel.Apid1());
if (channel.Apid2())
CaPmt.AddPid(channel.Apid2());
if (channel.Dpid1())
CaPmt.AddPid(channel.Dpid1());
if (ciHandler->SetCaPmt(CaPmt, Slot)) {
tunerStatus = tsCam;
startTime = 0;
}
}
}
if (ciHandler) {
if (ciHandler->Process() && useCa) {
if (tunerStatus == tsLocked) {
for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
cCiCaPmt CaPmt(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
if (CaPmt.Valid()) {
CaPmt.AddPid(channel.Vpid(), 2);
CaPmt.AddPid(channel.Apid1(), 4);
CaPmt.AddPid(channel.Apid2(), 4);
CaPmt.AddPid(channel.Dpid1(), 0);
if (ciHandler->SetCaPmt(CaPmt, Slot)) {
tunerStatus = tsCam;
startTime = 0;
}
}
}
else
tunerStatus = tsLocked;
}
}
}
}
else if (tunerStatus > tsLocked)
tunerStatus = tsLocked;
}
// in the beginning we loop more often to let the CAM connection start up fast
newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
}
dsyslog("tuner thread ended on device %d (pid=%d)", cardIndex + 1, getpid());
}
// --- cDvbDevice ------------------------------------------------------------
@ -313,13 +302,12 @@ cDvbDevice::cDvbDevice(int n)
{
dvbTuner = NULL;
frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
siProcessor = NULL;
spuDecoder = NULL;
playMode = pmNone;
// Devices that are present on all card types:
int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK);
int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK);
// Devices that are only present on cards with decoders:
@ -369,7 +357,6 @@ cDvbDevice::cDvbDevice(int n)
if (fd_frontend >= 0) {
dvb_frontend_info feinfo;
siProcessor = new cSIProcessor(DvbName(DEV_DVB_DEMUX, n));
if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) {
frontendType = feinfo.type;
ciHandler = cCiHandler::CreateCiHandler(DvbName(DEV_DVB_CA, n));
@ -382,12 +369,13 @@ cDvbDevice::cDvbDevice(int n)
esyslog("ERROR: can't open DVB device %d", n);
aPid1 = aPid2 = 0;
StartSectionHandler();
}
cDvbDevice::~cDvbDevice()
{
delete spuDecoder;
delete siProcessor;
delete dvbTuner;
// We're not explicitly closing any device files here, since this sometimes
// caused segfaults. Besides, the program is about to terminate anyway...
@ -445,6 +433,17 @@ bool cDvbDevice::HasDecoder(void) const
return fd_video >= 0 && fd_audio >= 0;
}
int cDvbDevice::ProvidesCa(const cChannel *Channel) const
{
if (Channel->Ca() >= 0x0100 && ciHandler) {
unsigned short ids[MAXCAIDS + 1];
for (int i = 0; i <= MAXCAIDS; i++) // '<=' copies the terminating 0!
ids[i] = Channel->Ca(i);
return ciHandler->ProvidesCa(ids);
}
return cDevice::ProvidesCa(Channel);
}
cOsdBase *cDvbDevice::NewOsd(int x, int y)
{
return new cDvbOsd(x, y);
@ -618,6 +617,30 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
return true;
}
int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
{
const char *FileName = DvbName(DEV_DVB_DEMUX, CardIndex());
int f = open(FileName, O_RDWR | O_NONBLOCK);
if (f >= 0) {
dmx_sct_filter_params sctFilterParams;
memset(&sctFilterParams, 0, sizeof(sctFilterParams));
sctFilterParams.pid = Pid;
sctFilterParams.timeout = 0;
sctFilterParams.flags = DMX_IMMEDIATE_START;
sctFilterParams.filter.filter[0] = Tid;
sctFilterParams.filter.mask[0] = Mask;
if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
return f;
else {
esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X)", Pid, Tid, Mask);
close(f);
}
}
else
esyslog("ERROR: can't open filter handle on '%s'", FileName);
return -1;
}
void cDvbDevice::TurnOffLiveMode(void)
{
// Avoid noise while switching:
@ -646,13 +669,18 @@ bool cDvbDevice::ProvidesSource(int Source) const
return true;
}
bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
{
return ProvidesSource(Channel->Source()) && ((Channel->Source() & cSource::st_Mask) != cSource::stSat || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()));
}
bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
{
bool result = false;
bool hasPriority = Priority < 0 || Priority > this->Priority();
bool needsDetachReceivers = false;
if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
if ((Channel->Vpid() || Channel->Apid1()) && ProvidesSource(Channel->Source()) && ProvidesCa(Channel)) {
result = hasPriority;
if (Priority >= 0 && Receiving()) {
if (dvbTuner->IsTunedTo(Channel)) {
@ -716,27 +744,19 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
TurnOnLivePIDs = false;
}
// Stop SI filtering:
if (siProcessor) {
siProcessor->SetCurrentTransponder(0, 0);
siProcessor->SetStatus(false);
}
// Turn off live PIDs if necessary:
if (TurnOffLivePIDs)
TurnOffLiveMode();
dvbTuner->Set(Channel, DoTune, !EITScanner.UsesDevice(this)); //XXX 1.3: this is an ugly hack - find a cleaner solution
dvbTuner->Set(Channel, DoTune, !EITScanner.UsesDevice(this)); //XXX 1.3: this is an ugly hack - find a cleaner solution//XXX
// PID settings:
if (TurnOnLivePIDs) {
aPid1 = Channel->Apid1();
aPid2 = Channel->Apid2();
int pPid = Channel->Ppid() ? Channel->Ppid() : Channel->Vpid();
if (!(AddPid(pPid, ptPcr) && AddPid(Channel->Apid1(), ptAudio) && AddPid(Channel->Vpid(), ptVideo))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(Channel->Apid1(), ptAudio) && AddPid(Channel->Vpid(), ptVideo))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
return false;
}
@ -747,16 +767,14 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
else if (StartTransferMode)
cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2()));
// Start SI filtering:
if (siProcessor) {
siProcessor->SetCurrentTransponder(Channel->Source(), Channel->Frequency());
siProcessor->SetStatus(true);
}
return true;
}
bool cDvbDevice::HasLock(void)
{
return dvbTuner->Locked();
}
void cDvbDevice::SetVolumeDevice(int Volume)
{
if (HasDecoder()) {
@ -830,16 +848,12 @@ bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
if (siProcessor)
siProcessor->SetStatus(true);
break;
case pmAudioVideo:
if (playMode == pmNone)
TurnOffLiveMode();
// continue with next...
case pmAudioOnlyBlack:
if (siProcessor)
siProcessor->SetStatus(false);
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo));
@ -848,8 +862,6 @@ bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
CHECK(ioctl(fd_video, VIDEO_PLAY));
break;
case pmAudioOnly:
if (siProcessor)
siProcessor->SetStatus(false);
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
CHECK(ioctl(fd_audio, AUDIO_STOP, true));
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
@ -859,8 +871,6 @@ bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
break;
case pmExtern_THIS_SHOULD_BE_AVOIDED:
if (siProcessor)
siProcessor->SetStatus(false);
close(fd_video);
close(fd_audio);
fd_video = fd_audio = -1;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbdevice.h 1.24 2003/11/07 13:17:13 kls Exp $
* $Id: dvbdevice.h 1.26 2004/01/03 10:21:50 kls Exp $
*/
#ifndef __DVBDEVICE_H
@ -14,7 +14,6 @@
#include <linux/dvb/version.h>
#include "device.h"
#include "dvbspu.h"
#include "eit.h"
#if DVB_API_VERSION != 3
#error VDR requires Linux DVB driver API version 3!
@ -45,6 +44,7 @@ protected:
public:
cDvbDevice(int n);
virtual ~cDvbDevice();
virtual int ProvidesCa(const cChannel *Channel) const;
virtual bool HasDecoder(void) const;
// OSD facilities
@ -62,15 +62,23 @@ private:
void TurnOffLiveMode(void);
public:
virtual bool ProvidesSource(int Source) const;
virtual bool ProvidesTransponder(const cChannel *Channel) const;
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
protected:
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
public:
virtual bool HasLock(void);
// PID handle facilities
protected:
virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
// Section filter facilities
protected:
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
// Image Grab facilities
private:
@ -95,11 +103,6 @@ protected:
virtual const char **GetAudioTracksDevice(int *CurrentTrack = NULL) const;
virtual void SetAudioTrackDevice(int Index);
// EIT facilities
private:
cSIProcessor *siProcessor;
// Player facilities
protected:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbplayer.c 1.22 2003/05/24 09:04:26 kls Exp $
* $Id: dvbplayer.c 1.23 2003/10/18 11:31:54 kls Exp $
*/
#include "dvbplayer.h"
@ -93,6 +93,7 @@ public:
};
cNonBlockingFileReader::cNonBlockingFileReader(void)
:cThread("non blocking file reader")
{
f = -1;
buffer = NULL;
@ -146,7 +147,6 @@ int cNonBlockingFileReader::Read(int FileHandle, uchar *Buffer, int Length)
void cNonBlockingFileReader::Action(void)
{
dsyslog("non blocking file reader thread started (pid=%d)", getpid());
active = true;
while (active) {
cMutexLock MutexLock(&mutex);
@ -165,7 +165,6 @@ void cNonBlockingFileReader::Action(void)
}
newSet.TimedWait(mutex, 1000);
}
dsyslog("non blocking file reader thread ended (pid=%d)", getpid());
}
// --- cDvbPlayer ------------------------------------------------------------
@ -235,6 +234,7 @@ public:
int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 };
cDvbPlayer::cDvbPlayer(const char *FileName)
:cThread("dvbplayer")
{
nonBlockingFileReader = NULL;
ringBuffer = NULL;
@ -405,8 +405,6 @@ void cDvbPlayer::Activate(bool On)
void cDvbPlayer::Action(void)
{
dsyslog("dvbplayer thread started (pid=%d)", getpid());
uchar *b = NULL;
uchar *p = NULL;
int pc = 0;
@ -550,8 +548,6 @@ void cDvbPlayer::Action(void)
cNonBlockingFileReader *nbfr = nonBlockingFileReader;
nonBlockingFileReader = NULL;
delete nbfr;
dsyslog("dvbplayer thread ended (pid=%d)", getpid());
}
void cDvbPlayer::Pause(void)

1618
eit.c

File diff suppressed because it is too large Load Diff

190
eit.h
View File

@ -1,186 +1,22 @@
/***************************************************************************
eit.h - description
-------------------
begin : Fri Aug 25 2000
copyright : (C) 2000 by Robert Schneider
email : Robert.Schneider@web.de
2001-08-15: Adapted to 'libdtv' by Rolf Hakenes <hakenes@hippomi.de>
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: eit.h 1.29 2003/05/17 09:15:56 kls Exp $
***************************************************************************/
/*
* eit.h: EIT section filter
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: eit.h 1.30 2003/12/21 14:51:50 kls Exp $
*/
#ifndef __EIT_H
#define __EIT_H
#include "channels.h"
#include "thread.h"
#include "tools.h"
#include "filter.h"
#define MAXEPGBUGFIXLEVEL 2
class cEventInfo : public cListObject {
friend class cSchedule;
friend class cEIT;
private:
unsigned char uTableID; // Table ID this event came from
tChannelID channelID; // Channel ID of program for that event
bool bIsFollowing; // true if this is the next event on this channel
bool bIsPresent; // true if this is the present event running
char *pExtendedDescription; // Extended description of this event
char *pSubtitle; // Subtitle of event
char *pTitle; // Title of event
unsigned short uEventID; // Event ID of this event
long lDuration; // duration of event in seconds
time_t tTime; // Start time
int nChannelNumber; // the actual channel number from VDR's channel list (used in cMenuSchedule for sorting by channel number)
class cEitFilter : public cFilter {
protected:
void SetTableID(unsigned char tableid);
void SetFollowing(bool foll);
void SetPresent(bool pres);
void SetTitle(const char *string);
void SetChannelID(tChannelID channelid);
void SetEventID(unsigned short evid);
void SetDuration(long l);
void SetTime(time_t t);
void SetExtendedDescription(const char *string);
void SetSubtitle(const char *string);
cEventInfo(tChannelID channelid, unsigned short eventid);
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public:
~cEventInfo();
const unsigned char GetTableID(void) const;
const char *GetTimeString(void) const;
const char *GetEndTimeString(void) const;
const char *GetDate(void) const;
bool IsFollowing(void) const;
bool IsPresent(void) const;
const char *GetExtendedDescription(void) const;
const char *GetSubtitle(void) const;
const char *GetTitle(void) const;
unsigned short GetEventID(void) const;
long GetDuration(void) const;
time_t GetTime(void) const;
tChannelID GetChannelID(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 char *Prefix = "") const;
static bool Read(FILE *f, cSchedule *Schedule);
void FixEpgBugs(void);
cEitFilter(void);
};
class cSchedule : public cListObject {
friend class cSchedules;
friend class cEIT;
private:
cEventInfo *pPresent;
cEventInfo *pFollowing;
tChannelID channelID;
cList<cEventInfo> Events;
protected:
void SetChannelID(tChannelID channelid);
bool SetFollowingEvent(cEventInfo *pEvent);
bool SetPresentEvent(cEventInfo *pEvent);
void Cleanup(time_t tTime);
void Cleanup(void);
cSchedule(tChannelID channelid = tChannelID::InvalidID);
public:
~cSchedule();
cEventInfo *AddEvent(cEventInfo *EventInfo);
const cEventInfo *GetPresentEvent(void) const;
const cEventInfo *GetFollowingEvent(void) const;
tChannelID GetChannelID(void) const;
const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
const cEventInfo *GetEventAround(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 char *Prefix = "") const;
static bool Read(FILE *f, cSchedules *Schedules);
};
class cSchedules : public cList<cSchedule> {
friend class cSchedule;
friend class cSIProcessor;
private:
const cSchedule *pCurrentSchedule;
tChannelID currentChannelID;
protected:
const cSchedule *AddChannelID(tChannelID channelid);
const cSchedule *SetCurrentChannelID(tChannelID channelid);
void Cleanup();
public:
cSchedules(void);
~cSchedules();
const cSchedule *GetSchedule(tChannelID channelid) const;
const cSchedule *GetSchedule(void) const;
void Dump(FILE *f, const char *Prefix = "") const;
static bool Read(FILE *f);
};
typedef struct sip_filter {
unsigned short pid;
u_char tid;
int handle;
bool inuse;
}SIP_FILTER;
class cCaDescriptor;
class cSIProcessor : public cThread {
private:
static int numSIProcessors;
static cSchedules *schedules;
static cMutex schedulesMutex;
static cList<cCaDescriptor> caDescriptors;
static cMutex caDescriptorsMutex;
static const char *epgDataFileName;
static time_t lastDump;
bool masterSIProcessor;
int currentSource;
int currentTransponder;
int statusCount;
int pmtIndex;
int pmtPid;
SIP_FILTER *filters;
char *fileName;
bool active;
void Action(void);
bool AddFilter(unsigned short pid, u_char tid, u_char mask = 0xFF);
bool DelFilter(unsigned short pid, u_char tid);
bool ShutDownFilters(void);
void NewCaDescriptor(struct Descriptor *d, int ServiceId);
public:
cSIProcessor(const char *FileName);
~cSIProcessor();
static void SetEpgDataFileName(const char *FileName);
static const char *GetEpgDataFileName(void);
static const cSchedules *Schedules(cMutexLock &MutexLock);
// Caller must provide a cMutexLock which has to survive the entire
// time the returned cSchedules is accessed. Once the cSchedules is no
// longer used, the cMutexLock must be destroyed.
static int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data);
///< Gets all CA descriptors for a given channel.
///< Copies all available CA descriptors for the given Source, Transponder and ServiceId
///< into the provided buffer at Data (at most BufSize bytes). Only those CA descriptors
///< are copied that match one of the given CA system IDs.
///< \return Returns the number of bytes copied into Data (0 if no CA descriptors are
///< available), or -1 if BufSize was too small to hold all CA descriptors.
static bool Read(FILE *f = NULL);
static void Clear(void);
void SetStatus(bool On);
void SetCurrentTransponder(int CurrentSource, int CurrentTransponder);
static bool SetCurrentChannelID(tChannelID channelid);
static void TriggerDump(void);
};
#endif
#endif //__EIT_H

144
eitscan.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: eitscan.c 1.14 2003/09/06 13:06:13 kls Exp $
* $Id: eitscan.c 1.15 2004/01/04 14:54:01 kls Exp $
*/
#include "eitscan.h"
@ -12,6 +12,68 @@
#include "channels.h"
#include "dvbdevice.h"
// --- cScanData -------------------------------------------------------------
class cScanData : public cListObject {
private:
int source;
int transponder;
public:
cScanData(int Source, int Transponder);
virtual bool operator< (const cListObject &ListObject);
int Source(void) { return source; }
int Transponder(void) { return transponder; }
cChannel *GetChannel(void);
};
cScanData::cScanData(int Source, int Transponder)
{
source = Source;
transponder = Transponder;
}
bool cScanData::operator< (const cListObject &ListObject)
{
cScanData *sd = (cScanData *)&ListObject;
return source < sd->source || source == sd->source && transponder < sd->transponder;
}
//XXX this might be done differently later...
cChannel *cScanData::GetChannel(void)
{
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
if (!Channel->GroupSep() && Channel->Source() == source && ISTRANSPONDER(Channel->Transponder(), transponder))
return Channel;
}
return NULL;
}
// --- cScanList -------------------------------------------------------------
class cScanList : public cList<cScanData> {
public:
cScanList(void);
void AddTransponder(const cChannel *Channel);
};
cScanList::cScanList(void)
{
for (cChannel *ch = Channels.First(); ch; ch = Channels.Next(ch))
AddTransponder(ch);
Sort();
}
void cScanList::AddTransponder(const cChannel *Channel)
{
for (cScanData *sd = First(); sd; sd = Next(sd)) {
if (sd->Source() == Channel->Source() && sd->Transponder() == Channel->Transponder())
return;
}
Add(new cScanData(Channel->Source(), Channel->Transponder()));
}
// --- cEITScanner -----------------------------------------------------------
cEITScanner EITScanner;
cEITScanner::cEITScanner(void)
@ -20,24 +82,12 @@ cEITScanner::cEITScanner(void)
currentDevice = NULL;
currentChannel = 0;
memset(lastChannel, 0, sizeof(lastChannel));
numTransponders = 0;
transponders = NULL;
scanList = NULL;
}
cEITScanner::~cEITScanner()
{
free(transponders);
}
bool cEITScanner::TransponderScanned(cChannel *Channel)
{
for (int i = 0; i < numTransponders; i++) {
if (transponders[i] == Channel->Frequency())
return true;
}
transponders = (int *)realloc(transponders, ++numTransponders * sizeof(int));
transponders[numTransponders - 1] = Channel->Frequency();
return false;
delete scanList;
}
void cEITScanner::Activity(void)
@ -54,37 +104,51 @@ void cEITScanner::Process(void)
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
time_t now = time(NULL);
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
for (int i = 0; i < cDevice::NumDevices(); i++) {
cDevice *Device = cDevice::GetDevice(i);
if (Device && Device->CardIndex() < MAXDVBDEVICES) {
if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
if (!(Device->Receiving(true) || Device->Replaying())) {
for (;;) {
cChannel *Channel = Channels.GetByNumber(lastChannel[Device->DeviceNumber()] + 1, 1);
if (Channel) {
lastChannel[Device->DeviceNumber()] = Channel->Number();
if (Channel->Sid() && Device->ProvidesChannel(Channel) && !TransponderScanned(Channel)) {
if (Device == cDevice::PrimaryDevice() && !currentChannel) {
currentChannel = Device->CurrentChannel();
if (Channels.Lock(false, 10)) {
if (!scanList)
scanList = new cScanList();
for (bool AnyDeviceSwitched = false; !AnyDeviceSwitched; ) {
cScanData *ScanData = NULL;
for (int i = 0; i < cDevice::NumDevices(); i++) {
cDevice *Device = cDevice::GetDevice(i);
if (Device) {
if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
if (!(Device->Receiving(true) || Device->Replaying())) {
if (!ScanData)
ScanData = scanList->First();
if (ScanData) {
cChannel *Channel = ScanData->GetChannel();
//XXX if (Device->ProvidesTransponder(Channel)) {
if ((!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= 0x0100) && Device->ProvidesTransponder(Channel)) { //XXX temporary for the 'sky' plugin
if (Device == cDevice::PrimaryDevice() && !currentChannel)
currentChannel = Device->CurrentChannel();
currentDevice = Device;//XXX see also dvbdevice.c!!!
Device->SwitchChannel(Channel, false);
currentDevice = NULL;
scanList->Del(ScanData);
ScanData = NULL;
AnyDeviceSwitched = true;
}
currentDevice = Device;
Device->SwitchChannel(Channel, false);
currentDevice = NULL;
break;
}
}
else {
if (lastChannel[Device->DeviceNumber()])
numTransponders = 0;
lastChannel[Device->DeviceNumber()] = 0;
break;
else
break;
}
}
}
}
}
if (ScanData && !AnyDeviceSwitched) {
scanList->Del(ScanData);
ScanData = NULL;
}
if (!scanList->Count()) {
delete scanList;
scanList = NULL;
break;
}
}
}
lastScan = time(NULL);
Channels.Unlock();
lastScan = time(NULL);
}
}
}
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: eitscan.h 1.4 2003/09/06 13:05:51 kls Exp $
* $Id: eitscan.h 1.5 2004/01/03 13:08:39 kls Exp $
*/
#ifndef __EITSCAN_H
@ -13,6 +13,8 @@
#include <time.h>
#include "config.h"
class cScanList;
class cEITScanner {
private:
enum { ActivityTimeout = 60,
@ -22,8 +24,7 @@ private:
cDevice *currentDevice;
int currentChannel;
int lastChannel[MAXDEVICES];
int numTransponders, *transponders;
bool TransponderScanned(cChannel *Channel);
cScanList *scanList;
public:
cEITScanner(void);
~cEITScanner();

684
epg.c Normal file
View File

@ -0,0 +1,684 @@
/*
* epg.c: Electronic Program Guide
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
* $Id: epg.c 1.3 2004/01/04 14:07:46 kls Exp $
*/
#include "epg.h"
#include <ctype.h>
#include <time.h>
// --- cEvent ----------------------------------------------------------------
cEvent::cEvent(tChannelID ChannelID, u_int16_t EventID)
{
channelID = ChannelID;
eventID = EventID;
tableID = 0;
version = 0xFF; // actual version numbers are 0..31
isPresent = isFollowing = false;
title = NULL;
shortText = NULL;
description = NULL;
startTime = 0;
duration = 0;
channelNumber = 0;
}
cEvent::~cEvent()
{
free(title);
free(shortText);
free(description);
}
void cEvent::SetEventID(u_int16_t EventID)
{
eventID = EventID;
}
void cEvent::SetTableID(uchar TableID)
{
tableID = TableID;
}
void cEvent::SetVersion(uchar Version)
{
version = Version;
}
void cEvent::SetIsPresent(bool IsPresent)
{
isPresent = IsPresent;
}
void cEvent::SetIsFollowing(bool IsFollowing)
{
isFollowing = IsFollowing;
}
void cEvent::SetTitle(const char *Title)
{
title = strcpyrealloc(title, Title);
}
void cEvent::SetShortText(const char *ShortText)
{
shortText = strcpyrealloc(shortText, ShortText);
}
void cEvent::SetDescription(const char *Description)
{
description = strcpyrealloc(description, Description);
}
void cEvent::SetStartTime(time_t StartTime)
{
startTime = StartTime;
}
void cEvent::SetDuration(int Duration)
{
duration = Duration;
}
const char *cEvent::GetDateString(void) const
{
static char buf[25];
struct tm tm_r;
strftime(buf, sizeof(buf), "%d.%m.%Y", localtime_r(&startTime, &tm_r));
return buf;
}
const char *cEvent::GetTimeString(void) const
{
static char buf[25];
struct tm tm_r;
strftime(buf, sizeof(buf), "%R", localtime_r(&startTime, &tm_r));
return buf;
}
const char *cEvent::GetEndTimeString(void) const
{
static char buf[25];
time_t EndTime = startTime + duration;
struct tm tm_r;
strftime(buf, sizeof(buf), "%R", localtime_r(&EndTime, &tm_r));
return buf;
}
void cEvent::Dump(FILE *f, const char *Prefix) const
{
if (startTime + duration >= time(NULL)) {
fprintf(f, "%sE %u %ld %d %X\n", Prefix, eventID, startTime, duration, tableID);
if (!isempty(title))
fprintf(f, "%sT %s\n", Prefix, title);
if (!isempty(shortText))
fprintf(f, "%sS %s\n", Prefix, shortText);
if (!isempty(description))
fprintf(f, "%sD %s\n", Prefix, description);
fprintf(f, "%se\n", Prefix);
}
}
bool cEvent::Read(FILE *f, cSchedule *Schedule)
{
if (Schedule) {
cEvent *Event = NULL;
char *s;
while ((s = readline(f)) != NULL) {
char *t = skipspace(s + 1);
switch (*s) {
case 'E': if (!Event) {
unsigned int EventID;
time_t StartTime;
int Duration;
unsigned int TableID = 0;
int n = sscanf(t, "%u %ld %d %X", &EventID, &StartTime, &Duration, &TableID);
if (n == 3 || n == 4) {
Event = (cEvent *)Schedule->GetEvent(EventID, StartTime);
if (!Event)
Event = Schedule->AddEvent(new cEvent(Schedule->ChannelID(), EventID));
if (Event) {
Event->SetTableID(TableID);
Event->SetStartTime(StartTime);
Event->SetDuration(Duration);
}
}
}
break;
case 'T': if (Event)
Event->SetTitle(t);
break;
case 'S': if (Event)
Event->SetShortText(t);
break;
case 'D': if (Event)
Event->SetDescription(t);
break;
case 'e': Event = NULL;
break;
case 'c': // to keep things simple we react on 'c' here
return true;
default: esyslog("ERROR: unexpected tag while reading EPG data: %s", s);
return false;
}
}
esyslog("ERROR: unexpected end of file while reading EPG data");
}
return false;
}
#define MAXEPGBUGFIXSTATS 7
#define MAXEPGBUGFIXCHANS 100
struct tEpgBugFixStats {
int hits;
int n;
tChannelID channelIDs[MAXEPGBUGFIXCHANS];
tEpgBugFixStats(void) { hits = n = 0; }
};
tEpgBugFixStats EpgBugFixStats[MAXEPGBUGFIXSTATS];
static void EpgBugFixStat(int Number, tChannelID ChannelID)
{
if (0 <= Number && Number < MAXEPGBUGFIXSTATS) {
tEpgBugFixStats *p = &EpgBugFixStats[Number];
p->hits++;
int i = 0;
for (; i < p->n; i++) {
if (p->channelIDs[i] == ChannelID)
break;
}
if (i == p->n && p->n < MAXEPGBUGFIXCHANS)
p->channelIDs[p->n++] = ChannelID;
}
}
void ReportEpgBugFixStats(bool Reset)
{
if (Setup.EPGBugfixLevel > 0) {
bool GotHits = false;
char buffer[1024];
for (int i = 0; i < MAXEPGBUGFIXSTATS; i++) {
const char *delim = "\t";
tEpgBugFixStats *p = &EpgBugFixStats[i];
if (p->hits) {
bool PrintedStats = false;
char *q = buffer;
*buffer = 0;
for (int c = 0; c < p->n; c++) {
cChannel *channel = Channels.GetByChannelID(p->channelIDs[c], true);
if (channel) {
if (!GotHits) {
dsyslog("=====================");
dsyslog("EPG bugfix statistics");
dsyslog("=====================");
dsyslog("IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED");
dsyslog("CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEvent::FixEpgBugs()");
dsyslog("IN VDR/epg.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!");
dsyslog("=====================");
dsyslog("Fix\tHits\tChannels");
GotHits = true;
}
if (!PrintedStats) {
q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits);
PrintedStats = true;
}
q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->Name());
delim = ", ";
if (q - buffer > 80) {
q += snprintf(q, sizeof(buffer) - (q - buffer), "%s...", delim);
break;
}
}
}
if (*buffer)
dsyslog("%s", buffer);
}
if (Reset)
p->hits = p->n = 0;
}
if (GotHits)
dsyslog("=====================");
}
}
void cEvent::FixEpgBugs(void)
{
// VDR can't usefully handle newline characters in the EPG data, so let's
// always convert them to blanks (independent of the setting of EPGBugfixLevel):
strreplace(title, '\n', ' ');
strreplace(shortText, '\n', ' ');
strreplace(description, '\n', ' ');
if (Setup.EPGBugfixLevel == 0)
return;
// Some TV stations apparently have their own idea about how to fill in the
// EPG data. Let's fix their bugs as good as we can:
if (title) {
// Some channels put too much information into the ShortText and leave the
// Description empty:
//
// Title
// (NAT, Year Min')[ ["ShortText". ]Description]
//
if (shortText && !description) {
if (*shortText == '(') {
char *e = strchr(shortText + 1, ')');
if (e) {
if (*(e + 1)) {
if (*++e == ' ')
if (*(e + 1) == '"')
e++;
}
else
e = NULL;
char *s = e ? strdup(e) : NULL;
free(shortText);
shortText = s;
EpgBugFixStat(0, ChannelID());
// now the fixes #1 and #2 below will handle the rest
}
}
}
// Some channels put the ShortText in quotes and use either the ShortText
// or the Description field, depending on how long the string is:
//
// Title
// "ShortText". Description
//
if ((shortText == NULL) != (description == NULL)) {
char *p = shortText ? shortText : description;
if (*p == '"') {
const char *delim = "\".";
char *e = strstr(p + 1, delim);
if (e) {
*e = 0;
char *s = strdup(p + 1);
char *d = strdup(e + strlen(delim));
free(shortText);
free(description);
shortText = s;
description = d;
EpgBugFixStat(1, ChannelID());
}
}
}
// Some channels put the Description into the ShortText (preceeded
// by a blank) if there is no actual ShortText and the Description
// is short enough:
//
// Title
// Description
//
if (shortText && !description) {
if (*shortText == ' ') {
memmove(shortText, shortText + 1, strlen(shortText));
description = shortText;
shortText = NULL;
EpgBugFixStat(2, ChannelID());
}
}
// Sometimes they repeat the Title in the ShortText:
//
// Title
// Title
//
if (shortText && strcmp(title, shortText) == 0) {
free(shortText);
shortText = NULL;
EpgBugFixStat(3, ChannelID());
}
// Some channels put the ShortText between double quotes, which is nothing
// but annoying (some even put a '.' after the closing '"'):
//
// Title
// "ShortText"[.]
//
if (shortText && *shortText == '"') {
int l = strlen(shortText);
if (l > 2 && (shortText[l - 1] == '"' || (shortText[l - 1] == '.' && shortText[l - 2] == '"'))) {
memmove(shortText, shortText + 1, l);
char *p = strrchr(shortText, '"');
if (p)
*p = 0;
EpgBugFixStat(4, ChannelID());
}
}
if (Setup.EPGBugfixLevel <= 1)
return;
// Some channels apparently try to do some formatting in the texts,
// which is a bad idea because they have no way of knowing the width
// of the window that will actually display the text.
// Remove excess whitespace:
title = compactspace(title);
shortText = compactspace(shortText);
description = compactspace(description);
// Remove superfluous hyphens:
if (description) {
char *p = description;
while (*p && *(p + 1) && *(p + 2)) {
if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) {
if (!startswith(p + 2, "und ")) { // special case in German, as in "Lach- und Sachgeschichten"
memmove(p, p + 2, strlen(p + 2) + 1);
EpgBugFixStat(5, ChannelID());
}
}
p++;
}
}
#define MAX_USEFUL_EPISODE_LENGTH 40
// Some channels put a whole lot of information in the ShortText and leave
// the Description totally empty. So if the ShortText length exceeds
// MAX_USEFUL_EPISODE_LENGTH, let's put this into the Description
// instead:
if (!isempty(shortText) && isempty(description)) {
if (strlen(shortText) > MAX_USEFUL_EPISODE_LENGTH) {
free(description);
description = shortText;
shortText = NULL;
EpgBugFixStat(6, ChannelID());
}
}
// Some channels use the ` ("backtick") character, where a ' (single quote)
// would be normally used. Actually, "backticks" in normal text don't make
// much sense, so let's replace them:
strreplace(title, '`', '\'');
strreplace(shortText, '`', '\'');
strreplace(description, '`', '\'');
}
}
// --- cSchedule -------------------------------------------------------------
cSchedule::cSchedule(tChannelID ChannelID)
{
channelID = ChannelID;
present = following = NULL;
}
cEvent *cSchedule::AddEvent(cEvent *Event)
{
events.Add(Event);
return Event;
}
const cEvent *cSchedule::GetPresentEvent(void) const
{
return GetEventAround(time(NULL));
}
const cEvent *cSchedule::GetFollowingEvent(void) const
{
const cEvent *pe = NULL;
time_t now = time(NULL);
time_t delta = INT_MAX;
for (cEvent *p = events.First(); p; p = events.Next(p)) {
time_t dt = p->StartTime() - now;
if (dt > 0 && dt < delta) {
delta = dt;
pe = p;
}
}
return pe;
}
const cEvent *cSchedule::GetEvent(u_int16_t EventID, time_t StartTime) const
{
// Returns either the event info with the given EventID or, if that one can't
// be found, the one with the given StartTime (or NULL if neither can be found)
cEvent *pt = NULL;
for (cEvent *pe = events.First(); pe; pe = events.Next(pe)) {
if (pe->EventID() == EventID)
return pe;
if (StartTime > 0 && pe->StartTime() == StartTime) // 'StartTime < 0' is apparently used with NVOD channels
pt = pe;
}
return pt;
}
const cEvent *cSchedule::GetEventAround(time_t Time) const
{
const cEvent *pe = NULL;
time_t delta = INT_MAX;
for (cEvent *p = events.First(); p; p = events.Next(p)) {
time_t dt = Time - p->StartTime();
if (dt >= 0 && dt < delta && p->StartTime() + p->Duration() >= Time) {
delta = dt;
pe = p;
}
}
return pe;
}
bool cSchedule::SetPresentEvent(cEvent *Event)
{
if (present)
present->SetIsPresent(false);
present = Event;
present->SetIsPresent(true);
return true;
}
bool cSchedule::SetFollowingEvent(cEvent *Event)
{
if (following)
following->SetIsFollowing(false);
following = Event;
following->SetIsFollowing(true);
return true;
}
void cSchedule::Cleanup(void)
{
Cleanup(time(NULL));
}
void cSchedule::Cleanup(time_t Time)
{
cEvent *Event;
for (int a = 0; true ; a++) {
Event = events.Get(a);
if (!Event)
break;
if (Event->StartTime() + Event->Duration() + 3600 < Time) { // adding one hour for safety
events.Del(Event);
a--;
}
}
}
void cSchedule::Dump(FILE *f, const char *Prefix) const
{
cChannel *channel = Channels.GetByChannelID(channelID, true);
if (channel) {
fprintf(f, "%sC %s %s\n", Prefix, channel->GetChannelID().ToString(), channel->Name());
for (cEvent *p = events.First(); p; p = events.Next(p))
p->Dump(f, Prefix);
fprintf(f, "%sc\n", Prefix);
}
}
bool cSchedule::Read(FILE *f, cSchedules *Schedules)
{
if (Schedules) {
char *s;
while ((s = readline(f)) != NULL) {
if (*s == 'C') {
s = skipspace(s + 1);
char *p = strchr(s, ' ');
if (p)
*p = 0; // strips optional channel name
if (*s) {
tChannelID channelID = tChannelID::FromString(s);
if (channelID.Valid()) {
cSchedule *p = Schedules->AddSchedule(channelID);
if (p) {
if (!cEvent::Read(f, p))
return false;
}
}
else {
esyslog("ERROR: illegal channel ID: %s", s);
return false;
}
}
}
else {
esyslog("ERROR: unexpected tag while reading EPG data: %s", s);
return false;
}
}
return true;
}
return false;
}
// --- cSchedulesLock --------------------------------------------------------
cSchedulesLock::cSchedulesLock(bool WriteLock, int TimeoutMs)
{
locked = cSchedules::schedules.rwlock.Lock(WriteLock, TimeoutMs);
}
cSchedulesLock::~cSchedulesLock()
{
if (locked)
cSchedules::schedules.rwlock.Unlock();
}
// --- cSchedules ------------------------------------------------------------
cSchedules cSchedules::schedules;
const char *cSchedules::epgDataFileName = NULL;
time_t cSchedules::lastCleanup = time(NULL);
time_t cSchedules::lastDump = time(NULL);
const cSchedules *cSchedules::Schedules(cSchedulesLock &SchedulesLock)
{
return SchedulesLock.Locked() ? &schedules : NULL;
}
void cSchedules::SetEpgDataFileName(const char *FileName)
{
delete epgDataFileName;
if (FileName)
epgDataFileName = strdup(FileName);
}
void cSchedules::Cleanup(bool Force)
{
if (Force)
lastDump = 0;
time_t now = time(NULL);
struct tm tm_r;
struct tm *ptm = localtime_r(&now, &tm_r);
if (now - lastCleanup > 3600 && ptm->tm_hour == 5) {
isyslog("cleaning up schedules data");
cSchedulesLock SchedulesLock(true, 1000);
cSchedules *s = (cSchedules *)Schedules(SchedulesLock);
if (s) {
for (cSchedule *p = s->First(); p; p = s->Next(p))
p->Cleanup(now);
}
lastCleanup = now;
ReportEpgBugFixStats(true);
}
if (epgDataFileName && now - lastDump > 600) {
cSafeFile f(epgDataFileName);
if (f.Open()) {
Dump(f);
f.Close();
}
else
LOG_ERROR;
lastDump = now;
}
}
bool cSchedules::ClearAll(void)
{
cSchedulesLock SchedulesLock(true, 1000);
cSchedules *s = (cSchedules *)Schedules(SchedulesLock);
if (s) {
s->Clear();
return true;
}
return false;
}
bool cSchedules::Dump(FILE *f, const char *Prefix)
{
cSchedulesLock SchedulesLock;
cSchedules *s = (cSchedules *)Schedules(SchedulesLock);
if (s) {
for (cSchedule *p = s->First(); p; p = s->Next(p))
p->Dump(f, Prefix);
return true;
}
return false;
}
bool cSchedules::Read(FILE *f)
{
cSchedulesLock SchedulesLock(true, 1000);
cSchedules *s = (cSchedules *)Schedules(SchedulesLock);
if (s) {
bool OwnFile = f == NULL;
if (OwnFile) {
if (epgDataFileName && access(epgDataFileName, R_OK) == 0) {
dsyslog("reading EPG data from %s", epgDataFileName);
if ((f = fopen(epgDataFileName, "r")) == NULL) {
LOG_ERROR;
return false;
}
}
else
return false;
}
bool result = cSchedule::Read(f, s);
if (OwnFile)
fclose(f);
return result;
}
return false;
}
cSchedule *cSchedules::AddSchedule(tChannelID ChannelID)
{
ChannelID.ClrRid();
cSchedule *p = (cSchedule *)GetSchedule(ChannelID);
if (!p) {
p = new cSchedule(ChannelID);
Add(p);
}
return p;
}
const cSchedule *cSchedules::GetSchedule(tChannelID ChannelID) const
{
ChannelID.ClrRid();
for (cSchedule *p = First(); p; p = Next(p)) {
if (p->ChannelID() == ChannelID)
return p;
}
return NULL;
}

134
epg.h Normal file
View File

@ -0,0 +1,134 @@
/*
* epg.h: Electronic Program Guide
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
* $Id: epg.h 1.3 2004/01/03 17:00:25 kls Exp $
*/
#ifndef __EPG_H
#define __EPG_H
#include "channels.h"
#include "thread.h"
#include "tools.h"
#define MAXEPGBUGFIXLEVEL 2
class cSchedule;
class cEvent : public cListObject {
private:
tChannelID channelID; // Channel ID of program for this event
u_int16_t eventID; // Event ID of this event
uchar tableID; // Table ID this event came from
uchar version; // Version number of section this event came from
//XXX present/following obsolete???
bool isPresent; // true if this is the present event running
bool isFollowing; // true if this is the next event on this channel
char *title; // Title of this event
char *shortText; // Short description of this event (typically the episode name in case of a series)
char *description; // Description of this event
time_t startTime; // Start time of this event
int duration; // Duration of this event in seconds
//XXX find an other solution, avoiding channelNumber???
int channelNumber; // the actual channel number from VDR's channel list (used in cMenuSchedule for sorting by channel number)
public:
cEvent(tChannelID ChannelID, u_int16_t EventID);
~cEvent();
tChannelID ChannelID(void) const { return channelID; }
u_int16_t EventID(void) const { return eventID; }
uchar TableID(void) const { return tableID; }
uchar Version(void) const { return version; }
bool IsPresent(void) const { return isPresent; }
bool IsFollowing(void) const { return isFollowing; }
const char *Title(void) const { return title; }
const char *ShortText(void) const { return shortText; }
const char *Description(void) const { return description; }
time_t StartTime(void) const { return startTime; }
int Duration(void) const { return duration; }
int ChannelNumber(void) const { return channelNumber; }
const char *GetDateString(void) const;
const char *GetTimeString(void) const;
const char *GetEndTimeString(void) const;
void SetEventID(u_int16_t EventID);
void SetTableID(uchar TableID);
void SetVersion(uchar Version);
void SetIsPresent(bool IsPresent);
void SetIsFollowing(bool IsFollowing);
void SetTitle(const char *Title);
void SetShortText(const char *ShortText);
void SetDescription(const char *Description);
void SetStartTime(time_t StartTime);
void SetDuration(int Duration);
void SetChannelNumber(int ChannelNumber) const { ((cEvent *)this)->channelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' //XXX
void Dump(FILE *f, const char *Prefix = "") const;
static bool Read(FILE *f, cSchedule *Schedule);
void FixEpgBugs(void);
};
class cSchedules;
class cSchedule : public cListObject {
private:
tChannelID channelID;
cList<cEvent> events;
cEvent *present;
cEvent *following;
public:
cSchedule(tChannelID ChannelID);
tChannelID ChannelID(void) const { return channelID; }
bool SetPresentEvent(cEvent *Event);
bool SetFollowingEvent(cEvent *Event);
void Cleanup(time_t Time);
void Cleanup(void);
cEvent *AddEvent(cEvent *Event);
const cEvent *GetPresentEvent(void) const;
const cEvent *GetFollowingEvent(void) const;
const cEvent *GetEvent(u_int16_t EventID, time_t StartTime = 0) const;
const cEvent *GetEventAround(time_t Time) const;
const cEvent *GetEventNumber(int n) const { return events.Get(n); }
int NumEvents(void) const { return events.Count(); }
void Dump(FILE *f, const char *Prefix = "") const;
static bool Read(FILE *f, cSchedules *Schedules);
};
class cSchedulesLock {
private:
bool locked;
public:
cSchedulesLock(bool WriteLock = false, int TimeoutMs = 0);
~cSchedulesLock();
bool Locked(void) { return locked; }
};
class cSchedules : public cList<cSchedule> {
friend class cSchedule;
friend class cSchedulesLock;
private:
cRwLock rwlock;
static cSchedules schedules;
static const char *epgDataFileName;
static time_t lastCleanup;
static time_t lastDump;
public:
static void SetEpgDataFileName(const char *FileName);
static const cSchedules *Schedules(cSchedulesLock &SchedulesLock);
///< Caller must provide a cSchedulesLock which has to survive the entire
///< time the returned cSchedules is accessed. Once the cSchedules is no
///< longer used, the cSchedulesLock must be destroyed.
static void Cleanup(bool Force = false);
static bool ClearAll(void);
static bool Dump(FILE *f, const char *Prefix = "");
static bool Read(FILE *f = NULL);
cSchedule *AddSchedule(tChannelID ChannelID);
const cSchedule *GetSchedule(tChannelID ChannelID) const;
};
void ReportEpgBugFixStats(bool Reset = false);
#endif //__EPG_H

126
filter.c Normal file
View File

@ -0,0 +1,126 @@
/*
* filter.c: Section filter
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: filter.c 1.1 2003/12/21 15:26:16 kls Exp $
*/
#include "filter.h"
#include "sections.h"
// --- cFilterData -----------------------------------------------------------
cFilterData::cFilterData(void)
{
pid = 0;
tid = 0;
mask = 0;
sticky = false;
}
cFilterData::cFilterData(u_short Pid, u_char Tid, u_char Mask, bool Sticky)
{
pid = Pid;
tid = Tid;
mask = Mask;
sticky = Sticky;
}
bool cFilterData::Is(u_short Pid, u_char Tid, u_char Mask)
{
return pid == Pid && tid == Tid && mask == Mask;
}
bool cFilterData::Matches(u_short Pid, u_char Tid)
{
return pid == Pid && tid == (Tid & mask);
}
// --- cFilter ---------------------------------------------------------------
cFilter::cFilter(void)
{
sectionHandler = NULL;
on = false;
}
cFilter::cFilter(u_short Pid, u_char Tid, u_char Mask)
{
sectionHandler = NULL;
on = false;
Set(Pid, Tid, Mask);
}
cFilter::~cFilter()
{
if (sectionHandler)
sectionHandler->Detach(this);
}
int cFilter::Source(void)
{
return sectionHandler ? sectionHandler->Source() : 0;
}
int cFilter::Transponder(void)
{
return sectionHandler ? sectionHandler->Transponder() : 0;
}
void cFilter::SetStatus(bool On)
{
if (sectionHandler && on != On) {
cFilterData *fd = data.First();
while (fd) {
if (On)
sectionHandler->Add(fd);
else {
sectionHandler->Del(fd);
if (!fd->sticky) {
cFilterData *next = data.Next(fd);
data.Del(fd);
fd = next;
continue;
}
}
fd = data.Next(fd);
}
on = On;
}
}
bool cFilter::Matches(u_short Pid, u_char Tid)
{
for (cFilterData *fd = data.First(); fd; fd = data.Next(fd)) {
if (fd->Matches(Pid, Tid))
return true;
}
return false;
}
void cFilter::Set(u_short Pid, u_char Tid, u_char Mask)
{
Add(Pid, Tid, Mask, true);
}
void cFilter::Add(u_short Pid, u_char Tid, u_char Mask, bool Sticky)
{
cFilterData *fd = new cFilterData(Pid, Tid, Mask, Sticky);
data.Add(fd);
if (sectionHandler && on)
sectionHandler->Add(fd);
}
void cFilter::Del(u_short Pid, u_char Tid, u_char Mask)
{
for (cFilterData *fd = data.First(); fd; fd = data.Next(fd)) {
if (fd->Is(Pid, Tid, Mask)) {
if (sectionHandler && on)
sectionHandler->Del(fd);
data.Del(fd);
return;
}
}
}

74
filter.h Normal file
View File

@ -0,0 +1,74 @@
/*
* filter.h: Section filter
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: filter.h 1.1 2003/12/22 11:41:40 kls Exp $
*/
#ifndef __FILTER_H
#define __FILTER_H
#include <sys/types.h>
#include "tools.h"
class cFilterData : public cListObject {
public:
u_short pid;
u_char tid;
u_char mask;
bool sticky;
cFilterData(void);
cFilterData(u_short Pid, u_char Tid, u_char Mask, bool Sticky);
bool Is(u_short Pid, u_char Tid, u_char Mask);
bool Matches(u_short Pid, u_char Tid);
};
class cSectionHandler;
class cFilter : public cListObject {
friend class cSectionHandler;
private:
cSectionHandler *sectionHandler;
cList<cFilterData> data;
bool on;
protected:
cFilter(void);
cFilter(u_short Pid, u_char Tid, u_char Mask = 0xFF);
virtual ~cFilter();
virtual void SetStatus(bool On);
///< Turns this filter on or off, depending on the value of On.
///< If the filter is turned off, any filter data that has been
///< added without the Sticky parameter set to 'true' will be
///< automatically deleted. Those parameters that have been added
///< with Sticky set to 'true' will be automatically reused when
///< SetStatus(true) is called.
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length) = 0;
///< Processes the data delivered to this filter.
///< Pid and Tid is one of the combinations added to this filter by
///< a previous call to Add(), Data is a pointer to Length bytes of
///< data. This function will be called from the section handler's
///< thread, so it has to use proper locking mechanisms in case it
///< accesses any global data. It is guaranteed that if several cFilters
///< are attached to the same cSectionHandler, only _one_ of them has
///< its Process() function called at any given time. It is allowed
///< that more than one cFilter are set up to receive the same Pid/Tid.
///< The Process() function must return as soon as possible.
int Source(void);
///< Returns the source of the data delivered to this filter.
int Transponder(void);
///< Returns the transponder of the data delivered to this filter.
bool Matches(u_short Pid, u_char Tid);
///< Indicates whether this filter wants to receive data from the given Pid/Tid.
void Set(u_short Pid, u_char Tid, u_char Mask = 0xFF);
///< Sets the given filter data by calling Add() with Sticky = true.
void Add(u_short Pid, u_char Tid, u_char Mask = 0xFF, bool Sticky = false);
///< Adds the given filter data to this filter.
///< If Sticky is true, this will survive a status change, otherwise
///< it will be automatically deleted.
void Del(u_short Pid, u_char Tid, u_char Mask = 0xFF);
///< Deletes the given filter data from this filter.
};
#endif //__FILTER_H

80
font.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: font.c 1.2 2000/11/18 15:16:08 kls Exp $
* $Id: font.c 1.4 2003/10/24 12:59:35 kls Exp $
*/
#include "font.h"
@ -12,24 +12,38 @@
#include "fontfix.c"
#include "fontosd.c"
#include "fontsml.c"
cFont::cFont(eDvbFont Font)
#include "fontfix-iso8859-7.c"
#include "fontosd-iso8859-7.c"
#include "fontsml-iso8859-7.c"
static void *FontData[eDvbCodeSize][eDvbFontSize] = {
{ FontOsd_iso8859_1, FontFix_iso8859_1, FontSml_iso8859_1 },
{ FontOsd_iso8859_7, FontFix_iso8859_7, FontSml_iso8859_7 }
};
static const char *FontCode[eDvbCodeSize] = {
"iso8859-1",
"iso8859-7"
};
eDvbCode cFont::code = code_iso8859_1;
cFont *cFont::fonts[eDvbFontSize] = { NULL };
cFont::cFont(void *Data)
{
#define FONTINDEX(Name)\
case font##Name: for (int i = 0; i < NUMCHARS; i++)\
data[i] = (tCharData *)&Font##Name[i < 32 ? 0 : i - 32];\
break;
switch (Font) {
default:
FONTINDEX(Osd);
FONTINDEX(Fix);
// TODO others...
}
SetData(Data);
}
int cFont::Width(const char *s)
void cFont::SetData(void *Data)
{
int h = ((tCharData *)Data)->height;
for (int i = 0; i < NUMCHARS; i++)
data[i] = (tCharData *)&((tPixelData *)Data)[(i < 32 ? 0 : i - 32) * (h + 2)];
}
int cFont::Width(const char *s) const
{
int w = 0;
while (s && *s)
@ -37,7 +51,7 @@ int cFont::Width(const char *s)
return w;
}
int cFont::Height(const char *s)
int cFont::Height(const char *s) const
{
int h = 0;
if (s && *s)
@ -45,3 +59,37 @@ int cFont::Height(const char *s)
return h;
}
bool cFont::SetCode(const char *Code)
{
for (int i = 0; i < eDvbCodeSize; i++) {
if (strcmp(Code, FontCode[i]) == 0) {
SetCode(eDvbCode(i));
return true;
}
}
return false;
}
void cFont::SetCode(eDvbCode Code)
{
if (code != Code) {
code = Code;
for (int i = 0; i < eDvbFontSize; i++) {
if (fonts[i])
fonts[i]->SetData(FontData[code][i]);
}
}
}
void cFont::SetFont(eDvbFont Font, void *Data)
{
delete fonts[Font];
fonts[Font] = new cFont(Data ? Data : FontData[code][Font]);
}
const cFont *cFont::GetFont(eDvbFont Font)
{
if (!fonts[Font])
SetFont(Font);
return fonts[Font];
}

35
font.h
View File

@ -4,19 +4,25 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: font.h 1.2 2000/11/18 14:51:45 kls Exp $
* $Id: font.h 1.4 2003/10/24 12:59:45 kls Exp $
*/
#ifndef __FONT_H
#define __FONT_H
#include <stdlib.h>
enum eDvbFont {
fontOsd,
fontFix,
/* TODO as soon as we have the font files...
fontTtxSmall,
fontTtxLarge,
*/
fontSml
#define eDvbFontSize (fontSml + 1)
};
enum eDvbCode {
code_iso8859_1,
code_iso8859_7
#define eDvbCodeSize (code_iso8859_7 + 1)
};
class cFont {
@ -28,14 +34,21 @@ public:
tPixelData lines[1];
};
private:
static eDvbCode code;
static cFont *fonts[];
const tCharData *data[NUMCHARS];
public:
cFont(eDvbFont Font);
int Width(unsigned char c) { return data[c]->width; }
int Width(const char *s);
int Height(unsigned char c) { return data[c]->height; }
int Height(const char *s);
const tCharData *CharData(unsigned char c) { return data[c]; }
cFont(void *Data);
void SetData(void *Data);
int Width(unsigned char c) const { return data[c]->width; }
int Width(const char *s) const;
int Height(unsigned char c) const { return data[c]->height; }
int Height(const char *s) const;
const tCharData *CharData(unsigned char c) const { return data[c]; }
static bool SetCode(const char *Code);
static void SetCode(eDvbCode Code);
static void SetFont(eDvbFont Font, void *Data = NULL);
static const cFont *GetFont(eDvbFont Font);
};
#endif //__FONT_H

6498
fontfix-iso8859-7.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
cFont::tPixelData FontFix[][28] = {
cFont::tPixelData FontFix_iso8859_1[][28] = {
{ // 32
15, 26,
0x00000000, // ...............

5826
fontosd-iso8859-7.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
cFont::tPixelData FontOsd[][29] = {
cFont::tPixelData FontOsd_iso8859_1[][29] = {
{ // 32
6, 27,
0x00000000, // ......

4930
fontsml-iso8859-7.c Normal file

File diff suppressed because it is too large Load Diff

5602
fontsml.c Normal file

File diff suppressed because it is too large Load Diff

418
i18n.c

File diff suppressed because it is too large Load Diff

3
i18n.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: i18n.h 1.6 2003/05/16 12:48:52 kls Exp $
* $Id: i18n.h 1.7 2003/10/19 15:02:05 kls Exp $
*/
#ifndef __I18N_H
@ -21,6 +21,7 @@ void I18nRegister(const tI18nPhrase * const Phrases, const char *Plugin);
const char *I18nTranslate(const char *s, const char *Plugin = NULL);
const char * const * I18nLanguages(void);
const char * const * I18nCharSets(void);
#ifdef PLUGIN_NAME_I18N
#define tr(s) I18nTranslate(s, PLUGIN_NAME_I18N)

View File

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,73 +0,0 @@
##############################################################
### ###
### Makefile: global makefile for libdtv ###
### ###
##############################################################
## $Revision: 1.3 $
## $Date: 2001/06/25 12:51:41 $
## $Author: hakenes $
##
## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
##
## libdtv is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## libdtv is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You may have received a copy of the GNU General Public License
## along with libdtv; see the file COPYING. If not, write to the
## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
## Boston, MA 02111-1307, USA.
#
#
#
#
# adapt this to your GNU make executable
#
MAKE = make
AR = ar
ARFLAGS = ru
RANLIB = ranlib
SUBDIRS = liblx libsi libvdr
all: newdist
new: clean newdist
clean:
@echo "making all clean..."
@for i in $(SUBDIRS);\
do \
( echo $$i; cd $$i ;\
$(MAKE) clean ) ;\
done
@rm -rf lib include libdtv.*
newdist:
@mkdir -p include lib
@echo "making all distributions..."
@for i in $(SUBDIRS) ;\
do \
( cd $$i ;\
$(MAKE) new dist ) ;\
done
@echo "making libdtv.a/libdtv.h..."
@cat include/* > libdtv.h
@mkdir -p tmp
@for i in $(SUBDIRS) ;\
do \
( cd tmp;\
$(AR) x ../lib/$$i.a;\
$(AR) $(ARFLAGS) ../libdtv.a *;\
rm -f *) ;\
done
@rm -rf lib include tmp

View File

@ -1,27 +0,0 @@
DTV System Information Library
==============================
This is intended to support the VDR application of Klaus Schmidinger with
extended EIT support, mainly on NVOD channels.
Bug reports and suggestions are very appreciated and should be sent to
hakenes@hippomi.de
Have fun,
(C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
libdtv is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libdtv is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You may have received a copy of the GNU General Public License
along with libdtv; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.

View File

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,62 +0,0 @@
##############################################################
### ###
### Makefile: local makefile for liblx ###
### ###
##############################################################
## $Revision: 1.2 $
## $Date: 2001/06/25 19:39:00 $
## $Author: hakenes $
##
## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
##
## dtv_scan is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## dtv_scan is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You may have received a copy of the GNU General Public License
## along with dtv_scan; see the file COPYING. If not, write to the
## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
## Boston, MA 02111-1307, USA.
#
#
#
CC ?= gcc
CFLAGS ?= -O2 -g -pedantic -Wmissing-prototypes -Wstrict-prototypes \
-Wimplicit -D__USE_FIXED_PROTOTYPES__ # -DDEBUG
AR = ar
ARFLAGS = r
RANLIB = ranlib
RM = rm -f
CP = cp
LXINCLUDE = liblx.h
LXLIB = liblx.a
LXOBJS = xMemMgt.o xListFuncs.o
all : $(LXLIB)
clean :
@echo "cleaning workspace..."
@$(RM) $(LXOBJS) $(LXLIB)
new : clean all
$(LXLIB) : $(LXOBJS)
@echo "updating library..."
@$(AR) $(ARFLAGS) $(LXLIB) $(LXOBJS)
@$(RANLIB) $(LXLIB)
dist: all
@echo "distributing liblx.a and liblx.h..."
@$(CP) $(LXLIB) ../lib
@$(CP) $(LXINCLUDE) ../include

View File

@ -1,449 +0,0 @@
/*
*
* liblx.h: definitions necessary for the liblx package
*
*
* $Revision: 1.2 $
* $Date: 2001/06/25 19:39:00 $
* $Author: hakenes $
*
* (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
*
* liblx is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* liblx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You may have received a copy of the GNU General Public License
* along with liblx; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef LIBLX_H
#define LIBLX_H
#ifndef NULL
#define NULL 0
#endif
/*
*
* list support structures
*
*/
struct NODE
{
struct NODE *Succ;
struct NODE *Pred;
char *Name;
unsigned short HashKey;
};
struct LIST
{
struct NODE *Head;
struct NODE *Tail;
char *Name;
unsigned long Size;
};
/*
*
* memory managment structures
*
*/
struct MEM_ENTRY
{
struct MEM_ENTRY *Succ;
struct MEM_ENTRY *Pred;
unsigned long Size;
};
struct MEM_CHUNK
{
struct MEM_CHUNK *Succ;
struct MEM_CHUNK *Pred;
unsigned long Size;
struct MEM_ENTRY *FirstFreeMemEntry;
struct MEM_ENTRY *FirstUsedMemEntry;
};
#ifdef __cplusplus
extern "C" {
#endif
/*
*
* list functions (package xList)
*
*/
unsigned short xHashKey (char *);
struct LIST *xNewList (char *);
struct NODE *xNewNode (char *, unsigned long);
struct NODE *xFindName (struct LIST *, char *);
/*
*
* memory management
*
*/
void xMemAllo (unsigned long, unsigned char **);
void xMemFre (unsigned char *);
void xMemFreeAll (struct MEM_CHUNK **);
void xMemMerge (struct MEM_CHUNK **);
struct MEM_CHUNK **xGetRemember (void);
void xSetRemember (struct MEM_CHUNK **);
void xPrintMemList (struct MEM_CHUNK **);
unsigned long xGetMemSize (struct MEM_CHUNK **);
extern unsigned long xAllocatedMemory;
char *xSetText (char *);
#ifdef __cplusplus
}
#endif
#define MEM_CHUNK_SIZE 65536
#define xMemAlloc(size, ptr) \
xMemAllo (((unsigned long)((size))), ((unsigned char **)((ptr))))
#define xMemFree(ptr) xMemFre (((unsigned char *)((ptr))))
/*
*
* list support macros
*
*/
/*---------------------------------------------------------------------*
| |
| xCreateNode (NodeStruct,Name) allocates a correctly sized and |
| typed node struct. |
| |
*---------------------------------------------------------------------*/
#define xCreateNode(NodeStruct,Name) \
(NodeStruct) = (void *) xNewNode(Name, sizeof(*(NodeStruct)))
/*---------------------------------------------------------------------*
| |
| xSize (List) scans for the ->Size field of a list struct |
| |
*---------------------------------------------------------------------*/
#define xSize(List) ((List) ? ((struct LIST *)(List))->Size : 0)
/*---------------------------------------------------------------------*
| |
| xName (NodeStruct) scans for the ->Node.Name of a node struct |
| |
*---------------------------------------------------------------------*/
#define xName(NodeStruct) (((struct NODE *)(NodeStruct))->Name)
/*---------------------------------------------------------------------*
| |
| xSucc (NodeStruct) scans for the ->Node.Succ of a node struct |
| |
*---------------------------------------------------------------------*/
#define xSucc(NodeStruct) (((struct NODE *)(NodeStruct))->Succ)
/*---------------------------------------------------------------------*
| |
| xPred (NodeStruct) scans for the ->Node.Pred of a node struct |
| |
*---------------------------------------------------------------------*/
#define xPred(NodeStruct) (((struct NODE *)(NodeStruct))->Pred)
/*---------------------------------------------------------------------*
| |
| xForeach(List,NodeStruct) builds a loop to process each list |
| element. |
| |
*---------------------------------------------------------------------*/
#define xForeach(List,NodeStruct) \
if (List) for ((NodeStruct) = (void *) ((struct LIST *)(List))->Head; \
(NodeStruct); (NodeStruct) = (void *) xSucc (NodeStruct))
/*---------------------------------------------------------------------*
| |
| xForeachReverse(List,NodeStruct) builds a loop to process each |
| element in reverse order. |
| |
*---------------------------------------------------------------------*/
#define xForeachReverse(List,NodeStruct) \
if (List) for ((NodeStruct) = (void *) ((struct LIST *)(List))->Tail; \
NodeStruct; (NodeStruct) = (void *) xPred (NodeStruct))
/*---------------------------------------------------------------------*
| |
| xRemove(List,NodeStruct) unchains a node struct out of a list. |
| |
*---------------------------------------------------------------------*/
#define xRemove(List,NodeStruct) \
do \
{ \
struct NODE *TmpNode; \
struct LIST *TmpList; \
\
TmpNode = ((struct NODE *)(NodeStruct)); \
TmpList = ((struct LIST *)(List)); \
\
if (TmpNode->Pred) \
(TmpNode->Pred)->Succ = TmpNode->Succ; \
else TmpList->Head = TmpNode->Succ; \
if (TmpNode->Succ) \
(TmpNode->Succ)->Pred = TmpNode->Pred; \
else TmpList->Tail = TmpNode->Pred; \
TmpList->Size --; \
} while (0)
/*************************************************************************
* *
* function : xAddHead *
* *
* arguments : List - pointer to a LIST structure *
* *
* Node - pointer to a NODE structure *
* *
*-----------------------------------------------------------------------*
* *
* xAddHead() inserts 'Node' at the head of 'List'. *
* *
*************************************************************************/
#define xAddHead(List, NodeStruct) \
do { \
struct NODE *TmpNode; \
struct LIST *TmpList; \
\
TmpNode = ((struct NODE *)(NodeStruct)); \
TmpList = ((struct LIST *)(List)); \
\
if (TmpList->Head) { \
TmpNode->Pred = NULL; \
TmpNode->Succ = TmpList->Head; \
(TmpList->Head)->Pred = TmpNode; \
TmpList->Head = TmpNode; } \
else { \
TmpList->Head = TmpNode; \
TmpList->Tail = TmpNode; \
TmpNode->Pred = NULL; \
TmpNode->Succ = NULL; } \
TmpList->Size++; \
} while (0)
/*************************************************************************
* *
* function : xAddTail *
* *
* arguments : List - pointer to a LIST structure *
* *
* Node - pointer to a NODE structure *
* *
*-----------------------------------------------------------------------*
* *
* xAddTail() inserts 'Node' at the tail of 'List'. *
* *
*************************************************************************/
#define xAddTail(List, NodeStruct) \
do { \
struct NODE *TmpNode; \
struct LIST *TmpList; \
\
TmpNode = ((struct NODE *)(NodeStruct)); \
TmpList = ((struct LIST *)(List)); \
\
if (TmpList->Head) { \
TmpNode->Succ = NULL; \
TmpNode->Pred = TmpList->Tail; \
(TmpList->Tail)->Succ = TmpNode; \
TmpList->Tail = TmpNode; } \
else { \
TmpList->Head = TmpNode; \
TmpList->Tail = TmpNode; \
TmpNode->Pred = NULL; \
TmpNode->Succ = NULL; } \
TmpList->Size++; \
} while (0)
/*************************************************************************
* *
* function : xRemHead *
* *
* arguments : List - pointer to a LIST structure *
* *
*-----------------------------------------------------------------------*
* *
* xRemHead() removes a Node from head of 'List'. *
* *
*************************************************************************/
#define xRemHead(List) \
do { \
struct LIST *TmpList; \
\
TmpList = ((struct LIST *)(List)); \
\
if (TmpList->Head) \
{ \
TmpList->Head = (TmpList->Head)->Succ; \
if (TmpList->Head) (TmpList->Head)->Pred = NULL; \
else TmpList->Tail = NULL; \
TmpList->Size--; \
} \
} while (0)
/*************************************************************************
* *
* function : xRemTail *
* *
* arguments : List - pointer to a LIST structure *
* *
*-----------------------------------------------------------------------*
* *
* xRemTail() removes a Node from the tail of 'List'. *
* *
*************************************************************************/
#define xRemTail(List) \
do { \
struct LIST *TmpList; \
\
TmpList = ((struct LIST *)(List)); \
\
if (TmpList->Tail) \
{ \
TmpList->Tail = (TmpList->Tail)->Pred; \
if (TmpList->Tail) (TmpList->Tail)->Succ = NULL; \
else TmpList->Head = NULL; \
TmpList->Size--; \
} \
} while (0)
/*************************************************************************
* *
* function : xConCat *
* *
* arguments : DestinationList - pointer to the destination *
* LIST structure *
* *
* SourceList - pointer to the source LIST structure *
* *
*-----------------------------------------------------------------------*
* *
* xConCat() concats 'SourceList' with 'DestinationList' and clears *
* 'SourceList'. *
* *
*************************************************************************/
#define xConCat(DestinationList, SourceList) \
do { \
struct LIST *SrcList; \
struct LIST *DstList; \
\
SrcList = ((struct LIST *)(SourceList)); \
DstList = ((struct LIST *)(DestinationList)); \
\
if (DstList && SrcList) \
{ \
if (DstList->Head) { \
if (SrcList->Head) { \
(DstList->Tail)->Succ = SrcList->Head; \
(SrcList->Head)->Pred = DstList->Tail; \
DstList->Tail = SrcList->Tail; \
DstList->Size += SrcList->Size; \
SrcList->Size = 0; \
SrcList->Head = NULL; \
SrcList->Tail = NULL; } } \
else { \
DstList->Head = SrcList->Head; \
DstList->Tail = SrcList->Tail; \
DstList->Size += SrcList->Size; \
SrcList->Size = 0; \
SrcList->Head = NULL; \
SrcList->Tail = NULL; } \
} \
else if (SrcList) ((struct LIST *)(DestinationList)) = SrcList; \
} while (0)
#define xJoinList(SourceList, DestinationList, NodeStruct) \
do { \
struct NODE *KeyNode; \
struct NODE *TmpNode; \
struct LIST *SrcList; \
struct LIST *DstList; \
\
KeyNode = ((struct NODE *)(NodeStruct)); \
SrcList = ((struct LIST *)(SourceList)); \
DstList = ((struct LIST *)(DestinationList)); \
\
if (SrcList->Head) \
{ \
TmpNode = KeyNode->Succ; \
KeyNode->Succ = SrcList->Head; \
SrcList->Tail->Succ = TmpNode; \
SrcList->Head->Pred = KeyNode; \
if (!TmpNode) DstList->Tail = SrcList->Tail; \
else TmpNode->Pred = SrcList->Tail; \
DstList->Size += SrcList->Size; \
SrcList->Size = 0; \
SrcList->Head = NULL; \
SrcList->Tail = NULL; \
} \
} while (0)
#define xJoin(SourceNode, DestinationList, NodeStruct) \
do { \
struct NODE *KeyNode; \
struct NODE *TmpNode; \
struct NODE *SrcNode; \
struct LIST *DstList; \
\
KeyNode = ((struct NODE *)(NodeStruct)); \
SrcNode = ((struct NODE *)(SourceNode)); \
DstList = ((struct LIST *)(DestinationList)); \
\
if (SrcNode) \
{ \
TmpNode = KeyNode->Succ; \
KeyNode->Succ = SrcNode; \
SrcNode->Succ = TmpNode; \
SrcNode->Pred = KeyNode; \
if (!TmpNode) DstList->Tail = SrcNode; \
else TmpNode->Pred = SrcNode; \
DstList->Size += 1; \
} \
} while (0)
#define xClearList(SrcList) \
do { \
(SrcList)->Size = 0; \
(SrcList)->Head = NULL; \
(SrcList)->Tail = NULL; \
} while (0)
#define xSetName(nodestruct, name) \
do { \
struct NODE *TmpNode; \
\
TmpNode = (struct NODE *) (nodestruct); \
\
TmpNode->Name = xSetText (name); \
TmpNode->HashKey = xHashKey (name); \
} while (0)
#endif

View File

@ -1,189 +0,0 @@
/*
*
* xListFuncs.c: list handling functions of liblx
*
*
* $Revision: 1.1 $
* $Date: 2001/06/25 12:29:47 $
* $Author: hakenes $
*
* (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
*
* liblx is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* liblx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You may have received a copy of the GNU General Public License
* along with liblx; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include <string.h>
#include "liblx.h"
/*************************************************************************
* *
* function : xHashKey *
* *
* arguments : Name - character pointer *
* *
* return : 16 Bit CRC checksum as hashkey *
* *
*************************************************************************/
unsigned short xHashKey (Name)
char *Name;
{
unsigned short Key = 0;
unsigned long Value;
char *Ptr;
if (!Name) return (0);
for (Ptr = Name; *Ptr; Ptr++) {
Value = ((Key >> 8) ^ (*Ptr)) & 0xFF;
Value = Value ^ (Value >> 4);
Key = 0xFFFF & ((Key << 8) ^ Value ^ (Value << 5) ^ (Value << 12));
}
return (Key);
}
/*************************************************************************
* *
* function : xNewNode *
* *
* arguments : Name - character pointer to the node's name *
* *
* Size - size of the surrounding structure in bytes *
* *
* return : pointer to a correct initialized NODE structure *
* *
*-----------------------------------------------------------------------*
* *
* xNewNode() allocates memory for a NODE structure and initializes *
* it properly. If argument Name points to a string, it copies that *
* into a new allocated memory area and assigns Node->Name to it. *
* Because NODE's are often part of bigger structures, the size of *
* the surrounding structure could be specified to allocate it. *
* *
*************************************************************************/
struct NODE *xNewNode (Name, Size)
char *Name;
unsigned long Size;
{
struct NODE *Node;
if (Size < sizeof(struct NODE)) Size = sizeof(struct NODE);
xMemAlloc (Size, &Node);
Node->Succ = NULL;
Node->Pred = NULL;
if (Name == NULL)
{
Node->Name = NULL;
Node->HashKey = 0;
}
else
{
xMemAlloc (strlen (Name) + 1, &(Node->Name));
strcpy (Node->Name, Name);
Node->HashKey = xHashKey (Name);
}
return (Node);
}
/*************************************************************************
* *
* function : xNewList *
* *
* arguments : Name - character pointer to the list's name *
* *
* return : pointer to a correct initialized LIST structure *
* *
*-----------------------------------------------------------------------*
* *
* xNewList() allocates memory for a LIST structure and initializes *
* it properly. If argument Name points to a string, it copies that *
* into a new allocated memory area and assigns List->Name to it. *
* *
*************************************************************************/
struct LIST *xNewList (Name)
char *Name;
{
struct LIST *List;
xMemAlloc (sizeof(struct LIST), &List);
List->Head = NULL;
List->Tail = NULL;
List->Size = 0;
if (Name == NULL)
{
List->Name = NULL;
}
else
{
xMemAlloc (strlen (Name) + 1, &(List->Name));
strcpy (List->Name, Name);
}
return (List);
}
/*************************************************************************
* *
* function : xFindName *
* *
* arguments : List - pointer to a LIST structure *
* *
* Name - pointer to a name string *
* *
* return : pointer to a NODE structure *
* *
*-----------------------------------------------------------------------*
* *
* xFindName() looks for element with name 'Name' in list 'List' and *
* returns its NODE structure. *
* *
*************************************************************************/
struct NODE *xFindName (List, Name)
struct LIST *List;
char *Name;
{
struct NODE *Node;
unsigned short HashKey;
if (!Name || !List) return (NULL);
HashKey = xHashKey (Name);
for (Node = List->Head; Node; Node = Node->Succ)
if (HashKey == Node->HashKey)
if (Node->Name)
if (strcmp (Node->Name, Name) == 0) return (Node);
return (NULL);
}

View File

@ -1,624 +0,0 @@
/*
*
* xMemMgt.c: memory management functions of liblx
*
*
* $Revision: 1.1 $
* $Date: 2001/06/25 12:29:47 $
* $Author: hakenes $
*
* (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
*
* liblx is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* liblx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You may have received a copy of the GNU General Public License
* along with liblx; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "liblx.h"
#ifdef DEBUG
void logPrintf(int, char *, ...);
#endif
static struct MEM_CHUNK *xRememberKey = NULL;
static struct MEM_CHUNK **xRememberPtr = &xRememberKey;
unsigned long xAllocatedMemory = 0;
/*************************************************************************
* *
* function : xMemAlloc *
* *
* parameter : Size - size of the requested memory area *
* *
* DataPointer - pointer to data pointer *
* *
* return : none *
* *
*-----------------------------------------------------------------------*
* *
* xMemAlloc() is a clustered, remembering memory management routine. *
* It uses its own tables for free and used memory blocks on private *
* memory area. With xMemFree(), you can free this memory likewise *
* the C free() routine, with xMemFreeAll() all memory at once. *
* By changing the current remember key with xSetRemember() you can *
* define a local memory area, which can be freed by only one call of *
* xMemFreeAll() (see xSetRemember() / xGetRemember()). *
* *
*************************************************************************/
void xMemAllo (Size, DataPointer)
unsigned long Size;
unsigned char **DataPointer;
{
struct MEM_CHUNK *MemChunk, *MemChunkPred;
struct MEM_ENTRY *MemEntry, *MemEntryPred;
long int NewSize;
unsigned short FoundFlag;
#ifdef DEBUG
unsigned char *ptr;
#endif
while (Size % 4) Size++;
if (Size > (MEM_CHUNK_SIZE - sizeof(struct MEM_CHUNK) -
sizeof(struct MEM_ENTRY)))
{
NewSize = Size + sizeof(struct MEM_CHUNK) + sizeof(struct MEM_ENTRY);
if (MemChunk = (*xRememberPtr))
{
do
{
MemChunkPred = MemChunk;
} while (MemChunk = MemChunk->Succ);
}
else MemChunkPred = (struct MEM_CHUNK *) &(*xRememberPtr);
MemChunk = MemChunkPred->Succ = (struct MEM_CHUNK *) malloc (NewSize);
xAllocatedMemory += NewSize;
#ifdef DEBUG
for (ptr = (unsigned char *) MemChunk; ptr < (unsigned char *)
(MemChunk) + NewSize; ptr++)
*ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA;
#endif
if (!MemChunk)
{
#ifdef DEBUG
logPrintf (0, "Not enough memory...\r\n");
#endif
exit (1);
}
MemChunk->Size = NewSize;
MemChunk->Pred = MemChunkPred;
MemChunk->Succ = NULL;
MemChunk->FirstFreeMemEntry = NULL;
MemChunk->FirstUsedMemEntry =
MemEntry = (struct MEM_ENTRY *) ((unsigned char *)MemChunk +
sizeof(struct MEM_CHUNK));
MemEntry->Size = Size;
MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstUsedMemEntry;
MemEntry->Succ = NULL;
*DataPointer = (unsigned char *) ((unsigned char *)MemEntry +
sizeof(struct MEM_ENTRY));
#ifdef DEBUG_CALLS
logPrintf (0, "xMemAlloc: %x, %d bytes\r\n", *DataPointer, Size);
#endif
return;
}
MemEntry = NULL;
FoundFlag = 0;
if (MemChunk = (*xRememberPtr))
{
do
{
if (MemEntry = MemChunk->FirstFreeMemEntry)
do
{
if (Size <= MemEntry->Size) FoundFlag = 1;
} while ((FoundFlag == 0) && (MemEntry = MemEntry->Succ));
MemChunkPred = MemChunk;
} while ((FoundFlag == 0) && (MemChunk = MemChunk->Succ));
}
else MemChunkPred = (struct MEM_CHUNK *) &(*xRememberPtr);
if (!MemEntry)
{
MemChunk = MemChunkPred->Succ =
(struct MEM_CHUNK *) malloc (MEM_CHUNK_SIZE);
xAllocatedMemory += MEM_CHUNK_SIZE;
#ifdef DEBUG
for (ptr = (unsigned char *) MemChunk; ptr < (unsigned char *)
(MemChunk) + MEM_CHUNK_SIZE; ptr++)
*ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA;
#endif
if (!MemChunk)
{
#ifdef DEBUG
logPrintf (0, "Not enough memory...\r\n");
#endif
exit (1);
}
MemChunk->Size = MEM_CHUNK_SIZE;
MemChunk->Pred = MemChunkPred;
MemChunk->Succ = NULL;
MemChunk->FirstUsedMemEntry = NULL;
MemChunk->FirstFreeMemEntry =
MemEntry = (struct MEM_ENTRY *)
((unsigned char *)MemChunk + sizeof(struct MEM_CHUNK));
MemEntry->Size = MEM_CHUNK_SIZE - sizeof(struct MEM_CHUNK) -
sizeof(struct MEM_ENTRY);
MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstFreeMemEntry;
MemEntry->Succ = NULL;
}
NewSize = MemEntry->Size - sizeof(struct MEM_ENTRY) - Size;
MemEntry->Size = Size;
*DataPointer = (unsigned char *)
((unsigned char *)MemEntry + sizeof(struct MEM_ENTRY));
#ifdef DEBUG
for (ptr = *DataPointer; ptr < (unsigned char *)
(*DataPointer) + Size; ptr++)
{
if (((unsigned long )ptr)&1)
{ if (*ptr != 0x55)
logPrintf (0, "freed memory was used\r\n"); }
else { if (*ptr != 0xAA)
logPrintf (0, "freed memory was used\r\n"); }
}
#endif
if (MemEntry->Succ)
((struct MEM_ENTRY *)MemEntry->Succ)->Pred = MemEntry->Pred;
((struct MEM_ENTRY *)MemEntry->Pred)->Succ = MemEntry->Succ;
if (MemChunk->FirstUsedMemEntry)
MemChunk->FirstUsedMemEntry->Pred = MemEntry;
MemEntry->Succ = MemChunk->FirstUsedMemEntry;
MemChunk->FirstUsedMemEntry = MemEntry;
MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstUsedMemEntry;
if (NewSize > 0)
{
MemEntry = (struct MEM_ENTRY *)
((unsigned char *)MemEntry + sizeof(struct MEM_ENTRY) + Size);
MemEntry->Size = NewSize;
if (MemChunk->FirstFreeMemEntry)
MemChunk->FirstFreeMemEntry->Pred = MemEntry;
MemEntry->Succ = MemChunk->FirstFreeMemEntry;
MemChunk->FirstFreeMemEntry = MemEntry;
MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstFreeMemEntry;
}
#ifdef DEBUG_CALLS
logPrintf (0, "xMemAlloc: %x, %d bytes\r\n", *DataPointer, Size);
#endif
return;
}
/*************************************************************************
* *
* function : xMemFree *
* *
* parameter : DataPointer - data pointer *
* *
* return : none *
* *
*-----------------------------------------------------------------------*
* *
* xMemFree() frees with xMemAlloc() allocated memory. *
* *
*************************************************************************/
void xMemFre (DataPointer)
unsigned char *DataPointer;
{
struct MEM_CHUNK *MemChunk, *MemChunkPred;
struct MEM_ENTRY *MemEntry, *TempEntry, *PredEntry, *SuccEntry;
unsigned short FoundFlag;
#ifdef DEBUG
unsigned char *ptr;
#endif
if (!DataPointer)
{
return;
}
else
{
MemEntry = NULL;
FoundFlag = 0;
if (MemChunk = (*xRememberPtr))
do
{
if (MemEntry = MemChunk->FirstUsedMemEntry)
do
{
if (DataPointer == (unsigned char *) ((unsigned char *) MemEntry +
sizeof(struct MEM_ENTRY))) FoundFlag = 1;
} while ((FoundFlag == 0) && (MemEntry = MemEntry->Succ));
} while ((FoundFlag == 0) && (MemChunk = MemChunk->Succ));
if (FoundFlag == 1)
{
#ifdef DEBUG_CALLS
logPrintf (0, "xMemFree: %x, %d bytes\r\n", DataPointer, MemEntry->Size);
#endif
if (MemEntry->Succ)
((struct MEM_ENTRY *)MemEntry->Succ)->Pred = MemEntry->Pred;
((struct MEM_ENTRY *)MemEntry->Pred)->Succ = MemEntry->Succ;
if (!MemChunk->FirstUsedMemEntry)
{
if (MemChunk->Succ)
((struct MEM_CHUNK *)MemChunk->Succ)->Pred = MemChunk->Pred;
((struct MEM_CHUNK *)MemChunk->Pred)->Succ = MemChunk->Succ;
if (xAllocatedMemory > 0) xAllocatedMemory -= MemChunk->Size;
free (MemChunk);
return;
}
FoundFlag = 0;
PredEntry = NULL;
SuccEntry = NULL;
if (TempEntry = MemChunk->FirstFreeMemEntry)
do
{
if ((struct MEM_ENTRY *)((unsigned char *)TempEntry +
TempEntry->Size + sizeof(struct MEM_ENTRY)) == MemEntry)
{
FoundFlag ++;
PredEntry = TempEntry;
}
if ((struct MEM_ENTRY *)((unsigned char *)MemEntry +
MemEntry->Size + sizeof(struct MEM_ENTRY)) == TempEntry)
{
FoundFlag ++;
SuccEntry = TempEntry;
}
} while ((FoundFlag != 2) && (TempEntry = TempEntry->Succ));
if (PredEntry)
{
if (SuccEntry)
{
/* Vorgdnger + Nachfolger */
if (SuccEntry->Succ)
((struct MEM_ENTRY *)SuccEntry->Succ)->Pred = SuccEntry->Pred;
((struct MEM_ENTRY *)SuccEntry->Pred)->Succ = SuccEntry->Succ;
PredEntry->Size += MemEntry->Size + sizeof(struct MEM_ENTRY) +
SuccEntry->Size + sizeof(struct MEM_ENTRY);
}
else
{
/* nur Vorgaenger */
PredEntry->Size += MemEntry->Size + sizeof(struct MEM_ENTRY);
}
#ifdef DEBUG
for (ptr = (unsigned char *) (PredEntry) + sizeof(struct MEM_ENTRY);
ptr < (unsigned char *) (PredEntry) + sizeof(struct MEM_ENTRY) +
PredEntry->Size; ptr++)
*ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA;
#endif
}
else
{
if (SuccEntry)
{
/* nur Nachfolger */
if (SuccEntry->Succ)
((struct MEM_ENTRY *)SuccEntry->Succ)->Pred = SuccEntry->Pred;
((struct MEM_ENTRY *)SuccEntry->Pred)->Succ = SuccEntry->Succ;
MemEntry->Size += SuccEntry->Size + sizeof(struct MEM_ENTRY);
}
if (MemChunk->FirstFreeMemEntry)
MemChunk->FirstFreeMemEntry->Pred = MemEntry;
MemEntry->Succ = MemChunk->FirstFreeMemEntry;
MemChunk->FirstFreeMemEntry = MemEntry;
MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstFreeMemEntry;
#ifdef DEBUG
for (ptr = (unsigned char *) (MemEntry) + sizeof(struct MEM_ENTRY);
ptr < (unsigned char *) (MemEntry) + sizeof(struct MEM_ENTRY) +
MemEntry->Size; ptr++)
*ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA;
#endif
}
}
#ifdef DEBUG_CALLS
else
logPrintf (0, "xMemFree: tried to free unallocated data %x\r\n", DataPointer);
#endif
}
return;
}
/*************************************************************************
* *
* function : xMemFreeAll *
* *
* parameter : RememberPtr *
* *
* return : none *
* *
*-----------------------------------------------------------------------*
* *
* xMemFreeAll() frees all with xMemAlloc() allocated memory. If Re- *
* memberPtr is not NULL, the MEM_CHUNK structure from the specified *
* Address is freed, otherwise the natural MEM_CHUNK will be done. *
* *
*************************************************************************/
void xMemFreeAll (RememberPtr)
struct MEM_CHUNK **RememberPtr;
{
struct MEM_CHUNK *MemChunk, *MemChunkPred;
if (RememberPtr)
{
if (MemChunkPred = (*RememberPtr))
do
{
MemChunk = MemChunkPred->Succ;
if (xAllocatedMemory > 0) xAllocatedMemory -= MemChunkPred->Size;
free (MemChunkPred);
} while (MemChunkPred = MemChunk);
*RememberPtr = NULL;
}
else
{
if (MemChunkPred = (*xRememberPtr))
do
{
MemChunk = MemChunkPred->Succ;
if (xAllocatedMemory > 0) xAllocatedMemory -= MemChunkPred->Size;
free (MemChunkPred);
} while (MemChunkPred = MemChunk);
*xRememberPtr = NULL;
}
}
/*************************************************************************
* *
* function : xMemMerge *
* *
* parameter : RememberPtr *
* *
* return : none *
* *
*-----------------------------------------------------------------------*
* *
* xMemMerge() merges the memory area pointed to by RememberKey with *
* the currently used in xRememberPtr. *
* *
*************************************************************************/
void xMemMerge (RememberPtr)
struct MEM_CHUNK **RememberPtr;
{
struct MEM_CHUNK *MemChunk, *MemChunkPred;
if (RememberPtr)
{
if (MemChunk = (*xRememberPtr))
{
while (MemChunk->Succ) MemChunk = MemChunk->Succ;
MemChunk->Succ = (*RememberPtr);
*RememberPtr = NULL;
}
else (*xRememberPtr = *RememberPtr);
}
return;
}
/*************************************************************************
* *
* function : xGetRemember *
* *
* parameter : none *
* *
* return : pointer to a MEM_CHUNK tree *
* *
*-----------------------------------------------------------------------*
* *
* xGetRemember() returns the currently used MEM_CHUNK tree. *
* *
*************************************************************************/
struct MEM_CHUNK **xGetRemember ()
{
return (xRememberPtr);
}
/*************************************************************************
* *
* function : xSetRemember *
* *
* parameter : pointer to a MEM_CHUNK tree *
* *
* return : none *
* *
*-----------------------------------------------------------------------*
* *
* xSetRemember() redefines the currently used MEM_CHUNK pointer. If *
* RememberPtr is NULL, the natural MEM_CHUNK is reloaded. *
* *
*************************************************************************/
void xSetRemember (RememberPtr)
struct MEM_CHUNK **RememberPtr;
{
if (RememberPtr)
xRememberPtr = RememberPtr;
else
xRememberPtr = &xRememberKey;
}
/*************************************************************************
* *
* function : xPrintMemList *
* *
* parameter : pointer to a MEM_CHUNK tree *
* *
* return : none *
* *
*-----------------------------------------------------------------------*
* *
* xPrintMemList() prints the currently allocated memory blocks of *
* the specified RememberPtr. *
* *
*************************************************************************/
void xPrintMemList (Remember)
struct MEM_CHUNK **Remember;
{
struct MEM_CHUNK *MemChunk;
struct MEM_ENTRY *MemEntry;
fprintf (stderr, "MemChunkPtr = %x\n", (int) Remember);
if (MemChunk = *Remember)
do
{
fprintf (stderr, "\tMemChunk at %x with Size %d\n", (int) MemChunk,
(int) MemChunk->Size);
if (MemEntry = MemChunk->FirstFreeMemEntry)
do
{
fprintf (stderr, "\t\tFree MemEntry at %x (%x) with Size %d\n",
(int) MemEntry, (int)((unsigned char *)MemEntry +
sizeof(struct MEM_ENTRY)), (int) MemEntry->Size);
} while (MemEntry = MemEntry->Succ);
if (MemEntry = MemChunk->FirstUsedMemEntry)
do
{
fprintf (stderr, "\t\tUsed MemEntry at %x (%x) with Size %d\n",
(int) MemEntry, (int)((unsigned char *)MemEntry +
sizeof(struct MEM_ENTRY)), (int) MemEntry->Size);
} while (MemEntry = MemEntry->Succ);
} while (MemChunk = MemChunk->Succ);
else fprintf (stderr, "\tNo current MemChunk\n");
}
/*************************************************************************
* *
* function : xGetMemSize *
* *
* parameter : pointer to a MEM_CHUNK tree *
* *
* return : none *
* *
*-----------------------------------------------------------------------*
* *
* xGetMemSize() gets the size of the currently allocated memory *
* blocks of the specified (or natural if NULL) RememberPtr *
* *
*************************************************************************/
unsigned long xGetMemSize (RememberPtr)
struct MEM_CHUNK **RememberPtr;
{
struct MEM_CHUNK *MemChunk;
struct MEM_ENTRY *MemEntry;
unsigned long Result = 0;
if (RememberPtr) MemChunk = *RememberPtr;
else MemChunk = xRememberKey;
if (MemChunk)
do { Result += (unsigned long) MemChunk->Size; }
while (MemChunk = MemChunk->Succ);
return (Result);
}
/*************************************************************************
* *
* function : xSetText *
* *
* arguments : xText - pointer to a string *
* *
* return : pointer to an new allocated string *
* *
*-----------------------------------------------------------------------*
* *
* xSetText() allocates memory for the string pointed to by 'xText' *
* and duplicates it. *
* *
*************************************************************************/
char *xSetText (xText)
char *xText;
{
char *NewText;
if (!xText) return (NULL);
xMemAlloc (strlen(xText) + 1, &NewText);
strcpy (NewText, xText);
return (NewText);
}

View File

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,83 +0,0 @@
##############################################################
### ###
### Makefile: local makefile for libsi ###
### ###
##############################################################
## $Revision: 1.4 $
## $Date: 2001/10/07 10:24:46 $
## $Author: hakenes $
##
## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
##
## dtv_scan is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## dtv_scan is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You may have received a copy of the GNU General Public License
## along with dtv_scan; see the file COPYING. If not, write to the
## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
## Boston, MA 02111-1307, USA.
#
#
#
.DELETE_ON_ERROR:
CC ?= gcc
CFLAGS ?= -O2 -g -Wmissing-prototypes -Wstrict-prototypes \
-DNAPI -Wimplicit -D__USE_FIXED_PROTOTYPES__ # -ansi -pedantic
INCDIRS = -Iinclude -I../include
DISTDIR = ../lib
DISTINCDIR = ../include
INCLUDES = include/libsi.h include/si_tables.h
MAKEDEPEND = gcc -M
LIBDIRS = -L. -L../lib
LIBS = -lsi -llx
AR = ar
ARFLAGS = ru
RANLIB = ranlib
SILIB = libsi.a
OBJS = si_parser.o si_debug_services.o
all : $(SILIB)
clean :
@echo cleaning workspace...
@rm -f $(OBJS) $(SILIB) *~
@rm -f Makefile.dep
depend : Makefile.dep
Makefile.dep :
@echo "updating dependencies..."
@$(MAKEDEPEND) $(INCDIRS) $(OBJS:%.o=%.c) $(SITEST_OBJS:%.o=%.c) \
$(SISCAN_OBJS:%.o=%.c) > Makefile.dep
new : clean depend all
dist: all
@echo "distributing $(SILIB) to $(DISTDIR)..."
@cp $(SILIB) $(DISTDIR)
@cp $(INCLUDES) $(DISTINCDIR)
@$(RANLIB) $(DISTDIR)/$(SILIB)
$(SILIB) : $(OBJS)
@echo updating library...
@$(AR) $(ARFLAGS) $(SILIB) $(OBJS)
@$(RANLIB) $(SILIB)
.c.o :
@echo compiling $<...
@$(CC) $(DEFINES) $(CFLAGS) $(INCDIRS) -c $<
-include Makefile.dep

View File

@ -1,2 +0,0 @@
DVB - System Information Library
================================

File diff suppressed because it is too large Load Diff

View File

@ -1,674 +0,0 @@
//////////////////////////////////////////////////////////////
/// ///
/// si_debug_services.c: debugging functions for libsi ///
/// ///
//////////////////////////////////////////////////////////////
// $Revision: 1.5 $
// $Date: 2003/02/04 18:45:35 $
// $Author: hakenes $
//
// (C) 2001-03 Rolf Hakenes <hakenes@hippomi.de>, under the
// GNU GPL with contribution of Oleg Assovski,
// www.satmania.com
//
// libsi is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// libsi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You may have received a copy of the GNU General Public License
// along with libsi; see the file COPYING. If not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../liblx/liblx.h"
#include "libsi.h"
#include "si_tables.h"
#include "si_debug_services.h"
void siDebugServices (struct LIST *Services)
{
struct Service *Service;
if (!Services) return;
xForeach (Services, Service)
{
printf ("Service\n=======\n");
printf (" ServiceID: %d\n", Service->ServiceID);
printf (" TransportStreamID: %d\n", Service->TransportStreamID);
printf (" OriginalNetworkID: %d\n", Service->OriginalNetworkID);
printf (" SdtVersion: %d\n", Service->SdtVersion);
printf (" Status: ");
if (GetScheduleFlag (Service->Status))
printf ("SCHEDULE_INFO ");
if (GetPresentFollowing(Service->Status))
printf ("PRESENT_FOLLOWING ");
switch (GetRunningStatus (Service->Status))
{
case RUNNING_STATUS_NOT_RUNNING:
printf ("RUNNING_STATUS_NOT_RUNNING\n");
break;
case RUNNING_STATUS_AWAITING:
printf ("RUNNING_STATUS_AWAITING\n");
break;
case RUNNING_STATUS_PAUSING:
printf ("RUNNING_STATUS_PAUSING\n");
break;
case RUNNING_STATUS_RUNNING:
printf ("RUNNING_STATUS_RUNNING\n");
break;
}
siDebugDescriptors (" ", Service->Descriptors);
siDebugEvents (" ", Service->Events);
}
return;
}
void siDebugService (struct Service *Service)
{
if (!Service) return;
printf ("Service\r\n=======\r\n");
printf (" ServiceID: %d\r\n", Service->ServiceID);
printf (" TransportStreamID: %d\r\n", Service->TransportStreamID);
printf (" OriginalNetworkID: %d\r\n", Service->OriginalNetworkID);
printf (" SdtVersion: %d\r\n", Service->SdtVersion);
printf (" Status: ");
if (GetScheduleFlag (Service->Status))
printf ("SCHEDULE_INFO ");
if (GetPresentFollowing(Service->Status))
printf ("PRESENT_FOLLOWING ");
switch (GetRunningStatus (Service->Status))
{
case RUNNING_STATUS_NOT_RUNNING:
printf ("RUNNING_STATUS_NOT_RUNNING\r\n");
break;
case RUNNING_STATUS_AWAITING:
printf ("RUNNING_STATUS_AWAITING\r\n");
break;
case RUNNING_STATUS_PAUSING:
printf ("RUNNING_STATUS_PAUSING\r\n");
break;
case RUNNING_STATUS_RUNNING:
printf ("RUNNING_STATUS_RUNNING\r\n");
break;
}
siDebugDescriptors ("\r ", Service->Descriptors);
siDebugEvents ("\r ", Service->Events);
return;
}
void siDebugEvents (char *Prepend, struct LIST *EventList)
{
struct Event *Event;
char NewPrepend[32];
if (!EventList) return;
xForeach (EventList, Event)
{
printf ("%sEvent\n%s=====\n", Prepend, Prepend);
printf ("%s EventID: %d\n", Prepend, Event->EventID);
printf ("%s ServiceID: %d\n", Prepend, Event->ServiceID);
printf ("%s TransportStreamID: %d\n", Prepend, Event->TransportStreamID);
printf ("%s OriginalNetworkID: %d\n", Prepend, Event->OriginalNetworkID);
printf ("%s EitVersion: %d\n", Prepend, Event->EitVersion);
printf ("%s StartTime: %s", Prepend, ctime (&Event->StartTime));
printf ("%s Duration: %d Minuten\n", Prepend, Event->Duration/60);
printf ("%s Status: ");
switch (GetRunningStatus (Event->Status))
{
case RUNNING_STATUS_NOT_RUNNING:
printf ("RUNNING_STATUS_NOT_RUNNING\n");
break;
case RUNNING_STATUS_AWAITING:
printf ("RUNNING_STATUS_AWAITING\n");
break;
case RUNNING_STATUS_PAUSING:
printf ("RUNNING_STATUS_PAUSING\n");
break;
case RUNNING_STATUS_RUNNING:
printf ("RUNNING_STATUS_RUNNING\n");
break;
}
sprintf (NewPrepend, "%s ", Prepend);
siDebugDescriptors (NewPrepend, Event->Descriptors);
}
return;
}
void siDebugPrograms (char *Prepend, struct LIST *ProgramList)
{
struct Program *Program;
char NewPrepend[32];
if (!ProgramList) return;
xForeach (ProgramList, Program)
{
printf ("%sProgram\n%s=======\n", Prepend, Prepend);
printf ("%s ProgramID: %d\n", Prepend, Program->ProgramID);
printf ("%s TransportStreamID: %d\n", Prepend, Program->TransportStreamID);
printf ("%s NetworkPID: %d\n", Prepend, Program->NetworkPID);
printf ("%s PatVersion: %d\n", Prepend, Program->PatVersion);
sprintf (NewPrepend, "%s ", Prepend);
siDebugPids (NewPrepend, Program->Pids);
}
return;
}
void siDebugProgram (struct Program *Program)
{
if (!Program) return;
printf ("Program\r\n=======\r\n");
printf (" ProgramID: %d\r\n", Program->ProgramID);
printf (" TransportStreamID: %d\r\n", Program->TransportStreamID);
printf (" NetworkPID: %d\r\n", Program->NetworkPID);
printf (" PatVersion: %d\r\n", Program->PatVersion);
siDebugPids ("\r ", Program->Pids);
return;
}
void siDebugPids (char *Prepend, struct LIST *PidList)
{
struct Pid *Pid;
struct PidInfo *PidInfo;
char NewPrepend[32];
int index;
if (!PidList) return;
xForeach (PidList, Pid)
{
printf ("%sPid\n%s===\n", Prepend, Prepend);
printf ("%s ProgramID: %d\n", Prepend, Pid->ProgramID);
printf ("%s PcrPid: %d\n", Prepend, Pid->PcrPID);
printf ("%s PmtVersion: %d\n", Prepend, Pid->PmtVersion);
sprintf (NewPrepend, "%s ", Prepend);
siDebugDescriptors (NewPrepend, Pid->Descriptors);
xForeach (Pid->InfoList, PidInfo)
{
printf ("%s PidInfo\n%s =======\n", Prepend, Prepend);
index = PidInfo->StreamType;
if (index > 0x0F && index <= 0x7F) index = 0x0E;
if (index >= 0x80) index = 0x0F;
printf ("%s StreamType: %s\n", Prepend, StreamTypes[index]);
printf ("%s ElementaryPid: %d\n", Prepend, PidInfo->ElementaryPid);
sprintf (NewPrepend, "%s ", Prepend);
siDebugDescriptors (NewPrepend, PidInfo->Descriptors);
}
}
return;
}
void siDebugDescriptors (char *Prepend, struct LIST *Descriptors)
{
struct Descriptor *Descriptor;
int i;
xForeach (Descriptors, Descriptor)
{
switch (DescriptorTag (Descriptor))
{
case DESCR_ANCILLARY_DATA:
printf ("%sDescriptor: Ancillary Data\n", Prepend);
printf ("%s Identifier: ", Prepend);
if (((struct AncillaryDataDescriptor *)Descriptor)->
Identifier & ANCILLARY_DATA_DVD_VIDEO)
printf ("DVD-Video Ancillary Data ");
if (((struct AncillaryDataDescriptor *)Descriptor)->
Identifier & ANCILLARY_DATA_EXTENDED)
printf ("Extended Ancillary Data ");
if (((struct AncillaryDataDescriptor *)Descriptor)->
Identifier & ANCILLARY_DATA_SWITCHING)
printf ("Announcement Switching Data ");
if (((struct AncillaryDataDescriptor *)Descriptor)->
Identifier & ANCILLARY_DATA_DAB)
printf ("DAB Ancillary Data ");
if (((struct AncillaryDataDescriptor *)Descriptor)->
Identifier & ANCILLARY_DATA_SCALE_FACTOR)
printf ("Scale Factor Error Check (ScF-CRC) ");
printf ("\n");
break;
case DESCR_NW_NAME:
printf ("%sDescriptor: Network Name\n", Prepend);
printf ("%s Name: %s\n", Prepend, xName (Descriptor));
break;
case DESCR_BOUQUET_NAME:
printf ("%sDescriptor: Bouquet Name\n", Prepend);
printf ("%s Name: %s\n", Prepend, xName (Descriptor));
break;
case DESCR_COMPONENT:
printf ("%sDescriptor: Component\n", Prepend);
printf ("%s Text: %s\n", Prepend, xName (Descriptor));
printf ("%s Content/Type: ", Prepend);
for (i = 0; i < COMPONENT_TYPE_NUMBER; i++)
if ((((struct ComponentDescriptor *)Descriptor)->
StreamContent == ComponentTypes[i].Content) &&
(((struct ComponentDescriptor *)Descriptor)->
ComponentType == ComponentTypes[i].Type))
{ printf ("%s\n", ComponentTypes[i].Description); break; }
if (i == COMPONENT_TYPE_NUMBER) { printf ("unbekannt\n"); }
printf ("%s ComponentTag: 0x%02x\n", Prepend,
((struct ComponentDescriptor *)Descriptor)->ComponentTag);
printf ("%s LanguageCode: %s\n", Prepend,
((struct ComponentDescriptor *)Descriptor)->LanguageCode);
break;
case DESCR_SERVICE:
printf ("%sDescriptor: Service\n", Prepend);
printf ("%s Name: %s\n", Prepend, xName (Descriptor));
printf ("%s ServiceType: ", Prepend);
for (i = 0; i < SERVICE_TYPE_NUMBER; i++)
if ((((struct ServiceDescriptor *)Descriptor)->
ServiceType == ServiceTypes[i].Type))
{ printf ("%s\n", ServiceTypes[i].Description); break; }
if (i == SERVICE_TYPE_NUMBER) { printf ("unbekannt\n"); }
printf ("%s ServiceProvider: %s\n", Prepend,
((struct ServiceDescriptor *)Descriptor)->ServiceProvider);
break;
case DESCR_COUNTRY_AVAIL:
printf ("%sDescriptor: Country Availability\n", Prepend);
printf ("%s Type: %s\n", Prepend, (((struct CountryAvailabilityDescriptor *)Descriptor)->
AvailibilityFlag == COUNTRIES_ARE_AVAILABLE) ? "countries are available" :
"countries are unavailable");
{
char *cptr = ((struct CountryAvailabilityDescriptor *)Descriptor)->CountryCodes; int j;
for (j = 0; j < ((struct CountryAvailabilityDescriptor *)Descriptor)->Amount; j++)
{ printf ("%s Country: %s\n", Prepend, cptr); cptr += 4; }
}
break;
case DESCR_SHORT_EVENT:
printf ("%sDescriptor: Short Event\n", Prepend);
printf ("%s Name: %s\n", Prepend, xName (Descriptor));
printf ("%s LanguageCode: %s\n", Prepend,
((struct ShortEventDescriptor *)Descriptor)->LanguageCode);
printf ("%s Text: %s\n", Prepend,
((struct ShortEventDescriptor *)Descriptor)->Text);
break;
case DESCR_EXTENDED_EVENT:
{
struct ExtendedEventItem *Item;
printf ("%sDescriptor: Extended Event\n", Prepend);
printf ("%s Text: %s\n", Prepend, xName (Descriptor));
printf ("%s DescriptorNumber: %d\n", Prepend,
((struct ExtendedEventDescriptor *)Descriptor)->DescriptorNumber);
printf ("%s LastDescriptorNumber: %d\n", Prepend,
((struct ExtendedEventDescriptor *)Descriptor)->LastDescriptorNumber);
printf ("%s LanguageCode: %s\n", Prepend,
((struct ExtendedEventDescriptor *)Descriptor)->LanguageCode);
xForeach (((struct ExtendedEventDescriptor *)Descriptor)->Items, Item)
{
printf ("%s Item:\n", Prepend);
printf ("%s Description: %s\n", Prepend, xName(Item));
printf ("%s Text: %s\n", Prepend, Item->Text);
}
}
break;
case DESCR_CA_IDENT:
printf ("%sDescriptor: Conditional Access Identity\n", Prepend);
{
int j,k;
for (j = 0; j < ((struct CaIdentifierDescriptor *)Descriptor)->Amount; j++)
{
printf ("%s SystemID: 0x%04x", Prepend, GetCaIdentifierID (Descriptor, j));
k = GetCaIdentifierID (Descriptor, j) >> 8;
if (k < 0 || k > MAX_CA_IDENT) printf (" (unknown)\n");
else printf (" (%s)\n", CaIdents[k]);
}
}
break;
case DESCR_CA:
{
int j,k;
printf ("%sDescriptor: Conditional Access\n", Prepend);
printf ("%s CA type: 0x%04x", Prepend, (((struct CaDescriptor *)Descriptor)->CA_type));
k = (((struct CaDescriptor *)Descriptor)->CA_type) >> 8;
if (k < 0 || k > MAX_CA_IDENT) printf (" (unknown)\n");
else printf (" (%s)\n", CaIdents[k]);
printf ("%s CA PID: %d\n", Prepend, (((struct CaDescriptor *)Descriptor)->CA_PID));
printf ("%s ProviderID: 0x%04X\n", Prepend, (((struct CaDescriptor *)Descriptor)->ProviderID));
if (((struct CaDescriptor *)Descriptor)->DataLength > 0)
{
printf ("%s CA data:", Prepend);
for (j = 0; j < ((struct CaDescriptor *)Descriptor)->DataLength; j++)
printf (" 0x%02x", GetCaData (Descriptor, j));
printf ("\n");
}
}
break;
case DESCR_CONTENT:
printf ("%sDescriptor: Content\n", Prepend);
{
int j;
for (j = 0; j < ((struct ContentDescriptor *)Descriptor)->Amount; j++)
{
printf ("%s Content: ", Prepend);
for (i = 0; i < CONTENT_TYPE_NUMBER; i++)
if ((GetContentContentNibble1(Descriptor, j) == ContentTypes[i].Nibble1) &&
(GetContentContentNibble2(Descriptor, j) == ContentTypes[i].Nibble2))
{ printf ("%s\n", ContentTypes[i].Description); break; }
if (i == CONTENT_TYPE_NUMBER) { printf ("unbekannt\n"); }
printf ("%s User-Nibble 1: 0x%1x\n", Prepend, GetContentUserNibble1(Descriptor, j));
printf ("%s User-Nibble 2: 0x%1x\n", Prepend, GetContentUserNibble2(Descriptor, j));
}
}
break;
case DESCR_PARENTAL_RATING:
{
struct ParentalRating *Rating;
printf ("%sDescriptor: Parental Rating\n", Prepend);
xForeach (((struct ParentalRatingDescriptor *)Descriptor)->Ratings, Rating)
{
printf ("%s Rating:\n");
printf ("%s LanguageCode: %s\n", Rating->LanguageCode);
printf ("%s Rating: ");
if (Rating->Rating == 0) printf ("(undefined)\n");
else { if (Rating->Rating <= 0x10) printf ("minimum age is %d\n", Rating->Rating + 3);
else printf ("(rating is provider defined)\n"); }
}
}
break;
case DESCR_NVOD_REF:
{
struct NvodReferenceItem *Item;
printf ("%sDescriptor: NVOD Reference\n", Prepend);
xForeach (((struct NvodReferenceDescriptor *)Descriptor)->Items, Item)
{
printf ("%s Item:\n", Prepend);
printf ("%s ServiceID: %d\n", Prepend, Item->ServiceID);
printf ("%s TransportStreamID: %d\n", Prepend, Item->TransportStreamID);
printf ("%s OriginalNetworkID: %d\n", Prepend, Item->OriginalNetworkID);
}
}
break;
case DESCR_TIME_SHIFTED_SERVICE:
printf ("%sDescriptor: Time Shifted Service\n", Prepend);
printf ("%s ReferenceServiceID: %d\n", Prepend,
((struct TimeShiftedServiceDescriptor *)
Descriptor)->ReferenceServiceID);
break;
case DESCR_TIME_SHIFTED_EVENT:
printf ("%sDescriptor: Time Shifted Event\n", Prepend);
printf ("%s ReferenceServiceID: %d\n", Prepend,
((struct TimeShiftedEventDescriptor *)
Descriptor)->ReferenceServiceID);
printf ("%s ReferenceEventID: %d\n", Prepend,
((struct TimeShiftedEventDescriptor *)
Descriptor)->ReferenceEventID);
break;
case DESCR_ISO_639_LANGUAGE:
printf ("%sDescriptor: ISO 639 Language\n", Prepend);
printf ("%s LanguageCode: %s\n", Prepend,
((struct Iso639LanguageDescriptor *)Descriptor)->LanguageCode);
break;
case DESCR_STREAM_ID:
printf ("%sDescriptor: Stream Identifier\n", Prepend);
printf ("%s ComponentTag: %d\n", Prepend,
((struct StreamIdentifierDescriptor *)Descriptor)->ComponentTag);
break;
case DESCR_LINKAGE:
printf ("%sDescriptor: Linkage\n", Prepend);
printf ("%s TransportStreamID: %d\n", Prepend,
((struct LinkageDescriptor *)Descriptor)->TransportStreamID);
printf ("%s OriginalNetworkID: %d\n", Prepend,
((struct LinkageDescriptor *)Descriptor)->OriginalNetworkID);
printf ("%s ServiceID: %d\n", Prepend,
((struct LinkageDescriptor *)Descriptor)->ServiceID);
printf ("%s LinkageType: %d\n", Prepend,
((struct LinkageDescriptor *)Descriptor)->LinkageType);
if (((struct LinkageDescriptor *)Descriptor)->PrivateDataLength)
{
int j;
printf ("%s PrivateData: ", Prepend);
for (j = 0; j < ((struct LinkageDescriptor *)
Descriptor)->PrivateDataLength; j++)
printf ("0x%02X ", ((struct LinkageDescriptor *)
Descriptor)->PrivateData[j]);
printf ("\n");
}
break;
case DESCR_TELETEXT:
{
struct TeletextItem *Item;
printf ("%sDescriptor: Teletext\n", Prepend);
xForeach (((struct TeletextDescriptor *)Descriptor)->Items, Item)
{
printf ("%s Item:\n");
printf ("%s LanguageCode: %s\n", Prepend, Item->LanguageCode);
printf ("%s Type: ", Prepend);
switch (Item->Type)
{
case 0x01: printf ("initial Teletext page\n"); break;
case 0x02: printf ("Teletext subtitle page\n"); break;
case 0x03: printf ("additional information page\n"); break;
case 0x04: printf ("programme schedule page\n"); break;
case 0x05: printf ("Teletext subtitle page ");
printf ("for hearing impaired people\n"); break;
default: printf ("reserved for future use\n"); break;
}
printf ("%s MagazineNumber: %x\n", Prepend, Item->MagazineNumber);
printf ("%s PageNumber: %x\n", Prepend, Item->PageNumber);
}
}
break;
case DESCR_SUBTITLING:
{
struct SubtitlingItem *Item;
printf ("%sDescriptor: Subtitling\n", Prepend);
xForeach (((struct SubtitlingDescriptor *)Descriptor)->Items, Item)
{
printf ("%s Item:\n");
printf ("%s LanguageCode: %s\n", Prepend, Item->LanguageCode);
printf ("%s Type: ", Prepend);
for (i = 0; i < COMPONENT_TYPE_NUMBER; i++)
if ((0x03 == ComponentTypes[i].Content) &&
(Item->Type == ComponentTypes[i].Type))
{ printf ("%s\n", ComponentTypes[i].Description); break; }
printf ("%s CompositionPageId: %x\n", Prepend, Item->CompositionPageId);
printf ("%s AncillaryPageId: %x\n", Prepend, Item->AncillaryPageId);
}
}
break;
case DESCR_SAT_DEL_SYS:
{
struct SatelliteDeliverySystemDescriptor *sds =
(struct SatelliteDeliverySystemDescriptor *)Descriptor;
printf ("%sDescriptor: Satellite Delivery System\n", Prepend);
printf ("%s Frequency: %ld\n", Prepend, sds->Frequency);
printf ("%s OrbitalPosition: %d\n", Prepend, sds->OrbitalPosition);
printf ("%s Polarization: %c\n", Prepend, sds->Polarization);
printf ("%s Modulation: %c\n", Prepend, sds->Modulation);
printf ("%s SymbolRate: %ld\n", Prepend, sds->SymbolRate);
printf ("%s FEC: %c\n", Prepend, sds->FEC);
}
break;
case DESCR_CABLE_DEL_SYS:
{
struct CableDeliverySystemDescriptor *cds =
(struct CableDeliverySystemDescriptor *)Descriptor;
printf ("%sDescriptor: Cable Delivery System\n", Prepend);
printf ("%s Frequency: %ld\n", Prepend, cds->Frequency);
printf ("%s SymbolRate: %ld\n", Prepend, cds->SymbolRate);
printf ("%s FEC outer: %d\n", Prepend, cds->FECouter);
printf ("%s FEC inner: %d\n", Prepend, cds->FECinner);
printf ("%s Modulation: %d\n", Prepend, cds->Modulation);
}
break;
case DESCR_TERR_DEL_SYS:
{
struct TerrestrialDeliverySystemDescriptor *tds =
(struct TerrestrialDeliverySystemDescriptor *)Descriptor;
printf ("%sDescriptor: Terrestrial Delivery System\n", Prepend);
printf ("%s Frequency: %ld\n", Prepend, tds->Frequency);
printf ("%s Bandwidth: %d\n", Prepend, tds->Bandwidth);
printf ("%s Constellation: %d\n", Prepend, tds->Constellation);
printf ("%s Hierarchy: %d\n", Prepend, tds->Hierarchy);
printf ("%s CodeRateHP: %d\n", Prepend, tds->CodeRateHP);
printf ("%s CodeRateLP: %d\n", Prepend, tds->CodeRateLP);
printf ("%s GuardInterval: %d\n", Prepend, tds->GuardInterval);
printf ("%s TransmissionMode: %d\n", Prepend, tds->TransmissionMode);
printf ("%s OtherFrequencyFlag: %d\n", Prepend, tds->OtherFrequencyFlag);
}
break;
case DESCR_SERVICE_LIST:
{
struct ServiceListEntry *Entry;
printf ("%sDescriptor: Service List\n", Prepend);
xForeach (((struct ServiceListDescriptor *)Descriptor)->ServiceList, Entry)
{
printf ("%s Entry:\n");
printf ("%s ServiceID: %d\n", Prepend, Entry->ServiceID);
printf ("%s ServiceType: %04x\n", Prepend, Entry->ServiceType);
}
}
break;
case DESCR_LOCAL_TIME_OFF:
{
struct LocalTimeOffsetEntry *Offset;
printf ("%sDescriptor: Local Time Offset\n", Prepend);
xForeach (((struct LocalTimeOffsetDescriptor *)Descriptor)->LocalTimeOffsets, Offset)
{
printf ("%s Offset:\n");
printf ("%s CountryCode: %s\n", Offset->CountryCode);
printf ("%s RegionID: %c\n", Offset->RegionID);
printf ("%s CurrentOffset: %ld\n", Offset->CurrentOffset);
printf ("%s ChangeTime: %ld\n", Offset->ChangeTime);
printf ("%s NextOffset: %ld\n", Offset->NextOffset);
}
}
break;
case DESCR_STUFFING:
case DESCR_VBI_DATA:
case DESCR_VBI_TELETEXT:
case DESCR_MOSAIC:
case DESCR_TELEPHONE:
case DESCR_ML_NW_NAME:
case DESCR_ML_BQ_NAME:
case DESCR_ML_SERVICE_NAME:
case DESCR_ML_COMPONENT:
case DESCR_PRIV_DATA_SPEC:
case DESCR_SERVICE_MOVE:
case DESCR_SHORT_SMOOTH_BUF:
case DESCR_FREQUENCY_LIST:
case DESCR_PARTIAL_TP_STREAM:
case DESCR_DATA_BROADCAST:
case DESCR_CA_SYSTEM:
case DESCR_DATA_BROADCAST_ID:
case DESCR_TRANSPORT_STREAM:
case DESCR_DSNG:
case DESCR_PDC:
case DESCR_AC3:
case DESCR_CELL_LIST:
case DESCR_CELL_FREQ_LINK:
case DESCR_ANNOUNCEMENT_SUPPORT:
default:
printf ("%sDescriptor: %02x (noch nicht unterstützt)\n", Prepend, DescriptorTag (Descriptor));
break;
}
}
return;
}
void siDumpDescriptor (void * Descriptor)
{
int Length, i;
unsigned char *ptr;
Length = GetDescriptorLength (Descriptor);
for (i = 0, ptr = (char*) Descriptor; i < Length; i++) {
if ((i % 8) == 0)
printf ("\n");
printf ("0x%02X ", (unsigned int) ptr[i]);
}
printf ( "\n");
}
void siDumpSection (void *Section)
{
int Length, i;
unsigned char *ptr;
char str[9];
Length = GetSectionLength (Section) + 3;
for (i = 0, ptr = (unsigned char*) Section, memset (str, 0, 9); i < Length; i++) {
if ((i % 8) == 0)
{
printf (" %s\n", str);
memset (str, 0, 8);
}
printf ("0x%02X ", (unsigned int) ptr[i]);
if (ptr[i] < 0x20 || (ptr[i] > 'z' && ptr[i] < ((unsigned char )'À')) )
str[i % 8] = '.';
else
str[i % 8] = ptr[i];
}
printf (" %*s\n", (8 - ((abs(i - 1) % 8) ? (abs(i - 1) % 8) : 8)) * 5, str);
}

View File

@ -1,245 +0,0 @@
//////////////////////////////////////////////////////////////
/// ///
/// si_debug_services.h: local debugging definitions ///
/// ///
//////////////////////////////////////////////////////////////
// $Revision: 1.2 $
// $Date: 2003/02/04 18:45:35 $
// $Author: hakenes $
//
// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
//
// libsi is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// libsi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You may have received a copy of the GNU General Public License
// along with libsi; see the file COPYING. If not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
struct component_type {
u_char Content;
u_char Type;
char *Description;
};
static struct component_type ComponentTypes[] = {
{ 0x01, 0x01, "video, 4:3 aspect ratio, 25 Hz" },
{ 0x01, 0x02, "video, 16:9 aspect ratio with pan vectors, 25 Hz" },
{ 0x01, 0x03, "video, 16:9 aspect ratio without pan vectors, 25 Hz" },
{ 0x01, 0x04, "video, > 16:9 aspect ratio, 25 Hz" },
{ 0x01, 0x05, "video, 4:3 aspect ratio, 30 Hz" },
{ 0x01, 0x06, "video, 16:9 aspect ratio with pan vectors, 30 Hz" },
{ 0x01, 0x07, "video, 16:9 aspect ratio without pan vectors, 30 Hz" },
{ 0x01, 0x08, "video, > 16:9 aspect ratio, 30 Hz" },
{ 0x01, 0x09, "HD video, 4:3 aspect ratio, 25 Hz" },
{ 0x01, 0x0A, "HD video, 16:9 aspect ratio with pan vectors, 25 Hz" },
{ 0x01, 0x0B, "HD video, 16:9 aspect ratio without pan vectors, 25 Hz" },
{ 0x01, 0x0C, "HD video, > 16:9 aspect ratio, 25 Hz" },
{ 0x01, 0x0D, "HD video, 4:3 aspect ratio, 30 Hz" },
{ 0x01, 0x0E, "HD video, 16:9 aspect ratio with pan vectors, 30 Hz" },
{ 0x01, 0x0F, "HD video, 16:9 aspect ratio without pan vectors, 30 Hz" },
{ 0x01, 0x10, "HD video, > 16:9 aspect ratio, 30 Hz" },
{ 0x02, 0x01, "audio, single mono channel" },
{ 0x02, 0x02, "audio, dual mono channel" },
{ 0x02, 0x03, "audio, stereo (2 channel)" },
{ 0x02, 0x04, "audio, multi lingual, multi channel" },
{ 0x02, 0x05, "audio, surround sound" },
{ 0x02, 0x40, "audio description for the visually impaired" },
{ 0x02, 0x41, "audio for the hard of hearing" },
{ 0x03, 0x01, "EBU Teletext subtitles" },
{ 0x03, 0x02, "associated EBU Teletext" },
{ 0x03, 0x03, "VBI data" },
{ 0x03, 0x10, "DVB subtitles (normal), no aspect criticality" },
{ 0x03, 0x11, "DVB subtitles (normal), aspect 4:3 only" },
{ 0x03, 0x12, "DVB subtitles (normal), aspect 16:9 only" },
{ 0x03, 0x13, "DVB subtitles (normal), aspect 2.21:1 only" },
{ 0x03, 0x20, "DVB subtitles (hard of hearing), no aspect criticality" },
{ 0x03, 0x21, "DVB subtitles (hard of hearing), aspect 4:3 only" },
{ 0x03, 0x22, "DVB subtitles (hard of hearing), aspect 16:9 only" },
{ 0x03, 0x23, "DVB subtitles (hard of hearing), aspect 2.21:1 only" }
};
#define COMPONENT_TYPE_NUMBER 35
struct service_type {
u_char Type;
char *Description;
};
static struct service_type ServiceTypes[] = {
{ 0x01, "digital television service" },
{ 0x02, "digital radio sound service" },
{ 0x03, "Teletext service" },
{ 0x04, "NVOD reference service" },
{ 0x05, "NVOD time-shifted service" },
{ 0x06, "mosaic service" },
{ 0x07, "PAL coded signal" },
{ 0x08, "SECAM coded signal" },
{ 0x09, "D/D2-MAC" },
{ 0x0A, "FM Radio" },
{ 0x0B, "NTSC coded signal" },
{ 0x0C, "data broadcast service" },
{ 0x0D, "common interface data" },
{ 0x0E, "RCS Map" },
{ 0x0F, "RCS FLS" },
{ 0x10, "DVB MHP service" }
};
#define SERVICE_TYPE_NUMBER 16
struct content_type {
u_char Nibble1;
u_char Nibble2;
char *Description;
};
static struct content_type ContentTypes[] = {
/* Movie/Drama: */
{ 0x01, 0x00, "movie/drama (general)" },
{ 0x01, 0x01, "detective/thriller" },
{ 0x01, 0x02, "adventure/western/war" },
{ 0x01, 0x03, "science fiction/fantasy/horror" },
{ 0x01, 0x04, "comedy" },
{ 0x01, 0x05, "soap/melodrama/folkloric" },
{ 0x01, 0x06, "romance" },
{ 0x01, 0x07, "serious/classical/religious/historical movie/drama" },
{ 0x01, 0x08, "adult movie/drama" },
/* News/Current affairs: */
{ 0x02, 0x00, "news/current affairs (general)" },
{ 0x02, 0x01, "news/weather report" },
{ 0x02, 0x02, "news magazine" },
{ 0x02, 0x03, "documentary" },
{ 0x02, 0x04, "discussion/interview/debate" },
/* Show/Game show: */
{ 0x03, 0x00, "show/game show (general)" },
{ 0x03, 0x01, "game show/quiz/contest" },
{ 0x03, 0x02, "variety show" },
{ 0x03, 0x03, "talk show" },
/* Sports: */
{ 0x04, 0x00, "sports (general)" },
{ 0x04, 0x01, "special events (Olympic Games, World Cup etc.)" },
{ 0x04, 0x02, "sports magazines" },
{ 0x04, 0x03, "football/soccer" },
{ 0x04, 0x04, "tennis/squash" },
{ 0x04, 0x05, "team sports (excluding football)" },
{ 0x04, 0x06, "athletics" },
{ 0x04, 0x07, "motor sport" },
{ 0x04, 0x08, "water sport" },
{ 0x04, 0x09, "winter sports" },
{ 0x04, 0x0A, "equestrian" },
{ 0x04, 0x0B, "martial sports" },
/* Children's/Youth programmes: */
{ 0x05, 0x00, "children's/youth programmes (general)" },
{ 0x05, 0x01, "pre-school children's programmes" },
{ 0x05, 0x02, "entertainment programmes for 6 to14" },
{ 0x05, 0x03, "entertainment programmes for 10 to 16" },
{ 0x05, 0x04, "informational/educational/school programmes" },
{ 0x05, 0x05, "cartoons/puppets" },
/* Music/Ballet/Dance: */
{ 0x06, 0x00, "music/ballet/dance (general)" },
{ 0x06, 0x01, "rock/pop" },
{ 0x06, 0x02, "serious music/classical music" },
{ 0x06, 0x03, "folk/traditional music" },
{ 0x06, 0x04, "jazz" },
{ 0x06, 0x05, "musical/opera" },
{ 0x06, 0x06, "ballet" },
/* Arts/Culture (without music): */
{ 0x07, 0x00, "arts/culture (without music, general)" },
{ 0x07, 0x01, "performing arts" },
{ 0x07, 0x02, "fine arts" },
{ 0x07, 0x03, "religion" },
{ 0x07, 0x04, "popular culture/traditional arts" },
{ 0x07, 0x05, "literature" },
{ 0x07, 0x06, "film/cinema" },
{ 0x07, 0x07, "experimental film/video" },
{ 0x07, 0x08, "broadcasting/press" },
{ 0x07, 0x09, "new media" },
{ 0x07, 0x0A, "arts/culture magazines" },
{ 0x07, 0x0B, "fashion" },
/* Social/Political issues/Economics: */
{ 0x08, 0x00, "social/political issues/economics (general)" },
{ 0x08, 0x01, "magazines/reports/documentary" },
{ 0x08, 0x02, "economics/social advisory" },
{ 0x08, 0x03, "remarkable people" },
/* Children's/Youth programmes: */
/* Education/ Science/Factual topics: */
{ 0x09, 0x00, "education/science/factual topics (general)" },
{ 0x09, 0x01, "nature/animals/environment" },
{ 0x09, 0x02, "technology/natural sciences" },
{ 0x09, 0x03, "medicine/physiology/psychology" },
{ 0x09, 0x04, "foreign countries/expeditions" },
{ 0x09, 0x05, "social/spiritual sciences" },
{ 0x09, 0x06, "further education" },
{ 0x09, 0x07, "languages" },
/* Leisure hobbies: */
{ 0x0A, 0x00, "leisure hobbies (general)" },
{ 0x0A, 0x01, "tourism/travel" },
{ 0x0A, 0x02, "handicraft" },
{ 0x0A, 0x03, "motoring" },
{ 0x0A, 0x04, "fitness & health" },
{ 0x0A, 0x05, "cooking" },
{ 0x0A, 0x06, "advertisement/shopping" },
{ 0x0A, 0x07, "gardening" },
{ 0x0B, 0x00, "original language" },
{ 0x0B, 0x01, "black & white" },
{ 0x0B, 0x02, "unpublished" },
{ 0x0B, 0x03, "live broadcast" }
};
#define CONTENT_TYPE_NUMBER 79
static char *StreamTypes[] = {
"ITU-T|ISO/IEC Reserved",
"ISO/IEC Video",
"13818-2 Video or 11172-2 constrained parameter video stream",
"ISO/IEC 11172 Audio",
"ISO/IEC 13818-3 Audio",
"private_sections",
"packets containing private data / Videotext",
"ISO/IEC 13522 MPEG",
"ITU-T Rec. H.222.1",
"ISO/IEC 13818-6 type A",
"ISO/IEC 13818-6 type B",
"ISO/IEC 13818-6 type C",
"ISO/IEC 13818-6 type D",
"ISO/IEC 13818-1 auxiliary",
"ITU-T Rec. H.222.0 | ISO 13818-1 Reserved",
"User private"
};
static char *CaIdents[] = {
"Standardized systems",
"Canal Plus",
"CCETT",
"Deutsche Telecom",
"Eurodec",
"France Telecom",
"Irdeto",
"Jerrold/GI",
"Matra Communication",
"News Datacom",
"Nokia",
"Norwegian Telekom",
"NTL",
"Philips",
"Scientific Atlanta",
"Sony",
"Tandberg Television",
"Thomson",
"TV/Com",
"HPT - Croatian Post and Telecommunications",
"HRT - Croatian Radio and Television",
"IBM",
"Nera",
"BetaTechnik"
};
#define MAX_CA_IDENT 24

File diff suppressed because it is too large Load Diff

View File

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,63 +0,0 @@
##############################################################
### ###
### Makefile: local makefile for libvdr ###
### ###
##############################################################
## $Revision: 1.3 $
## $Date: 2001/10/06 15:33:46 $
## $Author: hakenes $
##
## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
##
## libdtv is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## libdtv is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You may have received a copy of the GNU General Public License
## along with libdtv; see the file COPYING. If not, write to the
## Free Software Foundation, Inc., 59 Temple Place - Suite 330,
## Boston, MA 02111-1307, USA.
#
#
#
CC ?= gcc
CFLAGS ?= -O2 -g -Wmissing-prototypes -Wstrict-prototypes \
-Wimplicit -D__USE_FIXED_PROTOTYPES__ # -DDEBUG
CFLAGS += -I../include
AR = ar
ARFLAGS = r
RANLIB = ranlib
RM = rm -f
CP = cp
VDRINCLUDE = libvdr.h
VDRLIB = libvdr.a
VDROBJS = libvdr.o
all : $(VDRLIB)
clean :
@echo "cleaning workspace..."
@$(RM) $(VDROBJS) $(VDRLIB)
new : clean all
$(VDRLIB) : $(VDROBJS)
@echo "updating library..."
@$(AR) $(ARFLAGS) $(VDRLIB) $(VDROBJS)
@$(RANLIB) $(VDRLIB)
dist: all
@echo "distributing libvdr.a and libvdr.h..."
@$(CP) $(VDRLIB) ../lib
@$(CP) $(VDRINCLUDE) ../include

View File

@ -1,157 +0,0 @@
//////////////////////////////////////////////////////////////
/// ///
/// libvdr.c: routines to parse the DVB-SI stream ///
/// ///
//////////////////////////////////////////////////////////////
// $Revision: 1.1 $
// $Date: 2001/10/07 10:25:33 $
// $Author: hakenes $
//
// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
//
// libvdr is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// libvdr is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You may have received a copy of the GNU General Public License
// along with libvdr; see the file COPYING. If not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <liblx.h>
#include <libsi.h>
#include <si_tables.h>
#include "libvdr.h"
struct LIST *createVdrProgramInfos (unsigned char *siBuffer)
{
struct VdrProgramInfo *VdrProgramInfo;
struct LIST *Result, *EventList;
struct Event *Event;
struct Descriptor *Descriptor;
int GotVdrProgramInfo;
if (!siBuffer) return (NULL);
if (!(EventList = siParseEIT (siBuffer))) return (NULL);
Result = xNewList (NULL);
xForeach (EventList, Event)
{
VdrProgramInfo = NULL;
GotVdrProgramInfo = 0;
xForeach (Event->Descriptors, Descriptor)
{
if (!VdrProgramInfo)
{
CreateVdrProgramInfo(VdrProgramInfo,
Event->EventID, Event->TransportStreamID,
Event->ServiceID, Event->StartTime,
Event->Duration, Event->Status);
}
switch (Descriptor->Tag)
{
case DESCR_SHORT_EVENT:
{
if (!xName(Descriptor) || !xName(Descriptor)[0])
break;
VdrProgramInfo->ShortName =
xSetText (xName (Descriptor));
VdrProgramInfo->ShortText =
xSetText (((struct ShortEventDescriptor
*)Descriptor)->Text);
memcpy (VdrProgramInfo->LanguageCode, ((struct
ShortEventDescriptor *)Descriptor)->
LanguageCode, 4);
GotVdrProgramInfo = 1;
}
break;
case DESCR_TIME_SHIFTED_EVENT:
{
struct tm *StartTime;
VdrProgramInfo->ReferenceServiceID =
((struct TimeShiftedEventDescriptor
*)Descriptor)->ReferenceServiceID;
VdrProgramInfo->ReferenceEventID =
((struct TimeShiftedEventDescriptor
*)Descriptor)->ReferenceEventID;
GotVdrProgramInfo = 1;
}
break;
case DESCR_EXTENDED_EVENT:
{
struct ExtendedEventItem *Item;
if (xName (Descriptor))
AddToText (xName (Descriptor),
VdrProgramInfo->ExtendedName);
xForeach (((struct ExtendedEventDescriptor*)
Descriptor)->Items, Item)
{
AddItemToText (xName (Item),
VdrProgramInfo->ExtendedText);
AddItemToText (Item->Text,
VdrProgramInfo->ExtendedText);
}
}
break;
case DESCR_CONTENT:
{
int i, j;
for (j = 0; j < ((struct ContentDescriptor*)
Descriptor)->Amount; j++)
{
VdrProgramInfo->ContentNibble1 =
GetContentContentNibble1(Descriptor, j);
VdrProgramInfo->ContentNibble2 =
GetContentContentNibble2(Descriptor, j);
}
}
break;
case DESCR_PARENTAL_RATING:
{
struct ParentalRating *Rating;
xForeach (((struct ParentalRatingDescriptor *)
Descriptor)->Ratings, Rating)
if (!strncmp (VdrProgramInfo->LanguageCode,
Rating->LanguageCode, 3))
VdrProgramInfo->Rating = Rating->Rating;
}
break;
}
}
if (GotVdrProgramInfo) xAddTail (Result, VdrProgramInfo);
else xMemFree (VdrProgramInfo);
}
return (Result);
}

View File

@ -1,111 +0,0 @@
//////////////////////////////////////////////////////////////
/// ///
/// libvdr.h: definitions necessary for the libvdr package ///
/// ///
//////////////////////////////////////////////////////////////
// $Revision: 1.4 $
// $Date: 2001/10/06 15:33:46 $
// $Author: hakenes $
//
// (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL.
//
// libvdr is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// libvdr is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You may have received a copy of the GNU General Public License
// along with libvdr; see the file COPYING. If not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
#ifndef LIBVDR_H
#define LIBVDR_H
#ifdef __cplusplus
extern "C" {
#endif
struct LIST *createVdrProgramInfos (unsigned char *);
#ifdef __cplusplus
}
#endif
struct VdrProgramInfo {
struct NODE Node;
int EventID;
int TransportStreamID;
int ServiceID;
time_t StartTime;
time_t Duration;
unsigned short Status;
char LanguageCode[4];
unsigned short Rating;
unsigned short ContentNibble1;
unsigned short ContentNibble2;
char *ShortName;
char *ShortText;
char *ExtendedName;
char *ExtendedText;
int ReferenceServiceID;
int ReferenceEventID;
};
#define CreateVdrProgramInfo(cinf, evid, tpid, svid, stst, dura, sta) \
do \
{ \
xCreateNode (cinf, NULL); \
cinf->EventID = evid; \
cinf->TransportStreamID = tpid; \
cinf->ServiceID = svid; \
cinf->StartTime = stst; \
cinf->Duration = dura; \
cinf->Status = sta; \
cinf->LanguageCode[0] = 0; \
cinf->Rating = 0; \
cinf->ContentNibble1 = 0; \
cinf->ContentNibble2 = 0; \
cinf->ShortName = NULL; \
cinf->ShortText = NULL; \
cinf->ExtendedName = NULL; \
cinf->ExtendedText = NULL; \
cinf->ReferenceServiceID = 0; \
cinf->ReferenceEventID = 0; \
} while (0)
#define AddToText(src, dest) \
do { \
if (dest) \
{ \
char *tmbuf; \
xMemAlloc (strlen (src) + strlen (dest) + 4, &tmbuf); \
sprintf (tmbuf, "%s%s", (dest), (src)); \
xMemFree (dest); (dest) = tmbuf; \
} else { \
(dest) = xSetText (src); \
} \
} while (0)
#define AddItemToText(src, dest) \
do { \
if (dest) \
{ \
char *tmbuf; \
xMemAlloc (strlen (src) + strlen (dest) + 4, &tmbuf); \
sprintf (tmbuf, "%s|%s", (dest), (src)); \
xMemFree (dest); (dest) = tmbuf; \
} else { \
(dest) = xSetText (src); \
} \
} while (0)
#endif

52
libsi/Makefile Normal file
View File

@ -0,0 +1,52 @@
#
# Makefile for a libsi
#
# $Id: Makefile 1.2 2003/12/13 10:41:39 kls Exp $
### The C++ compiler and options:
CXX ?= g++
CXXFLAGS ?= -O2 -g -Wall -Woverloaded-virtual
AR = ar
ARFLAGS = ru
RANLIB = ranlib
### The directory environment:
INCLUDES +=
DEFINES +=
LIBS +=
### The object files (add further files here):
OBJS = util.o si.o section.o descriptor.o
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
MAKEDEP = g++ -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Targets:
all: libsi.a
libsi.a : $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
clean:
@-rm -f $(OBJS) $(DEPFILE) *.a *.so *.tgz core* *~
dist:
tar cvzf libsi.tar.gz -C .. libsi/util.c libsi/si.c libsi/section.c libsi/descriptor.c \
libsi/util.h libsi/si.h libsi/section.h libsi/descriptor.h libsi/headers.h libsi/Makefile libsi/gendescr.pl

635
libsi/descriptor.c Normal file
View File

@ -0,0 +1,635 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: descriptor.c 1.2 2003/12/13 10:42:05 kls Exp $
* *
***************************************************************************/
#include <string.h>
#include "descriptor.h"
namespace SI {
void ShortEventDescriptor::Parse() {
unsigned int offset=0;
const descr_short_event *s;
data.setPointerAndOffset<const descr_short_event>(s, offset);
languageCode[0]=s->lang_code1;
languageCode[1]=s->lang_code2;
languageCode[2]=s->lang_code3;
name.setDataAndOffset(data+offset, s->event_name_length, offset);
const descr_short_event_mid *mid;
data.setPointerAndOffset<const descr_short_event_mid>(mid, offset);
text.setData(data+offset, mid->text_length);
}
int ExtendedEventDescriptor::getDescriptorNumber() {
return s->descriptor_number;
}
int ExtendedEventDescriptor::getLastDescriptorNumber() {
return s->last_descriptor_number;
}
void ExtendedEventDescriptor::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const descr_extended_event>(s, offset);
languageCode[0]=s->lang_code1;
languageCode[1]=s->lang_code2;
languageCode[2]=s->lang_code3;
itemLoop.setDataAndOffset(data+offset, s->length_of_items, offset);
const descr_extended_event_mid *mid;
data.setPointerAndOffset<const descr_extended_event_mid>(mid, offset);
text.setData(data+offset, mid->text_length);
}
void ExtendedEventDescriptor::Item::Parse() {
unsigned int offset=0;
const item_extended_event *first;
data.setPointerAndOffset<const item_extended_event>(first, offset);
itemDescription.setDataAndOffset(data+offset, first->item_description_length, offset);
const item_extended_event_mid *mid;
data.setPointerAndOffset<const item_extended_event_mid>(mid, offset);
item.setData(data+offset, mid->item_length);
}
int ExtendedEventDescriptors::getTextLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ret+=d->text.getLength()+1; //plus a blank
ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it);
ret+=item.item.getLength();
ret+=item.itemDescription.getLength();
ret+=2; //the blanks
}
}
return ret;
}
//is there a case where this function does not return the same as getTextLength?
int ExtendedEventDescriptors::getMaximumTextLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ret+=d->text.getLength()+1; //plus a blank
ret+=d->itemLoop.getLength();
}
return ret;
}
char *ExtendedEventDescriptors::getText() {
char *text=new char[getMaximumTextLength()];
return getText(text);
}
//appends the Strings of every Descriptor in the group
char *ExtendedEventDescriptors::getText(char *buffer) {
int index=0, len;
char tempbuf[256];
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
d->text.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it);
item.item.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
item.itemDescription.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
}
}
buffer[index]='\0';
return buffer;
}
int TimeShiftedEventDescriptor::getReferenceServiceId() const {
return HILO(s->reference_service_id);
}
int TimeShiftedEventDescriptor::getReferenceEventId() const {
return HILO(s->reference_event_id);
}
void TimeShiftedEventDescriptor::Parse() {
s=data.getData<const descr_time_shifted_event>();
}
void ContentDescriptor::Parse() {
//this descriptor is only a header and a loop
nibbleLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader));
}
int ContentDescriptor::Nibble::getContentNibbleLevel1() const {
return s->content_nibble_level_1;
}
int ContentDescriptor::Nibble::getContentNibbleLevel2() const {
return s->content_nibble_level_2;
}
int ContentDescriptor::Nibble::getUserNibble1() const {
return s->user_nibble_1;
}
int ContentDescriptor::Nibble::getUserNibble2() const {
return s->user_nibble_2;
}
void ContentDescriptor::Nibble::Parse() {
s=data.getData<const nibble_content>();
}
void ParentalRatingDescriptor::Parse() {
//this descriptor is only a header and a loop
ratingLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader));
}
int ParentalRatingDescriptor::Rating::getRating() const {
return s->rating;
}
void ParentalRatingDescriptor::Rating::Parse() {
s=data.getData<const parental_rating>();
languageCode[0]=s->lang_code1;
languageCode[1]=s->lang_code2;
languageCode[2]=s->lang_code3;
}
int CaDescriptor::getCaType() const {
return HILO(s->CA_type);
}
int CaDescriptor::getCaPid() const {
return HILO(s->CA_PID);
}
void CaDescriptor::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const descr_ca>(s, offset);
privateData.assign(data.getData(offset), getLength()-offset);
}
int StreamIdentifierDescriptor::getComponentTag() const {
return s->component_tag;
}
void StreamIdentifierDescriptor::Parse() {
s=data.getData<const descr_stream_identifier>();
}
void NetworkNameDescriptor::Parse() {
name.setData(data+sizeof(descr_network_name), getLength()-sizeof(descr_network_name));
}
void CaIdentifierDescriptor::Parse() {
identifiers.setData(data+sizeof(descr_ca_identifier), getLength()-sizeof(descr_ca_identifier));
}
int CarouselIdentifierDescriptor::getCarouselId() const {
return (HILO(s->carousel_id_hi) << 16) | HILO(s->carousel_id_lo);
}
int CarouselIdentifierDescriptor::getFormatId() const {
return s->FormatId;
}
void CarouselIdentifierDescriptor::Parse() {
s=data.getData<const descr_carousel_identifier>();
}
void ServiceListDescriptor::Parse() {
serviceLoop.setData(data+sizeof(descr_service_list), getLength()-sizeof(descr_service_list));
}
int ServiceListDescriptor::Service::getServiceId() const {
return HILO(s->service_id);
}
int ServiceListDescriptor::Service::getServiceType() const {
return s->service_type;
}
void ServiceListDescriptor::Service::Parse() {
s=data.getData<const descr_service_list_loop>();
}
int SatelliteDeliverySystemDescriptor::getFrequency() const {
return (HILO(s->frequency_hi) << 16) | HILO(s->frequency_lo);
}
int SatelliteDeliverySystemDescriptor::getOrbitalPosition() const {
return HILO(s->orbital_position);
}
int SatelliteDeliverySystemDescriptor::getWestEastFlag() const {
return s->west_east_flag;
}
int SatelliteDeliverySystemDescriptor::getPolarization() const {
return s->polarization;
}
int SatelliteDeliverySystemDescriptor::getModulation() const {
return s->modulation;
}
int SatelliteDeliverySystemDescriptor::getSymbolRate() const {
return (HILO(s->symbol_rate_hi) << 12) | (s->symbol_rate_lo_1 << 4) | s->symbol_rate_lo_2;
}
int SatelliteDeliverySystemDescriptor::getFecInner() const {
return s->fec_inner;
}
void SatelliteDeliverySystemDescriptor::Parse() {
s=data.getData<const descr_satellite_delivery_system>();
}
int CableDeliverySystemDescriptor::getFrequency() const {
return (HILO(s->frequency_hi) << 16) | HILO(s->frequency_lo);
}
int CableDeliverySystemDescriptor::getFecOuter() const {
return s->fec_outer;
}
int CableDeliverySystemDescriptor::getModulation() const {
return s->modulation;
}
int CableDeliverySystemDescriptor::getSymbolRate() const {
return (HILO(s->symbol_rate_hi) << 12) | (s->symbol_rate_lo_1 << 4) | s->symbol_rate_lo_2;
}
int CableDeliverySystemDescriptor::getFecInner() const {
return s->fec_inner;
}
void CableDeliverySystemDescriptor::Parse() {
s=data.getData<const descr_cable_delivery_system>();
}
int TerrestrialDeliverySystemDescriptor::getFrequency() const {
return (HILO(s->frequency_hi) << 16) | HILO(s->frequency_lo);
}
int TerrestrialDeliverySystemDescriptor::getBandwidth() const {
return s->bandwidth;
}
int TerrestrialDeliverySystemDescriptor::getConstellation() const {
return s->constellation;
}
int TerrestrialDeliverySystemDescriptor::getHierarchy() const {
return s->hierarchy;
}
int TerrestrialDeliverySystemDescriptor::getCodeRateHP() const {
return s->code_rate_HP;
}
int TerrestrialDeliverySystemDescriptor::getCodeRateLP() const {
return s->code_rate_LP;
}
int TerrestrialDeliverySystemDescriptor::getGuardInterval() const {
return s->guard_interval;
}
int TerrestrialDeliverySystemDescriptor::getTransmissionMode() const {
return s->transmission_mode;
}
bool TerrestrialDeliverySystemDescriptor::getOtherFrequency() const {
return s->other_frequency_flag;
}
void TerrestrialDeliverySystemDescriptor::Parse() {
s=data.getData<const descr_terrestrial_delivery>();
}
int ServiceDescriptor::getServiceType() const {
return s->service_type;
}
void ServiceDescriptor::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const descr_service>(s, offset);
providerName.setDataAndOffset(data+offset, s->provider_name_length, offset);
const descr_service_mid *mid;
data.setPointerAndOffset<const descr_service_mid>(mid, offset);
serviceName.setData(data+offset, mid->service_name_length);
}
void NVODReferenceDescriptor::Parse() {
serviceLoop.setData(data+sizeof(descr_nvod_reference), getLength()-sizeof(descr_nvod_reference));
}
int NVODReferenceDescriptor::Service::getTransportStream() const {
return HILO(s->transport_stream_id);
}
int NVODReferenceDescriptor::Service::getOriginalNetworkId() const {
return HILO(s->original_network_id);
}
int NVODReferenceDescriptor::Service::getServiceId() const {
return HILO(s->service_id);
}
void NVODReferenceDescriptor::Service::Parse() {
s=data.getData<const item_nvod_reference>();
}
int TimeShiftedServiceDescriptor::getReferenceServiceId() const {
return HILO(s->reference_service_id);
}
void TimeShiftedServiceDescriptor::Parse() {
s=data.getData<const descr_time_shifted_service>();
}
int ComponentDescriptor::getStreamContent() const {
return s->stream_content;
}
int ComponentDescriptor::getComponentType() const {
return s->component_type;
}
int ComponentDescriptor::getComponentTag() const {
return s->component_tag;
}
void ComponentDescriptor::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const descr_component>(s, offset);
languageCode[0]=s->lang_code1;
languageCode[1]=s->lang_code2;
languageCode[2]=s->lang_code3;
description.setData(data+offset, getLength()-offset);
}
void SubtitlingDescriptor::Parse() {
subtitlingLoop.setData(data+sizeof(descr_subtitling), getLength()-sizeof(descr_subtitling));
}
int SubtitlingDescriptor::Subtitling::getSubtitlingType() const {
return s->subtitling_type;
}
int SubtitlingDescriptor::Subtitling::getCompositionPageId() const {
return HILO(s->composition_page_id);
}
int SubtitlingDescriptor::Subtitling::getAncillaryPageId() const {
return HILO(s->ancillary_page_id);
}
void SubtitlingDescriptor::Subtitling::Parse() {
s=data.getData<const item_subtitling>();
}
int ServiceMoveDescriptor::getNewOriginalNetworkId() const {
return HILO(s->new_original_network_id);
}
int ServiceMoveDescriptor::getNewTransportStreamId() const {
return HILO(s->new_transport_stream_id);
}
int ServiceMoveDescriptor::getNewServiceId() const {
return HILO(s->new_service_id);
}
void ServiceMoveDescriptor::Parse() {
s=data.getData<const descr_service_move>();
}
int FrequencyListDescriptor::getCodingType() const {
return s->coding_type;
}
void FrequencyListDescriptor::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const descr_frequency_list>(s, offset);
frequencies.setData(data+offset, getLength()-offset);
}
void ServiceIdentifierDescriptor::Parse() {
textualServiceIdentifier.setData(data+sizeof(descr_service_identifier), getLength()-sizeof(descr_service_identifier));
}
void MultilingualNameDescriptor::Parse() {
nameLoop.setData(data+sizeof(descr_multilingual_network_name), getLength()-sizeof(descr_multilingual_network_name));
}
void MultilingualNameDescriptor::Name::Parse() {
unsigned int offset=0;
const entry_multilingual_name *s;
data.setPointerAndOffset<const entry_multilingual_name>(s, offset);
languageCode[0]=s->lang_code1;
languageCode[1]=s->lang_code2;
languageCode[2]=s->lang_code3;
name.setData(data+offset, s->text_length);
}
int MultilingualComponentDescriptor::getComponentTag() const {
return s->component_tag;
}
void MultilingualComponentDescriptor::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const descr_multilingual_component>(s, offset);
nameLoop.setData(data+sizeof(descr_multilingual_component), getLength()-sizeof(descr_multilingual_component));
}
void MultilingualServiceNameDescriptor::Parse() {
nameLoop.setData(data+sizeof(descr_multilingual_network_name), getLength()-sizeof(descr_multilingual_network_name));
}
void MultilingualServiceNameDescriptor::Name::Parse() {
unsigned int offset=0;
const entry_multilingual_name *s;
data.setPointerAndOffset<const entry_multilingual_name>(s, offset);
languageCode[0]=s->lang_code1;
languageCode[1]=s->lang_code2;
languageCode[2]=s->lang_code3;
providerName.setDataAndOffset(data+offset, s->text_length, offset);
const entry_multilingual_service_name_mid *mid;
data.setPointerAndOffset<const entry_multilingual_service_name_mid>(mid, offset);
name.setData(data+offset, mid->service_name_length);
}
void ApplicationSignallingDescriptor::Parse() {
entryLoop.setData(data+sizeof(descr_application_signalling), getLength()-sizeof(descr_application_signalling));
}
int ApplicationSignallingDescriptor::ApplicationEntryDescriptor::getApplicationType() const {
return HILO(s->application_type);
}
int ApplicationSignallingDescriptor::ApplicationEntryDescriptor::getAITVersionNumber() const {
return s->AIT_version_number;
}
void ApplicationSignallingDescriptor::ApplicationEntryDescriptor::Parse() {
s=data.getData<const application_signalling_entry>();
}
bool MHP_ApplicationDescriptor::isServiceBound() const {
return s->service_bound_flag;
}
int MHP_ApplicationDescriptor::getVisibility() const {
return s->visibility;
}
int MHP_ApplicationDescriptor::getApplicationPriority() const {
return s->application_priority;
}
void MHP_ApplicationDescriptor::Parse() {
unsigned int offset=0;
const descr_application *dapp;
data.setPointerAndOffset<const descr_application>(dapp, offset);
profileLoop.setDataAndOffset(data+offset, dapp->application_profiles_length, offset);
data.setPointerAndOffset<const descr_application_end>(s, offset);
transportProtocolLabels.setData(data+offset, getLength()-offset);
}
int MHP_ApplicationDescriptor::Profile::getApplicationProfile() const {
return HILO(s->application_profile);
}
int MHP_ApplicationDescriptor::Profile::getVersionMajor() const {
return s->version_major;
}
int MHP_ApplicationDescriptor::Profile::getVersionMinor() const {
return s->version_minor;
}
int MHP_ApplicationDescriptor::Profile::getVersionMicro() const {
return s->version_micro;
}
void MHP_ApplicationDescriptor::Profile::Parse() {
s=data.getData<application_profile_entry>();
}
void MHP_ApplicationNameDescriptor::Parse() {
nameLoop.setData(data+sizeof(descr_application_name), getLength()-sizeof(descr_application_name));
}
void MHP_ApplicationNameDescriptor::NameEntry::Parse() {
const descr_application_name_entry *s;
s=data.getData<const descr_application_name_entry>();
name.setData(data+sizeof(descr_application_name_entry), s->application_name_length);
languageCode[0]=s->lang_code1;
languageCode[1]=s->lang_code2;
languageCode[2]=s->lang_code3;
}
int MHP_TransportProtocolDescriptor::getProtocolId() const {
return HILO(s->protocol_id);
}
int MHP_TransportProtocolDescriptor::getProtocolLabel() const {
return s->transport_protocol_label;
}
bool MHP_TransportProtocolDescriptor::isRemote() const {
return remote;
}
int MHP_TransportProtocolDescriptor::getComponentTag() const {
return componentTag;
}
void MHP_TransportProtocolDescriptor::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const descr_transport_protocol>(s, offset);
if (getProtocolId() == ObjectCarousel) {
const transport_via_oc *oc;
data.setPointerAndOffset<const transport_via_oc>(oc, offset);
remote=oc->remote;
if (remote) {
const transport_via_oc_remote_end *rem;
data.setPointerAndOffset<const transport_via_oc_remote_end>(rem, offset);
componentTag=rem->component_tag;
} else {
const transport_via_oc_end *rem;
data.setPointerAndOffset<const transport_via_oc_end>(rem, offset);
componentTag=rem->component_tag;
}
} else { //unimplemented
remote=false;
componentTag=-1;
}
}
void MHP_DVBJApplicationDescriptor::Parse() {
applicationLoop.setData(data+sizeof(descr_dvbj_application), getLength()-sizeof(descr_dvbj_application));
}
void MHP_DVBJApplicationDescriptor::ApplicationEntry::Parse() {
const descr_dvbj_application_entry *entry=data.getData<const descr_dvbj_application_entry>();
parameter.setData(data+sizeof(descr_dvbj_application_entry), entry->parameter_length);
}
void MHP_DVBJApplicationLocationDescriptor::Parse() {
unsigned int offset=0;
const descr_dvbj_application_location *first;
data.setPointerAndOffset<const descr_dvbj_application_location>(first, offset);
baseDirectory.setDataAndOffset(data+offset, first->base_directory_length, offset);
const descr_dvbj_application_location_mid *mid;
data.setPointerAndOffset<const descr_dvbj_application_location_mid>(mid, offset);
classPath.setDataAndOffset(data+offset, mid->classpath_extension_length, offset);
initialClass.setData(data+offset, getLength()-offset);
}
int MHP_ApplicationIconsDescriptor::getIconFlags() const {
return HILO(s->icon_flags);
}
void MHP_ApplicationIconsDescriptor::Parse() {
unsigned int offset=0;
const descr_application_icons_descriptor *first;
data.setPointerAndOffset<const descr_application_icons_descriptor>(first, offset);
iconLocator.setDataAndOffset(data+offset, first->icon_locator_length, offset);
data.setPointerAndOffset<const descr_application_icons_descriptor_end>(s, offset);
}
} //end of namespace

477
libsi/descriptor.h Normal file
View File

@ -0,0 +1,477 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: descriptor.h 1.2 2003/12/13 10:42:08 kls Exp $
* *
***************************************************************************/
#ifndef LIBSI_DESCRIPTOR_H
#define LIBSI_DESCRIPTOR_H
#include "si.h"
#include "headers.h"
namespace SI {
class ShortEventDescriptor : public Descriptor {
public:
char languageCode[3];
String name; //name of the event
String text; //short description
protected:
virtual void Parse();
};
class ExtendedEventDescriptor : public GroupDescriptor {
public:
class Item : public LoopElement {
public:
virtual int getLength() { return sizeof(item_extended_event)+sizeof(item_extended_event_mid)+item.getLength()+itemDescription.getLength(); }
String item;
String itemDescription;
protected:
virtual void Parse();
};
char languageCode[3];
int getDescriptorNumber();
int getLastDescriptorNumber();
StructureLoop<Item> itemLoop;
String text;
protected:
virtual void Parse();
private:
const descr_extended_event *s;
};
class ExtendedEventDescriptors : public DescriptorGroup {
public:
//don't use
int getTextLength();
//really fast
int getMaximumTextLength();
//same semantics as with SI::String
char *getText();
//buffer must at least be getTextLength(), getMaximumTextLength() is a good choice
char *getText(char *buffer);
};
class TimeShiftedEventDescriptor : public Descriptor {
public:
int getReferenceServiceId() const;
int getReferenceEventId() const;
protected:
virtual void Parse();
private:
const descr_time_shifted_event *s;
};
class ContentDescriptor : public Descriptor {
public:
class Nibble : public LoopElement {
public:
virtual int getLength() { return sizeof(nibble_content); }
int getContentNibbleLevel1() const;
int getContentNibbleLevel2() const;
int getUserNibble1() const;
int getUserNibble2() const;
protected:
virtual void Parse();
private:
const nibble_content *s;
};
StructureLoop<Nibble> nibbleLoop;
protected:
virtual void Parse();
};
class ParentalRatingDescriptor : public Descriptor {
public:
class Rating : public LoopElement {
public:
char languageCode[3];
int getRating() const;
virtual int getLength() { return sizeof(parental_rating); }
protected:
virtual void Parse();
private:
const parental_rating *s;
};
StructureLoop<Rating> ratingLoop;
protected:
virtual void Parse();
};
class CaDescriptor : public Descriptor {
public:
int getCaType() const;
int getCaPid() const;
CharArray privateData;
protected:
virtual void Parse();
private:
const descr_ca *s;
};
class StreamIdentifierDescriptor : public Descriptor {
public:
int getComponentTag() const;
protected:
virtual void Parse();
private:
const descr_stream_identifier *s;
};
class NetworkNameDescriptor : public Descriptor {
public:
String name;
protected:
virtual void Parse();
};
class CaIdentifierDescriptor : public Descriptor {
public:
TypeLoop<SixteenBit> identifiers;
protected:
virtual void Parse();
};
class CarouselIdentifierDescriptor : public Descriptor {
public:
int getCarouselId() const;
int getFormatId() const;
protected:
virtual void Parse();
private:
const descr_carousel_identifier *s;
};
class BouquetNameDescriptor : public NetworkNameDescriptor {
};
class ServiceListDescriptor : public Descriptor {
public:
class Service : public LoopElement {
public:
int getServiceId() const;
int getServiceType() const;
virtual int getLength() { return sizeof(descr_service_list_loop); }
protected:
virtual void Parse();
private:
const descr_service_list_loop *s;
};
StructureLoop<Service> serviceLoop;
protected:
virtual void Parse();
};
class SatelliteDeliverySystemDescriptor : public Descriptor {
public:
int getFrequency() const;
int getOrbitalPosition() const;
int getWestEastFlag() const;
int getPolarization() const;
int getModulation() const;
int getSymbolRate() const;
int getFecInner() const;
protected:
virtual void Parse();
private:
const descr_satellite_delivery_system *s;
};
class CableDeliverySystemDescriptor : public Descriptor {
public:
int getFrequency() const;
int getFecOuter() const;
int getModulation() const;
int getSymbolRate() const;
int getFecInner() const;
protected:
virtual void Parse();
private:
const descr_cable_delivery_system *s;
};
class TerrestrialDeliverySystemDescriptor : public Descriptor {
public:
int getFrequency() const;
int getBandwidth() const;
int getConstellation() const;
int getHierarchy() const;
int getCodeRateHP() const;
int getCodeRateLP() const;
int getGuardInterval() const;
int getTransmissionMode() const;
bool getOtherFrequency() const;
protected:
virtual void Parse();
private:
const descr_terrestrial_delivery *s;
};
class ServiceDescriptor : public Descriptor {
public:
int getServiceType() const;
String serviceName;
String providerName;
protected:
virtual void Parse();
private:
const descr_service *s;
};
class NVODReferenceDescriptor : public Descriptor {
public:
class Service : public LoopElement {
public:
int getTransportStream() const;
int getOriginalNetworkId() const;
int getServiceId() const;
virtual int getLength() { return sizeof(item_nvod_reference); }
protected:
virtual void Parse();
private:
const item_nvod_reference *s;
};
StructureLoop<Service> serviceLoop;
protected:
virtual void Parse();
};
class TimeShiftedServiceDescriptor : public Descriptor {
public:
int getReferenceServiceId() const;
protected:
virtual void Parse();
private:
const descr_time_shifted_service *s;
};
class ComponentDescriptor : public Descriptor {
public:
int getStreamContent() const;
int getComponentType() const;
int getComponentTag() const;
char languageCode[3];
String description;
protected:
virtual void Parse();
private:
const descr_component *s;
};
class SubtitlingDescriptor : public Descriptor {
public:
class Subtitling : public Descriptor {
public:
int getSubtitlingType() const;
int getCompositionPageId() const;
int getAncillaryPageId() const;
virtual int getLength() { return sizeof(item_nvod_reference); }
protected:
virtual void Parse();
private:
const item_subtitling *s;
};
StructureLoop<Subtitling> subtitlingLoop;
protected:
virtual void Parse();
};
class ServiceMoveDescriptor : public Descriptor {
public:
int getNewOriginalNetworkId() const;
int getNewTransportStreamId() const;
int getNewServiceId() const;
protected:
virtual void Parse();
private:
const descr_service_move *s;
};
class FrequencyListDescriptor : public Descriptor {
public:
int getCodingType() const;
TypeLoop<ThirtyTwoBit> frequencies;
protected:
virtual void Parse();
private:
const descr_frequency_list *s;
};
class ServiceIdentifierDescriptor : public Descriptor {
public:
String textualServiceIdentifier;
protected:
virtual void Parse();
};
//abstract base class
class MultilingualNameDescriptor : public Descriptor {
public:
class Name : public LoopElement {
public:
char languageCode[3];
String name;
virtual int getLength() { return sizeof(entry_multilingual_name)+name.getLength(); }
protected:
virtual void Parse();
};
StructureLoop<Name> nameLoop;
protected:
virtual void Parse();
};
class MultilingualNetworkNameDescriptor : public MultilingualNameDescriptor {
//inherits nameLoop from MultilingualNameDescriptor
};
class MultilingualBouquetNameDescriptor : public MultilingualNameDescriptor {
//inherits nameLoop from MultilingualNameDescriptor
};
class MultilingualComponentDescriptor : public MultilingualNameDescriptor {
public:
int getComponentTag() const;
//inherits nameLoop from MultilingualNameDescriptor
protected:
virtual void Parse();
private:
const descr_multilingual_component *s;
};
class MultilingualServiceNameDescriptor : public Descriptor {
public:
class Name : public MultilingualNameDescriptor::Name {
public:
virtual int getLength() { return sizeof(entry_multilingual_name)+providerName.getLength()+sizeof(entry_multilingual_service_name_mid)+name.getLength(); }
String providerName;
//inherits name, meaning: service name;
protected:
virtual void Parse();
};
StructureLoop<Name> nameLoop;
protected:
virtual void Parse();
};
//a descriptor currently unimplemented in this library
class UnimplementedDescriptor : public Descriptor {
protected:
virtual void Parse() {}
};
class ApplicationSignallingDescriptor : public Descriptor {
public:
class ApplicationEntryDescriptor : public LoopElement {
public:
virtual int getLength() { return sizeof(application_signalling_entry); }
int getApplicationType() const;
int getAITVersionNumber() const;
protected:
virtual void Parse();
private:
const application_signalling_entry *s;
};
StructureLoop<ApplicationEntryDescriptor> entryLoop;
protected:
virtual void Parse();
};
class MHP_ApplicationDescriptor : public Descriptor {
public:
class Profile : public LoopElement {
public:
virtual int getLength() { return sizeof(application_profile_entry); }
int getApplicationProfile() const;
int getVersionMajor() const;
int getVersionMinor() const;
int getVersionMicro() const;
private:
const application_profile_entry *s;
protected:
virtual void Parse();
};
StructureLoop<Profile> profileLoop;
bool isServiceBound() const;
int getVisibility() const;
int getApplicationPriority() const;
TypeLoop<EightBit> transportProtocolLabels;
private:
const descr_application_end *s;
protected:
virtual void Parse();
};
class MHP_ApplicationNameDescriptor : public Descriptor {
public:
class NameEntry : public LoopElement {
public:
virtual int getLength() { return sizeof(descr_application_name_entry)+name.getLength(); }
char languageCode[3];
String name;
protected:
virtual void Parse();
};
StructureLoop<NameEntry> nameLoop;
protected:
virtual void Parse();
};
class MHP_TransportProtocolDescriptor : public Descriptor {
public:
enum Protocol { ObjectCarousel = 0x01, IPviaDVB = 0x02, HTTPoverInteractionChannel = 0x03 };
int getProtocolId() const;
int getProtocolLabel() const;
bool isRemote() const;
int getComponentTag() const;
protected:
virtual void Parse();
private:
const descr_transport_protocol *s;
bool remote;
int componentTag;
};
class MHP_DVBJApplicationDescriptor : public Descriptor {
public:
class ApplicationEntry : public LoopElement {
public:
virtual int getLength() { return sizeof(descr_dvbj_application_entry)+parameter.getLength(); }
String parameter;
protected:
virtual void Parse();
};
StructureLoop<ApplicationEntry> applicationLoop;
protected:
virtual void Parse();
};
class MHP_DVBJApplicationLocationDescriptor : public Descriptor {
public:
String baseDirectory;
String classPath;
String initialClass;
protected:
virtual void Parse();
};
class MHP_ApplicationIconsDescriptor : public Descriptor {
public:
String iconLocator;
int getIconFlags() const;
protected:
virtual void Parse();
private:
const descr_application_icons_descriptor_end *s;
};
} //end of namespace
#endif //LIBSI_TABLE_H

83
libsi/gendescr.pl Executable file
View File

@ -0,0 +1,83 @@
#!/usr/bin/perl
# $Id: gendescr.pl 1.2 2003/12/13 10:40:53 kls Exp $
print "Name (ohne ...Descriptor):";
$name=<STDIN>;
$name =~ s/\n$//;
$inner = ($name =~ s/ä$//);
$name .= "Descriptor" unless ($inner);
print "Struct:";
$struct=<STDIN>;
$struct =~ s/\n$//;
mm:
$index=0;
$which=1;
print "Variablen:";
while ( <STDIN> ) {
if (/ä/) {
goto vv;
} elsif (/ü/) {
$which=1;
next;
}
$eingabe=$_;
$eingabe =~ s/(.{75,120} )/\1\n/g;
$eingabe =~ s/\n$//;
if ($which) {
$members[$index]=$eingabe;
} else {
$members_comments[$index]=$eingabe;
$index++;
print "Jep!\n";
}
$which= (! $which);
}
vv:
$filename_h="tempdescr.h";
$filename_c="tempdescr.c";
schreib();
sub schreib {
print "Danke.\n";
open(OUTPUT_H, ">>".$filename_h) or die "Could not open file!!";
open(OUTPUT_C, ">>".$filename_c) or die "Could not open file!!";
if ($inner) {
$offset=" ";
} else {
$offset="";
}
print(OUTPUT_H $offset."class ".$name);
if ($inner) {
print(OUTPUT_H " : public LoopElement {\n".$offset."public:");
} else {
print(OUTPUT_H " : public Descriptor {\n".$offset."public:");
}
#for ($i=0; $i<=$#vars;$i++) {
# print (OUTPUT "/*\n".$vars_comments[$i]." */\n".$vars[$i].";\n\n\n");
#}
for ($i=0; $i<=$#members;$i++) {
print (OUTPUT_H "\n".$offset." int get".$members[$i]."() const;");
}
print(OUTPUT_H "\n".$offset."virtual int getLength() { return sizeof(".$struct."); }") if ($inner);
print(OUTPUT_H "\n".$offset."protected:\n".$offset." virtual void Parse();");
print(OUTPUT_H "\n".$offset."private:\n".$offset." const ".$struct." *s;") if ($struct ne "");
print(OUTPUT_H "\n".$offset."};\n\n");
for ($i=0; $i<=$#members_comments;$i++) {
print (OUTPUT_C "int ".$name."::get".$members[$i]."() const {\n");
if ($members_comments[$i] =~ /^(.+)_hi$/) {
$varbase=$1;
print (OUTPUT_C " return HILO(s->".$varbase.");\n}\n\n");
} else {
print (OUTPUT_C " return s->".$members_comments[$i].";\n}\n\n");
}
}
print (OUTPUT_C "void ".$name."::Parse() {\n}\n\n");
print (OUTPUT_C "\n\n\n");
exit;
}

File diff suppressed because it is too large Load Diff

328
libsi/section.c Normal file
View File

@ -0,0 +1,328 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: section.c 1.2 2003/12/13 10:42:14 kls Exp $
* *
***************************************************************************/
#include "section.h"
#include <stdio.h>
namespace SI {
/*********************** PAT ***********************/
void PAT::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const pat>(s, offset);
associationLoop.setData(data+offset, getLength()-offset-4);
}
int PAT::getTransportStreamId() const {
return HILO(s->transport_stream_id);
}
int PAT::Association::getServiceId() const {
return HILO(s->program_number);
}
int PAT::Association::getPid() const {
return HILO(s->network_pid);
}
void PAT::Association::Parse() {
s=data.getData<pat_prog>();
}
/*********************** CAT ***********************/
void CAT::Parse() {
loop.setData(data+sizeof(cat), getLength()-sizeof(cat)-4);
}
/*********************** PMT ***********************/
void PMT::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const pmt>(s, offset);
commonDescriptors.setDataAndOffset(data+offset, HILO(s->program_info_length), offset);
streamLoop.setData(data+offset, getLength()-offset-4);
}
int PMT::getServiceId() const {
return HILO(s->program_number);
}
int PMT::getPCRPid() const {
return HILO(s->PCR_PID);
}
int PMT::Stream::getPid() const {
return HILO(s->elementary_PID);
}
int PMT::Stream::getStreamType() const {
return s->stream_type;
}
void PMT::Stream::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const pmt_info>(s, offset);
streamDescriptors.setData(data+offset, HILO(s->ES_info_length));
}
/*********************** NIT ***********************/
int NIT::getNetworkId() const {
return HILO(s->network_id);
}
void NIT::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const nit>(s, offset);
commonDescriptors.setDataAndOffset(data+offset, HILO(s->network_descriptor_length), offset);
const nit_mid *mid;
data.setPointerAndOffset<const nit_mid>(mid, offset);
transportStreamLoop.setData(data+offset, HILO(mid->transport_stream_loop_length));
}
int NIT::TransportStream::getTransportStreamId() const {
return HILO(s->transport_stream_id);
}
int NIT::TransportStream::getOriginalNetworkId() const {
return HILO(s->original_network_id);
}
void NIT::TransportStream::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const ni_ts>(s, offset);
transportStreamDescriptors.setData(data+offset, HILO(s->transport_descriptors_length));
}
/*********************** SDT ***********************/
void SDT::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const sdt>(s, offset);
serviceLoop.setData(data+offset, getLength()-offset-4); //4 is for CRC
}
int SDT::getTransportStreamId() const {
return HILO(s->transport_stream_id);
}
int SDT::getOriginalNetworkId() const {
return HILO(s->original_network_id);
}
int SDT::Service::getServiceId() const {
return HILO(s->service_id);
}
int SDT::Service::getEITscheduleFlag() const {
return s->eit_schedule_flag;
}
int SDT::Service::getEITpresentFollowingFlag() const {
return s->eit_present_following_flag;
}
RunningStatus SDT::Service::getRunningStatus() const {
return (RunningStatus)s->running_status;
}
int SDT::Service::getFreeCaMode() const {
return s->free_ca_mode;
}
void SDT::Service::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const sdt_descr>(s, offset);
serviceDescriptors.setData(data+offset, HILO(s->descriptors_loop_length));
}
/*********************** EIT ***********************/
int EIT::getServiceId() const {
return HILO(s->service_id);
}
int EIT::getTransportStreamId() const {
return HILO(s->transport_stream_id);
}
int EIT::getOriginalNetworkId() const {
return HILO(s->original_network_id);
}
bool EIT::isPresentFollowing() const {
return getTableId() == TableIdEIT_presentFollowing || getTableId() == TableIdEIT_presentFollowing_other;
}
bool EIT::isActualTS() const {
return
(getTableId() ==TableIdEIT_presentFollowing)
|| (TableIdEIT_schedule_first <= getTableId() && getTableId() <= TableIdEIT_schedule_last);
}
void EIT::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const eit>(s, offset);
//printf("%d %d %d %d %d\n", getServiceId(), getTransportStreamId(), getOriginalNetworkId(), isPresentFollowing(), isActualTS());
eventLoop.setData(data+offset, getLength()-offset-4); //4 is for CRC
}
time_t EIT::Event::getStartTime() const {
return DVBTime::getTime(s->mjd_hi, s->mjd_lo, s->start_time_h, s->start_time_m, s->start_time_s);
}
time_t EIT::Event::getDuration() const {
return DVBTime::getDuration(s->duration_h, s->duration_m, s->duration_s);
}
int EIT::Event::getEventId() const {
return HILO(s->event_id);
}
int EIT::Event::getMJD() const {
return HILO(s->mjd);
}
int EIT::Event::getStartTimeHour() const {
return DVBTime::bcdToDec(s->start_time_h);
}
int EIT::Event::getStartTimeMinute() const {
return DVBTime::bcdToDec(s->start_time_m);
}
int EIT::Event::getStartTimeSecond() const {
return DVBTime::bcdToDec(s->start_time_s);
}
int EIT::Event::getDurationHour() const {
return DVBTime::bcdToDec(s->duration_h);
}
int EIT::Event::getDurationMinute() const {
return DVBTime::bcdToDec(s->duration_m);
}
int EIT::Event::getDurationSecond() const {
return DVBTime::bcdToDec(s->duration_s);
}
RunningStatus EIT::Event::getRunningStatus() const {
return (RunningStatus)s->running_status;
}
int EIT::Event::getFreeCaMode() const {
return s->free_ca_mode;
}
void EIT::Event::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const eit_event>(s, offset);
//printf("%d %d %d\n", getStartTime(), getDuration(), getRunningStatus());
eventDescriptors.setData(data+offset, HILO(s->descriptors_loop_length));
}
/*********************** TDT ***********************/
time_t TDT::getTime() const {
return DVBTime::getTime(s->utc_mjd_hi, s->utc_mjd_lo, s->utc_time_h, s->utc_time_m, s->utc_time_s);
}
void TDT::Parse() {
s=data.getData<const tdt>();
}
/*********************** TOT ***********************/
time_t TOT::getTime() const {
return DVBTime::getTime(s->utc_mjd_hi, s->utc_mjd_lo, s->utc_time_h, s->utc_time_m, s->utc_time_s);
}
void TOT::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const tot>(s, offset);
descriptorLoop.setData(data+offset, getLength()-offset-4);
}
/*********************** RST ***********************/
void RST::Parse() {
unsigned int offset=0;
const rst *s;
data.setPointerAndOffset<const rst>(s, offset);
infoLoop.setData(data+offset, getLength()-offset);
}
int RST::RunningInfo::getTransportStreamId() const {
return HILO(s->transport_stream_id);
}
int RST::RunningInfo::getOriginalNetworkId() const {
return HILO(s->original_network_id);
}
int RST::RunningInfo::getServiceId() const {
return HILO(s->service_id);
}
int RST::RunningInfo::getEventId() const {
return HILO(s->event_id);
}
RunningStatus RST::RunningInfo::getRunningStatus() const {
return (RunningStatus)s->running_status;
}
void RST::RunningInfo::Parse() {
s=data.getData<const rst_info>();
}
/*********************** AIT ***********************/
int AIT::getApplicationType() const {
return HILO(first->application_type);
}
int AIT::getAITVersion() const {
return first->version_number;
}
void AIT::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const ait>(first, offset);
commonDescriptors.setDataAndOffset(data+offset, HILO(first->common_descriptors_length), offset);
const ait_mid *mid;
data.setPointerAndOffset<const ait_mid>(mid, offset);
applicationLoop.setData(data+offset, HILO(mid->application_loop_length));
}
long AIT::Application::getOrganisationId() const {
return data.FourBytes(0);
}
int AIT::Application::getApplicationId() const {
return HILO(s->application_id);
}
int AIT::Application::getControlCode() const {
return s->application_control_code;
}
void AIT::Application::Parse() {
unsigned int offset=0;
data.setPointerAndOffset<const ait_app>(s, offset);
applicationDescriptors.setData(data+offset, HILO(s->application_descriptors_length));
}
} //end of namespace

252
libsi/section.h Normal file
View File

@ -0,0 +1,252 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: section.h 1.2 2003/12/13 10:42:15 kls Exp $
* *
***************************************************************************/
#ifndef LIBSI_SECTION_H
#define LIBSI_SECTION_H
#include <time.h>
#include "si.h"
#include "headers.h"
namespace SI {
class PAT : public NumberedSection {
public:
PAT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
PAT() {}
class Association : public LoopElement {
public:
int getServiceId() const;
int getPid() const;
bool isNITPid() const { return getServiceId()==0; }
virtual int getLength() { return sizeof(pat_prog); }
protected:
virtual void Parse();
private:
const pat_prog *s;
};
int getTransportStreamId() const;
StructureLoop<Association> associationLoop;
protected:
virtual void Parse();
private:
const pat *s;
};
class CAT : public NumberedSection {
public:
CAT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
CAT() {}
DescriptorLoop loop;
protected:
virtual void Parse();
};
class PMT : public NumberedSection {
public:
PMT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
PMT() {}
class Stream : public LoopElement {
public:
int getPid() const;
int getStreamType() const;
DescriptorLoop streamDescriptors;
virtual int getLength() { return sizeof(pmt_info)+streamDescriptors.getLength(); }
protected:
virtual void Parse();
private:
const pmt_info *s;
};
DescriptorLoop commonDescriptors;
StructureLoop<Stream> streamLoop;
int getServiceId() const;
int getPCRPid() const;
protected:
virtual void Parse();
private:
const pmt *s;
};
class NIT : public NumberedSection {
public:
NIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
NIT() {}
class TransportStream : public LoopElement {
public:
int getTransportStreamId() const;
int getOriginalNetworkId() const;
virtual int getLength() { return sizeof(ni_ts)+transportStreamDescriptors.getLength(); }
DescriptorLoop transportStreamDescriptors;
protected:
virtual void Parse();
private:
const ni_ts *s;
};
DescriptorLoop commonDescriptors;
StructureLoop<TransportStream> transportStreamLoop;
int getNetworkId() const;
protected:
virtual void Parse();
private:
const nit *s;
};
//BAT has the same structure as NIT but different allowed descriptors
class BAT : public NIT {
public:
BAT(const unsigned char *data, bool doCopy=true) : NIT(data, doCopy) {}
BAT() {}
int getBouquetId() const { return getNetworkId(); }
};
class SDT : public NumberedSection {
public:
SDT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
SDT() {}
class Service : public LoopElement {
public:
int getServiceId() const;
int getEITscheduleFlag() const;
int getEITpresentFollowingFlag() const;
RunningStatus getRunningStatus() const;
int getFreeCaMode() const;
virtual int getLength() { return sizeof(sdt_descr)+serviceDescriptors.getLength(); }
DescriptorLoop serviceDescriptors;
protected:
virtual void Parse();
private:
const sdt_descr *s;
};
int getTransportStreamId() const;
int getOriginalNetworkId() const;
StructureLoop<Service> serviceLoop;
protected:
virtual void Parse();
private:
const sdt *s;
};
class EIT : public NumberedSection {
public:
EIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
EIT() {}
class Event : public LoopElement {
public:
int getEventId() const;
time_t getStartTime() const; //UTC
time_t getDuration() const;
int getMJD() const;
int getStartTimeHour() const; //UTC
int getStartTimeMinute() const; //UTC
int getStartTimeSecond() const; //UTC
int getDurationHour() const;
int getDurationMinute() const;
int getDurationSecond() const;
RunningStatus getRunningStatus() const;
int getFreeCaMode() const;
DescriptorLoop eventDescriptors;
virtual int getLength() { return sizeof(eit_event)+eventDescriptors.getLength(); }
protected:
virtual void Parse();
private:
const eit_event *s;
};
int getServiceId() const;
int getTransportStreamId() const;
int getOriginalNetworkId() const;
StructureLoop<Event> eventLoop;
//true if table conveys present/following information, false if it conveys schedule information
bool isPresentFollowing() const;
//true if table describes TS on which it is broadcast, false if it describes other TS
bool isActualTS() const;
protected:
virtual void Parse();
private:
const eit *s;
};
class TDT : public Section {
public:
TDT(const unsigned char *data, bool doCopy=true) : Section(data, doCopy) {}
TDT() {}
time_t getTime() const; //UTC
protected:
virtual void Parse();
private:
const tdt *s;
};
class TOT : public CRCSection {
public:
TOT(const unsigned char *data, bool doCopy=true) : CRCSection(data, doCopy) {}
TOT() {}
time_t getTime() const;
DescriptorLoop descriptorLoop;
protected:
virtual void Parse();
private:
const tot *s;
};
class RST : public Section {
public:
RST(const unsigned char *data, bool doCopy=true) : Section(data, doCopy) {}
RST() {}
class RunningInfo : public LoopElement {
public:
int getTransportStreamId() const;
int getOriginalNetworkId() const;
int getServiceId() const;
int getEventId() const;
RunningStatus getRunningStatus() const;
virtual int getLength() { return sizeof(rst_info); }
protected:
virtual void Parse();
private:
const rst_info *s;
};
StructureLoop<RunningInfo> infoLoop;
protected:
virtual void Parse();
};
class AIT : public NumberedSection {
public:
AIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
AIT() {}
class Application : public LoopElement {
public:
virtual int getLength() { return sizeof(ait_app)+applicationDescriptors.getLength(); }
long getOrganisationId() const;
int getApplicationId() const;
int getControlCode() const;
MHP_DescriptorLoop applicationDescriptors;
protected:
virtual void Parse();
const ait_app *s;
};
MHP_DescriptorLoop commonDescriptors;
StructureLoop<Application> applicationLoop;
int getApplicationType() const;
int getAITVersion() const;
protected:
const ait *first;
virtual void Parse();
};
} //end of namespace
#endif //LIBSI_TABLE_H

415
libsi/si.c Normal file
View File

@ -0,0 +1,415 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: si.c 1.3 2004/01/04 14:26:53 kls Exp $
* *
***************************************************************************/
#include <string.h>
#include "si.h"
#include "descriptor.h"
namespace SI {
Object::Object() {
}
Object::Object(CharArray &d) : data(d) {
}
void Object::setData(const unsigned char*d, unsigned int size, bool doCopy) {
data.assign(d, size, doCopy);
}
void Object::setData(CharArray &d) {
data=d;
}
Section::Section(const unsigned char *data, bool doCopy) {
setData(data, getLength(data), doCopy);
}
TableId Section::getTableId() const {
return getTableId(data.getData());
}
int Section::getLength() {
return getLength(data.getData());
}
TableId Section::getTableId(const unsigned char *d) {
return (TableId)((const SectionHeader *)d)->table_id;
}
int Section::getLength(const unsigned char *d) {
return HILO(((const SectionHeader *)d)->section_length)+sizeof(SectionHeader);
}
bool CRCSection::isValid() {
return CRC32::isValid((const char *)data.getData(), getLength()/*, data.FourBytes(getLength()-4)*/);
}
bool CRCSection::CheckCRCAndParse() {
if (!isValid())
return false;
CheckParse();
return true;
}
bool NumberedSection::getCurrentNextIndicator() const {
return data.getData<ExtendedSectionHeader>()->current_next_indicator;
}
int NumberedSection::getVersionNumber() const {
return data.getData<ExtendedSectionHeader>()->version_number;
}
int NumberedSection::getSectionNumber() const {
return data.getData<ExtendedSectionHeader>()->section_number;
}
int NumberedSection::getLastSectionNumber() const {
return data.getData<ExtendedSectionHeader>()->last_section_number;
}
int Descriptor::getLength() {
return getLength(data.getData());
}
DescriptorTag Descriptor::getDescriptorTag() const {
return getDescriptorTag(data.getData());
}
int Descriptor::getLength(const unsigned char *d) {
return ((const DescriptorHeader*)d)->descriptor_length+sizeof(DescriptorHeader);
}
DescriptorTag Descriptor::getDescriptorTag(const unsigned char *d) {
return (DescriptorTag)((const DescriptorHeader*)d)->descriptor_tag;
}
Descriptor *DescriptorLoop::getNext(Iterator &it) {
if (it.i<getLength()) {
return createDescriptor(it.i);
}
return 0;
}
Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor) {
Descriptor *d=0;
if (it.i<getLength()) {
const unsigned char *p=data.getData(it.i);
const unsigned char *end=p+getLength();
while (p < end) {
if (Descriptor::getDescriptorTag(p) == tag) {
d=createDescriptor(it.i);
break;
}
it.i+=Descriptor::getLength(p);
p+=Descriptor::getLength(p);
}
}
if (d && d->getDescriptorTag()==UnimplementedDescriptorTag)
return returnUnimplemetedDescriptor ? d : 0;
return d;
}
Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor) {
Descriptor *d=0;
if (it.i<getLength()) {
const unsigned char *p=data.getData(it.i);
const unsigned char *end=p+getLength();
while (p < end) {
for (int u=0; u<arrayLength;u++)
if (Descriptor::getDescriptorTag(p) == tags[u]) {
d=createDescriptor(it.i);
break;
}
if (d)
break;
it.i+=Descriptor::getLength(p);
p+=Descriptor::getLength(p);
}
}
if (d && d->getDescriptorTag()==UnimplementedDescriptorTag)
return returnUnimplemetedDescriptor ? d : 0;
return d;
}
Descriptor *DescriptorLoop::createDescriptor(int &i) {
Descriptor *d=Descriptor::getDescriptor(data+i, domain);
i+=d->getLength();
d->CheckParse();
return d;
}
DescriptorGroup::DescriptorGroup(bool del) {
array=0;
length=0;
deleteOnDesctruction=del;
}
DescriptorGroup::~DescriptorGroup() {
if (deleteOnDesctruction)
Delete();
delete[] array;
}
void DescriptorGroup::Delete() {
for (int i=0;i<length;i++)
if (array[i]!=0) {
delete array[i];
array[i]=0;
}
}
void DescriptorGroup::Add(GroupDescriptor *d) {
if (!array) {
length=d->getLastDescriptorNumber()+1;
array=new GroupDescriptor*[length]; //numbering is zero-based
for (int i=0;i<length;i++)
array[i]=0;
} else if (length != d->getLastDescriptorNumber()+1)
return; //avoid crash in case of misuse
array[d->getDescriptorNumber()]=d;
}
bool DescriptorGroup::isComplete() {
for (int i=0;i<length;i++)
if (array[i]==0)
return false;
return true;
}
char *String::getText() {
if (getLength() < 0 || getLength() >4095)
return "text error";
char *data=new char(getLength()+1);
decodeText(data);
return data;
}
char *String::getText(char *buffer) {
if (getLength() < 0 || getLength() >4095) {
strncpy(buffer, "text error", getLength()+1);
return buffer;
}
decodeText(buffer);
return buffer;
}
//taken from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de>
void String::decodeText(char *buffer) {
const unsigned char *from=data.getData(0);
char *to=buffer;
/* Disable detection of coding tables - libdtv doesn't do it either
if ( (0x01 <= *from) && (*from <= 0x1f) ) {
codeTable=*from
}
*/
for (int i = 0; i < getLength(); i++) {
if (*from == 0)
break;
if ( ((' ' <= *from) && (*from <= '~'))
|| (*from == '\n')
|| ((0xA0 <= *from) && (*from <= 0xFF))
)
*to++ = *from;
else if (*from == 0x8A)
*to++ = '\n';
else if (*from == 0x86 || *from == 0x87) //&& !(GDT_NAME_DESCRIPTOR & type))
*to++ = *from;
from++;
}
*to = '\0';
}
Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain) {
Descriptor *d=0;
switch (domain) {
case SI:
switch ((DescriptorTag)da.getData<DescriptorHeader>()->descriptor_tag) {
case CaDescriptorTag:
d=new CaDescriptor();
break;
case CarouselIdentifierDescriptorTag:
d=new CarouselIdentifierDescriptor();
break;
case NetworkNameDescriptorTag:
d=new NetworkNameDescriptor();
break;
case ServiceListDescriptorTag:
d=new ServiceListDescriptor();
break;
case SatelliteDeliverySystemDescriptorTag:
d=new SatelliteDeliverySystemDescriptor();
break;
case CableDeliverySystemDescriptorTag:
d=new CableDeliverySystemDescriptor();
break;
case TerrestrialDeliverySystemDescriptorTag:
d=new TerrestrialDeliverySystemDescriptor();
break;
case BouquetNameDescriptorTag:
d=new BouquetNameDescriptor();
break;
case ServiceDescriptorTag:
d=new ServiceDescriptor();
break;
case NVODReferenceDescriptorTag:
d=new NVODReferenceDescriptor();
break;
case TimeShiftedServiceDescriptorTag:
d=new TimeShiftedServiceDescriptor();
break;
case ComponentDescriptorTag:
d=new ComponentDescriptor();
break;
case StreamIdentifierDescriptorTag:
d=new StreamIdentifierDescriptor();
break;
case SubtitlingDescriptorTag:
d=new SubtitlingDescriptor();
break;
case MultilingualNetworkNameDescriptorTag:
d=new MultilingualNetworkNameDescriptor();
break;
case MultilingualBouquetNameDescriptorTag:
d=new MultilingualBouquetNameDescriptor();
break;
case MultilingualServiceNameDescriptorTag:
d=new MultilingualServiceNameDescriptor();
break;
case MultilingualComponentDescriptorTag:
d=new MultilingualComponentDescriptor();
break;
case ServiceMoveDescriptorTag:
d=new ServiceMoveDescriptor();
break;
case FrequencyListDescriptorTag:
d=new FrequencyListDescriptor();
break;
case ServiceIdentifierDescriptorTag:
d=new ServiceIdentifierDescriptor();
break;
case CaIdentifierDescriptorTag:
d=new CaIdentifierDescriptor();
break;
case ShortEventDescriptorTag:
d=new ShortEventDescriptor();
break;
case ExtendedEventDescriptorTag:
d=new ExtendedEventDescriptor();
break;
case TimeShiftedEventDescriptorTag:
d=new TimeShiftedEventDescriptor();
break;
case ContentDescriptorTag:
d=new ContentDescriptor();
break;
case ParentalRatingDescriptorTag:
d=new ParentalRatingDescriptor();
break;
case ApplicationSignallingDescriptorTag:
d=new ApplicationSignallingDescriptor();
break;
//note that it is no problem to implement one
//of the unimplemented descriptors.
//defined in ISO-13818-1
case VideoStreamDescriptorTag:
case AudioStreamDescriptorTag:
case HierarchyDescriptorTag:
case RegistrationDescriptorTag:
case DataStreamAlignmentDescriptorTag:
case TargetBackgroundGridDescriptorTag:
case VideoWindowDescriptorTag:
case ISO639LanguageDescriptorTag:
case SystemClockDescriptorTag:
case MultiplexBufferUtilizationDescriptorTag:
case CopyrightDescriptorTag:
case MaximumBitrateDescriptorTag:
case PrivateDataIndicatorDescriptorTag:
case SmoothingBufferDescriptorTag:
case STDDescriptorTag:
case IBPDescriptorTag:
//defined in ETSI EN 300 468
case StuffingDescriptorTag:
case VBIDataDescriptorTag:
case VBITeletextDescriptorTag:
case CountryAvailabilityDescriptorTag:
case MocaicDescriptorTag:
case LinkageDescriptorTag:
case TeletextDescriptorTag:
case TelephoneDescriptorTag:
case LocalTimeOffsetDescriptorTag:
case PrivateDataSpecifierDescriptorTag:
case CellListDescriptorTag:
case CellFrequencyLinkDescriptorTag:
case ServiceAvailabilityDescriptorTag:
case ShortSmoothingBufferDescriptorTag:
case PartialTransportStreamDescriptorTag:
case DataBroadcastDescriptorTag:
case DataBroadcastIdDescriptorTag:
case CaSystemDescriptorTag:
case AC3DescriptorTag:
case DSNGDescriptorTag:
case PDCDescriptorTag:
case AncillaryDataDescriptorTag:
case AnnouncementSupportDescriptorTag:
case AdaptationFieldDataDescriptorTag:
case TransportStreamDescriptorTag:
default:
d=new UnimplementedDescriptor();
break;
}
break;
case MHP:
switch ((DescriptorTag)da.getData<DescriptorHeader>()->descriptor_tag) {
// They once again start with 0x00 (see page 234, MHP specification)
case MHP_ApplicationDescriptorTag:
d=new MHP_ApplicationDescriptor();
break;
case MHP_ApplicationNameDescriptorTag:
d=new MHP_ApplicationNameDescriptor();
break;
case MHP_TransportProtocolDescriptorTag:
d=new MHP_TransportProtocolDescriptor();
break;
case MHP_DVBJApplicationDescriptorTag:
d=new MHP_DVBJApplicationDescriptor();
break;
case MHP_DVBJApplicationLocationDescriptorTag:
d=new MHP_DVBJApplicationLocationDescriptor();
break;
// 0x05 - 0x0A is unimplemented this library
case MHP_ExternalApplicationAuthorisationDescriptorTag:
case MHP_IPv4RoutingDescriptorTag:
case MHP_IPv6RoutingDescriptorTag:
case MHP_DVBHTMLApplicationDescriptorTag:
case MHP_DVBHTMLApplicationLocationDescriptorTag:
case MHP_DVBHTMLApplicationBoundaryDescriptorTag:
case MHP_ApplicationIconsDescriptorTag:
case MHP_PrefetchDescriptorTag:
case MHP_DelegatedApplicationDescriptorTag:
case MHP_ApplicationStorageDescriptorTag:
default:
d=new UnimplementedDescriptor();
break;
}
break;
}
d->setData(da);
return d;
}
} //end of namespace

392
libsi/si.h Normal file
View File

@ -0,0 +1,392 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: si.h 1.3 2003/12/26 14:09:30 kls Exp $
* *
***************************************************************************/
#ifndef LIBSI_SI_H
#define LIBSI_SI_H
#include <stdint.h>
#include "util.h"
#include "headers.h"
namespace SI {
enum TableId { TableIdPAT = 0x00, //program association section
TableIdCAT = 0x01, //conditional access section
TableIdPMT = 0x02, //program map section
TableIdTSDT = 0x03,//transport stream description section
TableIdNIT = 0x40, //network information, actual network section
TableIdNIT_other = 0x41, //network information section, other network
TableIdSDT = 0x42, //service description section
TableIdSDT_other = 0x46,
TableIdBAT = 0x46, //bouquet association section
TableIdEIT_presentFollowing = 0x4E, //event information section
TableIdEIT_presentFollowing_other = 0x4F,
//range from 0x50 to 0x5F
TableIdEIT_schedule_first = 0x50,
TableIdEIT_schedule_last = 0x5F,
//range from 0x60 to 0x6F
TableIdEIT_schedule_Other_first = 0x60,
TableIdEIT_schedule_Other_fast = 0x6F,
TableIdTDT = 0x70, //time date section
TableIdRST = 0x71, //running status section
TableIdST = 0x72, //stuffing section
TableIdTOT = 0x73, //time offset section
TableIdDIT = 0x7E, //discontinuity information section
TableIdSIT = 0x7F, //service information section
TableIdAIT = 0x74 //application information section
};
enum DescriptorTag {
// defined by ISO/IEC 13818-1
VideoStreamDescriptorTag = 0x02,
AudioStreamDescriptorTag = 0x03,
HierarchyDescriptorTag = 0x04,
RegistrationDescriptorTag = 0x05,
DataStreamAlignmentDescriptorTag = 0x06,
TargetBackgroundGridDescriptorTag = 0x07,
VideoWindowDescriptorTag = 0x08,
CaDescriptorTag = 0x09,
ISO639LanguageDescriptorTag = 0x0A,
SystemClockDescriptorTag = 0x0B,
MultiplexBufferUtilizationDescriptorTag = 0x0C,
CopyrightDescriptorTag = 0x0D,
MaximumBitrateDescriptorTag = 0x0E,
PrivateDataIndicatorDescriptorTag = 0x0F,
SmoothingBufferDescriptorTag = 0x10,
STDDescriptorTag = 0x11,
IBPDescriptorTag = 0x12,
// defined by ISO-13818-6 (DSM-CC)
CarouselIdentifierDescriptorTag = 0x13,
// 0x14 - 0x3F Reserved
// defined by ETSI (EN 300 468)
NetworkNameDescriptorTag = 0x40,
ServiceListDescriptorTag = 0x41,
StuffingDescriptorTag = 0x42,
SatelliteDeliverySystemDescriptorTag = 0x43,
CableDeliverySystemDescriptorTag = 0x44,
VBIDataDescriptorTag = 0x45,
VBITeletextDescriptorTag = 0x46,
BouquetNameDescriptorTag = 0x47,
ServiceDescriptorTag = 0x48,
CountryAvailabilityDescriptorTag = 0x49,
LinkageDescriptorTag = 0x4A,
NVODReferenceDescriptorTag = 0x4B,
TimeShiftedServiceDescriptorTag = 0x4C,
ShortEventDescriptorTag = 0x4D,
ExtendedEventDescriptorTag = 0x4E,
TimeShiftedEventDescriptorTag = 0x4F,
ComponentDescriptorTag = 0x50,
MocaicDescriptorTag = 0x51,
StreamIdentifierDescriptorTag = 0x52,
CaIdentifierDescriptorTag = 0x53,
ContentDescriptorTag = 0x54,
ParentalRatingDescriptorTag = 0x55,
TeletextDescriptorTag = 0x56,
TelephoneDescriptorTag = 0x57,
LocalTimeOffsetDescriptorTag = 0x58,
SubtitlingDescriptorTag = 0x59,
TerrestrialDeliverySystemDescriptorTag = 0x5A,
MultilingualNetworkNameDescriptorTag = 0x5B,
MultilingualBouquetNameDescriptorTag = 0x5C,
MultilingualServiceNameDescriptorTag = 0x5D,
MultilingualComponentDescriptorTag = 0x5E,
PrivateDataSpecifierDescriptorTag = 0x5F,
ServiceMoveDescriptorTag = 0x60,
ShortSmoothingBufferDescriptorTag = 0x61,
FrequencyListDescriptorTag = 0x62,
PartialTransportStreamDescriptorTag = 0x63,
DataBroadcastDescriptorTag = 0x64,
CaSystemDescriptorTag = 0x65,
DataBroadcastIdDescriptorTag = 0x66,
TransportStreamDescriptorTag = 0x67,
DSNGDescriptorTag = 0x68,
PDCDescriptorTag = 0x69,
AC3DescriptorTag = 0x6A,
AncillaryDataDescriptorTag = 0x6B,
CellListDescriptorTag = 0x6C,
CellFrequencyLinkDescriptorTag = 0x6D,
AnnouncementSupportDescriptorTag = 0x6E,
ApplicationSignallingDescriptorTag = 0x6F,
AdaptationFieldDataDescriptorTag = 0x70,
ServiceIdentifierDescriptorTag = 0x71,
ServiceAvailabilityDescriptorTag = 0x72,
// Defined by ETSI TS 102 812 (MHP)
// They once again start with 0x00 (see page 234, MHP specification)
MHP_ApplicationDescriptorTag = 0x00,
MHP_ApplicationNameDescriptorTag = 0x01,
MHP_TransportProtocolDescriptorTag = 0x02,
MHP_DVBJApplicationDescriptorTag = 0x03,
MHP_DVBJApplicationLocationDescriptorTag = 0x04,
// 0x05 - 0x0A is unimplemented this library
MHP_ExternalApplicationAuthorisationDescriptorTag = 0x05,
MHP_IPv4RoutingDescriptorTag = 0x06,
MHP_IPv6RoutingDescriptorTag = 0x07,
MHP_DVBHTMLApplicationDescriptorTag = 0x08,
MHP_DVBHTMLApplicationLocationDescriptorTag = 0x09,
MHP_DVBHTMLApplicationBoundaryDescriptorTag = 0x0A,
MHP_ApplicationIconsDescriptorTag = 0x0B,
MHP_PrefetchDescriptorTag = 0x0C,
MHP_DelegatedApplicationDescriptorTag = 0x0E,
MHP_ApplicationStorageDescriptorTag = 0x10,
//a descriptor currently unimplemented in this library
//the actual value 0xFF is "forbidden" according to the spec.
UnimplementedDescriptorTag = 0xFF
};
enum DescriptorTagDomain { SI, MHP };
enum RunningStatus { RunningStatusUndefined = 0,
RunningStatusNotRunning = 1,
RunningStatusStartsInAFewSeconds = 2,
RunningStatusPausing = 3,
RunningStatusRunning = 4
};
/* Some principles:
- Objects that return references to other objects contained in their data must make sure
that the returned objects have been parsed.
(the Loop subclasses take care of that.)
Note that this does not apply to Loops and Strings (their are never returned by reference, BTW).
*/
class Object : public Parsable {
public:
Object();
Object(CharArray &d);
//can only be called once since data is immutable
void setData(const unsigned char*data, unsigned int size, bool doCopy=true);
virtual int getLength() = 0;
protected:
CharArray data;
//is protected - not used for sections
template <class T> friend class StructureLoop;
void setData(CharArray &d);
};
class Section : public Object {
public:
//convenience: sets data and parses if doParse
Section(const unsigned char *data, bool doCopy=true);
Section() {}
TableId getTableId() const;
virtual int getLength();
static int getLength(const unsigned char *d);
static TableId getTableId(const unsigned char *d);
};
class CRCSection : public Section {
public:
//convenience: sets data and parses if doParse
CRCSection(const unsigned char *data, bool doCopy=true) : Section(data, doCopy) {}
CRCSection() {}
bool isValid();
//convenience: isValid+CheckParse
bool CheckCRCAndParse();
};
/* A section which has the ExtendedSectionHeader
(section_syntax_indicator==1) */
class NumberedSection : public CRCSection {
public:
NumberedSection(const unsigned char *data, bool doCopy=true) : CRCSection(data, doCopy) {}
NumberedSection() {}
bool getCurrentNextIndicator() const;
int getVersionNumber() const;
int getSectionNumber() const;
int getLastSectionNumber() const;
bool moreThanOneSection() const { return getLastSectionNumber()>1; }
};
class VariableLengthPart : public Object {
public:
//never forget to call this
void setData(CharArray d, int l) { Object::setData(d); length=l; }
//convenience method
void setDataAndOffset(CharArray d, int l, unsigned int &offset) { Object::setData(d); length=l; offset+=l; }
virtual int getLength() { return length; }
private:
int length;
};
class LoopElement : public Object {
};
class SubStructure : public LoopElement {
};
class Descriptor : public LoopElement {
public:
virtual int getLength();
DescriptorTag getDescriptorTag() const;
static int getLength(const unsigned char *d);
static DescriptorTag getDescriptorTag(const unsigned char *d);
protected:
friend class DescriptorLoop;
//returns a subclass of descriptor according to the data given.
//The object is allocated with new and must be delete'd.
//setData() will have been called, CheckParse() not.
//Never returns null - maybe the UnimplementedDescriptor.
static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain);
};
class Loop : public VariableLengthPart {
public:
class Iterator {
public:
Iterator() { i=0; }
void reset() { i=0; }
private:
template <class T> friend class StructureLoop;
friend class DescriptorLoop;
template <class T> friend class TypeLoop;
int i;
};
protected:
virtual void Parse() {}
};
//contains LoopElements of one type only
template <class T> class StructureLoop : public Loop {
public:
//currently you must use a while-loop testing for hasNext()
//i must be 0 to get the first descriptor (with the first call)
T getNext(Iterator &it)
{
CharArray d=data;
d.addOffset(it.i);
T ret;
ret.setData(d);
ret.CheckParse();
it.i+=ret.getLength();
return ret;
}
T* getNextAsPointer(Iterator &it)
{
if (getLength() <= it.i)
return 0;
CharArray d=data;
d.addOffset(it.i);
T *ret=new T();
ret->setData(d);
ret->CheckParse();
it.i+=ret->getLength();
return ret;
}
bool hasNext(Iterator &it) { return getLength() > it.i; }
};
//contains descriptors of different types
class DescriptorLoop : public Loop {
public:
DescriptorLoop() { domain=SI; }
//i must be 0 to get the first descriptor (with the first call)
//All returned descriptors must be delete'd.
//returns null if no more descriptors available
Descriptor *getNext(Iterator &it);
//return the next descriptor with given tag, or 0 if not available.
//if the descriptor found is not implemented,
// an UnimplementedDescriptor will be returned if returnUnimplemetedDescriptor==true,
// 0 will be returned if returnUnimplemetedDescriptor==false
Descriptor *getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor=false);
//return the next descriptor with one of the given tags, or 0 if not available.
Descriptor *getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor=false);
protected:
Descriptor *createDescriptor(int &i);
DescriptorTagDomain domain;
};
typedef uint8_t EightBit;
typedef uint16_t SixteenBit;
typedef uint32_t ThirtyTwoBit;
typedef uint64_t SixtyFourBit;
template <typename T> class TypeLoop : public Loop {
public:
int getCount() const { return getLength()/sizeof(T); }
T operator[](const unsigned int index) const
{
switch (sizeof(T)) {
case 1:
return data[index];
case 2:
return data.TwoBytes(index);
case 4:
return data.FourBytes(index);
case 8:
return (SixtyFourBit(data.FourBytes(index)) << 32) | data.FourBytes(index+4);
}
}
T getNext(Iterator &it) const
{
T ret=operator[](it.i);
it.i+=sizeof(T);
return ret;
}
bool hasNext(Iterator &it) { return getLength() > it.i; }
};
class MHP_DescriptorLoop : public DescriptorLoop {
public:
MHP_DescriptorLoop() { domain=MHP; }
};
//The content of the ExtendedEventDescriptor may be split over several
//descriptors if the text is longer than 256 bytes.
//The following classes provide base functionality to handle this case.
class GroupDescriptor : public Descriptor {
public:
virtual int getDescriptorNumber() = 0;
virtual int getLastDescriptorNumber() = 0;
};
class DescriptorGroup {
public:
DescriptorGroup(bool deleteOnDesctruction=true);
~DescriptorGroup();
void Add(GroupDescriptor *d);
void Delete();
int getLength() { return length; }
GroupDescriptor **getDescriptors() { return array; }
bool isComplete(); //if all descriptors have been added
protected:
int length;
GroupDescriptor **array;
bool deleteOnDesctruction;
};
class String : public VariableLengthPart {
public:
//A note to the length: getLength() returns the length of the raw data.
//The text may be shorter. Its length can be obtained with one of the
//above functions and strlen.
//returns text. Data is allocated with new and must be delete'd by the user.
char *getText();
//copies text into given buffer.
//a buffer of size getLength()+1 is guaranteed to be sufficiently large.
//In most descriptors the string length is an 8-bit field,
//so the maximum there is 256.
//returns the given buffer for convenience.
char * getText(char *buffer);
protected:
virtual void Parse() {}
void decodeText(char *buffer);
};
} //end of namespace
#endif //LIBSI_SI_H

281
libsi/util.c Normal file
View File

@ -0,0 +1,281 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg, Rolf Hakenes *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: util.c 1.3 2003/12/22 14:03:03 kls Exp $
* *
***************************************************************************/
#include <string.h>
#include "util.h"
namespace SI {
/*---------------------------- CharArray ----------------------------*/
CharArray::CharArray() : data_(0), off(0) {
}
CharArray::~CharArray() {
if (!data_)
return;
if (--data_->count_ == 0)
delete data_;
}
CharArray::CharArray(const CharArray &f) : data_(f.data_), off(f.off) {
if (data_)
++ data_->count_;
}
CharArray& CharArray::operator=(const CharArray &f) {
// DO NOT CHANGE THE ORDER OF THESE STATEMENTS!
// (This order properly handles self-assignment)
if (f.data_) {
++ f.data_->count_;
}
if (data_) {
if (--data_->count_ == 0)
delete data_;
}
data_ = f.data_;
off = f.off;
return *this;
}
void CharArray::assign(const unsigned char*data, unsigned int size, bool doCopy) {
//immutable
if (!data_)
data_= doCopy ? (Data*)new DataOwnData() : (Data*)new DataForeignData();
// This method might need to change things in *data_
// Thus it first checks if this is the only pointer to *data_
if (data_->count_ > 1) {
Data* d = doCopy ? (Data*)new DataOwnData() : (Data*)new DataForeignData();
-- data_->count_;
data_ = d;
}
data_->assign(data, size);
}
bool CharArray::operator==(const char *string) const {
//here we can use strcmp, string is null-terminated.
if (!data_)
return false;
return data_->size ? (!strcmp((const char*)data_->data, string)) : string[0]==0;
}
bool CharArray::operator==(const CharArray &other) const {
if (!data_ || !other.data_)
return !(data_ || other.data_); //true if both empty
if (data_->size != other.data_->size)
return false;
//do _not_ use strcmp! Data is not necessarily null-terminated.
for (unsigned int i=0;i<data_->size;i++)
if (data_->data[i] != other.data_->data[i])
return false;
return true;
}
CharArray CharArray::operator+(const unsigned int offset) const {
CharArray f(*this);
f.off+=offset;
return f;
}
CharArray::Data::Data() : count_(1) {
size=0;
data=0;
/*
lockingPid = 0;
locked = 0;
pthread_mutex_init(&mutex, NULL);
*/
}
CharArray::Data::~Data() {
/*
if (locked)
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
*/
}
/*CharArray::Data::Data(const Data& d) : count_(1) {
size=0;
data=0;
lockingPid = 0;
locked = 0;
pthread_mutex_init(&mutex, NULL);
}*/
CharArray::DataOwnData::~DataOwnData() {
Delete();
}
void CharArray::DataOwnData::assign(const unsigned char*d, unsigned int s) {
Delete();
size=s;
unsigned char *newdata=new unsigned char[size];
memcpy(newdata, d, size);
data=newdata;
}
void CharArray::DataOwnData::Delete() {
delete[] data;
}
CharArray::DataForeignData::~DataForeignData() {
Delete();
}
void CharArray::DataForeignData::assign(const unsigned char*d, unsigned int s) {
size=s;
data=d;
}
void CharArray::DataForeignData::Delete() {
//do not delete!
}
/*
void CharArray::Data::assign(unsigned int s) {
if (data)
delete[] data;
size=s;
if (size) { //new assignment may be zero length
data=new unsigned char[size];
memset(data, 0, size);
}
}
void CharArray::Data::Lock(void)
{
if ( !pthread_equal(pthread_self(), lockingPid) || !locked) {
pthread_mutex_lock(&mutex);
lockingPid = pthread_self();
}
locked++;
}
void CharArray::Data::Unlock(void)
{
if (!--locked) {
lockingPid = 0;
pthread_mutex_unlock(&mutex);
}
}
*/
Parsable::Parsable() {
parsed=false;
}
void Parsable::CheckParse() {
if (!parsed) {
parsed=true;
Parse();
}
}
//taken and adapted from libdtv, (c) Rolf Hakenes and VDR, (c) Klaus Schmidinger
time_t DVBTime::getTime(unsigned char date_hi, unsigned char date_lo, unsigned char time_hour, unsigned char time_minute, unsigned char time_second) {
u_int16_t mjd = date_hi << 8 | date_lo;
struct tm t;
t.tm_sec = bcdToDec(time_second);
t.tm_min = bcdToDec(time_minute);
t.tm_hour = bcdToDec(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;
return timegm(&t);
}
time_t DVBTime::getDuration(unsigned char time_hour, unsigned char time_minute, unsigned char time_second) {
return
bcdToDec(time_second)
+ bcdToDec(time_minute) * 60
+ bcdToDec(time_hour) *3600;
}
//taken and adapted from libdtv, (c) Rolf Hakenes
// CRC32 lookup table for polynomial 0x04c11db7
u_int32_t CRC32::crc_table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
u_int32_t CRC32::crc32 (const char *d, int len, u_int32_t crc)
{
register int i;
for (i=0; i<len; i++)
crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *d++) & 0xff];
return crc;
}
CRC32::CRC32(const char *d, int len, u_int32_t CRCvalue) {
data=d;
length=len;
value=CRCvalue;
}
} //end of namespace

157
libsi/util.h Normal file
View File

@ -0,0 +1,157 @@
/***************************************************************************
* Copyright (c) 2003 by Marcel Wiesweg *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: util.h 1.3 2003/12/22 14:07:41 kls Exp $
* *
***************************************************************************/
#ifndef LIBSI_UTIL_H
#define LIBSI_UTIL_H
#include <stdint.h>
#include <sys/types.h>
#include <pthread.h>
#include <time.h>
#define HILO(x) (x##_hi << 8 | x##_lo)
#define BCD_TIME_TO_SECONDS(x) ((3600 * ((10*((x##_h & 0xF0)>>4)) + (x##_h & 0xF))) + \
(60 * ((10*((x##_m & 0xF0)>>4)) + (x##_m & 0xF))) + \
((10*((x##_s & 0xF0)>>4)) + (x##_s & 0xF)))
namespace SI {
//Holds an array of unsigned char which is deleted
//when the last object pointing to it is deleted.
//Optimized for use in libsi.
class CharArray {
public:
CharArray();
CharArray(const CharArray &source);
CharArray& operator=(const CharArray &source);
~CharArray();
//can be called exactly once
void assign(const unsigned char*data, unsigned int size, bool doCopy=true);
//compares to a null-terminated string
bool operator==(const char *string) const;
//compares to another CharArray (data not necessarily null-terminated)
bool operator==(const CharArray &other) const;
//returns another CharArray with its offset incremented by offset
CharArray operator+(const unsigned int offset) const;
//access and convenience methods
const unsigned char* getData() const { return data_->data+off; }
const unsigned char* getData(int offset) const { return data_->data+offset+off; }
template <typename T> const T* getData() const { return (T*)(data_->data+off); }
template <typename T> const T* getData(int offset) const { return (T*)(data_->data+offset+off); }
//sets p to point to data+offset, increments offset
template <typename T> void setPointerAndOffset(const T* &p, unsigned int &offset) const { p=(T*)getData(offset); offset+=sizeof(T); }
unsigned char operator[](const unsigned int index) const { return data_->data ? data_->data[off+index] : 0; }
int getLength() const { return data_->size; }
u_int16_t TwoBytes(const unsigned int index) const { return data_->data ? data_->TwoBytes(off+index) : 0; }
u_int32_t FourBytes(const unsigned int index) const { return data_->data ? data_->FourBytes(off+index) : 0; }
void addOffset(unsigned int offset) { off+=offset; }
private:
class Data {
public:
Data();
virtual ~Data();
virtual void assign(const unsigned char*data, unsigned int size) = 0;
virtual void Delete() = 0;
u_int16_t TwoBytes(const unsigned int index) const
{ return (data[index] << 8) | data[index+1]; }
u_int32_t FourBytes(const unsigned int index) const
{ return (data[index] << 24) | (data[index+1] << 16) | (data[index+2] << 8) | data[index+3]; }
/*#ifdef CHARARRAY_THREADSAFE
void Lock();
void Unlock();
#else
void Lock() {}
void Unlock() {}
#endif
Data(const Data& d);
void assign(unsigned int size);
*/
const unsigned char*data;
unsigned int size;
unsigned count_;
// count_ is the number of CharArray objects that point at this
// count_ must be initialized to 1 by all constructors
// (it starts as 1 since it is pointed to by the CharArray object that created it)
/*
pthread_mutex_t mutex;
pid_t lockingPid;
pthread_t locked;
*/
};
class DataOwnData : public Data {
public:
DataOwnData() {}
virtual ~DataOwnData();
virtual void assign(const unsigned char*data, unsigned int size);
virtual void Delete();
};
class DataForeignData : public Data {
public:
DataForeignData() {}
virtual ~DataForeignData();
virtual void assign(const unsigned char*data, unsigned int size);
virtual void Delete();
};
Data* data_;
unsigned int off;
};
//abstract base class
class Parsable {
public:
void CheckParse();
protected:
Parsable();
virtual ~Parsable() {}
//actually parses given data.
virtual void Parse() = 0;
private:
bool parsed;
};
//taken and adapted from libdtv, (c) Rolf Hakenes and VDR, (c) Klaus Schmidinger
namespace DVBTime {
time_t getTime(unsigned char date_hi, unsigned char date_lo, unsigned char timehr, unsigned char timemi, unsigned char timese);
time_t getDuration(unsigned char timehr, unsigned char timemi, unsigned char timese);
inline unsigned char bcdToDec(unsigned char b) { return ((b >> 4) & 0x0F) * 10 + (b & 0x0F); }
};
//taken and adapted from libdtv, (c) Rolf Hakenes
class CRC32 {
public:
CRC32(const char *d, int len, u_int32_t CRCvalue=0xFFFFFFFF);
bool isValid() { return crc32(data, length, value) == 0; }
static bool isValid(const char *d, int len, u_int32_t CRCvalue=0xFFFFFFFF) { return crc32(d, len, CRCvalue) == 0; }
protected:
static u_int32_t crc_table[256];
static u_int32_t crc32 (const char *d, int len, u_int32_t CRCvalue);
const char *data;
int length;
u_int32_t value;
};
} //end of namespace
#endif

5
lirc.c
View File

@ -6,7 +6,7 @@
*
* LIRC support added by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16.
*
* $Id: lirc.c 1.6 2003/04/27 11:39:47 kls Exp $
* $Id: lirc.c 1.7 2003/10/18 11:34:02 kls Exp $
*/
#include "lirc.h"
@ -20,6 +20,7 @@
cLircRemote::cLircRemote(char *DeviceName)
:cRemote("LIRC")
,cThread("LIRC remote control")
{
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
@ -49,8 +50,6 @@ bool cLircRemote::Ready(void)
void cLircRemote::Action(void)
{
dsyslog("LIRC remote control thread started (pid=%d)", getpid());
int FirstTime = 0;
int LastTime = 0;
char buf[LIRC_BUFFER_SIZE];

245
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.273 2003/10/03 14:36:20 kls Exp $
* $Id: menu.c 1.276 2004/01/04 11:12:43 kls Exp $
*/
#include "menu.h"
@ -16,7 +16,6 @@
#include "channels.h"
#include "config.h"
#include "cutter.h"
#include "eit.h"
#include "i18n.h"
#include "menuitems.h"
#include "plugin.h"
@ -69,7 +68,7 @@ eOSState cMenuEditChanItem::ProcessKey(eKeys Key)
case kLeft|k_Repeat:
case kLeft: delta = -1;
case kRight|k_Repeat:
case kRight:
case kRight:
{
cChannel *channel = Channels.GetByNumber(*value + delta, delta);
if (channel) {
@ -458,7 +457,7 @@ eOSState cMenuEditSrcItem::ProcessKey(eKeys Key)
}
}
else if (NORMALKEY(Key) == kRight) {
if (source) {
if (source) {
if (source->Next())
source = (cSource *)source->Next();
}
@ -582,7 +581,7 @@ void cMenuEditChannel::Setup(void)
Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF));
Add(new cMenuEditCaItem( tr("CA"), &data.ca, true));
Add(new cMenuEditCaItem( tr("CA"), &data.caids[0], true));//XXX
Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 0));
/* XXX not yet used
Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0));
@ -616,7 +615,6 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
if (channel) {
*channel = data;
isyslog("edited channel %d %s", channel->Number(), data.ToText());
Timers.Save();
state = osBack;
}
else {
@ -627,7 +625,7 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
isyslog("added channel %d %s", channel->Number(), data.ToText());
state = osUser1;
}
Channels.Save();
Channels.SetModified();
}
else {
Interface->Error(tr("Channel settings are not unique!"));
@ -683,6 +681,7 @@ protected:
virtual void Move(int From, int To);
public:
cMenuChannels(void);
~cMenuChannels();
virtual eOSState ProcessKey(eKeys Key);
};
@ -694,6 +693,12 @@ cMenuChannels::cMenuChannels(void)
Add(new cMenuChannelItem(channel), channel->Number() == cDevice::CurrentChannel());
}
SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark"));
Channels.IncBeingEdited();
}
cMenuChannels::~cMenuChannels()
{
Channels.DecBeingEdited();
}
cChannel *cMenuChannels::GetChannel(int Index)
@ -705,11 +710,10 @@ cChannel *cMenuChannels::GetChannel(int Index)
void cMenuChannels::Propagate(void)
{
Channels.ReNumber();
Channels.Save();
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->Set();
Timers.Save(); // channel numbering has changed!
Display();
Channels.SetModified();
}
eOSState cMenuChannels::Switch(void)
@ -904,7 +908,7 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
if (state == osUnknown) {
switch (Key) {
case kOk: {
case kOk: {
cChannel *ch = Channels.GetByNumber(channel);
if (ch)
data.channel = ch;
@ -1128,29 +1132,29 @@ eOSState cMenuTimers::ProcessKey(eKeys Key)
class cMenuEvent : public cOsdMenu {
private:
const cEventInfo *eventInfo;
const cEvent *event;
public:
cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch = false);
cMenuEvent(const cEvent *Event, bool CanSwitch = false);
cMenuEvent(bool Now);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch)
cMenuEvent::cMenuEvent(const cEvent *Event, bool CanSwitch)
:cOsdMenu(tr("Event"))
{
eventInfo = EventInfo;
if (eventInfo) {
cChannel *channel = Channels.GetByChannelID(eventInfo->GetChannelID(), true);
event = Event;
if (event) {
cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
if (channel) {
char *buffer;
asprintf(&buffer, "%-17.*s\t%.*s %s - %s", 17, channel->Name(), 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString());
asprintf(&buffer, "%-17.*s\t%.*s %s - %s", 17, channel->Name(), 5, event->GetDateString(), event->GetTimeString(), event->GetEndTimeString());
SetTitle(buffer, false);
free(buffer);
int Line = 2;
cMenuTextItem *item;
const char *Title = eventInfo->GetTitle();
const char *Subtitle = eventInfo->GetSubtitle();
const char *ExtendedDescription = eventInfo->GetExtendedDescription();
const char *Title = event->Title();
const char *Subtitle = event->ShortText();
const char *ExtendedDescription = event->Description();
if (!isempty(Title)) {
Add(item = new cMenuTextItem(Title, 1, Line, Setup.OSDwidth - 2, -1, clrCyan));
Line += item->Height() + 1;
@ -1185,16 +1189,16 @@ eOSState cMenuEvent::ProcessKey(eKeys Key)
class cMenuWhatsOnItem : public cOsdItem {
public:
const cEventInfo *eventInfo;
cMenuWhatsOnItem(const cEventInfo *EventInfo);
const cEvent *event;
cMenuWhatsOnItem(const cEvent *Event);
};
cMenuWhatsOnItem::cMenuWhatsOnItem(const cEventInfo *EventInfo)
cMenuWhatsOnItem::cMenuWhatsOnItem(const cEvent *Event)
{
eventInfo = EventInfo;
event = Event;
char *buffer = NULL;
cChannel *channel = Channels.GetByNumber(eventInfo->GetChannelNumber());
asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", eventInfo->GetChannelNumber(), 6, channel ? channel->Name() : "???", 5, eventInfo->GetTimeString(), eventInfo->GetTitle());
cChannel *channel = Channels.GetByNumber(event->ChannelNumber());
asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", event->ChannelNumber(), 6, channel ? channel->Name() : "???", 5, event->GetTimeString(), event->Title());
SetText(buffer, false);
}
@ -1205,36 +1209,36 @@ private:
eOSState Record(void);
eOSState Switch(void);
static int currentChannel;
static const cEventInfo *scheduleEventInfo;
static const cEvent *scheduleEvent;
public:
cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr);
static int CurrentChannel(void) { return currentChannel; }
static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; }
static const cEventInfo *ScheduleEventInfo(void);
static const cEvent *ScheduleEvent(void);
virtual eOSState ProcessKey(eKeys Key);
};
int cMenuWhatsOn::currentChannel = 0;
const cEventInfo *cMenuWhatsOn::scheduleEventInfo = NULL;
const cEvent *cMenuWhatsOn::scheduleEvent = NULL;
static int CompareEventChannel(const void *p1, const void *p2)
{
return (int)( (*(const cEventInfo **)p1)->GetChannelNumber() - (*(const cEventInfo **)p2)->GetChannelNumber());
return (int)( (*(const cEvent **)p1)->ChannelNumber() - (*(const cEvent **)p2)->ChannelNumber());
}
cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6)
{
const cSchedule *Schedule = Schedules->First();
const cEventInfo **pArray = NULL;
const cEvent **pArray = NULL;
int num = 0;
while (Schedule) {
pArray = (const cEventInfo **)realloc(pArray, (num + 1) * sizeof(cEventInfo *));
pArray = (const cEvent **)realloc(pArray, (num + 1) * sizeof(cEvent *));
pArray[num] = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent();
if (pArray[num]) {
cChannel *channel = Channels.GetByChannelID(pArray[num]->GetChannelID(), true);
cChannel *channel = Channels.GetByChannelID(pArray[num]->ChannelID(), true);
if (channel) {
pArray[num]->SetChannelNumber(channel->Number());
num++;
@ -1243,20 +1247,20 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentCha
Schedule = (const cSchedule *)Schedules->Next(Schedule);
}
qsort(pArray, num, sizeof(cEventInfo *), CompareEventChannel);
qsort(pArray, num, sizeof(cEvent *), CompareEventChannel);
for (int a = 0; a < num; a++)
Add(new cMenuWhatsOnItem(pArray[a]), pArray[a]->GetChannelNumber() == CurrentChannelNr);
Add(new cMenuWhatsOnItem(pArray[a]), pArray[a]->ChannelNumber() == CurrentChannelNr);
currentChannel = CurrentChannelNr;
free(pArray);
SetHelp(Count() ? tr("Record") : NULL, Now ? tr("Next") : tr("Now"), tr("Button$Schedule"), tr("Switch"));
}
const cEventInfo *cMenuWhatsOn::ScheduleEventInfo(void)
const cEvent *cMenuWhatsOn::ScheduleEvent(void)
{
const cEventInfo *ei = scheduleEventInfo;
scheduleEventInfo = NULL;
const cEvent *ei = scheduleEvent;
scheduleEvent = NULL;
return ei;
}
@ -1264,7 +1268,7 @@ eOSState cMenuWhatsOn::Switch(void)
{
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
if (item) {
cChannel *channel = Channels.GetByChannelID(item->eventInfo->GetChannelID(), true);
cChannel *channel = Channels.GetByChannelID(item->event->ChannelID(), true);
if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
return osEnd;
}
@ -1276,7 +1280,7 @@ eOSState cMenuWhatsOn::Record(void)
{
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
if (item) {
cTimer *timer = new cTimer(item->eventInfo);
cTimer *timer = new cTimer(item->event);
cTimer *t = Timers.GetTimer(timer);
if (t) {
delete timer;
@ -1300,14 +1304,14 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
case kGreen: {
cMenuWhatsOnItem *mi = (cMenuWhatsOnItem *)Get(Current());
if (mi) {
scheduleEventInfo = mi->eventInfo;
currentChannel = mi->eventInfo->GetChannelNumber();
scheduleEvent = mi->event;
currentChannel = mi->event->ChannelNumber();
}
}
break;
case kBlue: return Switch();
case kOk: if (Count())
return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->eventInfo, true));
return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->event, true));
break;
default: break;
}
@ -1319,15 +1323,15 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
class cMenuScheduleItem : public cOsdItem {
public:
const cEventInfo *eventInfo;
cMenuScheduleItem(const cEventInfo *EventInfo);
const cEvent *event;
cMenuScheduleItem(const cEvent *Event);
};
cMenuScheduleItem::cMenuScheduleItem(const cEventInfo *EventInfo)
cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event)
{
eventInfo = EventInfo;
event = Event;
char *buffer = NULL;
asprintf(&buffer, "%.*s\t%.*s\t%s", 5, eventInfo->GetDate(), 5, eventInfo->GetTimeString(), eventInfo->GetTitle());
asprintf(&buffer, "%.*s\t%.*s\t%s", 5, event->GetDateString(), 5, event->GetTimeString(), event->Title());
SetText(buffer, false);
}
@ -1335,7 +1339,7 @@ cMenuScheduleItem::cMenuScheduleItem(const cEventInfo *EventInfo)
class cMenuSchedule : public cOsdMenu {
private:
cMutexLock mutexLock;
cSchedulesLock schedulesLock;
const cSchedules *schedules;
bool now, next;
int otherChannel;
@ -1356,7 +1360,7 @@ cMenuSchedule::cMenuSchedule(void)
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
if (channel) {
cMenuWhatsOn::SetCurrentChannel(channel->Number());
schedules = cSIProcessor::Schedules(mutexLock);
schedules = cSchedules::Schedules(schedulesLock);
PrepareSchedule(channel);
SetHelp(Count() ? tr("Record") : NULL, tr("Now"), tr("Next"));
}
@ -1364,12 +1368,12 @@ cMenuSchedule::cMenuSchedule(void)
cMenuSchedule::~cMenuSchedule()
{
cMenuWhatsOn::ScheduleEventInfo(); // makes sure any posted data is cleared
cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared
}
static int CompareEventTime(const void *p1, const void *p2)
{
return (int)((*(cEventInfo **)p1)->GetTime() - (*(cEventInfo **)p2)->GetTime());
return (int)((*(cEvent **)p1)->StartTime() - (*(cEvent **)p2)->StartTime());
}
void cMenuSchedule::PrepareSchedule(cChannel *Channel)
@ -1381,22 +1385,24 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel)
free(buffer);
if (schedules) {
const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID());
int num = Schedule->NumEvents();
const cEventInfo **pArray = MALLOC(const cEventInfo *, num);
if (pArray) {
time_t now = time(NULL);
int numreal = 0;
for (int a = 0; a < num; a++) {
const cEventInfo *EventInfo = Schedule->GetEventNumber(a);
if (EventInfo->GetTime() + EventInfo->GetDuration() > now)
pArray[numreal++] = EventInfo;
}
qsort(pArray, numreal, sizeof(cEventInfo *), CompareEventTime);
for (int a = 0; a < numreal; a++)
Add(new cMenuScheduleItem(pArray[a]));
free(pArray);
if (Schedule) {
int num = Schedule->NumEvents();
const cEvent **pArray = MALLOC(const cEvent *, num);
if (pArray) {
time_t now = time(NULL);
int numreal = 0;
for (int a = 0; a < num; a++) {
const cEvent *Event = Schedule->GetEventNumber(a);
if (Event->StartTime() + Event->Duration() > now)
pArray[numreal++] = Event;
}
qsort(pArray, numreal, sizeof(cEvent *), CompareEventTime);
for (int a = 0; a < numreal; a++)
Add(new cMenuScheduleItem(pArray[a]));
free(pArray);
}
}
}
}
@ -1405,7 +1411,7 @@ eOSState cMenuSchedule::Record(void)
{
cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
if (item) {
cTimer *timer = new cTimer(item->eventInfo);
cTimer *timer = new cTimer(item->event);
cTimer *t = Timers.GetTimer(timer);
if (t) {
delete timer;
@ -1438,7 +1444,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
if (!now && !next) {
int ChannelNr = 0;
if (Count()) {
cChannel *channel = Channels.GetByChannelID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetChannelID(), true);
cChannel *channel = Channels.GetByChannelID(((cMenuScheduleItem *)Get(Current()))->event->ChannelID(), true);
if (channel)
ChannelNr = channel->Number();
}
@ -1456,16 +1462,16 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
return Switch();
break;
case kOk: if (Count())
return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo, otherChannel));
return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->event, otherChannel));
break;
default: break;
}
}
else if (!HasSubMenu()) {
now = next = false;
const cEventInfo *ei = cMenuWhatsOn::ScheduleEventInfo();
const cEvent *ei = cMenuWhatsOn::ScheduleEvent();
if (ei) {
cChannel *channel = Channels.GetByChannelID(ei->GetChannelID(), true);
cChannel *channel = Channels.GetByChannelID(ei->ChannelID(), true);
if (channel) {
PrepareSchedule(channel);
if (channel->Number() != cDevice::CurrentChannel()) {
@ -1985,6 +1991,7 @@ private:
virtual void Set(void);
public:
cMenuSetupOSD(void) { Set(); }
virtual ~cMenuSetupOSD() { cFont::SetCode(I18nCharSets()[Setup.OSDLanguage]); }
virtual eOSState ProcessKey(eKeys Key);
};
@ -2011,6 +2018,7 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys Key)
if (data.OSDLanguage != osdLanguage) {
int OriginalOSDLanguage = Setup.OSDLanguage;
Setup.OSDLanguage = data.OSDLanguage;
cFont::SetCode(I18nCharSets()[Setup.OSDLanguage]);
Set();
Display();
Setup.OSDLanguage = OriginalOSDLanguage;
@ -2631,10 +2639,10 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched)
int EpgLines = withInfo ? 5 : 1;
lines = 0;
number = 0;
cChannel *channel = Channels.GetByNumber(Number);
channel = Channels.GetByNumber(Number);
Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? EpgLines : -EpgLines);
if (channel) {
DisplayChannel(channel);
DisplayChannel();
DisplayInfo();
}
lastTime = time_ms();
@ -2658,16 +2666,16 @@ cDisplayChannel::~cDisplayChannel()
Interface->Close();
}
void cDisplayChannel::DisplayChannel(const cChannel *Channel)
void cDisplayChannel::DisplayChannel(void)
{
int BufSize = Width() + 1;
char buffer[BufSize];
*buffer = 0;
if (Channel) {
if (Channel->GroupSep())
snprintf(buffer, BufSize, "%s", Channel->Name());
if (channel) {
if (channel->GroupSep())
snprintf(buffer, BufSize, "%s", channel->Name());
else
snprintf(buffer, BufSize, "%d%s %s", Channel->Number(), number ? "-" : "", Channel->Name());
snprintf(buffer, BufSize, "%d%s %s", channel->Number(), number ? "-" : "", channel->Name());
}
else if (number)
snprintf(buffer, BufSize, "%d-", number);
@ -2682,28 +2690,28 @@ void cDisplayChannel::DisplayChannel(const cChannel *Channel)
void cDisplayChannel::DisplayInfo(void)
{
if (withInfo) {
const cEventInfo *Present = NULL, *Following = NULL;
cMutexLock MutexLock;
const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
if (withInfo && channel) {
const cEvent *Present = NULL, *Following = NULL;
cSchedulesLock SchedulesLock;
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
if (Schedules) {
const cSchedule *Schedule = Schedules->GetSchedule();
const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
if (Schedule) {
const char *PresentTitle = NULL, *PresentSubtitle = NULL, *FollowingTitle = NULL, *FollowingSubtitle = NULL;
int Lines = 0;
if ((Present = Schedule->GetPresentEvent()) != NULL) {
PresentTitle = Present->GetTitle();
PresentTitle = Present->Title();
if (!isempty(PresentTitle))
Lines++;
PresentSubtitle = Present->GetSubtitle();
PresentSubtitle = Present->ShortText();
if (!isempty(PresentSubtitle))
Lines++;
}
if ((Following = Schedule->GetFollowingEvent()) != NULL) {
FollowingTitle = Following->GetTitle();
FollowingTitle = Following->Title();
if (!isempty(FollowingTitle))
Lines++;
FollowingSubtitle = Following->GetSubtitle();
FollowingSubtitle = Following->ShortText();
if (!isempty(FollowingSubtitle))
Lines++;
}
@ -2731,7 +2739,7 @@ void cDisplayChannel::DisplayInfo(void)
Interface->Flush();
lines = Lines;
lastTime = time_ms();
cStatus::MsgOsdProgramme(Present ? Present->GetTime() : 0, PresentTitle, PresentSubtitle, Following ? Following->GetTime() : 0, FollowingTitle, FollowingSubtitle);
cStatus::MsgOsdProgramme(Present ? Present->StartTime() : 0, PresentTitle, PresentSubtitle, Following ? Following->StartTime() : 0, FollowingTitle, FollowingSubtitle);
}
}
}
@ -2741,7 +2749,8 @@ void cDisplayChannel::DisplayInfo(void)
void cDisplayChannel::Refresh(void)
{
Interface->Clear();
DisplayChannel(Channels.GetByNumber(cDevice::CurrentChannel()));
channel = Channels.GetByNumber(cDevice::CurrentChannel());
DisplayChannel();
lastTime = time_ms();
lines = 0;
}
@ -2759,20 +2768,21 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
if (number >= 0) {
number = number * 10 + Key - k0;
if (number > 0) {
cChannel *channel = Channels.GetByNumber(number);
channel = Channels.GetByNumber(number);
Interface->Clear();
withInfo = false;
DisplayChannel(channel);
DisplayChannel();
lastTime = time_ms();
// Lets see if there can be any useful further input:
int n = channel ? number * 10 : 0;
while (channel && (channel = Channels.Next(channel)) != NULL) {
if (!channel->GroupSep()) {
if (n <= channel->Number() && channel->Number() <= n + 9) {
cChannel *ch = channel;
while (ch && (ch = Channels.Next(ch)) != NULL) {
if (!ch->GroupSep()) {
if (n <= ch->Number() && ch->Number() <= n + 9) {
n = 0;
break;
}
if (channel->Number() > n)
if (ch->Number() > n)
n *= 10;
}
}
@ -2803,10 +2813,10 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
group = Channels.GetPrevGroup(group < 1 ? 1 : group);
if (group < 0)
group = SaveGroup;
cChannel *channel = Channels.Get(group);
channel = Channels.Get(group);
if (channel) {
Interface->Clear();
DisplayChannel(channel);
DisplayChannel();
if (!channel->GroupSep())
group = -1;
}
@ -2833,7 +2843,8 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
Channels.SwitchTo(number);
else {
number = 0;
DisplayChannel(NULL);
channel = NULL;
DisplayChannel();
lastTime = time_ms();
return osContinue;
}
@ -2965,7 +2976,7 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key)
cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
{
eventInfo = NULL;
event = NULL;
instantId = NULL;
fileName = NULL;
recorder = NULL;
@ -2984,10 +2995,10 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
const char *Title = NULL;
const char *Subtitle = NULL;
const char *Summary = NULL;
if (GetEventInfo()) {
Title = eventInfo->GetTitle();
Subtitle = eventInfo->GetSubtitle();
Summary = eventInfo->GetExtendedDescription();
if (GetEvent()) {
Title = event->Title();
Subtitle = event->ShortText();
Summary = event->Description();
dsyslog("Title: '%s' Subtitle: '%s'", Title, Subtitle);
}
cRecording Recording(timer, Title, Subtitle, Summary);
@ -3036,19 +3047,19 @@ cRecordControl::~cRecordControl()
#define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording
bool cRecordControl::GetEventInfo(void)
bool cRecordControl::GetEvent(void)
{
const cChannel *channel = timer->Channel();
time_t Time = timer->Active() == taActInst ? timer->StartTime() + INSTANT_REC_EPG_LOOKAHEAD : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2;
for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
{
cMutexLock MutexLock;
const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
cSchedulesLock SchedulesLock;
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
if (Schedules) {
const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
if (Schedule) {
eventInfo = Schedule->GetEventAround(Time);
if (eventInfo) {
event = Schedule->GetEventAround(Time);
if (event) {
if (seconds > 0)
dsyslog("got EPG info after %d seconds", seconds);
return true;
@ -3215,6 +3226,20 @@ void cRecordControls::Process(time_t t)
}
}
void cRecordControls::ChannelDataModified(cChannel *Channel)
{
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) {
if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
isyslog("stopping recording due to modification of channel %d", Channel->Number());
RecordControls[i]->Stop(true);
// This will restart the recording, maybe even from a different
// device in case conditional access has changed.
}
}
}
}
bool cRecordControls::Active(void)
{
for (int i = 0; i < MAXRECORDCONTROLS; i++) {

13
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.h 1.57 2003/08/03 09:37:18 kls Exp $
* $Id: menu.h 1.59 2004/01/04 11:01:13 kls Exp $
*/
#ifndef __MENU_H
@ -12,6 +12,7 @@
#include "ci.h"
#include "device.h"
#include "epg.h"
#include "osd.h"
#include "dvbplayer.h"
#include "recorder.h"
@ -36,7 +37,8 @@ private:
int lines;
int lastTime;
int number;
void DisplayChannel(const cChannel *Channel);
cChannel *channel;
void DisplayChannel(void);
void DisplayInfo(void);
void Refresh(void);
public:
@ -113,10 +115,10 @@ private:
cDevice *device;
cTimer *timer;
cRecorder *recorder;
const cEventInfo *eventInfo;
const cEvent *event;
char *instantId;
char *fileName;
bool GetEventInfo(void);
bool GetEvent(void);
public:
cRecordControl(cDevice *Device, cTimer *Timer = NULL, bool Pause = false);
virtual ~cRecordControl();
@ -141,6 +143,7 @@ public:
static const char *GetInstantId(const char *LastInstantId);
static cRecordControl *GetRecordControl(const char *FileName);
static void Process(time_t t);
static void ChannelDataModified(cChannel *Channel);
static bool Active(void);
static void Shutdown(void);
};
@ -151,7 +154,7 @@ private:
bool visible, modeOnly, shown, displayFrames;
int lastCurrent, lastTotal;
time_t timeoutShow;
bool timeSearchActive, timeSearchHide;
bool timeSearchActive, timeSearchHide;
int timeSearchTime, timeSearchPos;
void TimeSearchDisplay(void);
void TimeSearchProcess(eKeys Key);

View File

@ -12,7 +12,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: newplugin 1.15 2003/05/09 14:59:28 kls Exp $
# $Id: newplugin 1.16 2003/12/21 15:45:18 kls Exp $
$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
@ -97,7 +97,7 @@ PACKAGE = vdr-\$(ARCHIVE)
INCLUDES += -I\$(VDRDIR)/include -I\$(DVBDIR)/include
DEFINES += -DPLUGIN_NAME_I18N='"\$(PLUGIN)"'
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"\$(PLUGIN)"'
### The object files (add further files here):

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osdbase.c 1.10 2003/08/24 11:38:27 kls Exp $
* $Id: osdbase.c 1.11 2003/10/19 14:32:32 kls Exp $
*/
#include "osdbase.h"
@ -131,7 +131,6 @@ cBitmap::cBitmap(int Width, int Height, int Bpp, bool ClearWithBackground)
cBitmap::~cBitmap()
{
delete font;
free(bitmap);
}
@ -139,8 +138,7 @@ eDvbFont cBitmap::SetFont(eDvbFont Font)
{
eDvbFont oldFont = fontType;
if (fontType != Font || !font) {
delete font;
font = new cFont(Font);
font = cFont::GetFont(Font);
fontType = Font;
}
return oldFont;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osdbase.h 1.6 2002/09/08 14:12:41 kls Exp $
* $Id: osdbase.h 1.8 2004/01/04 14:22:43 kls Exp $
*/
#ifndef __OSDBASE_H
@ -13,7 +13,7 @@
#include <stdio.h>
#include "font.h"
#define MAXNUMCOLORS 16
#define MAXNUMCOLORS 256
enum eDvbColor {
#ifdef DEBUG_OSD
@ -73,7 +73,7 @@ public:
class cBitmap : public cPalette {
private:
cFont *font;
const cFont *font;
eDvbFont fontType;
char *bitmap;
bool clearWithBackground;

378
pat.c Normal file
View File

@ -0,0 +1,378 @@
/*
* pat.c: PAT section filter
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: pat.c 1.3 2004/01/04 12:27:06 kls Exp $
*/
#include "pat.h"
#include <malloc.h>
#include "channels.h"
#include "libsi/section.h"
#include "libsi/descriptor.h"
#include "thread.h"
#define PMT_SCAN_TIMEOUT 10 // seconds
// --- cCaDescriptor ---------------------------------------------------------
class cCaDescriptor : public cListObject {
private:
int caSystem;
bool stream;
int length;
uchar *data;
public:
cCaDescriptor(int CaSystem, int CaPid, bool Stream, int Length, const uchar *Data);
virtual ~cCaDescriptor();
bool operator== (const cCaDescriptor &arg) const;
int CaSystem(void) { return caSystem; }
int Stream(void) { return stream; }
int Length(void) const { return length; }
const uchar *Data(void) const { return data; }
};
cCaDescriptor::cCaDescriptor(int CaSystem, int CaPid, bool Stream, int Length, const uchar *Data)
{
caSystem = CaSystem;
stream = Stream;
length = Length + 6;
data = MALLOC(uchar, length);
data[0] = SI::CaDescriptorTag;
data[1] = length - 2;
data[2] = (caSystem >> 8) & 0xFF;
data[3] = caSystem & 0xFF;
data[4] = ((CaPid >> 8) & 0x1F) | 0xE0;
data[5] = CaPid & 0xFF;
if (Length)
memcpy(&data[6], Data, Length);
}
cCaDescriptor::~cCaDescriptor()
{
free(data);
}
bool cCaDescriptor::operator== (const cCaDescriptor &arg) const
{
return length == arg.length && memcmp(data, arg.data, length) == 0;
}
// --- cCaDescriptors --------------------------------------------------------
class cCaDescriptors : public cListObject {
private:
int source;
int transponder;
int serviceId;
int numCaIds;
int caIds[MAXCAIDS + 1];
cList<cCaDescriptor> caDescriptors;
void AddCaId(int CaId);
public:
cCaDescriptors(int Source, int Transponder, int ServiceId);
bool operator== (const cCaDescriptors &arg) const;
bool Is(int Source, int Transponder, int ServiceId);
bool Is(cCaDescriptors * CaDescriptors);
bool Empty(void) { return caDescriptors.Count() == 0; }
void AddCaDescriptor(SI::CaDescriptor *d, bool Stream);
int GetCaDescriptors(const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
const int *CaIds(void) { return caIds; }
};
cCaDescriptors::cCaDescriptors(int Source, int Transponder, int ServiceId)
{
source = Source;
transponder = Transponder;
serviceId = ServiceId;
numCaIds = 0;
caIds[0] = 0;
}
bool cCaDescriptors::operator== (const cCaDescriptors &arg) const
{
cCaDescriptor *ca1 = caDescriptors.First();
cCaDescriptor *ca2 = arg.caDescriptors.First();
while (ca1 && ca2) {
if (!(*ca1 == *ca2))
return false;
ca1 = caDescriptors.Next(ca1);
ca2 = arg.caDescriptors.Next(ca2);
}
return !ca1 && !ca2;
}
bool cCaDescriptors::Is(int Source, int Transponder, int ServiceId)
{
return source == Source && transponder == Transponder && serviceId == ServiceId;
}
bool cCaDescriptors::Is(cCaDescriptors * CaDescriptors)
{
return Is(CaDescriptors->source, CaDescriptors->transponder, CaDescriptors->serviceId);
}
void cCaDescriptors::AddCaId(int CaId)
{
if (numCaIds < MAXCAIDS) {
for (int i = 0; i < numCaIds; i++) {
if (caIds[i] == CaId)
return;
}
caIds[numCaIds++] = CaId;
caIds[numCaIds] = 0;
}
}
void cCaDescriptors::AddCaDescriptor(SI::CaDescriptor *d, bool Stream)
{
cCaDescriptor *nca = new cCaDescriptor(d->getCaType(), d->getCaPid(), Stream, d->privateData.getLength(), d->privateData.getData());
for (cCaDescriptor *ca = caDescriptors.First(); ca; ca = caDescriptors.Next(ca)) {
if (*ca == *nca) {
delete nca;
return;
}
}
AddCaId(nca->CaSystem());
caDescriptors.Add(nca);
//#define DEBUG_CA_DESCRIPTORS 1
#ifdef DEBUG_CA_DESCRIPTORS
char buffer[1024];
char *q = buffer;
q += sprintf(q, "CAM: %04X %5d %5d %04X %d -", source, transponder, serviceId, d->getCaType(), Stream);
for (int i = 0; i < nca->Length(); i++)
q += sprintf(q, " %02X", nca->Data()[i]);
dsyslog(buffer);
#endif
}
int cCaDescriptors::GetCaDescriptors(const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
{
if (!CaSystemIds || !*CaSystemIds)
return 0;
if (BufSize > 0 && Data) {
int length = 0;
int IsStream = -1;
for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
const unsigned short *caids = CaSystemIds;
do {
if (d->CaSystem() == *caids) {
if (length + d->Length() <= BufSize) {
if (IsStream >= 0 && IsStream != d->Stream())
dsyslog("CAM: different stream flag in CA descriptors");
IsStream = d->Stream();
memcpy(Data + length, d->Data(), d->Length());
length += d->Length();
}
else
return -1;
}
} while (*++caids);
}
StreamFlag = IsStream == 1;
return length;
}
return -1;
}
// --- cCaDescriptorHandler --------------------------------------------------
class cCaDescriptorHandler : public cList<cCaDescriptors> {
private:
cMutex mutex;
public:
int AddCaDescriptors(cCaDescriptors *CaDescriptors);
// Returns 0 if this is an already known descriptor,
// 1 if it is an all new descriptor with actual contents,
// and 2 if an existing descriptor was changed.
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
};
int cCaDescriptorHandler::AddCaDescriptors(cCaDescriptors *CaDescriptors)
{
cMutexLock MutexLock(&mutex);
for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
if (ca->Is(CaDescriptors)) {
if (*ca == *CaDescriptors) {
delete CaDescriptors;
return 0;
}
Del(ca);
Add(CaDescriptors);
return 2;
}
}
Add(CaDescriptors);
return CaDescriptors->Empty() ? 0 : 1;
}
int cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
{
cMutexLock MutexLock(&mutex);
for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
if (ca->Is(Source, Transponder, ServiceId))
return ca->GetCaDescriptors(CaSystemIds, BufSize, Data, StreamFlag);
}
return 0;
}
cCaDescriptorHandler CaDescriptorHandler;
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag)
{
return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, StreamFlag);
}
// --- cPatFilter ------------------------------------------------------------
cPatFilter::cPatFilter(void)
{
pmtIndex = 0;
pmtPid = 0;
lastPmtScan = 0;
numPmtEntries = 0;
Set(0x00, 0x00); // PAT
}
void cPatFilter::SetStatus(bool On)
{
cFilter::SetStatus(On);
pmtIndex = 0;
pmtPid = 0;
lastPmtScan = 0;
numPmtEntries = 0;
}
void cPatFilter::Trigger(void)
{
numPmtEntries = 0;
}
bool cPatFilter::PmtVersionChanged(int PmtPid, int Version)
{
Version <<= 16;
for (int i = 0; i < numPmtEntries; i++) {
if ((pmtVersion[i] & 0x0000FFFF) == PmtPid) {
bool Changed = (pmtVersion[i] & 0x00FF0000) != Version;
if (Changed)
pmtVersion[i] = PmtPid | Version;
return Changed;
}
}
if (numPmtEntries < MAXPMTENTRIES)
pmtVersion[numPmtEntries++] = PmtPid | Version;
return true;
}
void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
if (Pid == 0x00) {
if (Tid == 0x00) {
if (pmtPid && time(NULL) - lastPmtScan > PMT_SCAN_TIMEOUT) {
Del(pmtPid, 0x02);
pmtPid = 0;
pmtIndex++;
lastPmtScan = time(NULL);
}
if (!pmtPid) {
SI::PAT pat(Data, false);
if (!pat.CheckCRCAndParse())
return;
SI::PAT::Association assoc;
int Index = 0;
for (SI::Loop::Iterator it; pat.associationLoop.hasNext(it); ) {
assoc = pat.associationLoop.getNext(it);
if (!assoc.isNITPid()) {
if (Index++ == pmtIndex) {
pmtPid = assoc.getPid();
Add(pmtPid, 0x02);
break;
}
}
}
if (!pmtPid)
pmtIndex = 0;
}
}
}
else if (Pid == pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) {
SI::PMT pmt(Data, false);
if (!pmt.CheckCRCAndParse())
return;
if (!PmtVersionChanged(pmtPid, pmt.getVersionNumber())) {
lastPmtScan = 0; // this triggers the next scan
return;
}
if (!Channels.Lock(true, 10)) {
numPmtEntries = 0; // to make sure we try again
return;
}
cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId());
if (Channel) {
SI::CaDescriptor *d;
cCaDescriptors *CaDescriptors = new cCaDescriptors(Channel->Source(), Channel->Transponder(), Channel->Sid());
// Scan the common loop:
for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)pmt.commonDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
CaDescriptors->AddCaDescriptor(d, false);
delete d;
}
// Scan the stream-specific loop:
SI::PMT::Stream stream;
int Vpid = 0;
int Ppid = pmt.getPCRPid();
int Apids[MAXAPIDS] = { 0 };
int Dpids[MAXAPIDS] = { 0 };
int Tpid = 0;
int NumApids = 0;
int NumDpids = 0;
for (SI::Loop::Iterator it; pmt.streamLoop.hasNext(it); ) {
stream = pmt.streamLoop.getNext(it);
switch (stream.getStreamType()) {
case 1: // STREAMTYPE_11172_VIDEO
case 2: // STREAMTYPE_13818_VIDEO
Vpid = stream.getPid();
break;
case 3: // STREAMTYPE_11172_AUDIO
case 4: // STREAMTYPE_13818_AUDIO
{
if (NumApids < MAXAPIDS)
Apids[NumApids++] = stream.getPid();
}
break;
case 5: // STREAMTYPE_13818_PRIVATE
case 6: // STREAMTYPE_13818_PES_PRIVATE
//XXX case 8: // STREAMTYPE_13818_DSMCC
{
SI::Descriptor *d;
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
switch (d->getDescriptorTag()) {
case SI::AC3DescriptorTag:
if (NumDpids < MAXAPIDS)
Dpids[NumDpids++] = stream.getPid();
break;
case SI::TeletextDescriptorTag:
Tpid = stream.getPid();
break;
default: ;
}
delete d;
}
}
break;
//default: printf("PID: %5d %5d %2d %3d %3d\n", pmt.getServiceId(), stream.getPid(), stream.getStreamType(), pmt.getVersionNumber(), Channel->Number());//XXX
}
for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)stream.streamDescriptors.getNext(it, SI::CaDescriptorTag)); ) {
CaDescriptors->AddCaDescriptor(d, true);
delete d;
}
}
Channel->SetPids(Vpid, Ppid, Apids[0], Apids[1], Dpids[0], Dpids[1], Tpid);
Channel->SetCaIds(CaDescriptors->CaIds());
Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
}
lastPmtScan = 0; // this triggers the next scan
Channels.Unlock();
}
}

43
pat.h Normal file
View File

@ -0,0 +1,43 @@
/*
* pat.h: PAT section filter
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: pat.h 1.3 2004/01/03 13:47:54 kls Exp $
*/
#ifndef __PAT_H
#define __PAT_H
#include "filter.h"
#define MAXPMTENTRIES 64
class cPatFilter : public cFilter {
private:
time_t lastPmtScan;
int pmtIndex;
int pmtPid;
int pmtVersion[MAXPMTENTRIES];
int numPmtEntries;
bool PmtVersionChanged(int PmtPid, int Version);
protected:
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public:
cPatFilter(void);
virtual void SetStatus(bool On);
void Trigger(void);
};
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag);
///< Gets all CA descriptors for a given channel.
///< Copies all available CA descriptors for the given Source, Transponder and ServiceId
///< into the provided buffer at Data (at most BufSize bytes). Only those CA descriptors
///< are copied that match one of the given CA system IDs.
///< \return Returns the number of bytes copied into Data (0 if no CA descriptors are
///< available), or -1 if BufSize was too small to hold all CA descriptors.
///< The return value in StreamFlag tells whether these CA descriptors are to be used
///< for the individual streams.
#endif //__PAT_H

5
rcu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: rcu.c 1.5 2003/05/02 14:42:40 kls Exp $
* $Id: rcu.c 1.6 2003/10/18 11:34:30 kls Exp $
*/
#include "rcu.h"
@ -18,6 +18,7 @@
cRcuRemote::cRcuRemote(char *DeviceName)
:cRemote("RCU")
,cThread("RCU remote control")
{
dp = 0;
mode = modeB;
@ -92,8 +93,6 @@ void cRcuRemote::Action(void)
} buffer;
#pragma pack()
dsyslog("RCU remote control thread started (pid=%d)", getpid());
time_t LastCodeRefresh = 0;
int FirstTime = 0;
uint64 LastCommand = 0;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recorder.c 1.7 2003/08/02 13:01:19 kls Exp $
* $Id: recorder.c 1.8 2003/10/18 11:35:02 kls Exp $
*/
#include <stdarg.h>
@ -25,6 +25,7 @@
cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(Ca, Priority, 5, VPid, APid1, APid2, DPid1, DPid2)
,cThread("recording")
{
ringBuffer = NULL;
remux = NULL;
@ -106,8 +107,6 @@ void cRecorder::Receive(uchar *Data, int Length)
void cRecorder::Action(void)
{
dsyslog("recording thread started (pid=%d)", getpid());
time_t t = time(NULL);
active = true;
while (active) {
@ -143,6 +142,4 @@ void cRecorder::Action(void)
else
usleep(1); // this keeps the CPU load low
}
dsyslog("recording thread ended (pid=%d)", getpid());
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: remote.c 1.38 2003/05/02 10:49:50 kls Exp $
* $Id: remote.c 1.39 2003/10/18 11:35:32 kls Exp $
*/
#include "remote.h"
@ -197,6 +197,7 @@ bool cKbdRemote::rawMode = false;
cKbdRemote::cKbdRemote(void)
:cRemote("KBD")
,cThread("KBD remote control")
{
active = false;
tcgetattr(STDIN_FILENO, &savedTm);
@ -245,7 +246,6 @@ int cKbdRemote::MapCodeToFunc(uint64 Code)
void cKbdRemote::Action(void)
{
dsyslog("KBD remote control thread started (pid=%d)", getpid());
cPoller Poller(STDIN_FILENO);
active = true;
while (active) {
@ -285,5 +285,4 @@ void cKbdRemote::Action(void)
}
}
}
dsyslog("KBD remote control thread ended (pid=%d)", getpid());
}

View File

@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
* $Id: ringbuffer.c 1.17 2003/05/12 17:38:11 kls Exp $
* $Id: ringbuffer.c 1.18 2003/10/12 14:25:09 kls Exp $
*/
#include "ringbuffer.h"
@ -75,7 +75,7 @@ cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics)
{
margin = Margin;
buffer = NULL;
getThreadPid = -1;
getThreadTid = 0;
if (Size > 1) { // 'Size - 1' must not be 0!
buffer = MALLOC(uchar, Size);
if (!buffer)
@ -125,7 +125,7 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
int percent = maxFill * 100 / (Size() - 1) / 5 * 5;
if (abs(lastPercent - percent) >= 5) {
if (percent > 75)
dsyslog("buffer usage: %d%% (pid=%d)", percent, getThreadPid);
dsyslog("buffer usage: %d%% (tid=%ld)", percent, getThreadTid);
lastPercent = percent;
}
}
@ -159,8 +159,8 @@ uchar *cRingBufferLinear::Get(int &Count)
{
uchar *p = NULL;
Lock();
if (getThreadPid < 0)
getThreadPid = getpid();
if (getThreadTid <= 0)
getThreadTid = pthread_self();
int rest = Size() - tail;
if (rest < margin && head < tail) {
int t = margin - rest;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ringbuffer.h 1.12 2003/05/12 17:35:10 kls Exp $
* $Id: ringbuffer.h 1.13 2003/10/12 13:57:56 kls Exp $
*/
#ifndef __RINGBUFFER_H
@ -46,7 +46,7 @@ private:
int margin, head, tail;
int lastGet;
uchar *buffer;
pid_t getThreadPid;
pthread_t getThreadTid;
public:
cRingBufferLinear(int Size, int Margin = 0, bool Statistics = false);
///< Creates a linear ring buffer.

146
sdt.c Normal file
View File

@ -0,0 +1,146 @@
/*
* sdt.c: SDT section filter
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: sdt.c 1.1 2004/01/04 11:54:42 kls Exp $
*/
#include "sdt.h"
#include "channels.h"
#include "libsi/section.h"
#include "libsi/descriptor.h"
// --- cSDT ------------------------------------------------------------------
class cSDT : public SI::SDT {
public:
cSDT(int Source, int Transponder, uchar &lastSdtVersion, cPatFilter *PatFilter, const u_char *Data);
};
cSDT::cSDT(int Source, int Transponder, uchar &lastSdtVersion, cPatFilter *PatFilter, const u_char *Data)
:SI::SDT(Data, false)
{
if (!CheckCRCAndParse())
return;
if (getVersionNumber() == lastSdtVersion)
return;
if (!Channels.Lock(true, 10))
return;
lastSdtVersion = getVersionNumber();
SI::SDT::Service SiSdtService;
for (SI::Loop::Iterator it; serviceLoop.hasNext(it); ) {
SiSdtService = serviceLoop.getNext(it);
cChannel *Channel = Channels.GetByChannelID(tChannelID(Source, getOriginalNetworkId(), getTransportStreamId(), SiSdtService.getServiceId()));
if (!Channel)
Channel = Channels.GetByChannelID(tChannelID(Source, 0, Transponder, SiSdtService.getServiceId()));
SI::Descriptor *d;
for (SI::Loop::Iterator it2; (d = SiSdtService.serviceDescriptors.getNext(it2)); ) {
switch (d->getDescriptorTag()) {
case SI::ServiceDescriptorTag: {
SI::ServiceDescriptor *sd = (SI::ServiceDescriptor *)d;
switch (sd->getServiceType()) {
case 0x01: // digital television service
//XXX TODO case 0x02: // digital radio sound service
//XXX TODO case 0x04: // NVOD reference service
//XXX TODO case 0x05: // NVOD time-shifted service
{
char buffer[1024];
char *p = sd->serviceName.getText(buffer);
char NameBuf[1024];
char ShortNameBuf[1024];
char *pn = NameBuf;
char *ps = ShortNameBuf;
int IsShortName = 0;
while (*p) {
if ((uchar)*p == 0x86)
IsShortName++;
else if ((uchar)*p == 0x87)
IsShortName--;
else {
*pn++ = *p;
if (IsShortName)
*ps++ = *p;
}
p++;
}
*pn = *ps = 0;
pn = NameBuf;
if (*NameBuf && *ShortNameBuf) {
*ps++ = ',';
strcpy(ps, NameBuf);
pn = ShortNameBuf;
}
if (Channel) {
Channel->SetId(getOriginalNetworkId(), getTransportStreamId(), SiSdtService.getServiceId());
Channel->SetName(pn);
// Using SiSdtService.getFreeCaMode() is no good, because some
// tv stations set this flag even for non-encrypted channels :-(
// The special value 0xFFFF was supposed to mean "unknown encryption"
// and would have been overwritten with real CA values later:
// Channel->SetCa(SiSdtService.getFreeCaMode() ? 0xFFFF : 0);
}
else if (*pn) {
Channel = Channels.NewChannel(Source, Transponder, pn, getOriginalNetworkId(), getTransportStreamId(), SiSdtService.getServiceId());
PatFilter->Trigger();
}
}
}
}
break;
// Using the CaIdentifierDescriptor is no good, because some tv stations
// just don't use it. The actual CA values are collected in pat.c:
/*
case SI::CaIdentifierDescriptorTag: {
SI::CaIdentifierDescriptor *cid = (SI::CaIdentifierDescriptor *)d;
if (Channel) {
for (SI::Loop::Iterator it; cid->identifiers.hasNext(it); )
Channel->SetCa(cid->identifiers.getNext(it));
}
}
break;
*/
case SI::NVODReferenceDescriptorTag: {
SI::NVODReferenceDescriptor *nrd = (SI::NVODReferenceDescriptor *)d;
for (SI::Loop::Iterator it; nrd->serviceLoop.hasNext(it); ) {
SI::NVODReferenceDescriptor::Service Service = nrd->serviceLoop.getNext(it);
//printf(" %04X-%04X-%04X\n", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId());//XXX TODO
}
}
break;
default: ;
}
delete d;
}
}
Channels.Unlock();
}
// --- cSdtFilter ------------------------------------------------------------
cSdtFilter::cSdtFilter(cPatFilter *PatFilter)
{
lastSdtVersion = 0xFF;
patFilter = PatFilter;
Set(0x11, 0x42); // SDT
}
void cSdtFilter::SetStatus(bool On)
{
cFilter::SetStatus(On);
lastSdtVersion = 0xFF;
}
void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
if (Source() && Transponder())
cSDT SDT(Source(), Transponder(), lastSdtVersion, patFilter, Data);
}

27
sdt.h Normal file
View File

@ -0,0 +1,27 @@
/*
* sdt.h: SDT section filter
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: sdt.h 1.1 2004/01/03 13:49:55 kls Exp $
*/
#ifndef __SDT_H
#define __SDT_H
#include "filter.h"
#include "pat.h"
class cSdtFilter : public cFilter {
private:
uchar lastSdtVersion;
cPatFilter *patFilter;
protected:
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public:
cSdtFilter(cPatFilter *PatFilter);
virtual void SetStatus(bool On);
};
#endif //__SDT_H

187
sections.c Normal file
View File

@ -0,0 +1,187 @@
/*
* sections.c: Section data handling
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: sections.c 1.2 2004/01/03 12:54:01 kls Exp $
*/
#include "sections.h"
#include <unistd.h>
#include "device.h"
// --- cFilterHandle----------------------------------------------------------
class cFilterHandle : public cListObject {
public:
cFilterData filterData;
int handle;
int used;
cFilterHandle(const cFilterData &FilterData);
};
cFilterHandle::cFilterHandle(const cFilterData &FilterData)
{
filterData = FilterData;
handle = -1;
used = 0;
}
// --- cSectionHandler -------------------------------------------------------
cSectionHandler::cSectionHandler(cDevice *Device)
:cThread("Section handler")
{
device = Device;
active = false;
source = 0;
transponder = 0;
statusCount = 0;
on = false;
Start();
}
cSectionHandler::~cSectionHandler()
{
active = false;
Cancel(3);
cFilter *fi;
while ((fi = filters.First()) != NULL)
Detach(fi);
}
void cSectionHandler::Add(const cFilterData *FilterData)
{
Lock();
statusCount++;
cFilterHandle *fh;
for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask))
break;
}
if (!fh) {
fh = new cFilterHandle(*FilterData);
filterHandles.Add(fh);
fh->handle = device->OpenFilter(FilterData->pid, FilterData->tid, FilterData->mask);
}
fh->used++;
Unlock();
}
void cSectionHandler::Del(const cFilterData *FilterData)
{
Lock();
statusCount++;
cFilterHandle *fh;
for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
if (--fh->used <= 0) {
close(fh->handle);
filterHandles.Del(fh);
break;
}
}
}
Unlock();
}
void cSectionHandler::Attach(cFilter *Filter)
{
Lock();
statusCount++;
filters.Add(Filter);
Filter->sectionHandler = this;
Filter->SetStatus(true);
Unlock();
}
void cSectionHandler::Detach(cFilter *Filter)
{
Lock();
statusCount++;
Filter->SetStatus(false);
Filter->sectionHandler = NULL;
filters.Del(Filter, false);
Unlock();
}
void cSectionHandler::SetSource(int Source, int Transponder)
{
Lock();
source = Source;
transponder = Transponder;
Unlock();
}
void cSectionHandler::SetStatus(bool On)
{
Lock();
if (on != On) {
statusCount++;
for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
fi->SetStatus(false);
if (On)
fi->SetStatus(true);
}
on = On;
}
Unlock();
}
void cSectionHandler::Action(void)
{
active = true;
while (active) {
Lock();
int NumFilters = filterHandles.Count();
pollfd pfd[NumFilters];
for (cFilterHandle *fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
int i = fh->Index();
pfd[i].fd = fh->handle;
pfd[i].events = POLLIN;
}
int oldStatusCount = statusCount;
Unlock();
if (poll(pfd, NumFilters, 1000) != 0) {
bool DeviceHasLock = device->HasLock();
if (!DeviceHasLock)
usleep(100000);
for (int i = 0; i < NumFilters; i++) {
if (pfd[i].revents & POLLIN) {
cFilterHandle *fh = NULL;
LOCK_THREAD;
if (statusCount != oldStatusCount)
break;
for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
if (pfd[i].fd == fh->handle)
break;
}
if (fh) {
// Read section data:
unsigned char buf[4096]; // max. allowed size for any EIT section
int r = safe_read(fh->handle, buf, sizeof(buf));
if (!DeviceHasLock)
continue; // we do the read anyway, to flush any data that might have come from a different transponder
if (r > 3) { // minimum number of bytes necessary to get section length
int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
if (len == r) {
// Distribute data to all attached filters:
int pid = fh->filterData.pid;
int tid = buf[0];
for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
if (fi->Matches(pid, tid))
fi->Process(pid, tid, buf, len);
}
}
else
dsyslog("read incomplete section - len = %d, r = %d", len, r);
}
}
}
}
}
}
}

45
sections.h Normal file
View File

@ -0,0 +1,45 @@
/*
* sections.h: Section data handling
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: sections.h 1.1 2003/12/21 14:37:00 kls Exp $
*/
#ifndef __SECTIONS_H
#define __SECTIONS_H
#include "filter.h"
#include "thread.h"
#include "tools.h"
class cDevice;
class cFilterHandle;
class cSectionHandler : public cThread {
friend class cFilter;
private:
cDevice *device;
bool active;
int source;
int transponder;
int statusCount;
bool on;
cList<cFilter> filters;
cList<cFilterHandle> filterHandles;
void Add(const cFilterData *FilterData);
void Del(const cFilterData *FilterData);
virtual void Action(void);
public:
cSectionHandler(cDevice *Device);
virtual ~cSectionHandler();
int Source(void) { return source; }
int Transponder(void) { return transponder; }
void Attach(cFilter *Filter);
void Detach(cFilter *Filter);
void SetSource(int Source, int Transponder);
void SetStatus(bool On);
};
#endif //__SECTIONS_H

17
svdrp.c
View File

@ -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.55 2003/08/31 11:24:47 kls Exp $
* $Id: svdrp.c 1.57 2003/12/28 10:09:30 kls Exp $
*/
#include "svdrp.h"
@ -155,7 +155,7 @@ bool cPUTEhandler::Process(const char *s)
else {
rewind(f);
if (cSchedules::Read(f)) {
cSIProcessor::TriggerDump();
cSchedules::Cleanup(true);
status = 250;
message = "EPG data processed";
}
@ -458,7 +458,7 @@ void cSVDRP::CmdCHAN(const char *Option)
void cSVDRP::CmdCLRE(const char *Option)
{
cSIProcessor::Clear();
cSchedules::ClearAll();
Reply(250, "EPG data cleared");
}
@ -476,7 +476,7 @@ void cSVDRP::CmdDELC(const char *Option)
}
Channels.Del(channel);
Channels.ReNumber();
Channels.Save();
Channels.SetModified();
isyslog("channel %s deleted", Option);
Reply(250, "Channel \"%s\" deleted", Option);
}
@ -707,8 +707,8 @@ void cSVDRP::CmdLSTC(const char *Option)
void cSVDRP::CmdLSTE(const char *Option)
{
cMutexLock MutexLock;
const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
cSchedulesLock SchedulesLock;
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
if (Schedules) {
FILE *f = fdopen(file, "w");
if (f) {
@ -810,9 +810,8 @@ void cSVDRP::CmdMODC(const char *Option)
if (Channels.HasUniqueChannelID(&ch, channel)) {
*channel = ch;
Channels.ReNumber();
Channels.Save();
Channels.SetModified();
isyslog("modifed channel %d %s", channel->Number(), channel->ToText());
Timers.Save();
Reply(250, "%d %s", channel->Number(), channel->ToText());
}
else
@ -886,7 +885,7 @@ void cSVDRP::CmdNEWC(const char *Option)
*channel = ch;
Channels.Add(channel);
Channels.ReNumber();
Channels.Save();
Channels.SetModified();
isyslog("new channel %d %s", channel->Number(), channel->ToText());
Reply(250, "%d %s", channel->Number(), channel->ToText());
}

112
thread.c
View File

@ -4,12 +4,14 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 1.25 2003/05/18 12:45:13 kls Exp $
* $Id: thread.c 1.30 2004/01/03 16:59:33 kls Exp $
*/
#include "thread.h"
#include <errno.h>
#include <malloc.h>
#include <signal.h>
#include <stdarg.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
@ -30,7 +32,7 @@ cCondVar::~cCondVar()
void cCondVar::Wait(cMutex &Mutex)
{
if (Mutex.locked && Mutex.lockingPid == getpid()) {
if (Mutex.locked) {
int locked = Mutex.locked;
Mutex.locked = 0; // have to clear the locked count here, as pthread_cond_wait
// does an implizit unlock of the mutex
@ -43,7 +45,7 @@ bool cCondVar::TimedWait(cMutex &Mutex, int TimeoutMs)
{
bool r = true; // true = condition signaled false = timeout
if (Mutex.locked && Mutex.lockingPid == getpid()) {
if (Mutex.locked) {
struct timeval now; // unfortunately timedwait needs the absolute time, not the delta :-(
if (gettimeofday(&now, NULL) == 0) { // get current time
now.tv_usec += TimeoutMs * 1000; // add the timeout
@ -61,7 +63,6 @@ bool cCondVar::TimedWait(cMutex &Mutex, int TimeoutMs)
if (pthread_cond_timedwait(&cond, &Mutex.mutex, &abstime) == ETIMEDOUT)
r = false;
Mutex.locked = locked;
Mutex.lockingPid = getpid();
}
}
return r;
@ -79,13 +80,46 @@ void cCondVar::Signal(void)
}
*/
// --- cRwLock ---------------------------------------------------------------
cRwLock::cRwLock(bool PreferWriter)
{
pthread_rwlockattr_t attr = { PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP };
pthread_rwlock_init(&rwlock, &attr);
}
cRwLock::~cRwLock()
{
pthread_rwlock_destroy(&rwlock);
}
bool cRwLock::Lock(bool Write, int TimeoutMs)
{
int Result = 0;
struct timespec abstime;
if (TimeoutMs) {
abstime.tv_sec = TimeoutMs / 1000;
abstime.tv_nsec = (TimeoutMs % 1000) * 1000000;
}
if (Write)
Result = TimeoutMs ? pthread_rwlock_timedwrlock(&rwlock, &abstime) : pthread_rwlock_wrlock(&rwlock);
else
Result = TimeoutMs ? pthread_rwlock_timedrdlock(&rwlock, &abstime) : pthread_rwlock_rdlock(&rwlock);
return Result == 0;
}
void cRwLock::Unlock(void)
{
pthread_rwlock_unlock(&rwlock);
}
// --- cMutex ----------------------------------------------------------------
cMutex::cMutex(void)
{
lockingPid = 0;
locked = 0;
pthread_mutex_init(&mutex, NULL);
pthread_mutexattr_t attr = { PTHREAD_MUTEX_ERRORCHECK_NP };
pthread_mutex_init(&mutex, &attr);
}
cMutex::~cMutex()
@ -95,19 +129,14 @@ cMutex::~cMutex()
void cMutex::Lock(void)
{
if (getpid() != lockingPid || !locked) {
pthread_mutex_lock(&mutex);
lockingPid = getpid();
}
pthread_mutex_lock(&mutex);
locked++;
}
void cMutex::Unlock(void)
{
if (!--locked) {
lockingPid = 0;
if (!--locked)
pthread_mutex_unlock(&mutex);
}
}
// --- cThread ---------------------------------------------------------------
@ -118,18 +147,33 @@ void cMutex::Unlock(void)
bool cThread::signalHandlerInstalled = false;
bool cThread::emergencyExitRequested = false;
cThread::cThread(void)
cThread::cThread(const char *Description)
{
if (!signalHandlerInstalled) {
signal(SIGIO, SignalHandler);
signalHandlerInstalled = true;
}
running = false;
parentPid = threadPid = 0;
parentTid = childTid = 0;
description = NULL;
SetDescription(Description);
}
cThread::~cThread()
{
free(description);
}
void cThread::SetDescription(const char *Description, ...)
{
free(description);
description = NULL;
if (Description) {
va_list ap;
va_start(ap, Description);
vasprintf(&description, Description, ap);
va_end(ap);
}
}
void cThread::SignalHandler(int signum)
@ -139,8 +183,13 @@ void cThread::SignalHandler(int signum)
void *cThread::StartThread(cThread *Thread)
{
Thread->threadPid = getpid();
Thread->childTid = pthread_self();
if (Thread->description)
dsyslog("%s thread started (pid=%d, tid=%ld)", Thread->description, getpid(), Thread->childTid);
Thread->Action();
if (Thread->description)
dsyslog("%s thread ended (pid=%d, tid=%ld)", Thread->description, getpid(), Thread->childTid);
Thread->childTid = 0;
return NULL;
}
@ -148,9 +197,9 @@ bool cThread::Start(void)
{
if (!running) {
running = true;
parentPid = getpid();
pthread_create(&thread, NULL, (void *(*) (void *))&StartThread, (void *)this);
pthread_setschedparam(thread, SCHED_RR, 0);
parentTid = pthread_self();
pthread_create(&childTid, NULL, (void *(*) (void *))&StartThread, (void *)this);
pthread_setschedparam(childTid, SCHED_RR, 0);
usleep(10000); // otherwise calling Active() immediately after Start() causes a "pure virtual method called" error
}
return true; //XXX return value of pthread_create()???
@ -158,12 +207,21 @@ bool cThread::Start(void)
bool cThread::Active(void)
{
if (threadPid) {
if (kill(threadPid, SIGIO) < 0) { // couldn't find another way of checking whether the thread is still running - any ideas?
if (errno == ESRCH)
threadPid = 0;
else
if (childTid) {
//
// Single UNIX Spec v2 says:
//
// The pthread_kill() function is used to request
// that a signal be delivered to the specified thread.
//
// As in kill(), if sig is zero, error checking is
// performed but no signal is actually sent.
//
int err;
if ((err = pthread_kill(childTid, 0)) != 0) {
if (err != ESRCH)
LOG_ERROR;
childTid = 0;
}
else
return true;
@ -180,14 +238,14 @@ void cThread::Cancel(int WaitSeconds)
return;
usleep(10000);
}
esyslog("ERROR: thread %d won't end (waited %d seconds) - cancelling it...", threadPid, WaitSeconds);
esyslog("ERROR: thread %ld won't end (waited %d seconds) - cancelling it...", childTid, WaitSeconds);
}
pthread_cancel(thread);
pthread_cancel(childTid);
}
void cThread::WakeUp(void)
{
kill(parentPid, SIGIO); // makes any waiting 'select()' call return immediately
pthread_kill(parentTid, SIGIO); // makes any waiting 'select()' call return immediately
}
bool cThread::EmergencyExit(bool Request)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.h 1.15 2003/05/03 14:03:36 kls Exp $
* $Id: thread.h 1.20 2004/01/03 16:58:50 kls Exp $
*/
#ifndef __THREAD_H
@ -28,11 +28,20 @@ public:
//void Signal(void);
};
class cRwLock {
private:
pthread_rwlock_t rwlock;
public:
cRwLock(bool PreferWriter = false);
~cRwLock();
bool Lock(bool Write, int TimeoutMs = 0);
void Unlock(void);
};
class cMutex {
friend class cCondVar;
private:
pthread_mutex_t mutex;
pid_t lockingPid;
int locked;
public:
cMutex(void);
@ -44,10 +53,10 @@ public:
class cThread {
friend class cThreadLock;
private:
pthread_t thread;
pthread_t parentTid, childTid;
cMutex mutex;
pid_t parentPid, threadPid;
bool running;
char *description;
static bool emergencyExitRequested;
static bool signalHandlerInstalled;
static void SignalHandler(int signum);
@ -59,8 +68,9 @@ protected:
virtual void Action(void) = 0;
void Cancel(int WaitSeconds = 0);
public:
cThread(void);
cThread(const char *Description = NULL);
virtual ~cThread();
void SetDescription(const char *Description, ...);
bool Start(void);
bool Active(void);
static bool EmergencyExit(bool Request = false);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: timers.c 1.6 2003/10/12 10:33:09 kls Exp $
* $Id: timers.c 1.8 2003/12/27 13:10:04 kls Exp $
*/
#include "timers.h"
@ -44,14 +44,14 @@ cTimer::cTimer(bool Instant, bool Pause)
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : channel->Name());
}
cTimer::cTimer(const cEventInfo *EventInfo)
cTimer::cTimer(const cEvent *Event)
{
startTime = stopTime = 0;
recording = pending = false;
active = true;
channel = Channels.GetByChannelID(EventInfo->GetChannelID(), true);
time_t tstart = EventInfo->GetTime();
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
channel = Channels.GetByChannelID(Event->ChannelID(), true);
time_t tstart = Event->StartTime();
time_t tstop = tstart + Event->Duration() + Setup.MarginStop * 60;
tstart -= Setup.MarginStart * 60;
struct tm tm_r;
struct tm *time = localtime_r(&tstart, &tm_r);
@ -64,9 +64,9 @@ cTimer::cTimer(const cEventInfo *EventInfo)
priority = Setup.DefaultPriority;
lifetime = Setup.DefaultLifetime;
*file = 0;
const char *Title = EventInfo->GetTitle();
const char *Title = Event->Title();
if (!isempty(Title))
strn0cpy(file, EventInfo->GetTitle(), sizeof(file));
strn0cpy(file, Event->Title(), sizeof(file));
firstday = 0;
summary = NULL;
}
@ -216,8 +216,10 @@ bool cTimer::Parse(const char *s)
strn0cpy(file, filebuffer, MaxFileName);
strreplace(file, '|', ':');
strreplace(summary, '|', '\n');
tChannelID cid = tChannelID::FromString(channelbuffer);
channel = cid.Valid() ? Channels.GetByChannelID(cid, true) : Channels.GetByNumber(atoi(channelbuffer));
if (isnumber(channelbuffer))
channel = Channels.GetByNumber(atoi(channelbuffer));
else
channel = Channels.GetByChannelID(tChannelID::FromString(channelbuffer), true);
if (!channel) {
esyslog("ERROR: channel %s not defined", channelbuffer);
result = false;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: timers.h 1.5 2003/05/11 13:35:53 kls Exp $
* $Id: timers.h 1.6 2003/12/13 13:04:21 kls Exp $
*/
#ifndef __TIMERS_H
@ -12,7 +12,7 @@
#include "channels.h"
#include "config.h"
#include "eit.h"
#include "epg.h"
#include "tools.h"
enum eTimerActive { taInactive = 0,
@ -39,7 +39,7 @@ private:
char *summary;
public:
cTimer(bool Instant = false, bool Pause = false);
cTimer(const cEventInfo *EventInfo);
cTimer(const cEvent *Event);
virtual ~cTimer();
cTimer& operator= (const cTimer &Timer);
virtual bool operator< (const cListObject &ListObject);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: transfer.c 1.14 2003/08/31 12:19:16 kls Exp $
* $Id: transfer.c 1.15 2003/10/18 11:36:03 kls Exp $
*/
#include "transfer.h"
@ -19,6 +19,7 @@
cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(0, -1, 5, VPid, APid1, APid2, DPid1, DPid2)
,cThread("transfer")
{
ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true);
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
@ -66,8 +67,6 @@ void cTransfer::Receive(uchar *Data, int Length)
void cTransfer::Action(void)
{
dsyslog("transfer thread started (pid=%d)", getpid());
int PollTimeouts = 0;
active = true;
while (active) {
@ -125,8 +124,6 @@ void cTransfer::Action(void)
else
usleep(1); // this keeps the CPU load low
}
dsyslog("transfer thread ended (pid=%d)", getpid());
}
void cTransfer::StripAudioPackets(uchar *b, int Length, uchar Except)

43
vdr.5
View File

@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
.\" $Id: vdr.5 1.20 2003/05/29 11:58:57 kls Exp $
.\" $Id: vdr.5 1.21 2004/01/02 15:24:21 kls Exp $
.\"
.TH vdr 5 "1 Jun 2003" "1.2.0" "Video Disk Recorder Files"
.SH NAME
@ -45,7 +45,7 @@ Such a delimiter will not appear in the Channels menu.
A \fBchannel definition\fR is a line with channel data, where the fields
are separated by ':' characters. Example:
\fBRTL:12188:h:S19.2E:27500:163:104:105:0:12003:0:0:0\fR
\fBRTL,RTL Television:12188:h:S19.2E:27500:163:104:105:0:12003:1:1089:0\fR
The line number of a channel definition (not counting group separators,
and based on a possible previous '@...' parameter)
@ -57,6 +57,13 @@ to right):
.B Name
The channel's name (if the name originally contains a ':' character
it has to be replaced by '|').
Some tv stations provide a way of deriving a "short name" from the
channel name, which can be used in situations where there is not
much space for displaying a long name. If a short name is available
for this channel, it preceeds the full name and is delimited by a comma,
as in
\fBRTL,RTL Television:...\fR
.TP
.B Frequency
The transponder frequency (as an integer). For DVB-S this value is in MHz. For DVB-C
@ -119,23 +126,33 @@ the audio PIDs, separated by a semicolon, as in
The teletext PID.
.TP
.B Conditional access
An integer defining how this channel can be accessed:
A hexadecimal integer defining how this channel can be accessed:
.TS
tab (@);
l l.
\fB0\fR@Free To Air
\fB1...4\fR@explicitly requires the DVB card with the given number
\fB>=100\fR@requires a specific decryption method defined in \fIca.conf\fR
\fB0000\fR@Free To Air
\fB0001...000F\fR@explicitly requires the device with the given number
\fB0010...00FF\fR@reserved for user defined assignments defined in \fIca.conf\fR
\fB0100...FFFF\fR@specific decryption methods as broadcast in the data stream\fR
.TE
Values in the range 0001...00FF will not be overwritten, all other values
will be automatically replaced by the actual CA system identifiers received
from the data stream. If there is more than one CA system id broadcast, they
will be separated by commas, as in
.B ...:1702,1722,1801:...
The values are in hex because that's the way they are defined in the "ETR 162"
document. Leading zeros may be omitted.
.TP
.B SID
The Service ID of this channel.
.TP
.B NID
The Network ID of this channel (for future use, currently always 0).
The Network ID of this channel.
.TP
.B TID
The Transport stream ID of this channel (for future use, currently always 0).
The Transport stream ID of this channel.
.TP
.B RID
The Radio ID of this channel (typically 0, may be used to distinguish channels where
@ -144,12 +161,12 @@ NID, TID and SID are all equal).
A particular channel can be uniquely identified by its \fBchannel\ ID\fR,
which is a string that looks like this:
\fBS19.2E-0-12188-12003-0\fR
\fBS19.2E-1-1089-12003-0\fR
The components of this string are the \fBSource\fR (S19.2E), \fBFrequency\fR
(12188, MHz) and \fBSID\fR (12003) as defined above. The parts that are currently
\fB0\fR are reserved for future use (the last part can be omitted if it is \fB0\fR,
so the above example could also be written as \fBS19.2E-0-12188-12003\fR).
The components of this string are the \fBSource\fR (S19.2E), \fBNID\fR
(1), \fBTID\fR (1089), \fBSID\fR (12003) and \fBRID\fR (0) as defined above.
The last part can be omitted if it is \fB0\fR,
so the above example could also be written as S19.2E-1-1089-12003).
.br
The \fBchannel\ ID\fR is used in the \fItimers.conf\fR and \fIepg.data\fR
files to properly identify the channels.

48
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/vdr
*
* $Id: vdr.c 1.169 2003/09/14 09:36:54 kls Exp $
* $Id: vdr.c 1.172 2004/01/04 11:12:05 kls Exp $
*/
#include <getopt.h>
@ -39,6 +39,7 @@
#include "diseqc.h"
#include "dvbdevice.h"
#include "eitscan.h"
#include "epg.h"
#include "i18n.h"
#include "interface.h"
#include "keys.h"
@ -93,10 +94,12 @@ int main(int argc, char *argv[])
#define DEFAULTSVDRPPORT 2001
#define DEFAULTWATCHDOG 0 // seconds
#define DEFAULTPLUGINDIR PLUGINDIR
#define DEFAULTEPGDATAFILENAME "epg.data"
int SVDRPport = DEFAULTSVDRPPORT;
const char *AudioCommand = NULL;
const char *ConfigDirectory = NULL;
const char *EpgDataFileName = DEFAULTEPGDATAFILENAME;
bool DisplayHelp = false;
bool DisplayVersion = false;
bool DaemonMode = false;
@ -146,7 +149,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg);
return 2;
break;
case 'E': cSIProcessor::SetEpgDataFileName(*optarg != '-' ? optarg : NULL);
case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL);
break;
case 'h': DisplayHelp = true;
break;
@ -239,7 +242,8 @@ int main(int argc, char *argv[])
" there may be several -D options (default: all DVB\n"
" devices will be used)\n"
" -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n"
" %s); use '-E-' to disable this\n"
" '%s' in the video directory)\n"
" '-E-' disables this\n"
" if FILE is a directory, the default EPG file will be\n"
" created in that directory\n"
" -h, --help print this help and exit\n"
@ -261,7 +265,7 @@ int main(int argc, char *argv[])
" -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
" seconds (default: %d); '0' disables the watchdog\n"
"\n",
cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'",
DEFAULTEPGDATAFILENAME,
DEFAULTPLUGINDIR,
DEFAULTSVDRPPORT,
VideoDirectory,
@ -358,6 +362,19 @@ int main(int argc, char *argv[])
))
return 2;
cFont::SetCode(I18nCharSets()[Setup.OSDLanguage]);
// EPG data:
if (EpgDataFileName) {
if (DirectoryOk(EpgDataFileName))
EpgDataFileName = AddDirectory(EpgDataFileName, DEFAULTEPGDATAFILENAME);
else if (*EpgDataFileName != '/' && *EpgDataFileName != '.')
EpgDataFileName = AddDirectory(VideoDirectory, EpgDataFileName);
}
cSchedules::SetEpgDataFileName(EpgDataFileName);
cSchedules::Read();
// DVB interfaces:
cDvbDevice::Initialize();
@ -436,8 +453,6 @@ int main(int argc, char *argv[])
else
cDevice::PrimaryDevice()->SetVolume(Setup.CurrentVolume, true);
cSIProcessor::Read();
// Signal handlers:
if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
@ -496,6 +511,25 @@ int main(int argc, char *argv[])
dsyslog("max. latency time %d seconds", MaxLatencyTime);
}
}
// Handle channel modifications:
if (!Channels.BeingEdited() && Channels.Modified()) {
if (Channels.Lock(false, 100)) {
Channels.Save(); //XXX only after user changes???
Timers.Save();
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
if (Channel && Channel->Modification(CHANNELMOD_RETUNE)) {
cRecordControls::ChannelDataModified(Channel);
if (Channel->Number() == cDevice::CurrentChannel()) {
if (!cDevice::PrimaryDevice()->Replaying()) {
isyslog("retuning due to modification of channel %d", Channel->Number());
Channels.SwitchTo(Channel->Number());
}
}
}
}
Channels.Unlock();
}
}
// Channel display:
if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
if (!Menu)
@ -779,6 +813,7 @@ int main(int argc, char *argv[])
}
// Disk housekeeping:
RemoveDeletedRecordings();
cSchedules::Cleanup();
// Plugins housekeeping:
PluginManager.Housekeeping();
}
@ -799,6 +834,7 @@ int main(int argc, char *argv[])
Setup.Save();
cDevice::Shutdown();
PluginManager.Shutdown(true);
ReportEpgBugFixStats();
if (WatchdogTimeout > 0)
dsyslog("max. latency time %d seconds", MaxLatencyTime);
isyslog("exiting");