Version 1.1.6

- Re-visited the race condition fix in the cDvbPlayer (thanks again to Andreas
  Schultz).
- Changed the VFAT handling to allow users who normally use it but have forgotten
  to set it when compiling a new version of VDR to at least see their recordings
  made with VFAT enabled (thanks to Christian Rienecker).
- Added some missing teletext PIDs (thanks to Joerg Riechardt).
- Fixed PID handling for cReceiver.
- Added a missing #include to ringbuffer.c (thanks to Martin Hammerschmid).
- Now using CC, CFLAGS, CXX and CXXFLAGS in Makefile.
- Changed the cDevice class to allow plugins to implement their own devices (see
  PLUGINS.html for details).
This commit is contained in:
Klaus Schmidinger 2002-08-04 18:00:00 +02:00
parent a4112a96a6
commit 527748826c
28 changed files with 1287 additions and 706 deletions

View File

@ -44,6 +44,7 @@ Martin Hammerschmid <martin@hammerschmid.com>
for suggesting to use the "Blue" button in the main menu to resume replay for suggesting to use the "Blue" button in the main menu to resume replay
for implementing pege up/down with the "Left" and "Right" keys for implementing pege up/down with the "Left" and "Right" keys
for detecting a deadlock when switching channels via Schedule/Now|Next/Switch for detecting a deadlock when switching channels via Schedule/Now|Next/Switch
for adding a missing #include to ringbuffer.c
Bastian Guse <bastian@nocopy.de> Bastian Guse <bastian@nocopy.de>
for writing the FORMATS entry for timers.conf for writing the FORMATS entry for timers.conf
@ -367,3 +368,9 @@ Paul Lacatus <paul@campina.iiruc.ro>
Istvan Koenigsberger <istvnko@hotmail.com> and Guido Josten <guido.josten@t-online.de> Istvan Koenigsberger <istvnko@hotmail.com> and Guido Josten <guido.josten@t-online.de>
for translating OSD texts to the Hungarian language for translating OSD texts to the Hungarian language
Christian Rienecker <C.Rienecker@deutschepost.de>
for making the VFAT handling more tolerant for users who forget to turn it on
Joerg Riechardt <J.Riechardt@gmx.de>
for filling in some missing teletext PIDs

14
HISTORY
View File

@ -1378,3 +1378,17 @@ Video Disk Recorder Revision History
- Fixed a possible race condition in the cDvbPlayer (thanks to Andreas Schultz - Fixed a possible race condition in the cDvbPlayer (thanks to Andreas Schultz
for pointing out this one). for pointing out this one).
- Disabled channels on Transponder 12070 in 'channels.conf', which apparently no longer transmits. - Disabled channels on Transponder 12070 in 'channels.conf', which apparently no longer transmits.
2002-08-04: Version 1.1.6
- Re-visited the race condition fix in the cDvbPlayer (thanks again to Andreas
Schultz).
- Changed the VFAT handling to allow users who normally use it but have forgotten
to set it when compiling a new version of VDR to at least see their recordings
made with VFAT enabled (thanks to Christian Rienecker).
- Added some missing teletext PIDs (thanks to Joerg Riechardt).
- Fixed PID handling for cReceiver.
- Added a missing #include to ringbuffer.c (thanks to Martin Hammerschmid).
- Now using CC, CFLAGS, CXX and CXXFLAGS in Makefile.
- Changed the cDevice class to allow plugins to implement their own devices (see
PLUGINS.html for details).

View File

@ -4,10 +4,16 @@
# See the main source file 'vdr.c' for copyright information and # See the main source file 'vdr.c' for copyright information and
# how to reach the author. # how to reach the author.
# #
# $Id: Makefile 1.42 2002/06/22 10:21:56 kls Exp $ # $Id: Makefile 1.44 2002/07/28 15:20:47 kls Exp $
.DELETE_ON_ERROR: .DELETE_ON_ERROR:
CC = gcc
CFLAGS = -O2
CXX = g++
CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual
DVBDIR = ../DVB DVBDIR = ../DVB
DTVDIR = ./libdtv DTVDIR = ./libdtv
MANDIR = /usr/local/man MANDIR = /usr/local/man
@ -21,7 +27,7 @@ INCLUDES = -I$(DVBDIR)/ost/include
DTVLIB = $(DTVDIR)/libdtv.a DTVLIB = $(DTVDIR)/libdtv.a
OBJS = audio.o config.o cutter.o device.o dvbplayer.o dvbosd.o eit.o eitscan.o font.o i18n.o\ OBJS = audio.o config.o cutter.o device.o dvbdevice.o dvbosd.o dvbplayer.o eit.o eitscan.o font.o i18n.o\
interface.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o receiver.o\ interface.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o receiver.o\
recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\ recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\
tools.o transfer.o vdr.o videodir.o tools.o transfer.o vdr.o videodir.o
@ -58,11 +64,11 @@ font: genfontfile fontfix.c fontosd.c
# Implicit rules: # Implicit rules:
%.o: %.c %.o: %.c
g++ -g -O2 -Wall -Woverloaded-virtual -c $(DEFINES) $(INCLUDES) $< $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies: # Dependencies:
MAKEDEP = g++ -MM -MG MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies DEPFILE = .dependencies
$(DEPFILE): Makefile $(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
@ -72,7 +78,7 @@ $(DEPFILE): Makefile
# The main program: # The main program:
vdr: $(OBJS) $(DTVLIB) vdr: $(OBJS) $(DTVLIB)
g++ -g -O2 -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr
# The font files: # The font files:
@ -84,7 +90,7 @@ fontosd.c:
# The font file generator: # The font file generator:
genfontfile: genfontfile.c genfontfile: genfontfile.c
gcc -o $@ -O2 -L/usr/X11R6/lib $< -lX11 $(CC) $(CFLAGS) -o $@ -L/usr/X11R6/lib $< -lX11
# The libdtv library: # The libdtv library:

View File

@ -12,7 +12,7 @@ This interface allows programmers to develop additional functionality for VDR co
separate from the core VDR source, without the need of patching the original separate from the core VDR source, without the need of patching the original
VDR code (and all the problems of correlating various patches). VDR code (and all the problems of correlating various patches).
<p> <p>
<!--X1.1.3--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%> <!--X1.1.3--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
This document is divided into two parts, the first one describing the This document is divided into two parts, the first one describing the
<a href="#Part I - The Outside Interface"><i>outside</i> interface</a> <a href="#Part I - The Outside Interface"><i>outside</i> interface</a>
of the plugin system, and the second one describing the of the plugin system, and the second one describing the
@ -23,18 +23,18 @@ The <i>inside</i> interface provides the plugin code access to VDR's internal da
structures and allows it to hook itself into specific areas to perform special actions. structures and allows it to hook itself into specific areas to perform special actions.
<!--X1.1.3--></td></tr></table> <!--X1.1.3--></td></tr></table>
<p> <p>
<!--X1.1.2--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%> <!--X1.1.3--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.2 are marked like this.
<!--X1.1.2--></td></tr></table>
<!--X1.1.3--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.3 are marked like this. Important modifications introduced in version 1.1.3 are marked like this.
<!--X1.1.3--></td></tr></table> <!--X1.1.3--></td></tr></table>
<!--X1.1.4--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%> <!--X1.1.4--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.4 are marked like this. Important modifications introduced in version 1.1.4 are marked like this.
<!--X1.1.4--></td></tr></table> <!--X1.1.4--></td></tr></table>
<!--X1.1.5--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%> <!--X1.1.5--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.5 are marked like this. Important modifications introduced in version 1.1.5 are marked like this.
<!--X1.1.5--></td></tr></table> <!--X1.1.5--></td></tr></table>
<!--X1.1.6--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.6 are marked like this.
<!--X1.1.6--></td></tr></table>
<a name="Part I - The Outside Interface"><hr><center><h1>Part I - The Outside Interface</h1></center> <a name="Part I - The Outside Interface"><hr><center><h1>Part I - The Outside Interface</h1></center>
@ -131,15 +131,12 @@ from the web, it will typically have a name like
<p> <p>
and will unpack into a directory named and will unpack into a directory named
<p> <p>
<!--X1.1.2--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<tt>hello-0.0.1</tt> <tt>hello-0.0.1</tt>
<!--X1.1.2--></td></tr></table>
<p> <p>
To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>Makefile</tt> To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>Makefile</tt>
you need to unpack such an archive into the <tt>VDR/PLUGINS/SRC</tt> directory and 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 create a symbolic link with the basic plugin name, as in
<!--X1.1.2--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
ln -s hello-0.0.1 hello ln -s hello-0.0.1 hello
</pre></td></tr></table><p> </pre></td></tr></table><p>
@ -149,7 +146,6 @@ of only lowercase characters and digits, it will only follow the symbolic links,
should lead to the current version of the plugin you want to use. This way you can should lead to the current version of the plugin you want to use. This way you can
have several different versions of a plugin source (like <tt>hello-0.0.1</tt> and have several different versions of a plugin source (like <tt>hello-0.0.1</tt> and
<tt>hello-0.0.2</tt>) and define which one to actually use through the symbolic link. <tt>hello-0.0.2</tt>) and define which one to actually use through the symbolic link.
<!--X1.1.2--></td></tr></table>
<a name="Initializing a new plugin directory"><hr><h2>Initializing a new plugin directory</h2> <a name="Initializing a new plugin directory"><hr><h2>Initializing a new plugin directory</h2>
@ -422,11 +418,9 @@ 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>, thread of its own), or wants to make use of <a href="#Internationalization">internationalization</a>,
it needs to implement the function it needs to implement the function
<!--X1.1.2--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
virtual bool Start(void); virtual bool Start(void);
</pre></td></tr></table><p> </pre></td></tr></table><p>
<!--X1.1.2--></td></tr></table>
which is called once for each plugin at program startup. which is called once for each plugin at program startup.
Inside this function the plugin must set up everything necessary to perform Inside this function the plugin must set up everything necessary to perform
@ -434,12 +428,10 @@ its task. This may, for instance, be a thread that collects data from the DVB
stream, which is later presented to the user via a function that is available stream, which is later presented to the user via a function that is available
from the main menu. from the main menu.
<p> <p>
<!--X1.1.2--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
A return value of <i>false</i> indicates that something has gone wrong and the A return value of <i>false</i> indicates that something has gone wrong and the
plugin will not be able to perform its task. In that case, the plugin should plugin will not be able to perform its task. In that case, the plugin should
write a proper error message to the log file. The first plugin that returns write a proper error message to the log file. The first plugin that returns
<i>false</i> from its <tt>Start()</tt> function will cause VDR to exit. <i>false</i> from its <tt>Start()</tt> function will cause VDR to exit.
<!--X1.1.2--></td></tr></table>
<p> <p>
If the plugin doesn't implement any background functionality or internationalized If the plugin doesn't implement any background functionality or internationalized
texts, it doesn't need to implement this function. texts, it doesn't need to implement this function.
@ -498,7 +490,6 @@ interaction is possible. If a specific action takes longer than a few seconds,
the plugin should launch a separate thread to do this. the plugin should launch a separate thread to do this.
</b> </b>
<!--X1.1.2--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<hr><h2>Housekeeping</h2> <hr><h2>Housekeeping</h2>
<center><i><b>Chores, chores...</b></i></center><p> <center><i><b>Chores, chores...</b></i></center><p>
@ -523,7 +514,6 @@ as possible! As long as the program stays inside this function, no other user
interaction is possible. If a specific action takes longer than a few seconds, interaction is possible. If a specific action takes longer than a few seconds,
the plugin should launch a separate thread to do this. the plugin should launch a separate thread to do this.
</b> </b>
<!--X1.1.2--></td></tr></table>
<a name="Setup parameters"><hr><h2>Setup parameters</h2> <a name="Setup parameters"><hr><h2>Setup parameters</h2>
@ -656,7 +646,6 @@ You can first assign the temporary values to the global variables and then do th
your setup parameters and use that one to copy all parameters with one single statement your setup parameters and use that one to copy all parameters with one single statement
(like VDR does with its cSetup class). (like VDR does with its cSetup class).
<!--X1.1.2--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<hr><h2>Configuration files</h2> <hr><h2>Configuration files</h2>
<center><i><b>I want my own stuff!</b></i></center><p> <center><i><b>I want my own stuff!</b></i></center><p>
@ -711,7 +700,6 @@ plugin class, by writing
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
const char *MyConfigDir = cPlugin::ConfigDirectory(); const char *MyConfigDir = cPlugin::ConfigDirectory();
</pre></td></tr></table><p> </pre></td></tr></table><p>
<!--X1.1.2--></td></tr></table>
<a name="Internationalization"><hr><h2>Internationalization</h2> <a name="Internationalization"><hr><h2>Internationalization</h2>
@ -826,7 +814,7 @@ and display their help and/or version information in addition to its own output.
If you want to make your plugin available to other VDR users, you'll need to If you want to make your plugin available to other VDR users, you'll need to
make a package that can be easily distributed. make a package that can be easily distributed.
<!--X1.1.3--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%> <!--X1.1.3--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
The <tt>Makefile</tt> that has been created by the call to The <tt>Makefile</tt> that has been created by the call to
<a href="#Initializing a new plugin directory"><tt>newplugin</tt></a> <a href="#Initializing a new plugin directory"><tt>newplugin</tt></a>
provides the target <tt>dist</tt>, which does this for you. provides the target <tt>dist</tt>, which does this for you.
@ -848,7 +836,7 @@ vdr-hello-0.0.1.tgz
in your source directory, where <tt>hello</tt> will be replaced with your actual in your source directory, where <tt>hello</tt> will be replaced with your actual
plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number. plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number.
<!--X1.1.3--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%> <!--X1.1.3--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<a name="Part II - The Inside Interface"><hr><center><h1>Part II - The Inside Interface</h1></center> <a name="Part II - The Inside Interface"><hr><center><h1>Part II - The Inside Interface</h1></center>
<hr><h2>Status monitor</h2> <hr><h2>Status monitor</h2>
@ -925,7 +913,7 @@ member functions are available in <tt>cStatus</tt>. You only need to implement
the functions you actually want to use. the functions you actually want to use.
<!--X1.1.3--></td></tr></table> <!--X1.1.3--></td></tr></table>
<!--X1.1.4--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%> <!--X1.1.4--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<hr><h2>Players</h2> <hr><h2>Players</h2>
<center><i><b>Play it again, Sam!</b></i></center><p> <center><i><b>Play it again, Sam!</b></i></center><p>
@ -1076,7 +1064,63 @@ that they already know. If you absolutely want to do things differently, just go
ahead - it's your show... ahead - it's your show...
<!--X1.1.4--></td></tr></table> <!--X1.1.4--></td></tr></table>
<!--X1.1.5--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%> <!--X1.1.6--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<hr><h2>Receivers</h2>
<center><i><b>Tapping into the stream...</b></i></center><p>
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>
#include &lt;vdr/receiver.h&gt;
class cMyReceiver : public cReceiver, cThread {
protected:
virtual void Activate(bool On);
virtual void Receive(uchar *Data, int Length);
public:
cMyReceiver(int Pid);
};
cMyReceiver::cMyReceiver(int Pid)
:cReceiver(0, -1, 1, Pid)
{
}
void cMyReceiver::Activate(bool On)
{
// start your own thread for processing the received data
}
void cMyReceiver::Receive(uchar *Data, int Length)
{
// buffer the data for processing in a separate thread
}
</pre></td></tr></table><p>
See the comments in <tt>VDR/receiver.h</tt> for details about the various
member functions of <tt>cReceiver</tt>.
<p>
The above example sets up a receiver that wants to receive data from only one
PID (for example the Teletext PID). In order to not interfere with other recording
operations, it sets its priority to <tt>-1</tt> (any negative value will allow
a <tt>cReceiver</tt> to be detached from its <tt>cDevice</tt> at any time.
<p>
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>
cMyReceiver *Receiver = new cMyReceiver(123);
cDevice::PrimaryDevice()-&gt;AttachReceiver(Receiver);
</pre></td></tr></table><p>
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.1.6--></td></tr></table>
<!--X1.1.5--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
<hr><h2>The On Screen Display</h2> <hr><h2>The On Screen Display</h2>
<center><i><b>Express yourself</b></i></center><p> <center><i><b>Express yourself</b></i></center><p>
@ -1108,5 +1152,122 @@ of these functions, and VDR/osd.c to see how VDR opens the OSD and sets up
its windows and color depths). its windows and color depths).
<!--X1.1.5--></td></tr></table> <!--X1.1.5--></td></tr></table>
<!--X1.1.6--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<hr><h2>Devices</h2>
<center><i><b>Expanding the possibilities</b></i></center><p>
By default VDR is based on using DVB PCI cards that are supported by the
LinuxDVB driver. However, a plugin can implement additional devices that
can be used as sources of MPEG data for viewing or recording, and also
as output devices for replaying. Such a device can be a physical card
that is installed in the PC (like, for instance, an MPEG encoder card that
allows the analog signal of a proprietary set-top box to be integrated
into a VDR system; or an analog TV receiver card, which does the MPEG encoding
"on the fly" - assuming your machine is fast enough), or just a software program that takes an MPEG data
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>
#include &lt;vdr/device.h&gt;
class cMyDevice : public cDevice {
...
};
</pre></td></tr></table><p>
The derived class must implement several virtual functions, according to
the abilities this new class of devices can provide. See the comments in the
file <tt>VDR/device.h</tt> for more information on the various functions,
and also <tt>VDR/dvbdevice.[hc]</tt> for details on the implementation of
the <tt>cDvbDevice</tt>, which is used to access the DVB PCI cards.
<p>
<b>Channel selection</b>
<p>
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>
virtual bool SetChannelDevice(const cChannel *Channel);
</pre></td></tr></table><p>
This function will be called with the desired channel and shall return whether
tuning to it was successful.
<p>
<b>Recording</b>
<p>
A device that can be used for recording must implement the functions
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
virtual bool OpenDvr(void);
virtual void CloseDvr(void);
virtual int GetTSPacket(uchar *Data);
</pre></td></tr></table><p>
which allow VDR to set the PIDs that shall be recorded, set up the device fro
recording (and shut it down again), and receive the MPEG data stream. The data
must be delivered in the form of a Transport Stream (TS), which consists of
packets that are all 188 bytes in size. Each call to <tt>GetTSPacket()</tt>
must deliver exactly one such packet (if one is currently available).
<p>
If this device allows receiving several different data streams, it can
implement
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
virtual bool CanBeReUsed(int Frequency, int Vpid);
</pre></td></tr></table><p>
to indicate this to VDR.
<p>
<b>Replaying</b>
<p>
The functions to implement replaying capabilites are
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
virtual bool HasDecoder(void) const;
virtual int SetPlayMode(bool On);
virtual void TrickSpeed(int Speed);
virtual void Clear(void);
virtual void Play(void);
virtual void Freeze(void);
virtual void Mute(void);
virtual void StillPicture(const uchar *Data, int Length);
virtual int PlayVideo(const uchar *Data, int Length);
</pre></td></tr></table><p>
In addition, the following functions may be implemented to provide further
functionality:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
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>
<b>Initializing new devices</b>
<p>
A derived cDevice class shall implement a static function
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
static bool Initialize(void);
</pre></td></tr></table><p>
in which it determines whether the necessary hardware to run this sort of
device is actually present in this machine (or whatever other prerequisites
might be important), and then creates as many device objects as necessary.
See <tt>VDR/dvbdevice.c</tt> for the implementation of the <tt>cDvbDevice</tt>
initialize function.
<p>
A plugin that adds devices to a VDR instance shall call this initializing
function from its <a href="#Getting started"><tt>Start()</tt></a> function.
<p>
Nothing needs to be done to shut down the devices. VDR will automatically
shut down (delete) all devices when the program terminates. It is therefore
important that the devices are created on the heap, using the <tt>new</tt>
operator!
<!--X1.1.6--></td></tr></table>
</body> </body>
</html> </html>

View File

@ -18,3 +18,7 @@ VDR Plugin 'hello' Revision History
2002-05-17: Version 0.0.4 2002-05-17: Version 0.0.4
- Makefile improvements. - Makefile improvements.
2002-08-04: Version 0.0.5
- Added a missing #include.

View File

@ -3,15 +3,16 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: hello.c 1.5 2002/05/14 21:23:25 kls Exp $ * $Id: hello.c 1.6 2002/08/04 15:13:35 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
#include <stdlib.h>
#include <vdr/interface.h> #include <vdr/interface.h>
#include <vdr/plugin.h> #include <vdr/plugin.h>
#include "i18n.h" #include "i18n.h"
static const char *VERSION = "0.0.4"; static const char *VERSION = "0.0.5";
static const char *DESCRIPTION = "A friendly greeting"; static const char *DESCRIPTION = "A friendly greeting";
static const char *MAINMENUENTRY = "Hello"; static const char *MAINMENUENTRY = "Hello";

View File

@ -7,7 +7,7 @@ BR3:11837:h:0:27500:201:202:204:0:28107
Hessen-3:11837:h:0:27500:301:302:304:0:28108 Hessen-3:11837:h:0:27500:301:302:304:0:28108
N3:12110:h:0:27500:2401:2402:2404:0:28224 N3:12110:h:0:27500:2401:2402:2404:0:28224
SR3:11837:h:0:27500:501:502:504:0:28110 SR3:11837:h:0:27500:501:502:504:0:28110
WDR:11837:h:0:27500:601:602:0:0:28111 WDR:11837:h:0:27500:601:602:604:0:28111
BR-alpha:11837:h:0:27500:701:702:704:0:28112 BR-alpha:11837:h:0:27500:701:702:704:0:28112
SWR BW:11837:h:0:27500:801:802:804:0:28113 SWR BW:11837:h:0:27500:801:802:804:0:28113
Phoenix:11837:h:0:27500:901:902:904:0:28114 Phoenix:11837:h:0:27500:901:902:904:0:28114
@ -24,7 +24,7 @@ Super RTL:12188:h:0:27500:165:120:65:0:12040
VOX:12188:h:0:27500:167:136:0:0:12060 VOX:12188:h:0:27500:167:136:0:0:12060
DW TV:10788:v:0:22000:305:306:0:0:8905 DW TV:10788:v:0:22000:305:306:0:0:8905
Kabel 1:12480:v:0:27500:511:512:33:0:899 Kabel 1:12480:v:0:27500:511:512:33:0:899
Neun Live:12480:v:0:27500:767:768:0:0:897 Neun Live:12480:v:0:27500:767:768:35:0:897
DSF:12480:v:0:27500:1023:1024:0:0:900 DSF:12480:v:0:27500:1023:1024:0:0:900
HOT:12480:v:0:27500:1279:1280:0:0:40 HOT:12480:v:0:27500:1279:1280:0:0:40
Bloomberg TV Germany:12551:v:0:22000:162:99:0:0:12160 Bloomberg TV Germany:12551:v:0:22000:162:99:0:0:12160
@ -111,7 +111,7 @@ BuLi 7:11719:h:0:27500:3327:3328,3329:0:101:245
BuLi 8:12031:h:0:27500:3071:3072,3073:0:101:208 BuLi 8:12031:h:0:27500:3071:3072,3073:0:101:208
BuLi 9:12031:h:0:27500:3327:3328,3329:0:101:209 BuLi 9:12031:h:0:27500:3327:3328,3329:0:101:209
: :
TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 :#TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601
Mosaico:11934:v:0:27500:165:100:0:0:29010 Mosaico:11934:v:0:27500:165:100:0:0:29010
Andalucia TV:11934:v:0:27500:166:104:0:0:29011 Andalucia TV:11934:v:0:27500:166:104:0:0:29011
TVC Internacional:11934:v:0:27500:167:108:0:0:0 TVC Internacional:11934:v:0:27500:167:108:0:0:0

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.102 2002/06/16 12:57:31 kls Exp $ * $Id: config.c 1.103 2002/08/04 12:03:11 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -301,7 +301,7 @@ bool cChannel::Switch(cDevice *Device, bool Log)
if (Log) if (Log)
isyslog("switching to channel %d", number); isyslog("switching to channel %d", number);
for (int i = 3; i--;) { for (int i = 3; i--;) {
switch (Device->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, tpid, ca, pnr)) { switch (Device->SetChannel(this)) {
case scrOk: return true; case scrOk: return true;
case scrNoTransfer: if (Interface) case scrNoTransfer: if (Interface)
Interface->Error(tr("Can't start Transfer Mode!")); Interface->Error(tr("Can't start Transfer Mode!"));
@ -1018,7 +1018,7 @@ cSetup::cSetup(void)
DefaultLifetime = 50; DefaultLifetime = 50;
UseSubtitle = 1; UseSubtitle = 1;
RecordingDirs = 1; RecordingDirs = 1;
VideoFormat = VIDEO_FORMAT_4_3; VideoFormat = 0;
RecordDolbyDigital = 1; RecordDolbyDigital = 1;
ChannelInfoPos = 0; ChannelInfoPos = 0;
OSDwidth = 52; OSDwidth = 52;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.120 2002/07/13 09:46:59 kls Exp $ * $Id: config.h 1.121 2002/07/27 12:00:30 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -19,7 +19,7 @@
#include "eit.h" #include "eit.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "1.1.5" #define VDRVERSION "1.1.6"
#define MAXPRIORITY 99 #define MAXPRIORITY 99
#define MAXLIFETIME 99 #define MAXLIFETIME 99

697
device.c
View File

@ -4,108 +4,42 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.c 1.5 2002/06/23 12:51:24 kls Exp $ * $Id: device.c 1.8 2002/08/04 15:18:05 kls Exp $
*/ */
#include "device.h" #include "device.h"
#include <errno.h> #include <errno.h>
extern "C" {
#define HAVE_BOOLEAN
#include <jpeglib.h>
}
#include <linux/videodev.h>
#include <ost/sec.h>
#include <poll.h> #include <poll.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include "eit.h"
#include "player.h" #include "player.h"
#include "receiver.h" #include "receiver.h"
#include "status.h" #include "status.h"
#include "transfer.h" #include "transfer.h"
#define DEV_VIDEO "/dev/video" // The default priority for non-primary devices:
#define DEV_OST_OSD "/dev/ost/osd"
#define DEV_OST_FRONTEND "/dev/ost/frontend"
#define DEV_OST_SEC "/dev/ost/sec"
#define DEV_OST_DVR "/dev/ost/dvr"
#define DEV_OST_DEMUX "/dev/ost/demux"
#define DEV_OST_VIDEO "/dev/ost/video"
#define DEV_OST_AUDIO "/dev/ost/audio"
// The default priority for non-primary DVB cards:
#define DEFAULTPRIORITY -2 #define DEFAULTPRIORITY -2
#define TS_SIZE 188
#define TS_SYNC_BYTE 0x47
#define PID_MASK_HI 0x1F
// The maximum time we wait before assuming that a recorded video data stream // The maximum time we wait before assuming that a recorded video data stream
// is broken: // is broken:
#define MAXBROKENTIMEOUT 30 // seconds #define MAXBROKENTIMEOUT 30 // seconds
static const char *OstName(const char *Name, int n)
{
static char buffer[_POSIX_PATH_MAX];
snprintf(buffer, sizeof(buffer), "%s%d", Name, n);
return buffer;
}
static int OstOpen(const char *Name, int n, int Mode, bool ReportError = false)
{
const char *FileName = OstName(Name, n);
int fd = open(FileName, Mode);
if (fd < 0 && ReportError)
LOG_ERROR_STR(FileName);
return fd;
}
int cDevice::numDevices = 0; int cDevice::numDevices = 0;
int cDevice::useDevice = 0; int cDevice::useDevice = 0;
int cDevice::nextCardIndex = 0;
cDevice *cDevice::device[MAXDEVICES] = { NULL }; cDevice *cDevice::device[MAXDEVICES] = { NULL };
cDevice *cDevice::primaryDevice = NULL; cDevice *cDevice::primaryDevice = NULL;
cDevice::cDevice(int n) cDevice::cDevice(void)
{ {
frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN cardIndex = nextCardIndex++;
siProcessor = NULL;
cardIndex = n;
// Devices that are present on all card types: SetVideoFormat(Setup.VideoFormat);
fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR);
// Devices that are only present on DVB-S cards:
fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
// Devices that are only present on cards with decoders:
fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR);
fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
// Video format:
SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
// We only check the devices that must be present - the others will be checked before accessing them://XXX
if (fd_frontend >= 0) {
siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
FrontendInfo feinfo;
if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0)
frontendType = feinfo.type;
else
LOG_ERROR;
}
else
esyslog("ERROR: can't open video device %d", n);
dvrFileName = strdup(OstName(DEV_OST_DVR, CardIndex()));
active = false; active = false;
currentChannel = 0; currentChannel = 0;
frequency = 0;
mute = false; mute = false;
volume = Setup.CurrentVolume; volume = Setup.CurrentVolume;
@ -115,17 +49,20 @@ cDevice::cDevice(int n)
for (int i = 0; i < MAXRECEIVERS; i++) for (int i = 0; i < MAXRECEIVERS; i++)
receiver[i] = NULL; receiver[i] = NULL;
ca = -1; ca = -1;
if (numDevices < MAXDEVICES) {
device[numDevices++] = this;
SetCaCaps(cardIndex);
}
else
esyslog("ERROR: too many devices!");
} }
cDevice::~cDevice() cDevice::~cDevice()
{ {
delete dvrFileName;
delete siProcessor;
Detach(player); Detach(player);
for (int i = 0; i < MAXRECEIVERS; i++) for (int i = 0; i < MAXRECEIVERS; i++)
Detach(receiver[i]); Detach(receiver[i]);
// We're not explicitly closing any device files here, since this sometimes
// caused segfaults. Besides, the program is about to terminate anyway...
} }
void cDevice::SetUseDevice(int n) void cDevice::SetUseDevice(int n)
@ -134,15 +71,44 @@ void cDevice::SetUseDevice(int n)
useDevice |= (1 << n); useDevice |= (1 << n);
} }
int cDevice::NextCardIndex(int n)
{
if (n > 0) {
nextCardIndex += n;
if (nextCardIndex >= MAXDEVICES)
esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
}
else if (n < 0)
esyslog("ERROR: illegal value in IncCardIndex(%d)", n);
return nextCardIndex;
}
void cDevice::MakePrimaryDevice(bool On)
{
}
bool cDevice::SetPrimaryDevice(int n) bool cDevice::SetPrimaryDevice(int n)
{ {
n--; n--;
if (0 <= n && n < numDevices && device[n]) { if (0 <= n && n < numDevices && device[n]) {
isyslog("setting primary device to %d", n + 1); isyslog("setting primary device to %d", n + 1);
if (primaryDevice)
primaryDevice->MakePrimaryDevice(false);
primaryDevice = device[n]; primaryDevice = device[n];
primaryDevice->MakePrimaryDevice(true);
return true; return true;
} }
esyslog("invalid devive number: %d", n + 1); esyslog("invalid device number: %d", n + 1);
return false;
}
bool cDevice::CanBeReUsed(int Frequency, int Vpid)
{
return false;
}
bool cDevice::HasDecoder(void) const
{
return false; return false;
} }
@ -156,20 +122,7 @@ cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool
for (int i = 0; i < numDevices; i++) { for (int i = 0; i < numDevices; i++) {
if ((Provides[i] = device[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job if ((Provides[i] = device[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job
//XXX+ dsyslog("GetDevice: %d %d %d %5d %5d", i, device[i]->HasDecoder(), device[i]->Receiving(), Frequency, device[i]->frequency);//XXX //XXX+ dsyslog("GetDevice: %d %d %d %5d %5d", i, device[i]->HasDecoder(), device[i]->Receiving(), Frequency, device[i]->frequency);//XXX
if ( (!device[i]->HasDecoder() // it's a "budget card" which can receive multiple channels... if (device[i]->CanBeReUsed(Frequency, Vpid)) {
&& device[i]->frequency == Frequency // ...and it is tuned to the requested frequency...
&& device[i]->Receiving() // ...and is already receiving
// need not check priority - if a budget card is already receiving on the requested
// frequency, we can attach another receiver regardless of priority
)
|| (device[i]->HasDecoder() // it's a "full featured card" which can receive only one channel...
&& device[i]->frequency == Frequency // ...and it is tuned to the requested frequency...
&& device[i]->pidHandles[ptVideo].pid == Vpid // ...and the requested video PID...
&& device[i]->Receiving() // ...and is already receiving
// need not check priority - if a full featured card is already receiving the requested
// frequency and video PID, we can attach another receiver regardless of priority
)
) {
d = device[i]; d = device[i];
if (ReUse) if (ReUse)
*ReUse = true; *ReUse = true;
@ -204,50 +157,14 @@ cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool
return d; return d;
} }
void cDevice::SetCaCaps(void) void cDevice::SetCaCaps(int Index)
{ {
for (int d = 0; d < numDevices; d++) { for (int d = 0; d < numDevices; d++) {
for (int i = 0; i < MAXCACAPS; i++) if (Index < 0 || Index == device[d]->CardIndex()) {
device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][i]; for (int i = 0; i < MAXCACAPS; i++)
} device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][i];
}
bool cDevice::Probe(const char *FileName)
{
if (access(FileName, F_OK) == 0) {
dsyslog("probing %s", FileName);
int f = open(FileName, O_RDONLY);
if (f >= 0) {
close(f);
return true;
}
else if (errno != ENODEV && errno != EINVAL)
LOG_ERROR_STR(FileName);
}
else if (errno != ENOENT)
LOG_ERROR_STR(FileName);
return false;
}
bool cDevice::Initialize(void)
{
numDevices = 0;
for (int i = 0; i < MAXDEVICES; i++) {
if (useDevice == 0 || (useDevice & (1 << i)) != 0) {
if (Probe(OstName(DEV_OST_FRONTEND, i)))
device[numDevices++] = new cDevice(i);
else
break;
} }
} }
primaryDevice = device[0];
if (numDevices > 0) {
isyslog("found %d video device%s", numDevices, numDevices > 1 ? "s" : "");
SetCaCaps();
}
else
esyslog("ERROR: no video device found, giving up!");
return numDevices > 0;
} }
void cDevice::Shutdown(void) void cDevice::Shutdown(void)
@ -261,106 +178,13 @@ void cDevice::Shutdown(void)
bool cDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) bool cDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{ {
int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR, true);
if (videoDev >= 0) {
int result = 0;
struct video_mbuf mbuf;
result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
if (result == 0) {
int msize = mbuf.size;
unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
if (mem && mem != (unsigned char *)-1) {
// set up the size and RGB
struct video_capability vc;
result |= ioctl(videoDev, VIDIOCGCAP, &vc);
struct video_mmap vm;
vm.frame = 0;
if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
(SizeY > 0) && (SizeY <= vc.maxheight)) {
vm.width = SizeX;
vm.height = SizeY;
}
else {
vm.width = vc.maxwidth;
vm.height = vc.maxheight;
}
vm.format = VIDEO_PALETTE_RGB24;
result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
// make RGB out of BGR:
int memsize = vm.width * vm.height;
unsigned char *mem1 = mem;
for (int i = 0; i < memsize; i++) {
unsigned char tmp = mem1[2];
mem1[2] = mem1[0];
mem1[0] = tmp;
mem1 += 3;
}
if (Quality < 0)
Quality = 255; //XXX is this 'best'???
isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
FILE *f = fopen(FileName, "wb");
if (f) {
if (Jpeg) {
// write JPEG file:
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, f);
cinfo.image_width = vm.width;
cinfo.image_height = vm.height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, Quality, true);
jpeg_start_compress(&cinfo, true);
int rs = vm.width * 3;
JSAMPROW rp[vm.height];
for (int k = 0; k < vm.height; k++)
rp[k] = &mem[rs * k];
jpeg_write_scanlines(&cinfo, rp, vm.height);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
}
else {
// write PNM file:
if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
LOG_ERROR_STR(FileName);
result |= 1;
}
}
fclose(f);
}
else {
LOG_ERROR_STR(FileName);
result |= 1;
}
munmap(mem, msize);
}
else
result |= 1;
}
close(videoDev);
return result == 0;
}
return false; return false;
} }
void cDevice::SetVideoFormat(videoFormat_t Format) void cDevice::SetVideoFormat(bool VideoFormat16_9)
{ {
if (HasDecoder())
CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format));
} }
// ptVideo ptAudio ptTeletext ptDolby ptOther
dmxPesType_t PesTypes[] = { DMX_PES_VIDEO, DMX_PES_AUDIO, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
//#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog(b); } //XXX+ //#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog(b); } //XXX+
#define PRINTPIDS(s) #define PRINTPIDS(s)
@ -375,13 +199,12 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
else if (a < 0 && i >= ptOther && !pidHandles[i].used) else if (a < 0 && i >= ptOther && !pidHandles[i].used)
a = i; a = i;
} }
dmxPesType_t PesType = PesTypes[ptOther];
if (n >= 0) { if (n >= 0) {
// The Pid is already in use // The Pid is already in use
if (++pidHandles[n].used == 2 && n <= ptTeletext) { if (++pidHandles[n].used == 2 && n <= ptTeletext) {
// It's a special PID that has to be switched into "tap" mode // It's a special PID that may have to be switched into "tap" mode
PRINTPIDS("A");//XXX+ PRINTPIDS("A");//XXX+
return SetPid(pidHandles[n].fd, PesTypes[n], Pid, DMX_OUT_TS_TAP); return SetPid(&pidHandles[n], n, true);
} }
PRINTPIDS("a");//XXX+ PRINTPIDS("a");//XXX+
return true; return true;
@ -389,8 +212,6 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
else if (PidType < ptOther) { else if (PidType < ptOther) {
// The Pid is not yet in use and it is a special one // The Pid is not yet in use and it is a special one
n = PidType; n = PidType;
PesType = PesTypes[PidType];
PRINTPIDS("B");//XXX+
} }
else if (a >= 0) { else if (a >= 0) {
// The Pid is not yet in use and we have a free slot // The Pid is not yet in use and we have a free slot
@ -400,217 +221,51 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
esyslog("ERROR: no free slot for PID %d", Pid); esyslog("ERROR: no free slot for PID %d", Pid);
if (n >= 0) { if (n >= 0) {
pidHandles[n].pid = Pid; pidHandles[n].pid = Pid;
pidHandles[n].fd = OstOpen(DEV_OST_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
pidHandles[n].used = 1; pidHandles[n].used = 1;
PRINTPIDS("C");//XXX+ PRINTPIDS("C");//XXX+
return SetPid(pidHandles[n].fd, PesType, Pid, PidType <= ptTeletext ? DMX_OUT_DECODER : DMX_OUT_TS_TAP); return SetPid(&pidHandles[n], n, true);
} }
} }
return true; return true;
} }
bool cDevice::DelPid(int Pid) void cDevice::DelPid(int Pid)
{ {
if (Pid) { if (Pid) {
for (int i = 0; i < MAXPIDHANDLES; i++) { for (int i = 0; i < MAXPIDHANDLES; i++) {
if (pidHandles[i].pid == Pid) { if (pidHandles[i].pid == Pid) {
switch (--pidHandles[i].used) { if (--pidHandles[i].used < 2) {
case 0: CHECK(ioctl(pidHandles[i].fd, DMX_STOP));//XXX+ is this necessary??? SetPid(&pidHandles[i], i, false);
close(pidHandles[i].fd); if (pidHandles[i].used == 0) {
pidHandles[i].fd = -1; pidHandles[i].handle = -1;
pidHandles[i].pid = 0; pidHandles[i].pid = 0;
break; }
case 1: if (i <= ptTeletext) }
SetPid(pidHandles[i].fd, PesTypes[i], Pid, DMX_OUT_DECODER);
break;
}
PRINTPIDS("D");//XXX+ PRINTPIDS("D");//XXX+
return pidHandles[i].used;
} }
} }
} }
}
bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
{
return false; return false;
} }
bool cDevice::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output) eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
{ {
if (Pid) {
CHECK(ioctl(fd, DMX_STOP));
if (Pid != 0x1FFF) {
dmxPesFilterParams pesFilterParams;
pesFilterParams.pid = Pid;
pesFilterParams.input = DMX_IN_FRONTEND;
pesFilterParams.output = Output;
pesFilterParams.pesType = PesType;
pesFilterParams.flags = DMX_IMMEDIATE_START;
//XXX+ pesFilterParams.flags = DMX_CHECK_CRC;//XXX
if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
LOG_ERROR;
return false;
}
//XXX+ CHECK(ioctl(fd, DMX_SET_BUFFER_SIZE, KILOBYTE(32)));//XXX
//XXX+ CHECK(ioctl(fd, DMX_START));//XXX
}
}
return true;
}
eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr)
{
StopReplay();
cStatus::MsgChannelSwitch(this, 0); cStatus::MsgChannelSwitch(this, 0);
StopReplay();
// Must set this anyway to avoid getting stuck when switching through // Must set this anyway to avoid getting stuck when switching through
// channels with 'Up' and 'Down' keys: // channels with 'Up' and 'Down' keys:
currentChannel = ChannelNumber; currentChannel = Channel->number;
// Avoid noise while switching:
if (HasDecoder()) {
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
}
// Stop setting system time:
if (siProcessor)
siProcessor->SetCurrentTransponder(0);
// If this card can't receive this channel, we must not actually switch // If this card can't receive this channel, we must not actually switch
// the channel here, because that would irritate the driver when we // the channel here, because that would irritate the driver when we
// start replaying in Transfer Mode immediately after switching the channel: // start replaying in Transfer Mode immediately after switching the channel:
bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Ca)); bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Channel->ca));
if (!NeedsTransferMode) {
// Turn off current PIDs:
if (HasDecoder()) {
DelPid(pidHandles[ptVideo].pid);
DelPid(pidHandles[ptAudio].pid);
DelPid(pidHandles[ptTeletext].pid);
DelPid(pidHandles[ptDolby].pid);
}
FrontendParameters Frontend;
switch (frontendType) {
case FE_QPSK: { // DVB-S
// Frequency offsets:
unsigned int freq = Frequency;
int tone = SEC_TONE_OFF;
if (freq < (unsigned int)Setup.LnbSLOF) {
freq -= Setup.LnbFrequLo;
tone = SEC_TONE_OFF;
}
else {
freq -= Setup.LnbFrequHi;
tone = SEC_TONE_ON;
}
Frontend.Frequency = freq * 1000UL;
Frontend.Inversion = INVERSION_AUTO;
Frontend.u.qpsk.SymbolRate = Srate * 1000UL;
Frontend.u.qpsk.FEC_inner = FEC_AUTO;
int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
// DiseqC:
secCommand scmd;
scmd.type = 0;
scmd.u.diseqc.addr = 0x10;
scmd.u.diseqc.cmd = 0x38;
scmd.u.diseqc.numParams = 1;
scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0);
secCmdSequence scmds;
scmds.voltage = volt;
scmds.miniCommand = SEC_MINI_NONE;
scmds.continuousTone = tone;
scmds.numCommands = Setup.DiSEqC ? 1 : 0;
scmds.commands = &scmd;
CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
}
break;
case FE_QAM: { // DVB-C
// Frequency and symbol rate:
Frontend.Frequency = Frequency * 1000000UL;
Frontend.Inversion = INVERSION_AUTO;
Frontend.u.qam.SymbolRate = Srate * 1000UL;
Frontend.u.qam.FEC_inner = FEC_AUTO;
Frontend.u.qam.QAM = QAM_64;
}
break;
case FE_OFDM: { // DVB-T
// Frequency and OFDM paramaters:
Frontend.Frequency = Frequency * 1000UL;
Frontend.Inversion = INVERSION_AUTO;
Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ;
Frontend.u.ofdm.HP_CodeRate=FEC_2_3;
Frontend.u.ofdm.LP_CodeRate=FEC_1_2;
Frontend.u.ofdm.Constellation=QAM_64;
Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K;
Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32;
Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE;
}
break;
default:
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
return scrFailed;
}
// Tuning:
CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
// Wait for channel sync:
if (cFile::FileReady(fd_frontend, 5000)) {
FrontendEvent event;
int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
if (res >= 0) {
if (event.type != FE_COMPLETION_EV) {
esyslog("ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1);
if (IsPrimaryDevice())
cThread::RaisePanic();
return scrFailed;
}
}
else
esyslog("ERROR %d in frontend get event (channel %d, card %d)", res, ChannelNumber, CardIndex() + 1);
}
else
esyslog("ERROR: timeout while tuning");
frequency = Frequency;
// PID settings:
if (HasDecoder()) {
if (!(AddPid(Vpid, ptVideo) && AddPid(Apid, ptAudio))) {//XXX+ dolby Dpid1!!! (if audio plugins are attached)
esyslog("ERROR: failed to set PIDs for channel %d", ChannelNumber);
return scrFailed;
}
if (IsPrimaryDevice())
AddPid(Tpid, ptTeletext);
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
}
}
if (IsPrimaryDevice() && siProcessor)
siProcessor->SetCurrentServiceID(Pnr);
eSetChannelResult Result = scrOk; eSetChannelResult Result = scrOk;
@ -618,30 +273,32 @@ eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Pol
// use the card that actually can receive it and transfer data from there: // use the card that actually can receive it and transfer data from there:
if (NeedsTransferMode) { if (NeedsTransferMode) {
cDevice *CaDevice = GetDevice(Ca, 0); cDevice *CaDevice = GetDevice(Channel->ca, 0);
if (CaDevice && !CaDevice->Receiving()) { if (CaDevice && !CaDevice->Receiving() && CaDevice->SetChannel(Channel) == scrOk)
if ((Result = CaDevice->SetChannel(ChannelNumber, Frequency, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) == scrOk) cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+
cControl::Launch(new cTransferControl(CaDevice, Vpid, Apid, 0, 0, 0));//XXX+
}
else else
Result = scrNoTransfer; Result = scrNoTransfer;
} }
else if (!SetChannelDevice(Channel))
Result = scrFailed;
if (HasDecoder()) { if (IsPrimaryDevice())
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); cSIProcessor::SetCurrentServiceID(Channel->pnr);
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
}
// Start setting system time: cStatus::MsgChannelSwitch(this, Channel->number);
if (Result == scrOk && siProcessor)
siProcessor->SetCurrentTransponder(Frequency);
cStatus::MsgChannelSwitch(this, ChannelNumber);
return Result; return Result;
} }
bool cDevice::SetChannelDevice(const cChannel *Channel)
{
return false;
}
void cDevice::SetVolumeDevice(int Volume)
{
}
bool cDevice::ToggleMute(void) bool cDevice::ToggleMute(void)
{ {
int OldVolume = volume; int OldVolume = volume;
@ -653,78 +310,40 @@ bool cDevice::ToggleMute(void)
void cDevice::SetVolume(int Volume, bool Absolute) void cDevice::SetVolume(int Volume, bool Absolute)
{ {
if (HasDecoder()) { volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME); SetVolumeDevice(volume);
audioMixer_t am; cStatus::MsgSetVolume(volume, Absolute);
am.volume_left = am.volume_right = volume; if (volume > 0)
CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); mute = false;
cStatus::MsgSetVolume(volume, Absolute); }
if (volume > 0)
mute = false; int cDevice::SetPlayMode(bool On)
} {
return -1;
} }
void cDevice::TrickSpeed(int Speed) void cDevice::TrickSpeed(int Speed)
{ {
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
} }
void cDevice::Clear(void) void cDevice::Clear(void)
{ {
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
if (fd_audio >= 0)
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
} }
void cDevice::Play(void) void cDevice::Play(void)
{ {
if (fd_audio >= 0)
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_CONTINUE));
} }
void cDevice::Freeze(void) void cDevice::Freeze(void)
{ {
if (fd_audio >= 0)
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_FREEZE));
} }
void cDevice::Mute(void) void cDevice::Mute(void)
{ {
if (fd_audio >= 0) {
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
}
} }
void cDevice::StillPicture(const uchar *Data, int Length) void cDevice::StillPicture(const uchar *Data, int Length)
{ {
Mute();
/* Using the VIDEO_STILLPICTURE ioctl call would be the
correct way to display a still frame, but unfortunately this
doesn't work with frames from VDR. So let's do pretty much the
same here as in DVB/driver/dvb.c's play_iframe() - I have absolutely
no idea why it works this way, but doesn't work with VIDEO_STILLPICTURE.
If anybody ever finds out what could be changed so that VIDEO_STILLPICTURE
could be used, please let me know!
kls 2002-03-23
*/
//#define VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
#ifdef VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
videoDisplayStillPicture sp = { (char *)Data, Length };
CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
#else
#define MIN_IFRAME 400000
for (int i = MIN_IFRAME / Length + 1; i > 0; i--) {
safe_write(fd_video, Data, Length);
usleep(1); // allows the buffer to be displayed in case the progress display is active
}
#endif
} }
bool cDevice::Replaying(void) bool cDevice::Replaying(void)
@ -741,19 +360,9 @@ bool cDevice::AttachPlayer(cPlayer *Player)
if (HasDecoder()) { if (HasDecoder()) {
if (player) if (player)
Detach(player); Detach(player);
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, true));
CHECK(ioctl(fd_audio, AUDIO_PLAY));
CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
CHECK(ioctl(fd_video, VIDEO_PLAY));
player = Player; player = Player;
player->device = this; player->device = this;
player->deviceFileHandle = fd_video; player->deviceFileHandle = SetPlayMode(true);
player->Activate(true); player->Activate(true);
return true; return true;
} }
@ -767,17 +376,7 @@ void cDevice::Detach(cPlayer *Player)
player->deviceFileHandle = -1; player->deviceFileHandle = -1;
player->device = NULL; player->device = NULL;
player = NULL; player = NULL;
SetPlayMode(false);
CHECK(ioctl(fd_video, VIDEO_STOP, true));
CHECK(ioctl(fd_audio, AUDIO_STOP, true));
CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
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);
} }
} }
@ -802,14 +401,11 @@ void cDevice::StopReplay(void)
int cDevice::PlayVideo(const uchar *Data, int Length) int cDevice::PlayVideo(const uchar *Data, int Length)
{ {
if (fd_video >= 0)
return write(fd_video, Data, Length);
return -1; return -1;
} }
int cDevice::PlayAudio(const uchar *Data, int Length) int cDevice::PlayAudio(const uchar *Data, int Length)
{ {
//XXX+
return -1; return -1;
} }
@ -828,7 +424,7 @@ int cDevice::Priority(void)
int cDevice::CanShift(int Ca, int Priority, int UsedCards) int cDevice::CanShift(int Ca, int Priority, int UsedCards)
{ {
return -1;//XXX+ too complex with multiple recordings per device return -1;//XXX+ too complex with multiple recordings per device
// Test whether a receiving on this DVB device can be shifted to another one // 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: // 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 int ShiftLevel = -1; // default means this device can't be shifted
if (UsedCards & (1 << CardIndex()) != 0) if (UsedCards & (1 << CardIndex()) != 0)
@ -882,7 +478,7 @@ int cDevice::ProvidesCa(int Ca)
bool cDevice::Receiving(void) bool cDevice::Receiving(void)
{ {
for (int i = 0; i < MAXRECEIVERS; i++) { for (int i = 0; i < MAXRECEIVERS; i++) {
if (receiver[i]) if (receiver[i] && receiver[i]->priority >= 0) // cReceiver with priority < 0 doesn't count
return true; return true;
} }
return false; return false;
@ -892,51 +488,31 @@ void cDevice::Action(void)
{ {
dsyslog("receiver thread started on device %d (pid=%d)", CardIndex() + 1, getpid()); dsyslog("receiver thread started on device %d (pid=%d)", CardIndex() + 1, getpid());
int fd_dvr = open(dvrFileName, O_RDONLY | O_NONBLOCK); if (OpenDvr()) {
if (fd_dvr >= 0) {
pollfd pfd;
pfd.fd = fd_dvr;
pfd.events = pfd.revents = POLLIN;
uchar b[TS_SIZE]; uchar b[TS_SIZE];
time_t t = time(NULL); time_t t = time(NULL);
active = true; active = true;
for (; active;) { for (; active;) {
// Read data from the DVR device: // Read data from the DVR device:
int r = GetTSPacket(b);
if (pfd.revents & POLLIN != 0) { if (r == TS_SIZE) {
int r = read(fd_dvr, b, sizeof(b)); if (*b == TS_SYNC_BYTE) {
if (r == TS_SIZE) { // We're locked on to a TS packet
if (*b == TS_SYNC_BYTE) { int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2];
// We're locked on to a TS packet // Distribute the packet to all attached receivers:
int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2]; Lock();
// Distribute the packet to all attached receivers: for (int i = 0; i < MAXRECEIVERS; i++) {
Lock(); if (receiver[i] && receiver[i]->WantsPid(Pid))
for (int i = 0; i < MAXRECEIVERS; i++) { receiver[i]->Receive(b, TS_SIZE);
if (receiver[i] && receiver[i]->WantsPid(Pid)) }
receiver[i]->Receive(b, TS_SIZE); Unlock();
}
Unlock();
}
t = time(NULL);
}
else if (r > 0)
esyslog("ERROR: got incomplete TS packet (%d bytes)", r);//XXX+ TODO do we have to read the rest???
else if (r < 0) {
if (FATALERRNO) {
if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library
esyslog("ERROR: DVB driver buffer overflow on device %d", CardIndex() + 1);
else {
LOG_ERROR;
break;
}
}
} }
t = time(NULL);
} }
else if (r > 0)
// Wait for more data to become available: esyslog("ERROR: got incomplete TS packet (%d bytes) on device %d", r, CardIndex() + 1);//XXX+ TODO do we have to read the rest???
else if (r < 0)
poll(&pfd, 1, 100); break;
//XXX+ put this into the recorder??? or give the receiver a flag whether it wants this? //XXX+ put this into the recorder??? or give the receiver a flag whether it wants this?
if (time(NULL) - t > MAXBROKENTIMEOUT) { if (time(NULL) - t > MAXBROKENTIMEOUT) {
@ -945,14 +521,26 @@ void cDevice::Action(void)
t = time(NULL); t = time(NULL);
} }
} }
close(fd_dvr); CloseDvr();
} }
else
LOG_ERROR_STR(dvrFileName);
dsyslog("receiver thread ended on device %d (pid=%d)", CardIndex() + 1, getpid()); dsyslog("receiver thread ended on device %d (pid=%d)", CardIndex() + 1, getpid());
} }
bool cDevice::OpenDvr(void)
{
return false;
}
void cDevice::CloseDvr(void)
{
}
int cDevice::GetTSPacket(uchar *Data)
{
return -1;
}
bool cDevice::AttachReceiver(cReceiver *Receiver) bool cDevice::AttachReceiver(cReceiver *Receiver)
{ {
//XXX+ check for same transponder??? //XXX+ check for same transponder???
@ -963,13 +551,8 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
StopReplay(); StopReplay();
for (int i = 0; i < MAXRECEIVERS; i++) { for (int i = 0; i < MAXRECEIVERS; i++) {
if (!receiver[i]) { if (!receiver[i]) {
//siProcessor->SetStatus(false);//XXX+ for (int n = 0; n < MAXRECEIVEPIDS; n++)
for (int n = 0; n < MAXRECEIVEPIDS; n++) { AddPid(Receiver->pids[n]);//XXX+ retval!
if (Receiver->pids[n])
AddPid(Receiver->pids[n]);//XXX+ retval!
else
break;
}
Receiver->Activate(true); Receiver->Activate(true);
Lock(); Lock();
Receiver->device = this; Receiver->device = this;
@ -995,12 +578,8 @@ void cDevice::Detach(cReceiver *Receiver)
receiver[i] = NULL; receiver[i] = NULL;
Receiver->device = NULL; Receiver->device = NULL;
Unlock(); Unlock();
for (int n = 0; n < MAXRECEIVEPIDS; n++) { for (int n = 0; n < MAXRECEIVEPIDS; n++)
if (Receiver->pids[n]) DelPid(Receiver->pids[n]);
DelPid(Receiver->pids[n]);
else
break;
}
} }
else if (receiver[i]) else if (receiver[i])
receiversLeft = true; receiversLeft = true;

207
device.h
View File

@ -4,38 +4,33 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.h 1.3 2002/06/23 11:50:24 kls Exp $ * $Id: device.h 1.5 2002/08/04 14:02:19 kls Exp $
*/ */
#ifndef __DEVICE_H #ifndef __DEVICE_H
#define __DEVICE_H #define __DEVICE_H
#include <stdlib.h> // FIXME: this is apparently necessary for the ost/... header files
// FIXME: shouldn't every header file include ALL the other header
// FIXME: files it depends on? The sequence in which header files
// FIXME: are included here should not matter - and it should NOT
// FIXME: be necessary to include <stdlib.h> here!
#include <ost/dmx.h>
#include <ost/frontend.h>
#include <ost/audio.h>
#include <ost/video.h>
#include "eit.h"
#include "thread.h" #include "thread.h"
#include "tools.h"
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed }; #define MAXDEVICES 16 // the maximum number of devices in the system
#define MAXCACAPS 16 // the maximum number of different CA values per device
#define MAXDEVICES 4 // the maximum number of devices in the system #define MAXPIDHANDLES 16 // the maximum number of different PIDs per device
#define MAXCACAPS 16 // the maximum number of different CA values per DVB device #define MAXRECEIVERS 16 // the maximum number of receivers per device
#define MAXPIDHANDLES 16 // the maximum number of different PIDs per DVB device
#define MAXRECEIVERS 16 // the maximum number of receivers per DVB device
#define MAXVOLUME 255 #define MAXVOLUME 255
#define VOLUMEDELTA 5 // used to increase/decrease the volume #define VOLUMEDELTA 5 // used to increase/decrease the volume
#define TS_SIZE 188
#define TS_SYNC_BYTE 0x47
#define PID_MASK_HI 0x1F
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
class cChannel;
class cPlayer; class cPlayer;
class cReceiver; class cReceiver;
class cDevice : cThread { class cDevice : cThread {
friend class cOsd;//XXX
private: private:
static int numDevices; static int numDevices;
static int useDevice; static int useDevice;
@ -43,106 +38,142 @@ private:
static cDevice *primaryDevice; static cDevice *primaryDevice;
public: public:
static int NumDevices(void) { return numDevices; } static int NumDevices(void) { return numDevices; }
// Returns the total number of DVB devices. // Returns the total number of devices.
static void SetUseDevice(int n); static void SetUseDevice(int n);
// Sets the 'useDevice' flag of the given DVB device. // Sets the 'useDevice' flag of the given device.
// If this function is not called before Initialize(), all DVB devices // If this function is not called before initializing, all devices
// will be used. // will be used.
static bool UseDevice(int n) { return useDevice == 0 || (useDevice & (1 << n)) != 0; }
// Tells whether the device with the given card index shall be used in
// this instance of VDR.
static bool SetPrimaryDevice(int n); static bool SetPrimaryDevice(int n);
// Sets the primary DVB device to 'n' (which must be in the range // Sets the primary device to 'n' (which must be in the range
// 1...numDevices) and returns true if this was possible. // 1...numDevices) and returns true if this was possible.
static cDevice *PrimaryDevice(void) { return primaryDevice; } static cDevice *PrimaryDevice(void) { return primaryDevice; }
// Returns the primary DVB device. // Returns the primary device.
static cDevice *GetDevice(int Ca, int Priority, int Frequency = 0, int Vpid = 0, bool *ReUse = NULL); static cDevice *GetDevice(int Ca, int Priority, int Frequency = 0, int Vpid = 0, bool *ReUse = NULL);
// Selects a free DVB device, avoiding the primaryDevice if possible. // Selects a free device, avoiding the primaryDevice if possible.
// If Ca is not 0, the device with the given number will be returned // If Ca is not 0, the device with the given number will be returned
// in case Ca is <= MAXDEVICES, or the device that provides the given // in case Ca is <= MAXDEVICES, or the device that provides the given
// value in its caCaps. // value in its caCaps.
// If there is a device that is already tuned to the given Frequency, // If there is a device that is already receiving and can be re-used to
// and that device is able to receive multiple channels ("budget" cards), // receive another data stream, that device will be returned.
// that device will be returned. Else if a ("full featured") device is // If all devices are currently receiving, the one receiving with the
// tuned to Frequency and Vpid, that one will be returned. // lowest priority (if any) that is lower than the given Priority
// If all DVB devices are currently receiving, the one receiving the
// lowest priority timer (if any) that is lower than the given Priority
// will be returned. // will be returned.
// If ReUse is given, the caller will be informed whether the device can be re-used // If ReUse is given, the caller will be informed whether the device can be re-used
// for a new recording. If ReUse returns 'true', the caller must NOT switch the channel // for a new recording. If ReUse returns 'true', the caller must NOT switch the channel
// (the device is already properly tuned). Otherwise the caller MUST switch the channel. // (the device is already properly tuned). Otherwise the caller MUST switch the channel.
static void SetCaCaps(void); static void SetCaCaps(int Index = -1);
// Sets the CaCaps of all DVB devices according to the Setup data. // Sets the CaCaps of the given device according to the Setup data.
static bool Probe(const char *FileName); // By default the CaCaps of all devices are set.
// Probes for existing DVB devices.
static bool Initialize(void);
// Initializes the DVB devices.
// Must be called before accessing any DVB functions.
static void Shutdown(void); static void Shutdown(void);
// Closes down all DVB devices. // Closes down all devices.
// Must be called at the end of the program. // Must be called at the end of the program.
private: private:
static int nextCardIndex;
int cardIndex; int cardIndex;
int caCaps[MAXCACAPS]; int caCaps[MAXCACAPS];
FrontendType frontendType; protected:
char *dvrFileName; cDevice(void);
bool active;
int fd_osd, fd_frontend, fd_sec, fd_audio, fd_video;
int OsdDeviceHandle(void) { return fd_osd; }
public:
cDevice(int n);
virtual ~cDevice(); virtual ~cDevice();
bool IsPrimaryDevice(void) { return this == primaryDevice; } static int NextCardIndex(int n = 0);
// Each device in a given machine must have a unique card index, which
// will be used to identify the device for assigning Ca parameters and
// deciding whether to actually use that device in this particular
// instance of VDR. Every time a new cDevice is created, it will be
// given the current nextCardIndex, and then nextCardIndex will be
// automatically incremented by 1. A derived class can determine whether
// a given device shall be used by checking UseDevice(NextCardIndex()).
// If a device is skipped, or if there are possible device indexes left
// after a derived class has set up all its devices, NextCardIndex(n)
// must be called, where n is the number of card indexes to skip.
virtual void MakePrimaryDevice(bool On);
// Informs a device that it will be the primary device. If there is
// anything the device needs to set up when it becomes the primary
// device (On = true) or to shut down when it no longer is the primary
// device (On = false), it should do so in this function.
public:
bool IsPrimaryDevice(void) const { return this == primaryDevice; }
int CardIndex(void) const { return cardIndex; } int CardIndex(void) const { return cardIndex; }
// Returns the card index of this device (0 ... MAXDEVICES - 1). // Returns the card index of this device (0 ... MAXDEVICES - 1).
int ProvidesCa(int Ca); int ProvidesCa(int Ca);
// Checks whether this DVB device provides the given value in its // Checks whether this device provides the given value in its
// caCaps. Returns 0 if the value is not provided, 1 if only this // 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. // value is provided, and > 1 if this and other values are provided.
// If the given value is equal to the number of this DVB device, // If the given value is equal to the number of this device,
// 1 is returned. If it is 0 (FTA), 1 plus the number of other values // 1 is returned. If it is 0 (FTA), 1 plus the number of other values
// in caCaps is returned. // in caCaps is returned.
bool HasDecoder(void) const { return fd_video >= 0 && fd_audio >= 0; } virtual bool CanBeReUsed(int Frequency, int Vpid);//XXX TODO make it more abstract
// Tells whether this device is already receiving and allows another
// receiver with the given settings to be attached to it.
virtual bool HasDecoder(void) const;
// Tells whether this device has an MPEG decoder.
// Channel facilities // Channel facilities
private: protected:
int currentChannel; int currentChannel;
int frequency;
public: public:
eSetChannelResult SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr); eSetChannelResult SetChannel(const cChannel *Channel);
// Sets the device to the given channel (general setup).
virtual bool SetChannelDevice(const cChannel *Channel);
// Sets the device to the given channel (actual physical setup).
static int CurrentChannel(void) { return primaryDevice ? primaryDevice->currentChannel : 0; } static int CurrentChannel(void) { return primaryDevice ? primaryDevice->currentChannel : 0; }
// Returns the number of the current channel on the primary device.
int Channel(void) { return currentChannel; } int Channel(void) { return currentChannel; }
// Returns the number of the current channel on this device.
// PID handle facilities // PID handle facilities
private: private:
bool active;
virtual void Action(void);
protected:
enum ePidType { ptVideo, ptAudio, ptTeletext, ptDolby, ptOther }; enum ePidType { ptVideo, ptAudio, ptTeletext, ptDolby, ptOther };
class cPidHandle { class cPidHandle {
public: public:
int pid; int pid;
int fd; int handle;
int used; int used;
cPidHandle(void) { pid = used = 0; fd = -1; } cPidHandle(void) { pid = used = 0; handle = -1; }
}; };
cPidHandle pidHandles[MAXPIDHANDLES]; cPidHandle pidHandles[MAXPIDHANDLES];
bool AddPid(int Pid, ePidType PidType = ptOther); bool AddPid(int Pid, ePidType PidType = ptOther);
bool DelPid(int Pid); // Adds a PID to the set of PIDs this device shall receive.
bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output); void DelPid(int Pid);
virtual void Action(void); // Deletes a PID from the set of PIDs this device shall receive.
virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
// Does the actual PID setting on this device.
// On indicates whether the PID shall be added or deleted.
// Handle->handle can be used by the device to store information it
// needs to receive this PID (for instance a file handle).
// Handle->used indicated how many receivers are using this PID.
// Type indicates some special types of PIDs, which the device may
// need to set in a specific way.
// Image Grab facilities // Image Grab facilities
public: public:
bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
// Grabs the currently visible screen image into the given file, with the
// given parameters.
// Video format facilities // Video format facilities
public: public:
virtual void SetVideoFormat(videoFormat_t Format); virtual void SetVideoFormat(bool VideoFormat16_9);
// Sets the output video format to either 16:9 or 4:3 (only useful
// if this device has an MPEG decoder).
// Volume facilities // Volume facilities
private: private:
bool mute; bool mute;
int volume; int volume;
protected:
virtual void SetVolumeDevice(int Volume);
// Sets the audio volume on this device (Volume = 0...255).
public: public:
bool IsMute(void) { return mute; } bool IsMute(void) { return mute; }
bool ToggleMute(void); bool ToggleMute(void);
@ -152,30 +183,46 @@ public:
// the current volume. // the current volume.
static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX??? static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
// EIT facilities
private:
cSIProcessor *siProcessor;
// Player facilities // Player facilities
private: private:
cPlayer *player; cPlayer *player;
protected:
virtual int SetPlayMode(bool On);
// Sets the device into play mode (On = true) or normal
// viewing mode (On = false). If On is true, it may return a file
// handle that a player can use to poll this device when replaying.
//XXX TODO should be implemented differently
public: public:
void TrickSpeed(int Speed); virtual void TrickSpeed(int Speed);
void Clear(void); // Sets the device into a mode where replay is done slower.
void Play(void); // Every single frame shall then be displayed the given number of
void Freeze(void); // times.
void Mute(void); virtual void Clear(void);
void StillPicture(const uchar *Data, int Length); // Clears all video and audio data from the device.
virtual void Play(void);
// Sets the device into play mode (after a previous trick
// mode).
virtual void Freeze(void);
// Puts the device into "freeze frame" mode.
virtual void Mute(void);
// Turns off audio while replaying.
virtual void StillPicture(const uchar *Data, int Length);
// Displays the given I-frame as a still picture.
virtual int PlayVideo(const uchar *Data, int Length);
// Actually plays the given data block as video. The data must be
// part of a PES (Packetized Elementary Stream) which can contain
// one video and one audio strem.
virtual int PlayAudio(const uchar *Data, int Length);
// Plays additional audio streams, like Dolby Digital.
bool Replaying(void); bool Replaying(void);
// Returns true if we are currently replaying. // Returns true if we are currently replaying.
void StopReplay(void); void StopReplay(void);
// Stops the current replay session (if any). // Stops the current replay session (if any).
bool AttachPlayer(cPlayer *Player); bool AttachPlayer(cPlayer *Player);
// Attaches the given player to this device.
void Detach(cPlayer *Player); void Detach(cPlayer *Player);
virtual int PlayVideo(const uchar *Data, int Length); // Detaches the given player from this device.
virtual int PlayAudio(const uchar *Data, int Length);
// Receiver facilities // Receiver facilities
@ -184,16 +231,30 @@ private:
int ca; int ca;
int Priority(void); int Priority(void);
// Returns the priority of the current receiving session (0..MAXPRIORITY), // Returns the priority of the current receiving session (0..MAXPRIORITY),
// or -1 if no receiver is currently active. The primary DVB device will // or -1 if no receiver is currently active. The primary device will
// always return at least Setup.PrimaryLimit-1. // always return at least Setup.PrimaryLimit-1.
int CanShift(int Ca, int Priority, int UsedCards = 0); int CanShift(int Ca, int Priority, int UsedCards = 0);
protected:
virtual bool OpenDvr(void);
// Opens the DVR of this device and prepares it to deliver a Transport
// Stream for use in a cReceiver.
virtual void CloseDvr(void);
// Shuts down the DVR.
virtual int GetTSPacket(uchar *Data);
// Gets exactly one TS packet from the DVR of this device and copies it
// into the given memory area (which is exactly 188 bytes in size).
// Returns the number of bytes copied into Data (which must be 188).
// If there is currently no TS packet available, 0 should be returned.
// In case of a non recoverable error, returns -1.
public: public:
int Ca(void) { return ca; } int Ca(void) { return ca; }
// Returns the ca of the current receiving session. // Returns the ca of the current receiving session.
bool Receiving(void); bool Receiving(void);
// Returns true if we are currently receiving. // Returns true if we are currently receiving.
bool AttachReceiver(cReceiver *Receiver); bool AttachReceiver(cReceiver *Receiver);
// Attaches the given receiver to this device.
void Detach(cReceiver *Receiver); void Detach(cReceiver *Receiver);
// Detaches the given receiver from this device.
}; };
#endif //__DEVICE_H #endif //__DEVICE_H

615
dvbdevice.c Normal file
View File

@ -0,0 +1,615 @@
/*
* dvbdevice.c: The DVB device interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbdevice.c 1.1 2002/08/04 12:24:25 kls Exp $
*/
#include "dvbdevice.h"
#include <errno.h>
extern "C" {
#ifdef boolean
#define HAVE_BOOLEAN
#endif
#include <jpeglib.h>
#undef boolean
}
#include <limits.h>
#include <linux/videodev.h>
#include <ost/audio.h>
#include <ost/sec.h>
#include <ost/video.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "dvbosd.h"
#include "player.h"
#include "receiver.h"
#include "status.h"
#include "transfer.h"
#define MAXDVBDEVICES 4
#define DEV_VIDEO "/dev/video"
#define DEV_OST_OSD "/dev/ost/osd"
#define DEV_OST_FRONTEND "/dev/ost/frontend"
#define DEV_OST_SEC "/dev/ost/sec"
#define DEV_OST_DVR "/dev/ost/dvr"
#define DEV_OST_DEMUX "/dev/ost/demux"
#define DEV_OST_VIDEO "/dev/ost/video"
#define DEV_OST_AUDIO "/dev/ost/audio"
static const char *OstName(const char *Name, int n)
{
static char buffer[PATH_MAX];
snprintf(buffer, sizeof(buffer), "%s%d", Name, n);
return buffer;
}
static int OstOpen(const char *Name, int n, int Mode, bool ReportError = false)
{
const char *FileName = OstName(Name, n);
int fd = open(FileName, Mode);
if (fd < 0 && ReportError)
LOG_ERROR_STR(FileName);
return fd;
}
cDvbDevice::cDvbDevice(int n)
{
frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
siProcessor = NULL;
// Devices that are present on all card types:
fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR);
// Devices that are only present on DVB-S cards:
fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
// Devices that are only present on cards with decoders:
fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR);
fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
// The DVR device (will be opened and closed as needed):
fd_dvr = -1;
// Video format:
SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
// We only check the devices that must be present - the others will be checked before accessing them://XXX
if (fd_frontend >= 0) {
siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
FrontendInfo feinfo;
if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0)
frontendType = feinfo.type;
else
LOG_ERROR;
}
else
esyslog("ERROR: can't open DVB device %d", n);
frequency = 0;
}
cDvbDevice::~cDvbDevice()
{
delete siProcessor;
// We're not explicitly closing any device files here, since this sometimes
// caused segfaults. Besides, the program is about to terminate anyway...
}
bool cDvbDevice::Probe(const char *FileName)
{
if (access(FileName, F_OK) == 0) {
dsyslog("probing %s", FileName);
int f = open(FileName, O_RDONLY);
if (f >= 0) {
close(f);
return true;
}
else if (errno != ENODEV && errno != EINVAL)
LOG_ERROR_STR(FileName);
}
else if (errno != ENOENT)
LOG_ERROR_STR(FileName);
return false;
}
bool cDvbDevice::Initialize(void)
{
int found = 0;
int i;
for (i = 0; i < MAXDVBDEVICES; i++) {
if (UseDevice(NextCardIndex())) {
if (Probe(OstName(DEV_OST_FRONTEND, i))) {
new cDvbDevice(i);
found++;
}
else
break;
}
else
NextCardIndex(1); // skips this one
}
NextCardIndex(MAXDVBDEVICES - i); // skips the rest
if (found > 0)
isyslog("found %d video device%s", found, found > 1 ? "s" : "");
else
isyslog("no DVB device found");
return found > 0;
}
void cDvbDevice::MakePrimaryDevice(bool On)
{
cDvbOsd::SetDvbDevice(On ? this : NULL);
}
bool cDvbDevice::CanBeReUsed(int Frequency, int Vpid)
{
return Receiving() // to be reused the DVB device must already be receiving...
&& frequency == Frequency // ...and tuned to the requested frequency...
&& (!HasDecoder() // ...and either be a "budget card" which can receive multiple channels...
|| pidHandles[ptVideo].pid == Vpid // ...or be a "full featured card" that's already tuned to the requested video PID
);
}
bool cDvbDevice::HasDecoder(void) const
{
return fd_video >= 0 && fd_audio >= 0;
}
bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{
int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR, true);
if (videoDev >= 0) {
int result = 0;
struct video_mbuf mbuf;
result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
if (result == 0) {
int msize = mbuf.size;
unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
if (mem && mem != (unsigned char *)-1) {
// set up the size and RGB
struct video_capability vc;
result |= ioctl(videoDev, VIDIOCGCAP, &vc);
struct video_mmap vm;
vm.frame = 0;
if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
(SizeY > 0) && (SizeY <= vc.maxheight)) {
vm.width = SizeX;
vm.height = SizeY;
}
else {
vm.width = vc.maxwidth;
vm.height = vc.maxheight;
}
vm.format = VIDEO_PALETTE_RGB24;
result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
// make RGB out of BGR:
int memsize = vm.width * vm.height;
unsigned char *mem1 = mem;
for (int i = 0; i < memsize; i++) {
unsigned char tmp = mem1[2];
mem1[2] = mem1[0];
mem1[0] = tmp;
mem1 += 3;
}
if (Quality < 0)
Quality = 255; //XXX is this 'best'???
isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
FILE *f = fopen(FileName, "wb");
if (f) {
if (Jpeg) {
// write JPEG file:
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, f);
cinfo.image_width = vm.width;
cinfo.image_height = vm.height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, Quality, true);
jpeg_start_compress(&cinfo, true);
int rs = vm.width * 3;
JSAMPROW rp[vm.height];
for (int k = 0; k < vm.height; k++)
rp[k] = &mem[rs * k];
jpeg_write_scanlines(&cinfo, rp, vm.height);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
}
else {
// write PNM file:
if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
LOG_ERROR_STR(FileName);
result |= 1;
}
}
fclose(f);
}
else {
LOG_ERROR_STR(FileName);
result |= 1;
}
munmap(mem, msize);
}
else
result |= 1;
}
close(videoDev);
return result == 0;
}
return false;
}
void cDvbDevice::SetVideoFormat(bool VideoFormat16_9)
{
if (HasDecoder())
CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, VideoFormat16_9 ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3));
}
// ptVideo ptAudio ptTeletext ptDolby ptOther
dmxPesType_t PesTypes[] = { DMX_PES_VIDEO, DMX_PES_AUDIO, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
{
if (Handle->pid) {
if (On) {
if (Handle->handle < 0) {
Handle->handle = OstOpen(DEV_OST_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
if (Handle->handle < 0)
return false;
}
}
else {
CHECK(ioctl(Handle->handle, DMX_STOP));
if (Handle->used == 0) {
close(Handle->handle);
Handle->handle = -1;
return true;
}
}
if (Handle->pid != 0x1FFF) {
dmxPesFilterParams pesFilterParams;
pesFilterParams.pid = Handle->pid;
pesFilterParams.input = DMX_IN_FRONTEND;
pesFilterParams.output = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP;
pesFilterParams.pesType = PesTypes[Type < ptOther ? Type : ptOther];
pesFilterParams.flags = DMX_IMMEDIATE_START;
//XXX+ pesFilterParams.flags = DMX_CHECK_CRC;//XXX
if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
LOG_ERROR;
return false;
}
//XXX+ CHECK(ioctl(Handle->handle, DMX_SET_BUFFER_SIZE, KILOBYTE(32)));//XXX
//XXX+ CHECK(ioctl(Handle->handle, DMX_START));//XXX
}
}
return true;
}
bool cDvbDevice::SetChannelDevice(const cChannel *Channel)
{
// Avoid noise while switching:
if (HasDecoder()) {
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
}
// Stop setting system time:
if (siProcessor)
siProcessor->SetCurrentTransponder(0);
// Turn off current PIDs:
if (HasDecoder()) {
DelPid(pidHandles[ptVideo].pid);
DelPid(pidHandles[ptAudio].pid);
DelPid(pidHandles[ptTeletext].pid);
DelPid(pidHandles[ptDolby].pid);
}
FrontendParameters Frontend;
switch (frontendType) {
case FE_QPSK: { // DVB-S
// Frequency offsets:
unsigned int freq = Channel->frequency;
int tone = SEC_TONE_OFF;
if (freq < (unsigned int)Setup.LnbSLOF) {
freq -= Setup.LnbFrequLo;
tone = SEC_TONE_OFF;
}
else {
freq -= Setup.LnbFrequHi;
tone = SEC_TONE_ON;
}
Frontend.Frequency = freq * 1000UL;
Frontend.Inversion = INVERSION_AUTO;
Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL;
Frontend.u.qpsk.FEC_inner = FEC_AUTO;
int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
// DiseqC:
secCommand scmd;
scmd.type = 0;
scmd.u.diseqc.addr = 0x10;
scmd.u.diseqc.cmd = 0x38;
scmd.u.diseqc.numParams = 1;
scmd.u.diseqc.params[0] = 0xF0 | ((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0);
secCmdSequence scmds;
scmds.voltage = volt;
scmds.miniCommand = SEC_MINI_NONE;
scmds.continuousTone = tone;
scmds.numCommands = Setup.DiSEqC ? 1 : 0;
scmds.commands = &scmd;
CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
}
break;
case FE_QAM: { // DVB-C
// Frequency and symbol rate:
Frontend.Frequency = Channel->frequency * 1000000UL;
Frontend.Inversion = INVERSION_AUTO;
Frontend.u.qam.SymbolRate = Channel->srate * 1000UL;
Frontend.u.qam.FEC_inner = FEC_AUTO;
Frontend.u.qam.QAM = QAM_64;
}
break;
case FE_OFDM: { // DVB-T
// Frequency and OFDM paramaters:
Frontend.Frequency = Channel->frequency * 1000UL;
Frontend.Inversion = INVERSION_AUTO;
Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ;
Frontend.u.ofdm.HP_CodeRate=FEC_2_3;
Frontend.u.ofdm.LP_CodeRate=FEC_1_2;
Frontend.u.ofdm.Constellation=QAM_64;
Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K;
Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32;
Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE;
}
break;
default:
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
return false;
}
// Tuning:
CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
// Wait for channel sync:
if (cFile::FileReady(fd_frontend, 5000)) {
FrontendEvent event;
int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
if (res >= 0) {
if (event.type != FE_COMPLETION_EV) {
esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->number, CardIndex() + 1);
if (IsPrimaryDevice())
cThread::RaisePanic();
return false;
}
}
else
esyslog("ERROR %d in frontend get event (channel %d, card %d)", res, Channel->number, CardIndex() + 1);
}
else
esyslog("ERROR: timeout while tuning");
frequency = Channel->frequency;
// PID settings:
if (HasDecoder()) {
if (!(AddPid(Channel->vpid, ptVideo) && AddPid(Channel->apid1, ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
esyslog("ERROR: failed to set PIDs for channel %d", Channel->number);
return false;
}
if (IsPrimaryDevice())
AddPid(Channel->tpid, ptTeletext);
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
}
if (HasDecoder()) {
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
}
// Start setting system time:
if (siProcessor)
siProcessor->SetCurrentTransponder(Channel->frequency);
return true;
}
void cDvbDevice::SetVolumeDevice(int Volume)
{
if (HasDecoder()) {
audioMixer_t am;
am.volume_left = am.volume_right = Volume;
CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
}
}
int cDvbDevice::SetPlayMode(bool On)
{
if (On) {
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, true));
CHECK(ioctl(fd_audio, AUDIO_PLAY));
CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
CHECK(ioctl(fd_video, VIDEO_PLAY));
return fd_video;
}
else {
CHECK(ioctl(fd_video, VIDEO_STOP, true));
CHECK(ioctl(fd_audio, AUDIO_STOP, true));
CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
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);
return -1;
}
}
void cDvbDevice::TrickSpeed(int Speed)
{
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
}
void cDvbDevice::Clear(void)
{
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
if (fd_audio >= 0)
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
}
void cDvbDevice::Play(void)
{
if (fd_audio >= 0)
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_CONTINUE));
}
void cDvbDevice::Freeze(void)
{
if (fd_audio >= 0)
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
if (fd_video >= 0)
CHECK(ioctl(fd_video, VIDEO_FREEZE));
}
void cDvbDevice::Mute(void)
{
if (fd_audio >= 0) {
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
}
}
void cDvbDevice::StillPicture(const uchar *Data, int Length)
{
Mute();
/* Using the VIDEO_STILLPICTURE ioctl call would be the
correct way to display a still frame, but unfortunately this
doesn't work with frames from VDR. So let's do pretty much the
same here as in DVB/driver/dvb.c's play_iframe() - I have absolutely
no idea why it works this way, but doesn't work with VIDEO_STILLPICTURE.
If anybody ever finds out what could be changed so that VIDEO_STILLPICTURE
could be used, please let me know!
kls 2002-03-23
*/
//#define VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
#ifdef VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
videoDisplayStillPicture sp = { (char *)Data, Length };
CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
#else
#define MIN_IFRAME 400000
for (int i = MIN_IFRAME / Length + 1; i > 0; i--) {
safe_write(fd_video, Data, Length);
usleep(1); // allows the buffer to be displayed in case the progress display is active
}
#endif
}
int cDvbDevice::PlayVideo(const uchar *Data, int Length)
{
if (fd_video >= 0)
return write(fd_video, Data, Length);
return -1;
}
int cDvbDevice::PlayAudio(const uchar *Data, int Length)
{
//XXX+
return -1;
}
bool cDvbDevice::OpenDvr(void)
{
CloseDvr();
fd_dvr = OstOpen(DEV_OST_DVR, CardIndex(), O_RDONLY | O_NONBLOCK, true);
return fd_dvr >= 0;
}
void cDvbDevice::CloseDvr(void)
{
if (fd_dvr >= 0) {
close(fd_dvr);
fd_dvr = -1;
}
}
int cDvbDevice::GetTSPacket(uchar *Data)
{
if (fd_dvr >= 0) {
pollfd pfd;
pfd.fd = fd_dvr;
pfd.events = POLLIN;
poll(&pfd, 1, 100);
if (pfd.revents & POLLIN != 0) {
int r = read(fd_dvr, Data, TS_SIZE);
if (r >= 0)
return r;
else if (FATALERRNO) {
if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library
esyslog("ERROR: DVB driver buffer overflow on device %d", CardIndex() + 1);
else {
LOG_ERROR;
return -1;
}
}
}
return 0;
}
else
return -1;
}

97
dvbdevice.h Normal file
View File

@ -0,0 +1,97 @@
/*
* dvbdevice.h: The DVB device interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbdevice.h 1.1 2002/08/04 12:19:10 kls Exp $
*/
#ifndef __DVBDEVICE_H
#define __DVBDEVICE_H
#include <stdlib.h> // FIXME: this is apparently necessary for the ost/... header files
// FIXME: shouldn't every header file include ALL the other header
// FIXME: files it depends on? The sequence in which header files
// FIXME: are included here should not matter - and it should NOT
// FIXME: be necessary to include <stdlib.h> here!
#include <ost/frontend.h>
#include "device.h"
#include "eit.h"
class cDvbDevice : public cDevice {
friend class cDvbOsd;
private:
static bool Probe(const char *FileName);
// Probes for existing DVB devices.
public:
static bool Initialize(void);
// Initializes the DVB devices.
// Must be called before accessing any DVB functions.
private:
FrontendType frontendType;
int fd_osd, fd_frontend, fd_sec, fd_audio, fd_video, fd_dvr;
int OsdDeviceHandle(void) const { return fd_osd; }
protected:
virtual void MakePrimaryDevice(bool On);
public:
cDvbDevice(int n);
virtual ~cDvbDevice();
virtual bool CanBeReUsed(int Frequency, int Vpid);
virtual bool HasDecoder(void) const;
// Channel facilities
private:
int frequency;
public:
virtual bool SetChannelDevice(const cChannel *Channel);
// PID handle facilities
protected:
virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
// Image Grab facilities
public:
virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
// Video format facilities
public:
virtual void SetVideoFormat(bool VideoFormat16_9);
// Volume facilities
protected:
virtual void SetVolumeDevice(int Volume);
// EIT facilities
private:
cSIProcessor *siProcessor;
// Player facilities
protected:
virtual int SetPlayMode(bool On);
public:
virtual void TrickSpeed(int Speed);
virtual void Clear(void);
virtual void Play(void);
virtual void Freeze(void);
virtual void Mute(void);
virtual void StillPicture(const uchar *Data, int Length);
virtual int PlayVideo(const uchar *Data, int Length);
virtual int PlayAudio(const uchar *Data, int Length);
// Receiver facilities
protected:
virtual bool OpenDvr(void);
virtual void CloseDvr(void);
virtual int GetTSPacket(uchar *Data);
};
#endif //__DVBDEVICE_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbosd.c 1.17 2002/05/18 13:39:02 kls Exp $ * $Id: dvbosd.c 1.18 2002/08/04 10:13:21 kls Exp $
*/ */
#include "dvbosd.h" #include "dvbosd.h"
@ -13,10 +13,12 @@
#include <sys/unistd.h> #include <sys/unistd.h>
#include "tools.h" #include "tools.h"
cDvbOsd::cDvbOsd(int OsdDev, int x, int y) const cDvbDevice *cDvbOsd::dvbDevice = NULL;
cDvbOsd::cDvbOsd(int x, int y)
:cOsdBase(x, y) :cOsdBase(x, y)
{ {
osdDev = OsdDev; osdDev = dvbDevice ? dvbDevice->OsdDeviceHandle() : -1;
if (osdDev < 0) if (osdDev < 0)
esyslog("ERROR: illegal OSD device handle (%d)!", osdDev); esyslog("ERROR: illegal OSD device handle (%d)!", osdDev);
} }
@ -27,6 +29,11 @@ cDvbOsd::~cDvbOsd()
CloseWindow(GetWindowNr(i)); CloseWindow(GetWindowNr(i));
} }
void cDvbOsd::SetDvbDevice(const cDvbDevice *DvbDevice)
{
dvbDevice = DvbDevice;
}
bool cDvbOsd::SetWindow(cWindow *Window) bool cDvbOsd::SetWindow(cWindow *Window)
{ {
if (Window) { if (Window) {

View File

@ -4,17 +4,19 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbosd.h 1.13 2002/05/18 13:38:09 kls Exp $ * $Id: dvbosd.h 1.14 2002/08/04 10:12:14 kls Exp $
*/ */
#ifndef __DVBOSD_H #ifndef __DVBOSD_H
#define __DVBOSD_H #define __DVBOSD_H
#include <ost/osd.h> #include <ost/osd.h>
#include "dvbdevice.h"
#include "osdbase.h" #include "osdbase.h"
class cDvbOsd : public cOsdBase { class cDvbOsd : public cOsdBase {
private: private:
static const cDvbDevice *dvbDevice;
int osdDev; int osdDev;
bool SetWindow(cWindow *Window); bool SetWindow(cWindow *Window);
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
@ -26,8 +28,9 @@ protected:
virtual void MoveWindow(cWindow *Window, int x, int y); virtual void MoveWindow(cWindow *Window, int x, int y);
virtual void CloseWindow(cWindow *Window); virtual void CloseWindow(cWindow *Window);
public: public:
cDvbOsd(int OsdDev, int x, int y); cDvbOsd(int x, int y);
virtual ~cDvbOsd(); virtual ~cDvbOsd();
static void SetDvbDevice(const cDvbDevice *DvbDevice);
}; };
#endif //__DVBOSD_H #endif //__DVBOSD_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbplayer.c 1.7 2002/07/14 14:30:36 kls Exp $ * $Id: dvbplayer.c 1.8 2002/07/27 11:57:48 kls Exp $
*/ */
#include "dvbplayer.h" #include "dvbplayer.h"
@ -90,6 +90,7 @@ private:
int replayFile; int replayFile;
bool eof; bool eof;
bool active; bool active;
bool running;
ePlayModes playMode; ePlayModes playMode;
ePlayDirs playDir; ePlayDirs playDir;
int trickSpeed; int trickSpeed;
@ -133,6 +134,7 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
index = NULL; index = NULL;
eof = false; eof = false;
active = true; active = true;
running = false;
playMode = pmPlay; playMode = pmPlay;
playDir = pdForward; playDir = pdForward;
trickSpeed = NORMAL_SPEED; trickSpeed = NORMAL_SPEED;
@ -285,8 +287,9 @@ void cDvbPlayer::Activate(bool On)
Start(); Start();
} }
else if (active) { else if (active) {
active = false; running = false;
Cancel(3); Cancel(3);
active = false;
} }
} }
@ -308,7 +311,8 @@ void cDvbPlayer::Action(void)
if (readIndex >= 0) if (readIndex >= 0)
isyslog("resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true)); isyslog("resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true));
while (active && NextFile()) { running = true;
while (running && NextFile()) {
pfd[1].fd = replayFile; // NextFile() may have returned a new file handle! pfd[1].fd = replayFile; // NextFile() may have returned a new file handle!
{ {
LOCK_THREAD; LOCK_THREAD;
@ -414,9 +418,9 @@ void cDvbPlayer::Action(void)
break; break;
} }
} }
active = running = false;
dsyslog("dvbplayer thread ended (pid=%d)", getpid()); dsyslog("dvbplayer thread ended (pid=%d)", getpid());
active = false;
} }
void cDvbPlayer::Pause(void) void cDvbPlayer::Pause(void)

4
eit.h
View File

@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
* $Id: eit.h 1.16 2002/03/10 10:56:57 kls Exp $ * $Id: eit.h 1.17 2002/08/04 11:30:24 kls Exp $
***************************************************************************/ ***************************************************************************/
#ifndef __EIT_H #ifndef __EIT_H
@ -158,7 +158,7 @@ public:
static bool Read(FILE *f = NULL); static bool Read(FILE *f = NULL);
void SetStatus(bool On); void SetStatus(bool On);
void SetCurrentTransponder(int CurrentTransponder); void SetCurrentTransponder(int CurrentTransponder);
bool SetCurrentServiceID(unsigned short servid); static bool SetCurrentServiceID(unsigned short servid);
}; };
#endif #endif

View File

@ -4,10 +4,11 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: eitscan.c 1.3 2002/06/22 13:02:40 kls Exp $ * $Id: eitscan.c 1.4 2002/07/28 15:10:23 kls Exp $
*/ */
#include "eitscan.h" #include "eitscan.h"
#include <stdlib.h>
cEITScanner::cEITScanner(void) cEITScanner::cEITScanner(void)
{ {

4
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.202 2002/07/14 10:55:37 kls Exp $ * $Id: menu.c 1.203 2002/08/03 09:55:44 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -1628,7 +1628,7 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
if (state == osBack && Key == kOk) { if (state == osBack && Key == kOk) {
if (Setup.PrimaryDVB != oldPrimaryDVB) { if (Setup.PrimaryDVB != oldPrimaryDVB) {
state = osSwitchDvb; state = osSwitchDvb;
cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat);
} }
} }
return state; return state;

4
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.c 1.31 2002/07/14 10:57:45 kls Exp $ * $Id: osd.c 1.32 2002/08/04 10:11:26 kls Exp $
*/ */
#include "osd.h" #include "osd.h"
@ -73,7 +73,7 @@ cOsdBase *cOsd::OpenRaw(int x, int y)
#ifdef DEBUG_OSD #ifdef DEBUG_OSD
return NULL; return NULL;
#else #else
return osd ? NULL : new cDvbOsd(cDevice::PrimaryDevice()->OsdDeviceHandle(), x, y); return osd ? NULL : new cDvbOsd(x, y);
#endif #endif
} }

View File

@ -4,18 +4,21 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: receiver.c 1.1 2002/06/08 09:58:29 kls Exp $ * $Id: receiver.c 1.3 2002/07/28 15:14:49 kls Exp $
*/ */
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include "receiver.h" #include "receiver.h"
#include "tools.h"
cReceiver::cReceiver(int Ca, int Priority, int NumPids, ...) cReceiver::cReceiver(int Ca, int Priority, int NumPids, ...)
{ {
device = NULL; device = NULL;
ca = Ca; ca = Ca;
priority = Priority; priority = Priority;
for (int i = 0; i < MAXRECEIVEPIDS; i++)
pids[i] = 0;
if (NumPids) { if (NumPids) {
va_list ap; va_list ap;
va_start(ap, NumPids); va_start(ap, NumPids);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: receiver.h 1.1 2002/06/08 15:32:51 kls Exp $ * $Id: receiver.h 1.2 2002/07/28 11:22:01 kls Exp $
*/ */
#ifndef __RECEIVER_H #ifndef __RECEIVER_H
@ -42,6 +42,9 @@ public:
// the given Priority. NumPids defines the number of PIDs that follow // the given Priority. NumPids defines the number of PIDs that follow
// this parameter. If any of these PIDs are 0, they will be silently ignored. // this parameter. If any of these PIDs are 0, they will be silently ignored.
// The total number of non-zero PIDs must not exceed MAXRECEIVEPIDS. // The total number of non-zero PIDs must not exceed MAXRECEIVEPIDS.
// Priority may be any value in the range 0..99. Negative values indicate
// that this cReceiver may be detached at any time (without blocking the
// cDevice it is attached to).
virtual ~cReceiver(); virtual ~cReceiver();
}; };

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.c 1.64 2002/06/22 10:11:49 kls Exp $ * $Id: recording.c 1.65 2002/07/27 12:55:14 kls Exp $
*/ */
#include "recording.h" #include "recording.h"
@ -22,12 +22,24 @@
#define RECEXT ".rec" #define RECEXT ".rec"
#define DELEXT ".del" #define DELEXT ".del"
#ifdef VFAT /* This was the original code, which works fine in a Linux only environment.
#define DATAFORMAT "%4d-%02d-%02d.%02d.%02d.%02d.%02d" RECEXT Unfortunately, because of windows and its brain dead file system, we have
#else to use a more complicated approach, in order to allow users who have enabled
the VFAT compile time option to see their recordings even if they forget to
enable VFAT when compiling a new version of VDR... Gee, do I hate Windows.
(kls 2002-07-27)
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT #define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
#endif
#define NAMEFORMAT "%s/%s/" DATAFORMAT #define NAMEFORMAT "%s/%s/" DATAFORMAT
*/
// start of implementation for brain dead systems
#define DATAFORMAT "%4d-%02d-%02d.%02d%*c%02d.%02d.%02d" RECEXT
#ifdef VFAT
#define nameFORMAT "%4d-%02d-%02d.%02d.%02d.%02d.%02d" RECEXT
#else
#define nameFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
#endif
#define NAMEFORMAT "%s/%s/" nameFORMAT
// end of implementation for brain dead systems
#define RESUMEFILESUFFIX "/resume.vdr" #define RESUMEFILESUFFIX "/resume.vdr"
#define SUMMARYFILESUFFIX "/summary.vdr" #define SUMMARYFILESUFFIX "/summary.vdr"

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: remux.h 1.5 2001/06/23 14:06:59 kls Exp $ * $Id: remux.h 1.6 2002/08/04 10:27:07 kls Exp $
*/ */
#ifndef __REMUX_H #ifndef __REMUX_H
@ -12,6 +12,7 @@
#include <time.h> //XXX FIXME: DVB/ost/include/ost/dmx.h should include <time.h> itself!!! #include <time.h> //XXX FIXME: DVB/ost/include/ost/dmx.h should include <time.h> itself!!!
#include <ost/dmx.h> #include <ost/dmx.h>
#include "tools.h"
// Picture types: // Picture types:
#define NO_PICTURE 0 #define NO_PICTURE 0
@ -24,7 +25,6 @@
#define RESULTBUFFERSIZE (MINVIDEODATA * 4) #define RESULTBUFFERSIZE (MINVIDEODATA * 4)
typedef unsigned char uchar;
class cTS2PES; class cTS2PES;
class cRemux { class cRemux {

View File

@ -7,10 +7,11 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the * Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org). * LinuxDVB driver (see linuxtv.org).
* *
* $Id: ringbuffer.c 1.9 2002/06/16 11:24:40 kls Exp $ * $Id: ringbuffer.c 1.10 2002/07/28 12:47:32 kls Exp $
*/ */
#include "ringbuffer.h" #include "ringbuffer.h"
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "tools.h" #include "tools.h"

View File

@ -4,15 +4,14 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: ringbuffer.h 1.6 2002/06/16 11:30:07 kls Exp $ * $Id: ringbuffer.h 1.7 2002/08/04 10:27:30 kls Exp $
*/ */
#ifndef __RINGBUFFER_H #ifndef __RINGBUFFER_H
#define __RINGBUFFER_H #define __RINGBUFFER_H
#include "thread.h" #include "thread.h"
#include "tools.h"
typedef unsigned char uchar;//XXX+
class cRingBuffer { class cRingBuffer {
private: private:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.67 2002/05/18 15:10:45 kls Exp $ * $Id: tools.c 1.68 2002/08/03 15:44:53 kls Exp $
*/ */
#include "tools.h" #include "tools.h"
@ -407,7 +407,7 @@ bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
char *ReadLink(const char *FileName) char *ReadLink(const char *FileName)
{ {
char RealName[_POSIX_PATH_MAX]; char RealName[PATH_MAX];
const char *TargetName = NULL; const char *TargetName = NULL;
int n = readlink(FileName, RealName, sizeof(RealName) - 1); int n = readlink(FileName, RealName, sizeof(RealName) - 1);
if (n < 0) { if (n < 0) {

11
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * The project's page is at http://www.cadsoft.de/people/kls/vdr
* *
* $Id: vdr.c 1.117 2002/06/23 11:23:34 kls Exp $ * $Id: vdr.c 1.118 2002/08/04 09:56:30 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -33,6 +33,7 @@
#include "config.h" #include "config.h"
#include "cutter.h" #include "cutter.h"
#include "device.h" #include "device.h"
#include "dvbdevice.h"
#include "eitscan.h" #include "eitscan.h"
#include "i18n.h" #include "i18n.h"
#include "interface.h" #include "interface.h"
@ -326,11 +327,9 @@ int main(int argc, char *argv[])
// DVB interfaces: // DVB interfaces:
if (!cDevice::Initialize()) if (!cDvbDevice::Initialize())
return 2; return 2;
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
cSIProcessor::Read(); cSIProcessor::Read();
// Start plugins: // Start plugins:
@ -338,6 +337,10 @@ int main(int argc, char *argv[])
if (!PluginManager.StartPlugins()) if (!PluginManager.StartPlugins())
return 2; return 2;
// Primary device:
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
// OSD: // OSD:
cOsd::Initialize(); cOsd::Initialize();