Version 1.1.3

- Improved the VDR Makefile to avoid a warning if the '.dependencies' file does
  not exist, and also using $(MAKE) to call recursive makes.
- Changed the name of the 'package' target in the plugin Makefiles to 'dist'
  (following the suggestions in the "GNU Make" manual). If you already have started
  a plugin project, you may want to change this in your Makefile accordingly.
- Improved the plugin Makefile to avoid a warning if the '.dependencies' file does
  not exist, and also using $(shell...) to get the version numbers. If you already have
  started a plugin project, you may want to change this in your Makefile accordingly.
- Fixed some function headers to make them compile with gcc 3.x (thanks to
  Gregoire Favre).
- Fixed the cutting mechanism to make it re-sync in case a frame is larger than the
  buffer (thanks to Sven Grothklags).
- Added an error message if the directory specified in the '-L' option can't be
  accessed (suggested by Stefan Huelswitt).
- Rearranged OSD class names to make 'cOsd' available for the main OSD interface.
- Completely moved OSD handling out of the cDvbApi class, into the new cOsd.
- Implemented cStatus to allow plugins to set up a status monitor.
  See PLUGINS.html for details.
- Moved the cEITScanner out of dvbapi.h/.c, into the new eitscan.h/.c.
- Added Swedish language texts (thanks to Tomas Prybil).
- Fixed parsing 'E' records in epg2html.pl (thanks to Matthias Fechner for pointing
  out this one).
- Removed compiler option '-m486' to make it work on non-Intel platforms. If you
  have already started a plugin project, you may want to make sure you remove this
  option from your existing Makefile.
- Completely rearranged the recording and replay functions to make them available
  to plugins.
- Replay is now done in a single thread (no more syncing between input and output
  thread necessary).
- It is now possible to record several channels on the same transponder with "budget
  cards". VDR automatically attaches a recording timer to a card that already
  records on the appropriate transponder. How many parallel recordings can actually
  be done depends on the computer's performance. Currently any number of recordings
  gets attached to a card, so you should carefully plan your timers to not exceed
  the limit. On a K6-II/450 it was possible to record three channels from transponder
  12480 with a single WinTV NOVA-S.
- Timers that record two successive shows on the same channel may now overlap and
  will use the same DVB card. During the time where both timers record the data
  is simply saved to both files.
- The following limitations apply to this version:
  + Transfer mode doesn't work yet.
  + The '-a' option (for Dolby Digital audio) doesn't work yet.
  + Switching between different language tracks doesn't work yet.
  + Cutting doesn't work yet.
This commit is contained in:
Klaus Schmidinger 2002-06-16 18:00:00 +02:00
parent d07e3829f7
commit f06d2c27fc
61 changed files with 5097 additions and 3584 deletions

View File

@ -137,6 +137,8 @@ Stefan Huelswitt <huels@iname.com>
for suggesting to make 'package' target in the plugin's Makefile produce a package that
expands to a directory with just the plugin name and version number
for suggesting to make the config directory available to plugins
for suggesting to add an error message if the directory specified in the '-L'
option can't be accessed
Ulrich Röder <roeder@efr-net.de>
for pointing out that there are channels that have a symbol rate higher than
@ -338,3 +340,25 @@ Oliver Lorei <oliverlorei@cityweb.de>
Andreas Böttger <fboettger@t-online.de>
for reporting a bug in skipping forward in time shift mode near the end of the recording
Onno Kreuzinger <ok@solutas.net>
for reporting leftover references to the file FORMATS in MANUAL and svdrp.c
Rudi Hofer (Rudi.Hofer@cadsoft.de)
for his help in keeping 'channels.conf' up to date
Gregoire Favre <greg@ulima.unil.ch>
for fixing some function headers to make them compile with gcc 3.x
Sven Grothklags <sven@uni-paderborn.de>
for fixing the cutting mechanism to make it re-sync in case a frame is larger
than the buffer
Tomas Prybil <tomas.prybil@copper.se>
for translating OSD texts to the Swedish language
Matthias Fechner <matthiasfechner@web.de>
for pointing out a bug in parsing 'E' records in epg2html.pl
Paul Lacatus <paul@campina.iiruc.ro>
for translating OSD texts to the Romanian language

71
HISTORY
View File

@ -951,7 +951,7 @@ Video Disk Recorder Revision History
- Changed the [dei]syslog macros in tools.h to use a variable number of args,
thus making it safe to use them in nested 'if/else' statements.
- Fixed error handling in establishing an SVDRP connection (thanks to Davide
Achilli) for pointing this out).
Achilli for pointing out this one).
- The new configuration file 'svdrphosts.conf' is now used to define which
hosts may access the SVDRP port (by default only 'localhost' has access).
See FORMATS for details.
@ -1144,7 +1144,7 @@ Video Disk Recorder Revision History
- New command command line option '-V' to display the VDR version.
- Adjusting column width for channel numbers in case there are more than 999
channels.
- Checking the return value of '...FileRady...' calls in dvbapi.c for better
- Checking the return value of '...FileReady...' calls in dvbapi.c for better
performance under heavy system load.
- New 'make' target 'install', which copies the manual pages and executables
to their appropriate system locations and creates the /video directory if
@ -1188,7 +1188,7 @@ Video Disk Recorder Revision History
- Now the EPG scan skips channels that have their 'Ca' parameter explicitly set
to an other DVB card (suggested by Sergei Haller).
- Fixed a possible hangup when reading a broken epg.data file (thanks to Henning
Holtschneider for pointing this one out).
Holtschneider for pointing out this one).
- Fixed a bug in the editing process in case a previously edited file with the
same name was manually deleted on a system with more than one video directory
(thanks to Dirk Wiebel for reporting this one).
@ -1261,7 +1261,8 @@ Video Disk Recorder Revision History
interface. 'osdbase.c/.h' now implements the abstract OSD, while 'dvbosd.c/.h'
is the actual implementation for the DVB hardware. This is in preparation for
allowing additional kinds of OSD hardware implementations.
- Fixed leftover references to the file FORMATS in MANUAL and svdrp.c.
- Fixed leftover references to the file FORMATS in MANUAL and svdrp.c (thanks to
Onno Kreuzinger for reporting this one).
- Avoiding ambiguities in the cList template class in case one defines a "list of
lists" (thanks to Stefan Huelswitt).
- Simplified the basic cMenuSetupPage class for easier use in plugins.
@ -1284,3 +1285,65 @@ Video Disk Recorder Revision History
See PLUGINS.html, section "Configuration files" for details.
- Improved the [eid]syslog() macros, so that the LOG_... macros don't need to be
given any more.
2002-05-26: Version 1.0.3
- Updated 'Premiere Sport 2' in channels.conf (thanks to Rudi Hofer).
- Fixed some function headers to make them compile with gcc 3.x (thanks to
Gregoire Favre).
- Fixed the cutting mechanism to make it re-sync in case a frame is larger than the
buffer (thanks to Sven Grothklags).
- Added Swedish language texts (thanks to Tomas Prybil).
2002-06-10: Version 1.0.4
- Added Romanian language texts (thanks to Paul Lacatus).
- Removed compiler option '-m486' to make it work on non-Intel platforms (thanks
to Alastair McKinstry for pointing this out).
2002-06-16: Version 1.1.3
- Improved the VDR Makefile to avoid a warning if the '.dependencies' file does
not exist, and also using $(MAKE) to call recursive makes.
- Changed the name of the 'package' target in the plugin Makefiles to 'dist'
(following the suggestions in the "GNU Make" manual). If you already have started
a plugin project, you may want to change this in your Makefile accordingly.
- Improved the plugin Makefile to avoid a warning if the '.dependencies' file does
not exist, and also using $(shell...) to get the version numbers. If you already have
started a plugin project, you may want to change this in your Makefile accordingly.
- Fixed some function headers to make them compile with gcc 3.x (thanks to
Gregoire Favre).
- Fixed the cutting mechanism to make it re-sync in case a frame is larger than the
buffer (thanks to Sven Grothklags).
- Added an error message if the directory specified in the '-L' option can't be
accessed (suggested by Stefan Huelswitt).
- Rearranged OSD class names to make 'cOsd' available for the main OSD interface.
- Completely moved OSD handling out of the cDvbApi class, into the new cOsd.
- Implemented cStatus to allow plugins to set up a status monitor.
See PLUGINS.html for details.
- Moved the cEITScanner out of dvbapi.h/.c, into the new eitscan.h/.c.
- Added Swedish language texts (thanks to Tomas Prybil).
- Fixed parsing 'E' records in epg2html.pl (thanks to Matthias Fechner for pointing
out this one).
- Removed compiler option '-m486' to make it work on non-Intel platforms. If you
have already started a plugin project, you may want to make sure you remove this
option from your existing Makefile.
- Completely rearranged the recording and replay functions to make them available
to plugins.
- Replay is now done in a single thread (no more syncing between input and output
thread necessary).
- It is now possible to record several channels on the same transponder with "budget
cards". VDR automatically attaches a recording timer to a card that already
records on the appropriate transponder. How many parallel recordings can actually
be done depends on the computer's performance. Currently any number of recordings
gets attached to a card, so you should carefully plan your timers to not exceed
the limit. On a K6-II/450 it was possible to record three channels from transponder
12480 with a single WinTV NOVA-S.
- Timers that record two successive shows on the same channel may now overlap and
will use the same DVB card. During the time where both timers record the data
is simply saved to both files.
- The following limitations apply to this version:
+ Transfer mode doesn't work yet.
+ The '-a' option (for Dolby Digital audio) doesn't work yet.
+ Switching between different language tracks doesn't work yet.
+ Cutting doesn't work yet.

View File

@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: Makefile 1.35 2002/05/10 10:24:46 kls Exp $
# $Id: Makefile 1.40 2002/06/10 16:31:34 kls Exp $
.DELETE_ON_ERROR:
@ -21,9 +21,10 @@ INCLUDES = -I$(DVBDIR)/ost/include
DTVLIB = $(DTVDIR)/libdtv.a
OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o\
menuitems.o osdbase.o osd.o plugin.o recording.o remote.o remux.o ringbuffer.o\
svdrp.o thread.o tools.o vdr.o videodir.o
OBJS = audio.o config.o device.o dvbplayer.o dvbosd.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\
recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\
tools.o vdr.o videodir.o
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
@ -57,7 +58,7 @@ font: genfontfile fontfix.c fontosd.c
# Implicit rules:
%.o: %.c
g++ -g -O2 -Wall -Woverloaded-virtual -m486 -c $(DEFINES) $(INCLUDES) $<
g++ -g -O2 -Wall -Woverloaded-virtual -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
@ -66,7 +67,7 @@ DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
include $(DEPFILE)
-include $(DEPFILE)
# The main program:
@ -88,7 +89,7 @@ genfontfile: genfontfile.c
# The libdtv library:
$(DTVLIB) $(DTVDIR)/libdtv.h:
make -C $(DTVDIR) all
$(MAKE) -C $(DTVDIR) all
# The 'include' directory (for plugins):
@ -99,10 +100,10 @@ include-dir:
# Plugins:
plugins: include-dir
@for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do make -C "$(PLUGINDIR)/SRC/$$i" all; done
@for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/SRC/$$i" all; done
plugins-clean:
@for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do make -C "$(PLUGINDIR)/SRC/$$i" clean; done
@for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/SRC/$$i" clean; done
@-rm -f $(PLUGINDIR)/lib/*
# Install the files:
@ -119,7 +120,7 @@ install:
# Housekeeping:
clean:
make -C $(DTVDIR) clean
$(MAKE) -C $(DTVDIR) clean
-rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~
-rm -rf include
fontclean:

View File

@ -4,7 +4,7 @@
</head>
<body bgcolor="white">
<h1>The VDR Plugin System</h1>
<center><h1>The VDR Plugin System</h1></center>
VDR provides an easy to use plugin interface that allows additional functionality
to be added to the program by implementing a dynamically loadable library file.
@ -12,18 +12,30 @@ This interface allows programmers to develop additional functionality for VDR co
separate from the core VDR source, without the need of patching the original
VDR code (and all the problems of correlating various patches).
<p>
This document describes the "outside" interface of the plugin system.
It handles everything necessary for a plugin to get hooked into the core
<!--X1.1.3--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
This document is divided into two parts, the first one describing the
<a href="#Part I - The Outside Interface"><i>outside</i> interface</a>
of the plugin system, and the second one describing the
<a href="#Part II - The Inside Interface"><i>inside</i> interface</a>.
The <i>outside</i> interface handles everything necessary for a plugin to get hooked into the core
VDR program and present itself to the user.
The <i>inside</i> interface provides the plugin code access to VDR's internal data
structures and allows it to hook itself into specific areas to perform special actions.
<!--X1.1.3--></td></tr></table>
<p>
<!--X1.1.1--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.1 are marked like this.
<!--X1.1.1--></td></tr></table>
<!--X1.1.2--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan>&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=red>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.3 are marked like this.
<!--X1.1.3--></td></tr></table>
<!--<p>TODO: Link to the document about VDR base classes to use when implementing actual functionality (yet to be written).-->
<a name="Part I - The Outside Interface"><hr><center><h1>Part I - The Outside Interface</h1></center>
<hr><h2>Quick start</h2>
<center><i><b>Can't wait, can't wait!</b></i></center><p>
@ -117,7 +129,7 @@ from the web, it will typically have a name like
<p>
and will unpack into a directory named
<p>
<!--X1.1.2--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<tt>hello-0.0.1</tt>
<!--X1.1.2--></td></tr></table>
<p>
@ -125,7 +137,7 @@ To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>
you need to unpack such an archive into the <tt>VDR/PLUGINS/SRC</tt> directory and
create a symbolic link with the basic plugin name, as in
<!--X1.1.2--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
ln -s hello-0.0.1 hello
</pre></td></tr></table><p>
@ -191,7 +203,7 @@ its memory. You don't need to worry about the details behind all this.
If your plugin requires additional source files, simply add them to your plugin's
source directory and adjust the <tt>Makefile</tt> accordingly.
<p>
<!--X1.1.1--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime>&nbsp;</td><td width=100%>
Header files usually contain preprocessor statements that prevent the same
file (or rather its contents, to be precise) from being included more than once, like
@ -410,7 +422,7 @@ If a plugin implements a function that runs in the background (presumably in a
thread of its own), or wants to make use of <a href="#Internationalization">internationalization</a>,
it needs to implement the function
<!--X1.1.2--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
virtual bool Start(void);
</pre></td></tr></table><p>
@ -422,7 +434,7 @@ 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
from the main menu.
<p>
<!--X1.1.2--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
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
write a proper error message to the log file. The first plugin that returns
@ -486,7 +498,7 @@ interaction is possible. If a specific action takes longer than a few seconds,
the plugin should launch a separate thread to do this.
</b>
<!--X1.1.2--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<hr><h2>Housekeeping</h2>
<center><i><b>Chores, chores...</b></i></center><p>
@ -533,7 +545,7 @@ previously stored in the global setup data (see below). It shall return
<i>true</i> if the parameter was parsed correctly, <i>false</i> in case of
an error. If <i>false</i> is returned, an error message will be written to
the log file (and program execution will continue).
<!--X1.1.1--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime>&nbsp;</td><td width=100%>
A possible implementation of <tt>SetupParse()</tt> could look like this:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
@ -588,7 +600,7 @@ needs setup parameters that are not directly user adjustable. It can use
<tt>SetupStore()</tt> and <tt>SetupParse()</tt> without presenting these
parameters to the user.
<!--X1.1.1--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime>&nbsp;</td><td width=100%>
<a name="The Setup menu"><hr><h2>The Setup menu</h2>
<center><i><b>Have it your way!</b></i></center><p>
@ -648,7 +660,7 @@ your setup parameters and use that one to copy all parameters with one single st
(like VDR does with its cSetup class).
<!--X1.1.1--></td></tr></table>
<!--X1.1.2--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan>&nbsp;</td><td width=100%>
<hr><h2>Configuration files</h2>
<center><i><b>I want my own stuff!</b></i></center><p>
@ -815,16 +827,18 @@ 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
make a package that can be easily distributed.
<!--X1.1.3--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
The <tt>Makefile</tt> that has been created by the call to
<a href="#Initializing a new plugin directory"><tt>newplugin</tt></a>
provides the target <tt>package</tt>, which does this for you.
provides the target <tt>dist</tt>, which does this for you.
<p>
Simply change into your source directory and execute <tt>make package</tt>:
Simply change into your source directory and execute <tt>make dist</tt>:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
cd VDR/PLUGINS/SRC/hello
make package
make dist
</pre></td></tr></table><p>
<!--X1.1.3--></td></tr></table>
After this you should find a file named like
@ -835,5 +849,82 @@ vdr-hello-0.0.1.tgz
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.
<!--X1.1.3--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<a name="Part II - The Inside Interface"><hr><center><h1>Part II - The Inside Interface</h1></center>
<hr><h2>Status monitor</h2>
<center><i><b>A piece of the action</b></i></center><p>
If a plugin wants to get informed on various events in VDR, it can derive a class from
<tt>cStatus</tt>, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
#include &lt;vdr/status.h&gt;
class cMyStatusMonitor : public cStatus {
protected:
virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
};
void cMyStatusMonitor::ChannelSwitch(const cDevice *Device, int ChannelNumber)
{
if (ChannelNumber)
dsyslog("channel switched to %d on DVB %d", ChannelNumber, Device-&gt;CardIndex());
else
dsyslog("about to switch channel on DVB %d", Device-&gt;CardIndex());
}
</pre></td></tr></table><p>
An object of this class will be informed whenever the channel is switched on one of
the DVB devices. It could be used in a plugin like this:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
#include &lt;vdr/plugin.h&gt;
class cPluginStatus : public cPlugin {
private:
cMyStatusMonitor *statusMonitor;
public:
cPluginStatus(void);
virtual ~cPluginStatus();
...
virtual bool Start(void);
...
};
cPluginStatus::cPluginStatus(void)
{
statusMonitor = NULL;
}
cPluginStatus::~cPluginStatus()
{
delete statusMonitor;
}
bool cPluginStatus::Start(void)
{
statusMonitor = new cMyStatusMonitor;
return true;
}
</pre></td></tr></table><p>
Note that the actual object is created in the <tt>Start()</tt> function, not in the
constructor! It is also important to delete the object in the destructor, in order to
avoid memory leaks.
<p>
A Plugin can implement any number of <tt>cStatus</tt> derived objects, and once
the plugin has been started it may create and delete them as necessary.
No further action apart from creating an object derived from <tt>cStatus</tt>
is necessary. VDR will automatically hook it into a list of status monitors, with
their individual virtual member functions being called in the same sequence as the
objects were created.
<p>
See the file <tt>status.h</tt> for detailed information on which status monitor
member functions are available in <tt>cStatus</tt>. You only need to implement
the functions you actually want to use.
<!--X1.1.3--></td></tr></table>
</body>
</html>

View File

@ -14,3 +14,7 @@ VDR Plugin 'hello' Revision History
- Changed return type of cPluginHello::Start().
- Added cPluginHello::Housekeeping().
- Modified package generation.
2002-05-17: Version 0.0.4
- Makefile improvements.

View File

@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile 1.2 2002/05/12 15:09:07 kls Exp $
# $Id: Makefile 1.4 2002/06/10 16:24:06 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@ -11,7 +11,7 @@ PLUGIN = hello
### The version number of this plugin (taken from the main source file):
VERSION = `grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g'`
VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
### The directory environment:
@ -23,7 +23,7 @@ TMPDIR = /tmp
### The version number of VDR (taken from VDR's "config.h"):
VDRVERSION = `grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g'`
VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
### The name of the distribution archive:
@ -43,7 +43,7 @@ OBJS = $(PLUGIN).o i18n.o
### The C++ compiler and options:
CXX = g++
CXXFLAGS = -O2 -Wall -Woverloaded-virtual -m486
CXXFLAGS = -O2 -Wall -Woverloaded-virtual
### Implicit rules:
@ -57,7 +57,7 @@ DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
include $(DEPFILE)
-include $(DEPFILE)
### Targets:
@ -67,7 +67,7 @@ libvdr-$(PLUGIN).so: $(OBJS)
$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
@cp $@ $(LIBDIR)/$@.$(VDRVERSION)
package: clean
dist: clean
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@mkdir $(TMPDIR)/$(ARCHIVE)
@cp -a * $(TMPDIR)/$(ARCHIVE)

View File

@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: hello.c 1.4 2002/05/12 10:18:59 kls Exp $
* $Id: hello.c 1.5 2002/05/14 21:23:25 kls Exp $
*/
#include <getopt.h>
@ -11,7 +11,7 @@
#include <vdr/plugin.h>
#include "i18n.h"
static const char *VERSION = "0.0.3";
static const char *VERSION = "0.0.4";
static const char *DESCRIPTION = "A friendly greeting";
static const char *MAINMENUENTRY = "Hello";

340
PLUGINS/SRC/status/COPYING Normal file
View File

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

View File

@ -0,0 +1,6 @@
VDR Plugin 'status' Revision History
------------------------------------
2002-05-18: Version 0.0.1
- Initial revision.

View File

@ -0,0 +1,79 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id$
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name.
#
PLUGIN = status
### The version number of this plugin (taken from the main source file):
VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
### The directory environment:
DVBDIR = ../../../../DVB/ost/include
VDRDIR = ../../..
VDRINC = $(VDRDIR)/include
LIBDIR = ../../lib
TMPDIR = /tmp
### The version number of VDR (taken from VDR's "config.h"):
VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
### The name of the distribution archive:
ARCHIVE = $(PLUGIN)-$(VERSION)
PACKAGE = vdr-$(ARCHIVE)
### Includes and Defines (add further entries here):
INCLUDES = -I$(VDRINC) -I$(DVBDIR)
DEFINES = -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
OBJS = $(PLUGIN).o
### The C++ compiler and options:
CXX = g++
CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
MAKEDEP = g++ -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Targets:
all: libvdr-$(PLUGIN).so
libvdr-$(PLUGIN).so: $(OBJS)
$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
@cp $@ $(LIBDIR)/$@.$(VDRVERSION)
package: clean
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@mkdir $(TMPDIR)/$(ARCHIVE)
@cp -a * $(TMPDIR)/$(ARCHIVE)
@tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@echo Distribution package created as $(PACKAGE).tgz
clean:
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~

11
PLUGINS/SRC/status/README Normal file
View File

@ -0,0 +1,11 @@
This is a "plugin" for the Video Disk Recorder (VDR).
Written by: Klaus Schmidinger <kls@cadsoft.de>
Project's homepage: www.cadsoft.de/people/kls/vdr
Latest version available at: www.cadsoft.de/people/kls/vdr/software.htm
See the file COPYING for license information.
Description: This is an example that shows the use of cStatus.

179
PLUGINS/SRC/status/status.c Normal file
View File

@ -0,0 +1,179 @@
/*
* status.c: A plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
* $Id$
*/
#include <vdr/plugin.h>
#include <vdr/status.h>
static const char *VERSION = "0.0.1";
static const char *DESCRIPTION = "Status monitor test";
static const char *MAINMENUENTRY = NULL;
// ---
class cStatusTest : public cStatus {
protected:
virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
virtual void Recording(const cDevice *Device, const char *Name);
virtual void Replaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name);
virtual void SetVolume(int Volume, bool Absolute);
virtual void OsdClear(void);
virtual void OsdTitle(const char *Title);
virtual void OsdStatusMessage(const char *Message);
virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue);
virtual void OsdCurrentItem(const char *Text);
virtual void OsdTextItem(const char *Text, bool Scroll);
virtual void OsdChannel(const char *Text);
virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle);
};
void cStatusTest::ChannelSwitch(const cDevice *Device, int ChannelNumber)
{
dsyslog("status: cStatusTest::ChannelSwitch %d %d", Device->CardIndex(), ChannelNumber);
}
void cStatusTest::Recording(const cDevice *Device, const char *Name)
{
dsyslog("status: cStatusTest::Recording %d %s", Device->CardIndex(), Name);
}
void cStatusTest::Replaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name)
{
dsyslog("status: cStatusTest::Replaying %s", Name);
}
void cStatusTest::SetVolume(int Volume, bool Absolute)
{
dsyslog("status: cStatusTest::SetVolume %d %d", Volume, Absolute);
}
void cStatusTest::OsdClear(void)
{
dsyslog("status: cStatusTest::OsdClear");
}
void cStatusTest::OsdTitle(const char *Title)
{
dsyslog("status: cStatusTest::OsdTitle '%s'", Title);
}
void cStatusTest::OsdStatusMessage(const char *Message)
{
dsyslog("status: cStatusTest::OsdStatusMessage '%s'", Message);
}
void cStatusTest::OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
dsyslog("status: cStatusTest::OsdHelpKeys %s - %s - %s - %s", Red, Green, Yellow, Blue);
}
void cStatusTest::OsdCurrentItem(const char *Text)
{
dsyslog("status: cStatusTest::OsdCurrentItem %s", Text);
}
void cStatusTest::OsdTextItem(const char *Text, bool Scroll)
{
dsyslog("status: cStatusTest::OsdTextItem %s %d", Text, Scroll);
}
void cStatusTest::OsdChannel(const char *Text)
{
dsyslog("status: cStatusTest::OsdChannel %s", Text);
}
void cStatusTest::OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle)
{
char buffer[25];
struct tm tm_r;
dsyslog("status: cStatusTest::OsdProgramme");
strftime(buffer, sizeof(buffer), "%R", localtime_r(&PresentTime, &tm_r));
dsyslog("%5s %s", buffer, PresentTitle);
dsyslog("%5s %s", "", PresentSubtitle);
strftime(buffer, sizeof(buffer), "%R", localtime_r(&FollowingTime, &tm_r));
dsyslog("%5s %s", buffer, FollowingTitle);
dsyslog("%5s %s", "", FollowingSubtitle);
}
// ---
class cPluginStatus : public cPlugin {
private:
// Add any member variables or functions you may need here.
cStatusTest *statusTest;
public:
cPluginStatus(void);
virtual ~cPluginStatus();
virtual const char *Version(void) { return VERSION; }
virtual const char *Description(void) { return DESCRIPTION; }
virtual const char *CommandLineHelp(void);
virtual bool ProcessArgs(int argc, char *argv[]);
virtual bool Start(void);
virtual void Housekeeping(void);
virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; }
virtual cOsdMenu *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
};
cPluginStatus::cPluginStatus(void)
{
// Initialize any member varaiables here.
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
statusTest = NULL;
}
cPluginStatus::~cPluginStatus()
{
// Clean up after yourself!
delete statusTest;
}
const char *cPluginStatus::CommandLineHelp(void)
{
// Return a string that describes all known command line options.
return NULL;
}
bool cPluginStatus::ProcessArgs(int argc, char *argv[])
{
// Implement command line argument processing here if applicable.
return true;
}
bool cPluginStatus::Start(void)
{
// Start any background activities the plugin shall perform.
statusTest = new cStatusTest;
return true;
}
void cPluginStatus::Housekeeping(void)
{
// Perform any cleanup or other regular tasks.
}
cOsdMenu *cPluginStatus::MainMenuAction(void)
{
// Perform the action when selected from the main VDR menu.
return NULL;
}
cMenuSetupPage *cPluginStatus::SetupMenu(void)
{
// Return a setup menu in case the plugin supports one.
return NULL;
}
bool cPluginStatus::SetupParse(const char *Name, const char *Value)
{
// Parse your own setup parameters and store their values.
return false;
}
VDRPLUGINCREATOR(cPluginStatus); // Don't touch this!

11
audio.c Normal file
View File

@ -0,0 +1,11 @@
/*
* audio.c: The basic audio interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: audio.c 1.1 2002/05/30 11:08:54 kls Exp $
*/
#include "audio.h"

13
audio.h Normal file
View File

@ -0,0 +1,13 @@
/*
* audio.h: The basic audio interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: audio.h 1.1 2002/05/30 11:07:28 kls Exp $
*/
#ifndef __AUDIO_H
#define __AUDIO_H
#endif //__AUDIO_H

View File

@ -4,16 +4,16 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.c 1.101 2002/05/13 16:28:12 kls Exp $
* $Id: config.c 1.102 2002/06/16 12:57:31 kls Exp $
*/
#include "config.h"
#include <ctype.h>
#include <stdlib.h>
#include "dvbapi.h"
#include "i18n.h"
#include "interface.h"
#include "plugin.h"
#include "recording.h"
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
// format characters in order to allow any number of blanks after a numeric
@ -293,15 +293,15 @@ bool cChannel::Save(FILE *f)
return fprintf(f, ToText()) > 0;
}
bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
bool cChannel::Switch(cDevice *Device, bool Log)
{
if (!DvbApi)
DvbApi = cDvbApi::PrimaryDvbApi;
if (!DvbApi->Recording() && !groupSep) {
if (!Device)
Device = cDevice::PrimaryDevice();
if (!(Device->IsPrimaryDevice() && Device->Receiving()) && !groupSep) {
if (Log)
isyslog("switching to channel %d", number);
for (int i = 3; i--;) {
switch (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) {
switch (Device->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, tpid, ca, pnr)) {
case scrOk: return true;
case scrNoTransfer: if (Interface)
Interface->Error(tr("Can't start Transfer Mode!"));
@ -312,7 +312,7 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
}
return false;
}
if (DvbApi->Recording())
if (Device->IsPrimaryDevice() && Device->Receiving())
Interface->Error(tr("Channel locked (recording)!"));
return false;
}
@ -326,7 +326,7 @@ cTimer::cTimer(bool Instant)
startTime = stopTime = 0;
recording = pending = false;
active = Instant ? taActInst : taInactive;
cChannel *ch = Channels.GetByNumber(cDvbApi::CurrentChannel());
cChannel *ch = Channels.GetByNumber(cDevice::CurrentChannel());
channel = ch ? ch->number : 0;
time_t t = time(NULL);
struct tm tm_r;
@ -836,10 +836,10 @@ cChannel *cChannels::GetByServiceID(unsigned short ServiceId)
return NULL;
}
bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi)
bool cChannels::SwitchTo(int Number, cDevice *Device)
{
cChannel *channel = GetByNumber(Number);
return channel && channel->Switch(DvbApi);
return channel && channel->Switch(Device);
}
const char *cChannels::GetChannelNameByNumber(int Number)
@ -957,6 +957,7 @@ bool cSetupLine::operator< (const cListObject &ListObject)
bool cSetupLine::Parse(char *s)
{
//dsyslog("cSetupLine::Parse '%s'", s);//XXX-
char *p = strchr(s, '=');
if (p) {
*p = 0;
@ -974,6 +975,7 @@ bool cSetupLine::Parse(char *s)
}
name = strdup(Name);
value = strdup(Value);
//dsyslog("cSetupLine::Parse '%s' = '%s'", name, value);//XXX-
return true;
}
}
@ -982,6 +984,7 @@ bool cSetupLine::Parse(char *s)
bool cSetupLine::Save(FILE *f)
{
//dsyslog("cSetupLine::Save '%s' = '%s'", name, value);//XXX-
return fprintf(f, "%s%s%s = %s\n", plugin ? plugin : "", plugin ? "." : "", name, value) > 0;
}
@ -1095,7 +1098,7 @@ bool cSetup::Load(const char *FileName)
void cSetup::StoreCaCaps(const char *Name)
{
for (int d = 0; d < MAXDVBAPI; d++) {
for (int d = 0; d < MAXDEVICES; d++) {
char buffer[MAXPARSEBUFFER];
char *q = buffer;
*buffer = 0;
@ -1115,7 +1118,7 @@ bool cSetup::ParseCaCaps(const char *Value)
{
char *p;
int d = strtol(Value, &p, 10);
if (d > 0 && d <= MAXDVBAPI) {
if (d > 0 && d <= MAXDEVICES) {
d--;
int i = 0;
while (p != Value && p && *p) {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.116 2002/05/13 16:28:16 kls Exp $
* $Id: config.h 1.118 2002/05/31 10:20:56 kls Exp $
*/
#ifndef __CONFIG_H
@ -15,11 +15,11 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "dvbapi.h"
#include "device.h"
#include "eit.h"
#include "tools.h"
#define VDRVERSION "1.1.2"
#define VDRVERSION "1.1.3"
#define MAXPRIORITY 99
#define MAXLIFETIME 99
@ -118,7 +118,7 @@ public:
const char *ToText(void);
bool Parse(const char *s);
bool Save(FILE *f);
bool Switch(cDvbApi *DvbApi = NULL, bool Log = true);
bool Switch(cDevice *Device = NULL, bool Log = true);
};
enum eTimerActive { taInactive = 0,
@ -294,7 +294,7 @@ public:
cChannel *GetByNumber(int Number);
cChannel *GetByServiceID(unsigned short ServiceId);
const char *GetChannelNameByNumber(int Number);
bool SwitchTo(int Number, cDvbApi *DvbApi = NULL);
bool SwitchTo(int Number, cDevice *Device = NULL);
int MaxNumber(void) { return maxNumber; }
};
@ -385,7 +385,7 @@ public:
int MinEventTimeout, MinUserInactivity;
int MultiSpeedMode;
int ShowReplayMode;
int CaCaps[MAXDVBAPI][MAXCACAPS];
int CaCaps[MAXDEVICES][MAXCACAPS];
int CurrentChannel;
int CurrentVolume;
int __EndData__;

1017
device.c Normal file

File diff suppressed because it is too large Load Diff

199
device.h Normal file
View File

@ -0,0 +1,199 @@
/*
* device.h: The basic device interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.h 1.1 2002/06/09 15:48:32 kls Exp $
*/
#ifndef __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"
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
#define MAXDEVICES 4 // the maximum number of devices in the system
#define MAXCACAPS 16 // the maximum number of different CA values per DVB 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 VOLUMEDELTA 5 // used to increase/decrease the volume
class cPlayer;
class cReceiver;
class cDevice : cThread {
friend class cOsd;//XXX
private:
static int numDevices;
static int useDevice;
static cDevice *device[MAXDEVICES];
static cDevice *primaryDevice;
public:
static int NumDevices(void) { return numDevices; }
// Returns the total number of DVB devices.
static void SetUseDevice(int n);
// Sets the 'useDevice' flag of the given DVB device.
// If this function is not called before Initialize(), all DVB devices
// will be used.
static bool SetPrimaryDevice(int n);
// Sets the primary DVB device to 'n' (which must be in the range
// 1...numDevices) and returns true if this was possible.
static cDevice *PrimaryDevice(void) { return primaryDevice; }
// Returns the primary DVB device.
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.
// 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
// value in its caCaps.
// If there is a device that is already tuned to the given Frequency,
// and that device is able to receive multiple channels ("budget" cards),
// that device will be returned. Else if a ("full featured") device is
// tuned to Frequency and Vpid, that one will be returned.
// 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.
// 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
// (the device is already properly tuned). Otherwise the caller MUST switch the channel.
static void SetCaCaps(void);
// Sets the CaCaps of all DVB devices according to the Setup data.
static bool Probe(const char *FileName);
// 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);
// Closes down all DVB devices.
// Must be called at the end of the program.
private:
int cardIndex;
int caCaps[MAXCACAPS];
FrontendType frontendType;
char *dvrFileName;
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();
bool IsPrimaryDevice(void) { return this == primaryDevice; }
int CardIndex(void) const { return cardIndex; }
// Returns the card index of this device (0 ... MAXDEVICES - 1).
int ProvidesCa(int Ca);
// Checks whether this DVB device provides the given value in its
// caCaps. Returns 0 if the value is not provided, 1 if only this
// value is provided, and > 1 if this and other values are provided.
// If the given value is equal to the number of this DVB device,
// 1 is returned. If it is 0 (FTA), 1 plus the number of other values
// in caCaps is returned.
bool HasDecoder(void) const { return fd_video >= 0 && fd_audio >= 0; }
// Channel facilities
private:
int currentChannel;
int frequency;
public:
eSetChannelResult SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr);
static int CurrentChannel(void) { return primaryDevice ? primaryDevice->currentChannel : 0; }
int Channel(void) { return currentChannel; }
// PID handle facilities
private:
enum ePidType { ptVideo, ptAudio, ptTeletext, ptDolby, ptOther };
class cPidHandle {
public:
int pid;
int fd;
int used;
cPidHandle(void) { pid = used = 0; fd = -1; }
};
cPidHandle pidHandles[MAXPIDHANDLES];
bool AddPid(int Pid, ePidType PidType = ptOther);
bool DelPid(int Pid);
bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output);
virtual void Action(void);
// Image Grab facilities
public:
bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
// Video format facilities
public:
virtual void SetVideoFormat(videoFormat_t Format);
// Volume facilities
private:
bool mute;
int volume;
public:
bool IsMute(void) { return mute; }
bool ToggleMute(void);
// Turns the volume off or on and returns the new mute state.
void SetVolume(int Volume, bool Absolute = false);
// Sets the volume to the given value, either absolutely or relative to
// the current volume.
static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
// EIT facilities
private:
cSIProcessor *siProcessor;
// Player facilities
private:
cPlayer *player;
public:
void TrickSpeed(int Speed);
void Clear(void);
void Play(void);
void Freeze(void);
void Mute(void);
void StillPicture(const uchar *Data, int Length);
bool Replaying(void);
// Returns true if we are currently replaying.
void StopReplay(void);
// Stops the current replay session (if any).
bool Attach(cPlayer *Player);
void Detach(cPlayer *Player);
virtual int PlayVideo(const uchar *Data, int Length);
virtual int PlayAudio(const uchar *Data, int Length);
// Receiver facilities
private:
cReceiver *receiver[MAXRECEIVERS];
int ca;
int Priority(void);
// Returns the priority of the current receiving session (0..MAXPRIORITY),
// or -1 if no receiver is currently active. The primary DVB device will
// always return at least Setup.PrimaryLimit-1.
int CanShift(int Ca, int Priority, int UsedCards = 0);
public:
int Ca(void) { return ca; }
// Returns the ca of the current receiving session.
bool Receiving(void);
// Returns true if we are currently receiving.
bool Attach(cReceiver *Receiver);
void Detach(cReceiver *Receiver);
};
#endif //__DEVICE_H

12
dmxdev.c.diff Normal file
View File

@ -0,0 +1,12 @@
--- dmxdev.c Mon Apr 1 10:59:46 2002
+++ dmxdev.c Sun Jun 16 11:02:38 2002
@@ -1048,6 +1048,9 @@
if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
return (POLLIN | POLLRDNORM | POLLPRI);
+ if (dmxdev->dvr_buffer.error)
+ return (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+
return 0;
} else
return (POLLOUT | POLLWRNORM | POLLPRI);

2846
dvbapi.c

File diff suppressed because it is too large Load Diff

335
dvbapi.h
View File

@ -1,335 +0,0 @@
/*
* dvbapi.h: Interface to the DVB driver
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.h 1.69 2002/04/21 09:49:22 kls Exp $
*/
#ifndef __DVBAPI_H
#define __DVBAPI_H
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
#include <ncurses.h>
#undef ERR //XXX ncurses defines this - but this clashes with newer system header files
#endif
#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 <linux/videodev.h>
#include <ost/dmx.h>
#include <ost/sec.h>
#include <ost/frontend.h>
#include <ost/video.h>
#include <ost/audio.h>
#include <ost/osd.h>
#include <stdio.h>
#include "dvbosd.h"
#include "eit.h"
#include "thread.h"
#define FRAMESPERSEC 25
// The maximum file size is limited by the range that can be covered
// with 'int'. 4GB might be possible (if the range is considered
// 'unsigned'), 2GB should be possible (even if the range is considered
// 'signed'), so let's use 2000MB for absolute safety (the actual file size
// may be slightly higher because we stop recording only before the next
// 'I' frame, to have a complete Group Of Pictures):
#define MAXVIDEOFILESIZE 2000 // MB
#define MINVIDEOFILESIZE 100 // MB
#define MAXVOLUME 255
#define VOLUMEDELTA 5 // used to increase/decrease the volume
const char *IndexToHMSF(int Index, bool WithFrame = false);
// Converts the given index to a string, optionally containing the frame number.
int HMSFToIndex(const char *HMSF);
// Converts the given string (format: "hh:mm:ss.ff") to an index.
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
class cChannel;
class cRecordBuffer;
class cPlayBuffer;
class cReplayBuffer;
class cTransferBuffer;
class cCuttingBuffer;
class cVideoCutter {
private:
static char *editedVersionName;
static cCuttingBuffer *cuttingBuffer;
static bool error;
static bool ended;
public:
static bool Start(const char *FileName);
static void Stop(void);
static bool Active(void);
static bool Error(void);
static bool Ended(void);
};
class cDvbApi {
friend class cRecordBuffer;
friend class cReplayBuffer;
friend class cTransferBuffer;
private:
FrontendType frontendType;
int fd_osd, fd_frontend, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt;
int vPid, aPid1, aPid2, dPid1, dPid2;
bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output);
bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); }
bool SetApid1(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa1, DMX_PES_AUDIO, Apid, Output); }
bool SetApid2(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa2, DMX_PES_OTHER, Apid, Output); }
bool SetDpid1(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd1, DMX_PES_OTHER, Dpid, Output); }
bool SetDpid2(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd2, DMX_PES_OTHER, Dpid, Output); }
bool SetTpid(int Tpid, dmxOutput_t Output) { return SetPid(fd_demuxt, DMX_PES_TELETEXT, Tpid, Output); }
bool SetPids(bool ForRecording);
cDvbApi(int n);
public:
~cDvbApi();
#define MAXDVBAPI 4 // the maximum number of DVB cards in the system
#define MAXCACAPS 16 // the maximum number of different CA values per DVB card
static int NumDvbApis;
private:
static cDvbApi *dvbApi[MAXDVBAPI];
static int useDvbApi;
int cardIndex;
int caCaps[MAXCACAPS];
int CanShift(int Ca, int Priority, int UsedCards = 0);
public:
static cDvbApi *PrimaryDvbApi;
static void SetUseDvbApi(int n);
// Sets the 'useDvbApi' flag of the given DVB device.
// If this function is not called before Init(), all DVB devices
// will be used.
static bool SetPrimaryDvbApi(int n);
// Sets the primary DVB device to 'n' (which must be in the range
// 1...NumDvbApis) and returns true if this was possible.
static cDvbApi *GetDvbApi(int Ca, int Priority);
// Selects a free DVB device, avoiding the PrimaryDvbApi if possible.
// If Ca is not 0, the device with the given number will be returned
// in case Ca is <= MAXDVBAPI, or the device that provides the given
// value in its caCaps.
// If all DVB devices are currently recording, the one recording the
// lowest priority timer (if any) that is lower than the given Priority
// will be returned.
// The caller must check whether the returned DVB device is actually
// recording and stop recording if necessary.
int CardIndex(void) { return cardIndex; }
// Returns the card index of this DvbApi (0 ... MAXDVBAPI - 1).
static void SetCaCaps(void);
// Sets the CaCaps of all DVB devices according to the Setup data.
int ProvidesCa(int Ca);
// Checks whether this DVB device provides the given value in its
// caCaps. Returns 0 if the value is not provided, 1 if only this
// value is provided, and > 1 if this and other values are provided.
// If the given value is equal to the number of this DVB device,
// 1 is returned. If it is 0 (FTA), 1 plus the number of other values
// in caCaps is returned.
static bool Probe(const char *FileName);
// Probes for existing DVB devices.
static bool Init(void);
// Initializes the DVB API.
// Must be called before accessing any DVB functions.
static void Cleanup(void);
// Closes down all DVB devices.
// Must be called at the end of the program.
// EIT facilities
private:
cSIProcessor *siProcessor;
public:
// Image Grab facilities
bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
// On Screen Display facilities
private:
enum { charWidth = 12, // average character width
lineHeight = 27 // smallest text height
};
#ifdef DEBUG_OSD
WINDOW *window;
enum { MaxColorPairs = 16 };
int colorPairs[MaxColorPairs];
void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground);
#else
cDvbOsd *osd;
#endif
int cols, rows;
public:
void Open(int w, int h);
void Close(void);
void Clear(void);
void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground);
void SetBitmap(int x, int y, const cBitmap &Bitmap);
void ClrEol(int x, int y, eDvbColor color = clrBackground);
int CellWidth(void);
int LineHeight(void);
int Width(unsigned char c);
int WidthInCells(const char *s);
eDvbFont SetFont(eDvbFont Font);
void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground);
void Flush(void);
// Video format facilities:
void SetVideoFormat(videoFormat_t Format);
// Channel facilities
private:
int currentChannel;
public:
eSetChannelResult SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr);
static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; }
int Channel(void) { return currentChannel; }
// Transfer facilities
private:
cTransferBuffer *transferBuffer;
cDvbApi *transferringFromDvbApi;
public:
bool Transferring(void);
// Returns true if we are currently transferring video data.
private:
cDvbApi *StartTransfer(int TransferToVideoDev);
// Starts transferring video data from this DVB device to TransferToVideoDev.
void StopTransfer(void);
// Stops transferring video data (in case a transfer is currently active).
// Record/Replay facilities
private:
cRecordBuffer *recordBuffer;
cPlayBuffer *replayBuffer;
int ca;
int priority;
int Priority(void);
// Returns the priority of the current recording session (0..MAXPRIORITY),
// or -1 if no recording is currently active. The primary DVB device will
// always return at least Setup.PrimaryLimit-1.
int SetModeRecord(void);
// Initiates recording mode and returns the file handle to read from.
void SetModeReplay(void);
void SetModeNormal(bool FromRecording);
public:
int Ca(void) { return ca; }
// Returns the ca of the current recording session.
int SecondsToFrames(int Seconds);
// Returns the number of frames corresponding to the given number of seconds.
bool Recording(void);
// Returns true if we are currently recording.
bool Replaying(void);
// Returns true if we are currently replaying.
bool StartRecord(const char *FileName, int Ca, int Priority);
// Starts recording the current channel into the given file, with
// the given ca and priority.
// In order to be able to record longer movies,
// a numerical suffix will be appended to the file name. The inital
// value of that suffix will be larger than any existing file under
// the given name, thus allowing an interrupted recording to continue
// gracefully.
// Returns true if recording was started successfully.
// If there is already a recording session active, false will be
// returned.
void StopRecord(void);
// Stops the current recording session (if any).
bool StartReplay(const char *FileName);
// Starts replaying the given file.
// If there is already a replay session active, it will be stopped
// and the new file will be played back.
void StopReplay(void);
// Stops the current replay session (if any).
void Pause(void);
// Pauses the current replay session, or resumes a paused session.
void Play(void);
// Resumes normal replay mode.
void Forward(void);
// Runs the current replay session forward at a higher speed.
void Backward(void);
// Runs the current replay session backwards at a higher speed.
void SkipSeconds(int Seconds);
// Skips the given number of seconds in the current replay session.
// The sign of 'Seconds' determines the direction in which to skip.
// Use a very large negative value to go all the way back to the
// beginning of the recording.
int SkipFrames(int Frames);
// Returns the new index into the current replay session after skipping
// the given number of frames (no actual repositioning is done!).
// The sign of 'Frames' determines the direction in which to skip.
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
// Returns the current and total frame index, optionally snapped to the
// nearest I-frame.
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
// Returns the current replay mode (if applicable).
// 'Play' tells whether we are playing or pausing, 'Forward' tells whether
// we are going forward or backward and 'Speed' is -1 if this is normal
// play/pause mode, 0 if it is single speed fast/slow forward/back mode
// and >0 if this is multi speed mode.
void Goto(int Index, bool Still = false);
// Positions to the given index and displays that frame as a still picture
// if Still is true.
// Audio track facilities
public:
bool CanToggleAudioTrack(void);
// Returns true if we are currently replaying and this recording has two
// audio tracks, or if the current channel has two audio PIDs.
bool ToggleAudioTrack(void);
// Toggles the audio track if possible.
// Dolby Digital audio facilities
private:
static char *audioCommand;
public:
static void SetAudioCommand(const char *Command);
static const char *AudioCommand(void) { return audioCommand; }
// Volume facilities:
private:
bool mute;
int volume;
public:
bool IsMute(void) { return mute; }
bool ToggleMute(void);
// Turns the volume off or on and returns the new mute state.
void SetVolume(int Volume, bool Absolute = false);
// Sets the volume to the given value, either absolutely or relative to
// the current volume.
static int CurrentVolume(void) { return PrimaryDvbApi ? PrimaryDvbApi->volume : 0; }
};
class cEITScanner {
private:
enum { ActivityTimeout = 60,
ScanTimeout = 20
};
time_t lastScan, lastActivity;
int currentChannel, lastChannel;
int numTransponders, *transponders;
bool TransponderScanned(cChannel *Channel);
public:
cEITScanner(void);
~cEITScanner();
bool Active(void) { return currentChannel; }
void Activity(void);
void Process(void);
};
#endif //__DVBAPI_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbosd.c 1.15 2002/05/13 16:29:20 kls Exp $
* $Id: dvbosd.c 1.17 2002/05/18 13:39:02 kls Exp $
*/
#include "dvbosd.h"
@ -13,12 +13,12 @@
#include <sys/unistd.h>
#include "tools.h"
cDvbOsd::cDvbOsd(int VideoDev, int x, int y)
:cOsd(x, y)
cDvbOsd::cDvbOsd(int OsdDev, int x, int y)
:cOsdBase(x, y)
{
videoDev = VideoDev;
if (videoDev < 0)
esyslog("ERROR: illegal video device handle (%d)!", videoDev);
osdDev = OsdDev;
if (osdDev < 0)
esyslog("ERROR: illegal OSD device handle (%d)!", osdDev);
}
cDvbOsd::~cDvbOsd()
@ -44,7 +44,7 @@ bool cDvbOsd::SetWindow(cWindow *Window)
void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data)
{
if (videoDev >= 0) {
if (osdDev >= 0) {
osd_cmd_t dc;
dc.cmd = cmd;
dc.color = color;
@ -58,7 +58,7 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co
sigfillset(&set);
sigdelset(&set, SIGALRM);
sigprocmask(SIG_BLOCK, &set, &oldset);
ioctl(videoDev, OSD_SEND_CMD, &dc);
ioctl(osdDev, OSD_SEND_CMD, &dc);
if (cmd == OSD_SetBlock) // XXX this is the only command that takes longer
usleep(5000); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places
// XXX and sometimes the OSD was no longer displayed).

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbosd.h 1.11 2002/05/10 14:22:07 kls Exp $
* $Id: dvbosd.h 1.13 2002/05/18 13:38:09 kls Exp $
*/
#ifndef __DVBOSD_H
@ -13,9 +13,9 @@
#include <ost/osd.h>
#include "osdbase.h"
class cDvbOsd : public cOsd {
class cDvbOsd : public cOsdBase {
private:
int videoDev;
int osdDev;
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);
protected:
@ -26,7 +26,7 @@ protected:
virtual void MoveWindow(cWindow *Window, int x, int y);
virtual void CloseWindow(cWindow *Window);
public:
cDvbOsd(int VideoDev, int x, int y);
cDvbOsd(int OsdDev, int x, int y);
virtual ~cDvbOsd();
};

733
dvbplayer.c Normal file
View File

@ -0,0 +1,733 @@
/*
* dvbplayer.c: The DVB player
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbplayer.c 1.1 2002/06/16 10:59:45 kls Exp $
*/
#include "dvbplayer.h"
#include <poll.h>
#include "recording.h"
#include "ringbuffer.h"
#include "thread.h"
// --- ReadFrame -------------------------------------------------------------
int ReadFrame(int f, uchar *b, int Length, int Max)
{
if (Length == -1)
Length = Max; // this means we read up to EOF (see cIndex)
else if (Length > Max) {
esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max);
Length = Max;
}
int r = safe_read(f, b, Length);
if (r < 0)
LOG_ERROR;
return r;
}
// --- cBackTrace ----------------------------------------------------------
#define AVG_FRAME_SIZE 15000 // an assumption about the average frame size
#define DVB_BUF_SIZE (256 * 1024) // an assumption about the dvb firmware buffer size
#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) // how many entries are needed to backtrace buffer contents
class cBackTrace {
private:
int index[BACKTRACE_ENTRIES];
int length[BACKTRACE_ENTRIES];
int pos, num;
public:
cBackTrace(void);
void Clear(void);
void Add(int Index, int Length);
int Get(bool Forward);
};
cBackTrace::cBackTrace(void)
{
Clear();
}
void cBackTrace::Clear(void)
{
pos = num = 0;
}
void cBackTrace::Add(int Index, int Length)
{
index[pos] = Index;
length[pos] = Length;
if (++pos >= BACKTRACE_ENTRIES)
pos = 0;
if (num < BACKTRACE_ENTRIES)
num++;
}
int cBackTrace::Get(bool Forward)
{
int p = pos;
int n = num;
int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); //XXX (256 * 1024) == DVB_BUF_SIZE ???
int i = -1;
while (n && l > 0) {
if (--p < 0)
p = BACKTRACE_ENTRIES - 1;
i = index[p] - 1;
l -= length[p];
n--;
}
return i;
}
// --- cDvbPlayer ------------------------------------------------------------
//XXX+ also used in recorder.c - find a better place???
// The size of the array used to buffer video data:
// (must be larger than MINVIDEODATA - see remux.h)
#define VIDEOBUFSIZE MEGABYTE(1)
// The maximum size of a single frame:
#define MAXFRAMESIZE KILOBYTE(192)
// The number of frames to back up when resuming an interrupted replay session:
#define RESUMEBACKUP (10 * FRAMESPERSEC)
class cDvbPlayer : public cPlayer, cThread {
private:
enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill };
enum ePlayDirs { pdForward, pdBackward };
static int Speeds[];
cRingBufferFrame *ringBuffer;
cBackTrace *backTrace;
cFileName *fileName;
cIndexFile *index;
int replayFile;
bool eof;
bool active;
ePlayModes playMode;
ePlayDirs playDir;
int trickSpeed;
int readIndex, writeIndex;
cFrame *readFrame;
const cFrame *playFrame;
void TrickSpeed(int Increment);
void Empty(void);
void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
int Resume(void);
bool Save(void);
protected:
virtual void Activate(bool On);
virtual void Action(void);
public:
cDvbPlayer(const char *FileName);
virtual ~cDvbPlayer();
bool Active(void) { return active; }
void Pause(void);
void Play(void);
void Forward(void);
void Backward(void);
int SkipFrames(int Frames);
void SkipSeconds(int Seconds);
void Goto(int Position, bool Still = false);
void GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
};
#define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct?
#define NORMAL_SPEED 4 // the index of the '1' entry in the following array
#define MAX_SPEEDS 3 // the offset of the maximum speed from normal speed in either direction
#define SPEED_MULT 12 // the speed multiplier
int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 };
cDvbPlayer::cDvbPlayer(const char *FileName)
{
ringBuffer = NULL;
backTrace = NULL;
index = NULL;
eof = false;
active = false;
playMode = pmPlay;
playDir = pdForward;
trickSpeed = NORMAL_SPEED;
readIndex = writeIndex = -1;
readFrame = NULL;
playFrame = NULL;
isyslog("replay %s", FileName);
fileName = new cFileName(FileName, false);
replayFile = fileName->Open();
if (replayFile < 0)
return;
ringBuffer = new cRingBufferFrame(VIDEOBUFSIZE);
// Create the index file:
index = new cIndexFile(FileName, false);
if (!index)
esyslog("ERROR: can't allocate index");
else if (!index->Ok()) {
delete index;
index = NULL;
}
backTrace = new cBackTrace;
}
cDvbPlayer::~cDvbPlayer()
{
Detach();
Save();
delete index;
delete fileName;
delete backTrace;
delete ringBuffer;
}
void cDvbPlayer::TrickSpeed(int Increment)
{
int nts = trickSpeed + Increment;
if (Speeds[nts] == 1) {
trickSpeed = nts;
if (playMode == pmFast)
Play();
else
Pause();
}
else if (Speeds[nts]) {
trickSpeed = nts;
int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT;
int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult;
if (sp > MAX_VIDEO_SLOWMOTION)
sp = MAX_VIDEO_SLOWMOTION;
DeviceTrickSpeed(sp);
}
}
void cDvbPlayer::Empty(void)
{
Lock();
if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
readIndex = writeIndex;
readFrame = NULL;
playFrame = NULL;
ringBuffer->Clear();
backTrace->Clear();
DeviceClear();
Unlock();
}
void cDvbPlayer::StripAudioPackets(uchar *b, int Length, uchar Except)
{
if (index) {
for (int i = 0; i < Length - 6; i++) {
if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
uchar c = b[i + 3];
int l = b[i + 4] * 256 + b[i + 5] + 6;
switch (c) {
case 0xBD: // dolby
if (Except)
;//XXX+ PlayExternalDolby(&b[i], Length - i);
// continue with deleting the data - otherwise it disturbs DVB replay
case 0xC0 ... 0xC1: // audio
if (c == 0xC1)
;//XXX+ canToggleAudioTrack = true;
if (!Except || c != Except) {
int n = l;
for (int j = i; j < Length && n--; j++)
b[j] = 0x00;
}
break;
case 0xE0 ... 0xEF: // video
break;
default:
//esyslog("ERROR: unexpected packet id %02X", c);
l = 0;
}
if (l)
i += l - 1; // the loop increments, too!
}
/*XXX
else
esyslog("ERROR: broken packet header");
XXX*/
}
}
}
bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset)
{
if (FileNumber > 0)
replayFile = fileName->SetOffset(FileNumber, FileOffset);
else if (replayFile >= 0 && eof)
replayFile = fileName->NextFile();
eof = false;
return replayFile >= 0;
}
int cDvbPlayer::Resume(void)
{
if (index) {
int Index = index->GetResume();
if (Index >= 0) {
uchar FileNumber;
int FileOffset;
if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset))
return Index;
}
}
return -1;
}
bool cDvbPlayer::Save(void)
{
if (index) {
int Index = writeIndex;
if (Index >= 0) {
Index -= RESUMEBACKUP;
if (Index > 0)
Index = index->GetNextIFrame(Index, false);
else
Index = 0;
if (Index >= 0)
return index->StoreResume(Index);
}
}
return false;
}
void cDvbPlayer::Activate(bool On)
{
if (On) {
if (replayFile >= 0)
Start();
}
else if (active) {
active = false;
Cancel(3);
}
}
void cDvbPlayer::Action(void)
{
active = true;
dsyslog("dvbplayer thread started (pid=%d)", getpid());
uchar b[MAXFRAMESIZE];
const uchar *p = NULL;
int pc = 0;
pollfd pfd[2];
pfd[0].fd = DeviceFileHandle();
pfd[0].events = pfd[0].revents = POLLOUT;
pfd[1].fd = replayFile;
pfd[1].events = pfd[1].revents = POLLIN;
readIndex = Resume();
if (readIndex >= 0)
isyslog("resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true));
while (active && NextFile()) {
{
LOCK_THREAD;
// Read the next frame from the file:
if (!readFrame && (pfd[1].revents & POLLIN)) {
if (playMode != pmStill) {
int r = 0;
if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
uchar FileNumber;
int FileOffset, Length;
int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, true);
if (Index >= 0) {
if (!NextFile(FileNumber, FileOffset))
break;
}
else {
// can't call Play() here, because those functions may only be
// called from the foreground thread - and we also don't need
// to empty the buffer here
DevicePlay();
playMode = pmPlay;
playDir = pdForward;
continue;
}
readIndex = Index;
r = ReadFrame(replayFile, b, Length, sizeof(b));
// must call StripAudioPackets() here because the buffer is not emptied
// when falling back from "fast forward" to "play" (see above)
StripAudioPackets(b, r);
}
else if (index) {
uchar FileNumber;
int FileOffset, Length;
readIndex++;
if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))
break;
r = ReadFrame(replayFile, b, Length, sizeof(b));
}
else // allows replay even if the index file is missing
r = read(replayFile, b, sizeof(b));
if (r > 0)
readFrame = new cFrame(b, r, ftUnknown, readIndex);
else if (r == 0)
eof = true;
else if (r < 0 && FATALERRNO) {
LOG_ERROR;
break;
}
}
else//XXX
usleep(1); // this keeps the CPU load low
}
// Store the frame in the buffer:
if (readFrame) {
if (ringBuffer->Put(readFrame))
readFrame = NULL;
}
// Get the next frame from the buffer:
if (!playFrame) {
playFrame = ringBuffer->Get();
p = NULL;
pc = 0;
}
// Play the frame:
if (playFrame && (pfd[0].revents & POLLOUT)) {
if (!p) {
p = playFrame->Data();
pc = playFrame->Count();
}
if (p) {
int w = PlayVideo(p, pc);
if (w > 0) {
p += w;
pc -= w;
}
else if (w < 0 && FATALERRNO) {
LOG_ERROR;
break;
}
}
if (pc == 0) {
writeIndex = playFrame->Index();
backTrace->Add(playFrame->Index(), playFrame->Count());
ringBuffer->Drop(playFrame);
playFrame = NULL;
p = 0;
}
}
}
// Wait for input or output to become ready:
if (poll(pfd, readFrame ? 1 : 2, 10) < 0 && FATALERRNO) {
LOG_ERROR;
break;
}
}
dsyslog("dvbplayer thread ended (pid=%d)", getpid());
active = false;
}
void cDvbPlayer::Pause(void)
{
if (playMode == pmPause || playMode == pmStill)
Play();
else {
LOCK_THREAD;
if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))
Empty();
DeviceFreeze();
playMode = pmPause;
}
}
void cDvbPlayer::Play(void)
{
if (playMode != pmPlay) {
LOCK_THREAD;
if (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))
Empty();
DevicePlay();
playMode = pmPlay;
playDir = pdForward;
}
}
void cDvbPlayer::Forward(void)
{
if (index) {
switch (playMode) {
case pmFast:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdForward ? 1 : -1);
break;
}
else if (playDir == pdForward) {
Play();
break;
}
// run into pmPlay
case pmPlay: {
LOCK_THREAD;
Empty();
DeviceMute();
playMode = pmFast;
playDir = pdForward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS);
}
break;
case pmSlow:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdForward ? -1 : 1);
break;
}
else if (playDir == pdForward) {
Pause();
break;
}
// run into pmPause
case pmStill:
case pmPause:
DeviceMute();
playMode = pmSlow;
playDir = pdForward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS);
break;
}
}
}
void cDvbPlayer::Backward(void)
{
if (index) {
switch (playMode) {
case pmFast:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdBackward ? 1 : -1);
break;
}
else if (playDir == pdBackward) {
Play();
break;
}
// run into pmPlay
case pmPlay: {
LOCK_THREAD;
Empty();
DeviceMute();
playMode = pmFast;
playDir = pdBackward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS);
}
break;
case pmSlow:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdBackward ? -1 : 1);
break;
}
else if (playDir == pdBackward) {
Pause();
break;
}
// run into pmPause
case pmStill:
case pmPause: {
LOCK_THREAD;
Empty();
DeviceMute();
playMode = pmSlow;
playDir = pdBackward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS);
}
break;
}
}
}
int cDvbPlayer::SkipFrames(int Frames)
{
if (index && Frames) {
int Current, Total;
GetIndex(Current, Total, true);
int OldCurrent = Current;
Current = index->GetNextIFrame(Current + Frames, Frames > 0);
return Current >= 0 ? Current : OldCurrent;
}
return -1;
}
void cDvbPlayer::SkipSeconds(int Seconds)
{
if (index && Seconds) {
LOCK_THREAD;
Empty();
int Index = writeIndex;
if (Index >= 0) {
Index = max(Index + Seconds * FRAMESPERSEC, 0);
if (Index > 0)
Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true);
if (Index >= 0)
readIndex = writeIndex = Index - 1; // Input() will first increment it!
}
Play();
}
}
void cDvbPlayer::Goto(int Index, bool Still)
{
if (index) {
LOCK_THREAD;
Empty();
if (++Index <= 0)
Index = 1; // not '0', to allow GetNextIFrame() below to work!
uchar FileNumber;
int FileOffset, Length;
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
uchar b[MAXFRAMESIZE];
int r = ReadFrame(replayFile, b, Length, sizeof(b));
if (r > 0) {
if (playMode == pmPause)
DevicePlay();
StripAudioPackets(b, r);
DeviceStillPicture(b, r);
}
playMode = pmStill;
}
readIndex = writeIndex = Index;
}
}
void cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
{
if (index) {
if (playMode == pmStill)
Current = max(readIndex, 0);
else {
Current = max(writeIndex, 0);
if (SnapToIFrame) {
int i1 = index->GetNextIFrame(Current + 1, false);
int i2 = index->GetNextIFrame(Current, true);
Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2;
}
}
Total = index->Last();
}
else
Current = Total = -1;
}
bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
{
Play = (playMode == pmPlay || playMode == pmFast);
Forward = (playDir == pdForward);
if (playMode == pmFast || playMode == pmSlow)
Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0;
else
Speed = -1;
return true;
}
// --- cDvbPlayerControl -----------------------------------------------------
cDvbPlayerControl::cDvbPlayerControl(void)
{
player = NULL;
}
cDvbPlayerControl::~cDvbPlayerControl()
{
Stop();
}
bool cDvbPlayerControl::Active(void)
{
return player && player->Active();
}
bool cDvbPlayerControl::Start(const char *FileName)
{
delete player;
player = new cDvbPlayer(FileName);
if (cDevice::PrimaryDevice()->Attach(player))
return true;
Stop();
return false;
}
void cDvbPlayerControl::Stop(void)
{
delete player;
player = NULL;
}
void cDvbPlayerControl::Pause(void)
{
if (player)
player->Pause();
}
void cDvbPlayerControl::Play(void)
{
if (player)
player->Play();
}
void cDvbPlayerControl::Forward(void)
{
if (player)
player->Forward();
}
void cDvbPlayerControl::Backward(void)
{
if (player)
player->Backward();
}
void cDvbPlayerControl::SkipSeconds(int Seconds)
{
if (player)
player->SkipSeconds(Seconds);
}
int cDvbPlayerControl::SkipFrames(int Frames)
{
if (player)
return player->SkipFrames(Frames);
return -1;
}
bool cDvbPlayerControl::GetIndex(int &Current, int &Total, bool SnapToIFrame)
{
if (player) {
player->GetIndex(Current, Total, SnapToIFrame);
return true;
}
return false;
}
bool cDvbPlayerControl::GetReplayMode(bool &Play, bool &Forward, int &Speed)
{
return player && player->GetReplayMode(Play, Forward, Speed);
}
void cDvbPlayerControl::Goto(int Position, bool Still)
{
if (player)
player->Goto(Position, Still);
}

60
dvbplayer.h Normal file
View File

@ -0,0 +1,60 @@
/*
* dvbplayer.h: The DVB player
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbplayer.h 1.1 2002/06/16 10:59:14 kls Exp $
*/
#ifndef __DVBPLAYER_H
#define __DVBPLAYER_H
#include "player.h"
#include "thread.h"
class cDvbPlayer;
class cDvbPlayerControl : public cControl {
private:
cDvbPlayer *player;
public:
cDvbPlayerControl(void);
virtual ~cDvbPlayerControl();
bool Active(void);
bool Start(const char *FileName);
// Starts replaying the given file.
void Stop(void);
// Stops the current replay session (if any).
void Pause(void);
// Pauses the current replay session, or resumes a paused session.
void Play(void);
// Resumes normal replay mode.
void Forward(void);
// Runs the current replay session forward at a higher speed.
void Backward(void);
// Runs the current replay session backwards at a higher speed.
int SkipFrames(int Frames);
// Returns the new index into the current replay session after skipping
// the given number of frames (no actual repositioning is done!).
// The sign of 'Frames' determines the direction in which to skip.
void SkipSeconds(int Seconds);
// Skips the given number of seconds in the current replay session.
// The sign of 'Seconds' determines the direction in which to skip.
// Use a very large negative value to go all the way back to the
// beginning of the recording.
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
// Returns the current and total frame index, optionally snapped to the
// nearest I-frame.
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
// Returns the current replay mode (if applicable).
// 'Play' tells whether we are playing or pausing, 'Forward' tells whether
// we are going forward or backward and 'Speed' is -1 if this is normal
// play/pause mode, 0 if it is single speed fast/slow forward/back mode
// and >0 if this is multi speed mode.
void Goto(int Index, bool Still = false);
// Positions to the given index and displays that frame as a still picture
// if Still is true.
};
#endif //__DVBPLAYER_H

3
eit.c
View File

@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: eit.c 1.45 2002/05/13 16:35:49 kls Exp $
* $Id: eit.c 1.46 2002/05/31 10:26:56 kls Exp $
***************************************************************************/
#include "eit.h"
@ -26,6 +26,7 @@
#include <iomanip.h>
#include <iostream.h>
#include <limits.h>
#include <ost/dmx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

84
eitscan.c Normal file
View File

@ -0,0 +1,84 @@
/*
* eitscan.c: EIT scanner
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: eitscan.c 1.2 2002/06/02 09:02:05 kls Exp $
*/
#include "eitscan.h"
cEITScanner::cEITScanner(void)
{
lastScan = lastActivity = time(NULL);
currentChannel = 0;
lastChannel = 0;
numTransponders = 0;
transponders = NULL;
}
cEITScanner::~cEITScanner()
{
delete transponders;
}
bool cEITScanner::TransponderScanned(cChannel *Channel)
{
for (int i = 0; i < numTransponders; i++) {
if (transponders[i] == Channel->frequency)
return true;
}
transponders = (int *)realloc(transponders, ++numTransponders * sizeof(int));
transponders[numTransponders - 1] = Channel->frequency;
return false;
}
void cEITScanner::Activity(void)
{
if (currentChannel) {
Channels.SwitchTo(currentChannel);
currentChannel = 0;
}
lastActivity = time(NULL);
}
void cEITScanner::Process(void)
{
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
time_t now = time(NULL);
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
for (int i = 0; i < MAXDEVICES; i++) {
cDevice *Device = cDevice::GetDevice(i + 1, MAXPRIORITY + 1);
if (Device) {
if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
if (!(Device->Receiving() || Device->Replaying()/*XXX+ || Device->Transferring()XXX*/)) {
int oldCh = lastChannel;
int ch = oldCh + 1;
while (ch != oldCh) {
if (ch > Channels.MaxNumber()) {
ch = 1;
numTransponders = 0;
}
cChannel *Channel = Channels.GetByNumber(ch);
if (Channel) {
if (Channel->ca <= MAXDEVICES && !Device->ProvidesCa(Channel->ca))
break; // the channel says it explicitly needs a different card
if (Channel->pnr && !TransponderScanned(Channel)) {
if (Device == cDevice::PrimaryDevice() && !currentChannel)
currentChannel = Device->Channel();
Channel->Switch(Device, false);
lastChannel = ch;
break;
}
}
ch++;
}
}
}
}
}
lastScan = time(NULL);
}
}
}

33
eitscan.h Normal file
View File

@ -0,0 +1,33 @@
/*
* eitscan.h: EIT scanner
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: eitscan.h 1.1 2002/05/20 11:00:05 kls Exp $
*/
#ifndef __EITSCAN_H
#define __EITSCAN_H
#include <time.h>
#include "config.h"
class cEITScanner {
private:
enum { ActivityTimeout = 60,
ScanTimeout = 20
};
time_t lastScan, lastActivity;
int currentChannel, lastChannel;
int numTransponders, *transponders;
bool TransponderScanned(cChannel *Channel);
public:
cEITScanner(void);
~cEITScanner();
bool Active(void) { return currentChannel; }
void Activity(void);
void Process(void);
};
#endif //__EITSCAN_H

View File

@ -12,7 +12,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: epg2html.pl 1.3 2002/02/26 22:10:47 kls Exp $
# $Id: epg2html.pl 1.4 2002/05/30 09:46:46 kls Exp $
@Index = ();
@ -45,7 +45,7 @@ while (<>) {
push(@Index, qq{<a href="$Page">$Channel</a><br>\n});
my %Events = ();
while (<>) {
if (/^E (.*?) (.*?) (.*?)/) {
if (/^E (.*?) (.*?) ([^ ]*)/) {
(my $Time, $Duration) = ($2, $3);
my $Title = "", $Subtitle = "", $Description = "";
while (<>) {

361
i18n.c

File diff suppressed because it is too large Load Diff

4
i18n.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: i18n.h 1.2 2002/05/05 13:42:31 kls Exp $
* $Id: i18n.h 1.4 2002/06/10 16:14:02 kls Exp $
*/
#ifndef __I18N_H
@ -12,7 +12,7 @@
#include <stdio.h>
const int I18nNumLanguages = 12;
const int I18nNumLanguages = 14;
typedef const char *tI18nPhrase[I18nNumLanguages];

View File

@ -4,13 +4,15 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.48 2002/05/13 16:30:22 kls Exp $
* $Id: interface.c 1.52 2002/06/16 13:23:40 kls Exp $
*/
#include "interface.h"
#include <ctype.h>
#include <unistd.h>
#include "i18n.h"
#include "osd.h"
#include "status.h"
cInterface *Interface = NULL;
@ -50,7 +52,7 @@ void cInterface::Open(int NumCols, int NumLines)
NumCols = Setup.OSDwidth;
if (NumLines == 0)
NumLines = Setup.OSDheight;
cDvbApi::PrimaryDvbApi->Open(width = NumCols, height = NumLines);
cOsd::Open(width = NumCols, height = NumLines);
}
}
@ -59,7 +61,7 @@ void cInterface::Close(void)
if (open == 1)
Clear();
if (!--open) {
cDvbApi::PrimaryDvbApi->Close();
cOsd::Close();
width = height = 0;
}
}
@ -125,31 +127,32 @@ eKeys cInterface::Wait(int Seconds, bool KeepChar)
void cInterface::Clear(void)
{
if (open)
cDvbApi::PrimaryDvbApi->Clear();
cOsd::Clear();
cStatus::MsgOsdClear();
}
void cInterface::ClearEol(int x, int y, eDvbColor Color)
{
if (open)
cDvbApi::PrimaryDvbApi->ClrEol(x, y, Color);
cOsd::ClrEol(x, y, Color);
}
void cInterface::Fill(int x, int y, int w, int h, eDvbColor Color)
{
if (open)
cDvbApi::PrimaryDvbApi->Fill(x, y, w, h, Color);
cOsd::Fill(x, y, w, h, Color);
}
void cInterface::SetBitmap(int x, int y, const cBitmap &Bitmap)
{
if (open)
cDvbApi::PrimaryDvbApi->SetBitmap(x, y, Bitmap);
cOsd::SetBitmap(x, y, Bitmap);
}
void cInterface::Flush(void)
{
if (open)
cDvbApi::PrimaryDvbApi->Flush();
cOsd::Flush();
}
void cInterface::SetCols(int *c)
@ -163,7 +166,7 @@ void cInterface::SetCols(int *c)
eDvbFont cInterface::SetFont(eDvbFont Font)
{
return cDvbApi::PrimaryDvbApi->SetFont(Font);
return cOsd::SetFont(Font);
}
char *cInterface::WrapText(const char *Text, int Width, int *Height)
@ -183,7 +186,7 @@ char *cInterface::WrapText(const char *Text, int Width, int *Height)
char *Delim = NULL;
int w = 0;
Width *= cDvbApi::PrimaryDvbApi->CellWidth();
Width *= cOsd::CellWidth();
while (*t && t[strlen(t) - 1] == '\n')
t[strlen(t) - 1] = 0; // skips trailing newlines
@ -198,7 +201,7 @@ char *cInterface::WrapText(const char *Text, int Width, int *Height)
}
else if (isspace(*p))
Blank = p;
int cw = cDvbApi::PrimaryDvbApi->Width(*p);
int cw = cOsd::Width(*p);
if (w + cw > Width) {
if (Blank) {
*Blank = '\n';
@ -237,7 +240,7 @@ char *cInterface::WrapText(const char *Text, int Width, int *Height)
void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{
if (open)
cDvbApi::PrimaryDvbApi->Text(x, y, s, FgColor, BgColor);
cOsd::Text(x, y, s, FgColor, BgColor);
}
void cInterface::WriteText(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
@ -278,7 +281,7 @@ void cInterface::Title(const char *s)
strn0cpy(buffer, s, n + 1);
Write(1, 0, buffer, clrBlack, clrCyan);
t++;
Write(-(cDvbApi::PrimaryDvbApi->WidthInCells(t) + 1), 0, t, clrBlack, clrCyan);
Write(-(cOsd::WidthInCells(t) + 1), 0, t, clrBlack, clrCyan);
}
else {
int x = (Width() - strlen(s)) / 2;
@ -286,6 +289,7 @@ void cInterface::Title(const char *s)
x = 0;
Write(x, 0, s, clrBlack, clrCyan);
}
cStatus::MsgOsdTitle(s);
}
void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor)
@ -298,6 +302,7 @@ void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor)
x = 0;
Write(x, Line, s, FgColor, BgColor);
}
cStatus::MsgOsdStatusMessage(s);
}
void cInterface::Info(const char *s)
@ -337,12 +342,12 @@ void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvb
{
if (open) {
const int w = Width() / 4;
cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, Text ? BgColor : clrBackground);
cOsd::Fill(Index * w, -1, w, 1, Text ? BgColor : clrBackground);
if (Text) {
int l = (w - int(strlen(Text))) / 2;
if (l < 0)
l = 0;
cDvbApi::PrimaryDvbApi->Text(Index * w + l, -1, Text, FgColor, BgColor);
cOsd::Text(Index * w + l, -1, Text, FgColor, BgColor);
}
}
}
@ -353,6 +358,7 @@ void cInterface::Help(const char *Red, const char *Green, const char *Yellow, co
HelpButton(1, Green, clrBlack, clrGreen);
HelpButton(2, Yellow, clrBlack, clrYellow);
HelpButton(3, Blue, clrWhite, clrBlue);
cStatus::MsgOsdHelpKeys(Red, Green, Yellow, Blue);
}
void cInterface::QueryKeys(void)
@ -478,6 +484,6 @@ void cInterface::DisplayRecording(int Index, bool On)
bool cInterface::Recording(void)
{
// This is located here because the Interface has to do with the "PrimaryDvbApi" anyway
return cDvbApi::PrimaryDvbApi->Recording();
// This is located here because the Interface has to do with the "PrimaryDevice" anyway
return cDevice::PrimaryDevice()->Receiving();
}

View File

@ -4,14 +4,14 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.h 1.25 2002/04/19 13:17:15 kls Exp $
* $Id: interface.h 1.26 2002/05/18 13:43:20 kls Exp $
*/
#ifndef __INTERFACE_H
#define __INTERFACE_H
#include "config.h"
#include "dvbapi.h"
#include "osdbase.h"
#include "remote.h"
#include "svdrp.h"

225
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.192 2002/05/13 16:30:50 kls Exp $
* $Id: menu.c 1.197 2002/06/16 13:23:51 kls Exp $
*/
#include "menu.h"
@ -18,12 +18,15 @@
#include "i18n.h"
#include "menuitems.h"
#include "plugin.h"
#include "recording.h"
#include "status.h"
#include "videodir.h"
#define MENUTIMEOUT 120 // seconds
#define MAXWAIT4EPGINFO 10 // seconds
#define MODETIMEOUT 3 // seconds
#define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS)
#define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels...
@ -375,7 +378,7 @@ eOSState cMenuEditCaItem::ProcessKey(eKeys Key)
}
}
else if (NORMALKEY(Key) == kRight) {
if (ca && ca->Next() && (allowCardNr || ((cCaDefinition *)ca->Next())->Number() > MAXDVBAPI)) {
if (ca && ca->Next() && (allowCardNr || ((cCaDefinition *)ca->Next())->Number() > MAXDEVICES)) {
ca = (cCaDefinition *)ca->Next();
*value = ca->Number();
}
@ -493,7 +496,7 @@ cMenuChannels::cMenuChannels(void)
//TODO
int i = 0;
cChannel *channel;
int curr = ((channel = Channels.GetByNumber(cDvbApi::CurrentChannel())) != NULL) ? channel->Index() : -1;
int curr = ((channel = Channels.GetByNumber(cDevice::CurrentChannel())) != NULL) ? channel->Index() : -1;
while ((channel = Channels.Get(i)) != NULL) {
Add(new cMenuChannelItem(i, channel), i == curr);
@ -1144,7 +1147,7 @@ cMenuSchedule::cMenuSchedule(void)
{
now = next = false;
otherChannel = 0;
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
if (channel) {
cMenuWhatsOn::SetCurrentChannel(channel->number);
schedules = cSIProcessor::Schedules(mutexLock);
@ -1263,7 +1266,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
cChannel *channel = Channels.GetByServiceID(ei->GetServiceID());
if (channel) {
PrepareSchedule(channel);
if (channel->number != cDvbApi::CurrentChannel()) {
if (channel->number != cDevice::CurrentChannel()) {
otherChannel = channel->number;
SetHelp(tr("Record"), tr("Now"), tr("Next"), tr("Switch"));
}
@ -1440,7 +1443,7 @@ eOSState cMenuRecordings::Rewind(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri && !ri->IsDirectory()) {
cDvbApi::PrimaryDvbApi->StopReplay(); // must do this first to be able to rewind the currently replayed recording
cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
cResumeFile ResumeFile(ri->FileName());
ResumeFile.Delete();
return Play();
@ -1613,7 +1616,7 @@ public:
cMenuSetupDVB::cMenuSetupDVB(void)
{
SetSection(tr("DVB"));
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis));
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
}
@ -1625,7 +1628,7 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
if (state == osBack && Key == kOk) {
if (Setup.PrimaryDVB != oldPrimaryDVB) {
state = osSwitchDvb;
cDvbApi::PrimaryDvbApi->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
}
}
return state;
@ -1658,7 +1661,7 @@ public:
cMenuSetupCICAM::cMenuSetupCICAM(void)
{
SetSection(tr("CICAM"));
for (int d = 0; d < cDvbApi::NumDvbApis; d++) {
for (int d = 0; d < cDevice::NumDevices(); d++) {
for (int i = 0; i < 2; i++) {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%s%d %d", tr("Setup.CICAM$CICAM DVB"), d + 1, i + 1);
@ -1672,7 +1675,7 @@ eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
eOSState state = cMenuSetupBase::ProcessKey(Key);
if (state == osBack && Key == kOk)
cDvbApi::SetCaCaps();
cDevice::SetCaCaps();
return state;
}
@ -2023,12 +2026,14 @@ void cMenuMain::Set(void)
// Editing control:
/*XXX+
if (cVideoCutter::Active())
Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit));
XXX*/
// Color buttons:
SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
SetHelp(tr("Record"), /*XXX+ cDevice::PrimaryDevice()->CanToggleAudioTrack() ? tr("Language") :XXX*/ NULL, NULL, replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
Display();
lastActivity = time(NULL);
}
@ -2058,7 +2063,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
}
break;
case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
cVideoCutter::Stop();
//XXX+cVideoCutter::Stop();
return osEnd;
}
break;
@ -2081,11 +2086,13 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
state = osRecord;
break;
case kGreen: if (!HasSubMenu()) {
if (cDvbApi::PrimaryDvbApi->CanToggleAudioTrack()) {
/*XXX+
if (cDevice::PrimaryDevice()->CanToggleAudioTrack()) {
Interface->Clear();
cDvbApi::PrimaryDvbApi->ToggleAudioTrack();
cDevice::PrimaryDevice()->ToggleAudioTrack();
state = osEnd;
}
XXX*/
}
break;
case kBlue: if (!HasSubMenu())
@ -2113,7 +2120,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
#define INFOTIMEOUT 5000 //ms
cDisplayChannel::cDisplayChannel(int Number, bool Switched)
:cOsdBase(true)
:cOsdObject(true)
{
group = -1;
withInfo = !Switched || Setup.ShowInfoOnChSwitch;
@ -2130,10 +2137,10 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched)
}
cDisplayChannel::cDisplayChannel(eKeys FirstKey)
:cOsdBase(true)
:cOsdObject(true)
{
group = -1;
oldNumber = cDvbApi::CurrentChannel();
oldNumber = cDevice::CurrentChannel();
number = 0;
lastTime = time_ms();
int EpgLines = Setup.ShowInfoOnChSwitch ? 5 : 1;
@ -2162,6 +2169,7 @@ void cDisplayChannel::DisplayChannel(const cChannel *Channel)
Interface->Write(0, 0, buffer);
const char *date = DayDateTime();
Interface->Write(-strlen(date), 0, date);
cStatus::MsgOsdChannel(buffer);
}
void cDisplayChannel::DisplayInfo(void)
@ -2215,6 +2223,7 @@ void cDisplayChannel::DisplayInfo(void)
Interface->Flush();
lines = Lines;
lastTime = time_ms();
cStatus::MsgOsdProgramme(Present ? Present->GetTime() : 0, PresentTitle, PresentSubtitle, Following ? Following->GetTime() : 0, FollowingTitle, FollowingSubtitle);
}
}
}
@ -2250,7 +2259,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
case kRight:
withInfo = false;
if (group < 0) {
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
if (channel)
group = channel->Index();
}
@ -2322,10 +2331,10 @@ cVolumeBar::cVolumeBar(int Width, int Height, int Current, int Total, const char
cDisplayVolume *cDisplayVolume::displayVolume = NULL;
cDisplayVolume::cDisplayVolume(void)
:cOsdBase(true)
:cOsdObject(true)
{
displayVolume = this;
timeout = time_ms() + (cDvbApi::PrimaryDvbApi->IsMute() ? MUTETIMEOUT : VOLUMETIMEOUT);
timeout = time_ms() + (cDevice::PrimaryDevice()->IsMute() ? MUTETIMEOUT : VOLUMETIMEOUT);
Interface->Open(Setup.OSDwidth, -1);
Show();
}
@ -2338,13 +2347,13 @@ cDisplayVolume::~cDisplayVolume()
void cDisplayVolume::Show(void)
{
cDvbApi *dvbApi = cDvbApi::PrimaryDvbApi;
if (dvbApi->IsMute()) {
cDevice *device = cDevice::PrimaryDevice();
if (device->IsMute()) {
Interface->Fill(0, 0, Width(), 1, clrTransparent);
Interface->Write(0, 0, tr("Mute"), clrGreen);
}
else {
int Current = cDvbApi::CurrentVolume();
int Current = cDevice::CurrentVolume();
int Total = MAXVOLUME;
const char *Prompt = tr("Volume ");
#ifdef DEBUG_OSD
@ -2354,7 +2363,7 @@ void cDisplayVolume::Show(void)
Interface->Fill(l, 0, p, 1, clrGreen);
Interface->Fill(l + p, 0, Width() - l - p, 1, clrWhite);
#else
cVolumeBar VolumeBar(Width() * dvbApi->CellWidth(), dvbApi->LineHeight(), Current, Total, Prompt);
cVolumeBar VolumeBar(Width() * cOsd::CellWidth(), cOsd::LineHeight(), Current, Total, Prompt);
Interface->SetBitmap(0, 0, VolumeBar);
#endif
}
@ -2384,7 +2393,7 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key)
timeout = time_ms() + VOLUMETIMEOUT;
break;
case kMute:
if (cDvbApi::PrimaryDvbApi->IsMute()) {
if (cDevice::PrimaryDevice()->IsMute()) {
Show();
timeout = time_ms() + MUTETIMEOUT;
}
@ -2402,41 +2411,45 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key)
// --- cRecordControl --------------------------------------------------------
cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer)
{
eventInfo = NULL;
instantId = NULL;
fileName = NULL;
dvbApi = DvbApi;
if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX
recorder = NULL;
device = Device;
if (!device) device = cDevice::PrimaryDevice();//XXX
timer = Timer;
if (!timer) {
timer = new cTimer(true);
Timers.Add(timer);
Timers.Save();
asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->CardIndex() + 1);
asprintf(&instantId, cDevice::NumDevices() > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), device->CardIndex() + 1);
}
timer->SetPending(true);
timer->SetRecording(true);
if (Channels.SwitchTo(timer->channel, dvbApi)) {
const char *Title = NULL;
const char *Subtitle = NULL;
const char *Summary = NULL;
if (GetEventInfo()) {
Title = eventInfo->GetTitle();
Subtitle = eventInfo->GetSubtitle();
Summary = eventInfo->GetExtendedDescription();
dsyslog("Title: '%s' Subtitle: '%s'", Title, Subtitle);
}
cRecording Recording(timer, Title, Subtitle, Summary);
fileName = strdup(Recording.FileName());
cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName);
if (dvbApi->StartRecord(fileName, Channels.GetByNumber(timer->channel)->ca, timer->priority))
Recording.WriteSummary();
Interface->DisplayRecording(dvbApi->CardIndex(), true);
const char *Title = NULL;
const char *Subtitle = NULL;
const char *Summary = NULL;
if (GetEventInfo()) {
Title = eventInfo->GetTitle();
Subtitle = eventInfo->GetSubtitle();
Summary = eventInfo->GetExtendedDescription();
dsyslog("Title: '%s' Subtitle: '%s'", Title, Subtitle);
}
cRecording Recording(timer, Title, Subtitle, Summary);
fileName = strdup(Recording.FileName());
cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName);
cChannel *ch = Channels.GetByNumber(timer->channel);
recorder = new cRecorder(fileName, ch->ca, timer->priority, ch->vpid, ch->apid1, ch->apid2, ch->dpid1, ch->dpid2);
if (device->Attach(recorder)) {
Recording.WriteSummary();
cStatus::MsgRecording(device, fileName);
Interface->DisplayRecording(device->CardIndex(), true);
}
else
cThread::EmergencyExit(true);
DELETENULL(recorder);
}
cRecordControl::~cRecordControl()
@ -2479,7 +2492,8 @@ bool cRecordControl::GetEventInfo(void)
void cRecordControl::Stop(bool KeepInstant)
{
if (timer) {
dvbApi->StopRecord();
cStatus::MsgRecording(device, NULL);
DELETENULL(recorder);
timer->SetRecording(false);
if ((IsInstant() && !KeepInstant) || (timer->IsSingleEvent() && !timer->Matches())) {
// checking timer->Matches() to make sure we don't delete the timer
@ -2489,14 +2503,14 @@ void cRecordControl::Stop(bool KeepInstant)
Timers.Save();
}
timer = NULL;
Interface->DisplayRecording(dvbApi->CardIndex(), false);
Interface->DisplayRecording(device->CardIndex(), false);
cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName);
}
}
bool cRecordControl::Process(time_t t)
{
if (!timer || !timer->Matches(t))
if (!recorder || !timer || !timer->Matches(t))
return false;
AssertFreeDiskSpace(timer->priority);
return true;
@ -2504,20 +2518,27 @@ bool cRecordControl::Process(time_t t)
// --- cRecordControls -------------------------------------------------------
cRecordControl *cRecordControls::RecordControls[MAXDVBAPI] = { NULL };
cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL };
bool cRecordControls::Start(cTimer *Timer)
{
int ch = Timer ? Timer->channel : cDvbApi::CurrentChannel();
int ch = Timer ? Timer->channel : cDevice::CurrentChannel();
cChannel *channel = Channels.GetByNumber(ch);
if (channel) {
cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca, Timer ? Timer->priority : Setup.DefaultPriority);
if (dvbApi) {
Stop(dvbApi);
for (int i = 0; i < MAXDVBAPI; i++) {
bool ReUse = false;
cDevice *device = cDevice::GetDevice(channel->ca, Timer ? Timer->priority : Setup.DefaultPriority, channel->frequency, channel->vpid, &ReUse);
if (device) {
if (!ReUse) {
Stop(device);
if (!channel->Switch(device)) {
cThread::EmergencyExit(true);
return false;
}
}
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (!RecordControls[i]) {
RecordControls[i] = new cRecordControl(dvbApi, Timer);
RecordControls[i] = new cRecordControl(device, Timer);
return true;
}
}
@ -2532,7 +2553,7 @@ bool cRecordControls::Start(cTimer *Timer)
void cRecordControls::Stop(const char *InstantId)
{
for (int i = 0; i < MAXDVBAPI; i++) {
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) {
const char *id = RecordControls[i]->InstantId();
if (id && strcmp(id, InstantId) == 0)
@ -2541,12 +2562,12 @@ void cRecordControls::Stop(const char *InstantId)
}
}
void cRecordControls::Stop(cDvbApi *DvbApi)
void cRecordControls::Stop(cDevice *Device)
{
for (int i = 0; i < MAXDVBAPI; i++) {
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) {
if (RecordControls[i]->Uses(DvbApi)) {
isyslog("stopping recording on DVB device %d due to higher priority", DvbApi->CardIndex() + 1);
if (RecordControls[i]->Uses(Device)) {
isyslog("stopping recording on DVB device %d due to higher priority", Device->CardIndex() + 1);
RecordControls[i]->Stop(true);
}
}
@ -2555,11 +2576,11 @@ void cRecordControls::Stop(cDvbApi *DvbApi)
bool cRecordControls::StopPrimary(bool DoIt)
{
if (cDvbApi::PrimaryDvbApi->Recording()) {
cDvbApi *dvbApi = cDvbApi::GetDvbApi(cDvbApi::PrimaryDvbApi->Ca(), 0);
if (dvbApi) {
if (cDevice::PrimaryDevice()->Receiving()) {
cDevice *device = cDevice::GetDevice(cDevice::PrimaryDevice()->Ca(), 0);
if (device) {
if (DoIt)
Stop(cDvbApi::PrimaryDvbApi);
Stop(cDevice::PrimaryDevice());
return true;
}
}
@ -2568,7 +2589,7 @@ bool cRecordControls::StopPrimary(bool DoIt)
const char *cRecordControls::GetInstantId(const char *LastInstantId)
{
for (int i = 0; i < MAXDVBAPI; i++) {
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) {
if (!LastInstantId && RecordControls[i]->InstantId())
return RecordControls[i]->InstantId();
@ -2581,7 +2602,7 @@ const char *cRecordControls::GetInstantId(const char *LastInstantId)
cRecordControl *cRecordControls::GetRecordControl(const char *FileName)
{
for (int i = 0; i < MAXDVBAPI; i++) {
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
return RecordControls[i];
}
@ -2590,7 +2611,7 @@ cRecordControl *cRecordControls::GetRecordControl(const char *FileName)
void cRecordControls::Process(time_t t)
{
for (int i = 0; i < MAXDVBAPI; i++) {
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) {
if (!RecordControls[i]->Process(t))
DELETENULL(RecordControls[i]);
@ -2600,13 +2621,19 @@ void cRecordControls::Process(time_t t)
bool cRecordControls::Active(void)
{
for (int i = 0; i < MAXDVBAPI; i++) {
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i])
return true;
}
return false;
}
void cRecordControls::Shutdown(void)
{
for (int i = 0; i < MAXRECORDCONTROLS; i++)
DELETENULL(RecordControls[i]);
}
// --- cProgressBar ----------------------------------------------------------
class cProgressBar : public cBitmap {
@ -2658,22 +2685,24 @@ char *cReplayControl::title = NULL;
cReplayControl::cReplayControl(void)
{
dvbApi = cDvbApi::PrimaryDvbApi;
visible = modeOnly = shown = displayFrames = false;
lastCurrent = lastTotal = -1;
timeoutShow = 0;
timeSearchActive = false;
if (fileName) {
marks.Load(fileName);
if (!dvbApi->StartReplay(fileName))
Interface->Error(tr("Channel locked (recording)!"));
if (!Start(fileName))
Interface->Error(tr("Channel locked (recording)!"));//XXX+
else
cStatus::MsgReplaying(this, fileName);
}
}
cReplayControl::~cReplayControl()
{
Hide();
dvbApi->StopReplay();
cStatus::MsgReplaying(this, NULL);
Stop();
}
void cReplayControl::SetRecording(const char *FileName, const char *Title)
@ -2719,7 +2748,7 @@ void cReplayControl::Hide(void)
void cReplayControl::DisplayAtBottom(const char *s)
{
if (s) {
int w = dvbApi->WidthInCells(s);
int w = cOsd::WidthInCells(s);
int d = max(Width() - w, 0) / 2;
if (modeOnly) //XXX remove when displaying replay mode differently
Interface->Fill(0, -1, Interface->Width(), 1, clrTransparent); //XXX remove when displaying replay mode differently
@ -2735,7 +2764,7 @@ void cReplayControl::ShowMode(void)
if (Setup.ShowReplayMode && !timeSearchActive) {
bool Play, Forward;
int Speed;
if (dvbApi->GetReplayMode(Play, Forward, Speed)) {
if (GetReplayMode(Play, Forward, Speed)) {
bool NormalPlay = (Play && Speed == -1);
if (!visible) {
@ -2773,7 +2802,7 @@ bool cReplayControl::ShowProgress(bool Initial)
{
int Current, Total;
if (dvbApi->GetIndex(Current, Total) && Total > 0) {
if (GetIndex(Current, Total) && Total > 0) {
if (!visible) {
Interface->Open(Setup.OSDwidth, -3);
needsFastResponse = visible = true;
@ -2795,8 +2824,8 @@ bool cReplayControl::ShowProgress(bool Initial)
Interface->Fill(0, 1, p, 1, clrGreen);
Interface->Fill(p, 1, Width() - p, 1, clrWhite);
#else
cProgressBar ProgressBar(Width() * dvbApi->CellWidth(), dvbApi->LineHeight(), Current, Total, marks);
Interface->SetBitmap(0, dvbApi->LineHeight(), ProgressBar);
cProgressBar ProgressBar(Width() * cOsd::CellWidth(), cOsd::LineHeight(), Current, Total, marks);
Interface->SetBitmap(0, cOsd::LineHeight(), ProgressBar);
if (!Initial)
Interface->Flush();
#endif
@ -2848,14 +2877,14 @@ void cReplayControl::TimeSearchProcess(eKeys Key)
int dir = (Key == kRight ? 1 : -1);
if (dir > 0)
Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
dvbApi->SkipSeconds(Seconds * dir);
SkipSeconds(Seconds * dir);
timeSearchActive = false;
}
break;
case kUp:
case kDown:
Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
dvbApi->Goto(Seconds * FRAMESPERSEC, Key == kDown);
Goto(Seconds * FRAMESPERSEC, Key == kDown);
timeSearchActive = false;
break;
default:
@ -2893,7 +2922,7 @@ void cReplayControl::TimeSearch(void)
void cReplayControl::MarkToggle(void)
{
int Current, Total;
if (dvbApi->GetIndex(Current, Total, true)) {
if (GetIndex(Current, Total, true)) {
cMark *m = marks.Get(Current);
lastCurrent = -1; // triggers redisplay
if (m)
@ -2910,10 +2939,10 @@ void cReplayControl::MarkJump(bool Forward)
{
if (marks.Count()) {
int Current, Total;
if (dvbApi->GetIndex(Current, Total)) {
if (GetIndex(Current, Total)) {
cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current);
if (m)
dvbApi->Goto(m->position, true);
Goto(m->position, true);
}
displayFrames = true;
}
@ -2922,11 +2951,11 @@ void cReplayControl::MarkJump(bool Forward)
void cReplayControl::MarkMove(bool Forward)
{
int Current, Total;
if (dvbApi->GetIndex(Current, Total)) {
if (GetIndex(Current, Total)) {
cMark *m = marks.Get(Current);
if (m) {
displayFrames = true;
int p = dvbApi->SkipFrames(Forward ? 1 : -1);
int p = SkipFrames(Forward ? 1 : -1);
cMark *m2;
if (Forward) {
if ((m2 = marks.Next(m)) != NULL && m2->position <= p)
@ -2936,7 +2965,7 @@ void cReplayControl::MarkMove(bool Forward)
if ((m2 = marks.Prev(m)) != NULL && m2->position >= p)
return;
}
dvbApi->Goto(m->position = p, true);
Goto(m->position = p, true);
marks.Save();
}
}
@ -2944,6 +2973,7 @@ void cReplayControl::MarkMove(bool Forward)
void cReplayControl::EditCut(void)
{
/*XXX+
if (fileName) {
Hide();
if (!cVideoCutter::Active()) {
@ -2956,12 +2986,13 @@ void cReplayControl::EditCut(void)
Interface->Error(tr("Editing process already active!"));
ShowMode();
}
XXX*/
}
void cReplayControl::EditTest(void)
{
int Current, Total;
if (dvbApi->GetIndex(Current, Total)) {
if (GetIndex(Current, Total)) {
cMark *m = marks.Get(Current);
if (!m)
m = marks.GetNext(Current);
@ -2969,8 +3000,8 @@ void cReplayControl::EditTest(void)
if ((m->Index() & 0x01) != 0)
m = marks.Next(m);
if (m) {
dvbApi->Goto(m->position - dvbApi->SecondsToFrames(3));
dvbApi->Play();
Goto(m->position - SecondsToFrames(3));
Play();
}
}
}
@ -2978,7 +3009,7 @@ void cReplayControl::EditTest(void)
eOSState cReplayControl::ProcessKey(eKeys Key)
{
if (!dvbApi->Replaying())
if (!Active())
return osEnd;
if (visible) {
if (timeoutShow && time(NULL) > timeoutShow) {
@ -3000,21 +3031,21 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
bool DoShowMode = true;
switch (Key) {
// Positioning:
case kUp: dvbApi->Play(); break;
case kDown: dvbApi->Pause(); break;
case kUp: Play(); break;
case kDown: Pause(); break;
case kLeft|k_Release:
if (Setup.MultiSpeedMode) break;
case kLeft: dvbApi->Backward(); break;
case kLeft: Backward(); break;
case kRight|k_Release:
if (Setup.MultiSpeedMode) break;
case kRight: dvbApi->Forward(); break;
case kRight: Forward(); break;
case kRed: TimeSearch(); break;
case kGreen|k_Repeat:
case kGreen: dvbApi->SkipSeconds(-60); break;
case kGreen: SkipSeconds(-60); break;
case kYellow|k_Repeat:
case kYellow: dvbApi->SkipSeconds( 60); break;
case kYellow: SkipSeconds( 60); break;
case kBlue: Hide();
dvbApi->StopReplay();
Stop();
return osEnd;
default: {
DoShowMode = false;

25
menu.h
View File

@ -4,14 +4,16 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.h 1.42 2002/04/13 15:31:41 kls Exp $
* $Id: menu.h 1.44 2002/06/14 12:33:35 kls Exp $
*/
#ifndef __MENU_H
#define __MENU_H
#include "dvbapi.h"
#include "device.h"
#include "osd.h"
#include "dvbplayer.h"
#include "recorder.h"
#include "recording.h"
class cMenuMain : public cOsdMenu {
@ -24,7 +26,7 @@ public:
virtual eOSState ProcessKey(eKeys Key);
};
class cDisplayChannel : public cOsdBase {
class cDisplayChannel : public cOsdObject {
private:
int group;
bool withInfo;
@ -40,7 +42,7 @@ public:
virtual eOSState ProcessKey(eKeys Key);
};
class cDisplayVolume : public cOsdBase {
class cDisplayVolume : public cOsdObject {
private:
int timeout;
static cDisplayVolume *displayVolume;
@ -76,17 +78,18 @@ public:
class cRecordControl {
private:
cDvbApi *dvbApi;
cDevice *device;
cTimer *timer;
cRecorder *recorder;
const cEventInfo *eventInfo;
char *instantId;
char *fileName;
bool GetEventInfo(void);
public:
cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL);
cRecordControl(cDevice *Device, cTimer *Timer = NULL);
virtual ~cRecordControl();
bool Process(time_t t);
bool Uses(cDvbApi *DvbApi) { return DvbApi == dvbApi; }
bool Uses(cDevice *Device) { return Device == device; }
void Stop(bool KeepInstant = false);
bool IsInstant(void) { return instantId; }
const char *InstantId(void) { return instantId; }
@ -96,21 +99,21 @@ public:
class cRecordControls {
private:
static cRecordControl *RecordControls[MAXDVBAPI];
static cRecordControl *RecordControls[];
public:
static bool Start(cTimer *Timer = NULL);
static void Stop(const char *InstantId);
static void Stop(cDvbApi *DvbApi);
static void Stop(cDevice *Device);
static bool StopPrimary(bool DoIt = false);
static const char *GetInstantId(const char *LastInstantId);
static cRecordControl *GetRecordControl(const char *FileName);
static void Process(time_t t);
static bool Active(void);
static void Shutdown(void);
};
class cReplayControl : public cOsdBase {
class cReplayControl : public cDvbPlayerControl {
private:
cDvbApi *dvbApi;
cMarks marks;
bool visible, modeOnly, shown, displayFrames;
int lastCurrent, lastTotal;

View File

@ -4,13 +4,14 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menuitems.c 1.2 2002/05/11 10:49:45 kls Exp $
* $Id: menuitems.c 1.6 2002/06/16 13:23:56 kls Exp $
*/
#include "menuitems.h"
#include <ctype.h>
#include "i18n.h"
#include "plugin.h"
#include "status.h"
// --- cMenuEditItem ---------------------------------------------------------
@ -186,18 +187,18 @@ void cMenuEditStrItem::Set(void)
strncpy(buf, value, pos);
snprintf(buf + pos, sizeof(buf) - pos - 2, fmt, *(value + pos), value + pos + 1);
int width = Interface->Width() - Interface->GetCols()[0];
if (cDvbApi::PrimaryDvbApi->WidthInCells(buf) <= width) {
if (cOsd::WidthInCells(buf) <= width) {
// the whole buffer fits on the screen
SetValue(buf);
return;
}
width *= cDvbApi::PrimaryDvbApi->CellWidth();
width -= cDvbApi::PrimaryDvbApi->Width('>'); // assuming '<' and '>' have the same with
width *= cOsd::CellWidth();
width -= cOsd::Width('>'); // assuming '<' and '>' have the same with
int w = 0;
int i = 0;
int l = strlen(buf);
while (i < l && w <= width)
w += cDvbApi::PrimaryDvbApi->Width(buf[i++]);
w += cOsd::Width(buf[i++]);
if (i >= pos + 4) {
// the cursor fits on the screen
buf[i - 1] = '>';
@ -214,7 +215,7 @@ void cMenuEditStrItem::Set(void)
else
i--;
while (i >= 0 && w <= width)
w += cDvbApi::PrimaryDvbApi->Width(buf[i--]);
w += cOsd::Width(buf[i--]);
buf[++i] = '<';
SetValue(buf + i);
}
@ -397,6 +398,7 @@ void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor)
// scroll indicators use inverted color scheme!
if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor);
if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor);
cStatus::MsgOsdTextItem(text);
}
void cMenuTextItem::ScrollUp(bool Page)
@ -406,6 +408,7 @@ void cMenuTextItem::ScrollUp(bool Page)
offset = max(offset - (Page ? h : 1), 0);
Display();
}
cStatus::MsgOsdTextItem(NULL, true);
}
void cMenuTextItem::ScrollDown(bool Page)
@ -415,6 +418,7 @@ void cMenuTextItem::ScrollDown(bool Page)
offset = min(offset + (Page ? h : 1), lines - h);
Display();
}
cStatus::MsgOsdTextItem(NULL, false);
}
eOSState cMenuTextItem::ProcessKey(eKeys Key)
@ -471,7 +475,7 @@ void cMenuSetupPage::SetPlugin(cPlugin *Plugin)
SetSection(buf);
}
void cMenuSetupPage::SetupStore(const char *Name, const char *Value = NULL)
void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
{
if (plugin)
plugin->SetupStore(Name, Value);

View File

@ -12,7 +12,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: newplugin 1.4 2002/05/12 15:02:13 kls Exp $
# $Id: newplugin 1.6 2002/06/10 16:24:34 kls Exp $
$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
@ -66,7 +66,7 @@ PLUGIN = $PLUGIN_NAME
### The version number of this plugin (taken from the main source file):
VERSION = `grep 'static const char \\*VERSION *=' \$(PLUGIN).c | awk '{ print \$\$6 }' | sed -e 's/[";]//g'`
VERSION = \$(shell grep 'static const char \\*VERSION *=' \$(PLUGIN).c | awk '{ print \$\$6 }' | sed -e 's/[";]//g')
### The directory environment:
@ -78,7 +78,7 @@ TMPDIR = /tmp
### The version number of VDR (taken from VDR's "config.h"):
VDRVERSION = `grep 'define VDRVERSION ' \$(VDRDIR)/config.h | awk '{ print \$\$3 }' | sed -e 's/"//g'`
VDRVERSION = \$(shell grep 'define VDRVERSION ' \$(VDRDIR)/config.h | awk '{ print \$\$3 }' | sed -e 's/"//g')
### The name of the distribution archive:
@ -98,7 +98,7 @@ OBJS = \$(PLUGIN).o
### The C++ compiler and options:
CXX = g++
CXXFLAGS = -O2 -Wall -Woverloaded-virtual -m486
CXXFLAGS = -O2 -Wall -Woverloaded-virtual
### Implicit rules:
@ -112,7 +112,7 @@ DEPFILE = .dependencies
\$(DEPFILE): Makefile
\@\$(MAKEDEP) \$(DEFINES) \$(INCLUDES) \$(OBJS:%.o=%.c) > \$\@
include \$(DEPFILE)
-include \$(DEPFILE)
### Targets:
@ -251,7 +251,7 @@ The next steps you should perform now are:
sub CreateFile
{
my ($Name, $Content) = @_;
open(FILE, ">$PLUGINDIR/$Name") || die "$Name: $!\n";
open(FILE, ">$PLUGINDIR/$Name") || die "$Name: V113 $!\n";
print FILE $Content;
close(FILE);
}

243
osd.c
View File

@ -4,12 +4,243 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.c 1.25 2002/05/12 11:38:39 kls Exp $
* $Id: osd.c 1.29 2002/06/16 13:24:00 kls Exp $
*/
#include "osd.h"
#include <string.h>
#include "device.h"
#include "i18n.h"
#include "status.h"
// --- cOsd ------------------------------------------------------------------
#ifdef DEBUG_OSD
WINDOW *cOsd::window = NULL;
int cOsd::colorPairs[MaxColorPairs] = { 0 };
#else
cDvbOsd *cOsd::osd = NULL;
#endif
int cOsd::cols = 0;
int cOsd::rows = 0;
void cOsd::Initialize(void)
{
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
initscr();
keypad(stdscr, true);
nonl();
cbreak();
noecho();
timeout(10);
#endif
#if defined(DEBUG_OSD)
start_color();
leaveok(stdscr, true);
#endif
}
void cOsd::Shutdown(void)
{
Close();
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
endwin();
#endif
}
#ifdef DEBUG_OSD
void cOsd::SetColor(eDvbColor colorFg, eDvbColor colorBg)
{
int color = (colorBg << 16) | colorFg | 0x80000000;
for (int i = 0; i < MaxColorPairs; i++) {
if (!colorPairs[i]) {
colorPairs[i] = color;
init_pair(i + 1, colorFg, colorBg);
wattrset(window, COLOR_PAIR(i + 1));
break;
}
else if (color == colorPairs[i]) {
wattrset(window, COLOR_PAIR(i + 1));
break;
}
}
}
#endif
void cOsd::Open(int w, int h)
{
int d = (h < 0) ? Setup.OSDheight + h : 0;
h = abs(h);
cols = w;
rows = h;
#ifdef DEBUG_OSD
window = subwin(stdscr, h, w, d, (Setup.OSDwidth - w) / 2);
syncok(window, true);
#define B2C(b) (((b) * 1000) / 255)
#define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
//XXX
SETCOLOR(clrBackground, 0x00, 0x00, 0x00, 127); // background 50% gray
SETCOLOR(clrBlack, 0x00, 0x00, 0x00, 255);
SETCOLOR(clrRed, 0xFC, 0x14, 0x14, 255);
SETCOLOR(clrGreen, 0x24, 0xFC, 0x24, 255);
SETCOLOR(clrYellow, 0xFC, 0xC0, 0x24, 255);
SETCOLOR(clrBlue, 0x00, 0x00, 0xFC, 255);
SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255);
SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255);
SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255);
#else
w *= charWidth;
h *= lineHeight;
d *= lineHeight;
int x = (720 - w + charWidth) / 2; //TODO PAL vs. NTSC???
int y = (576 - Setup.OSDheight * lineHeight) / 2 + d;
//XXX
osd = new cDvbOsd(cDevice::PrimaryDevice()->OsdDeviceHandle(), x, y);
//XXX TODO this should be transferred to the places where the individual windows are requested (there's too much detailed knowledge here!)
if (h / lineHeight == 5) { //XXX channel display
osd->Create(0, 0, w, h, 4);
}
else if (h / lineHeight == 1) { //XXX info display
osd->Create(0, 0, w, h, 4);
}
else if (d == 0) { //XXX full menu
osd->Create(0, 0, w, lineHeight, 2);
osd->Create(0, lineHeight, w, (Setup.OSDheight - 3) * lineHeight, 2);
osd->AddColor(clrBackground);
osd->AddColor(clrCyan);
osd->AddColor(clrWhite);
osd->AddColor(clrBlack);
osd->Create(0, (Setup.OSDheight - 2) * lineHeight, w, 2 * lineHeight, 4);
}
else { //XXX progress display
/*XXX
osd->Create(0, 0, w, lineHeight, 1);
osd->Create(0, lineHeight, w, lineHeight, 2, false);
osd->Create(0, 2 * lineHeight, w, lineHeight, 1);
XXX*///XXX some pixels are not drawn correctly with lower bpp values
osd->Create(0, 0, w, 3*lineHeight, 4);
}
#endif
}
void cOsd::Close(void)
{
#ifdef DEBUG_OSD
if (window) {
delwin(window);
window = 0;
}
#else
delete osd;
osd = NULL;
#endif
}
void cOsd::Clear(void)
{
#ifdef DEBUG_OSD
SetColor(clrBackground, clrBackground);
Fill(0, 0, cols, rows, clrBackground);
#else
osd->Clear();
#endif
}
void cOsd::Fill(int x, int y, int w, int h, eDvbColor color)
{
if (x < 0) x = cols + x;
if (y < 0) y = rows + y;
#ifdef DEBUG_OSD
SetColor(color, color);
for (int r = 0; r < h; r++) {
wmove(window, y + r, x); // ncurses wants 'y' before 'x'!
whline(window, ' ', w);
}
wsyncup(window); // shouldn't be necessary because of 'syncok()', but w/o it doesn't work
#else
osd->Fill(x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1, color);
#endif
}
void cOsd::SetBitmap(int x, int y, const cBitmap &Bitmap)
{
#ifndef DEBUG_OSD
osd->SetBitmap(x, y, Bitmap);
#endif
}
void cOsd::ClrEol(int x, int y, eDvbColor color)
{
Fill(x, y, cols - x, 1, color);
}
int cOsd::CellWidth(void)
{
#ifdef DEBUG_OSD
return 1;
#else
return charWidth;
#endif
}
int cOsd::LineHeight(void)
{
#ifdef DEBUG_OSD
return 1;
#else
return lineHeight;
#endif
}
int cOsd::Width(unsigned char c)
{
#ifdef DEBUG_OSD
return 1;
#else
return osd->Width(c);
#endif
}
int cOsd::WidthInCells(const char *s)
{
#ifdef DEBUG_OSD
return strlen(s);
#else
return (osd->Width(s) + charWidth - 1) / charWidth;
#endif
}
eDvbFont cOsd::SetFont(eDvbFont Font)
{
#ifdef DEBUG_OSD
return Font;
#else
return osd->SetFont(Font);
#endif
}
void cOsd::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg)
{
if (x < 0) x = cols + x;
if (y < 0) y = rows + y;
#ifdef DEBUG_OSD
SetColor(colorFg, colorBg);
wmove(window, y, x); // ncurses wants 'y' before 'x'!
waddnstr(window, s, cols - x);
#else
osd->Text(x * charWidth, y * lineHeight, s, colorFg, colorBg);
#endif
}
void cOsd::Flush(void)
{
#ifdef DEBUG_OSD
refresh();
#else
if (osd)
osd->Flush();
#endif
}
// --- cOsdItem --------------------------------------------------------------
@ -200,8 +431,11 @@ void cOsdMenu::Display(void)
}
for (int i = first; i < count; i++) {
cOsdItem *item = Get(i);
if (item)
if (item) {
item->Display(i - first, i == current ? clrBlack : clrWhite, i == current ? clrCyan : clrBackground);
if (i == current)
cStatus::MsgOsdCurrentItem(item->Text());
}
if (++n == MAXOSDITEMS) //TODO get this from Interface!!!
break;
}
@ -225,8 +459,11 @@ void cOsdMenu::RefreshCurrent(void)
void cOsdMenu::DisplayCurrent(bool Current)
{
cOsdItem *item = Get(current);
if (item)
if (item) {
item->Display(current - first, Current ? clrBlack : clrWhite, Current ? clrCyan : clrBackground);
if (Current)
cStatus::MsgOsdCurrentItem(item->Text());
}
}
void cOsdMenu::Clear(void)

47
osd.h
View File

@ -4,14 +4,19 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.h 1.29 2002/05/12 11:19:22 kls Exp $
* $Id: osd.h 1.31 2002/05/18 14:00:15 kls Exp $
*/
#ifndef __OSD_H
#define __OSD_H
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
#include <ncurses.h>
#endif
#include "config.h"
#include "dvbosd.h"
#include "interface.h"
#include "osdbase.h"
#include "tools.h"
#define MAXOSDITEMS (Setup.OSDheight - 4)
@ -47,6 +52,38 @@ enum eOSState { osUnknown,
osUser10,
};
class cOsd {
private:
enum { charWidth = 12, // average character width
lineHeight = 27 // smallest text height
};
#ifdef DEBUG_OSD
static WINDOW *window;
enum { MaxColorPairs = 16 };
static int colorPairs[MaxColorPairs];
static void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground);
#else
static cDvbOsd *osd;
#endif
static int cols, rows;
public:
static void Initialize(void);
static void Shutdown(void);
static void Open(int w, int h);
static void Close(void);
static void Clear(void);
static void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground);
static void SetBitmap(int x, int y, const cBitmap &Bitmap);
static void ClrEol(int x, int y, eDvbColor color = clrBackground);
static int CellWidth(void);
static int LineHeight(void);
static int Width(unsigned char c);
static int WidthInCells(const char *s);
static eDvbFont SetFont(eDvbFont Font);
static void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground);
static void Flush(void);
};
class cOsdItem : public cListObject {
private:
const char *text;
@ -69,19 +106,19 @@ public:
virtual eOSState ProcessKey(eKeys Key);
};
class cOsdBase {
class cOsdObject {
protected:
bool needsFastResponse;
public:
cOsdBase(bool FastResponse = false) { needsFastResponse = FastResponse; }
virtual ~cOsdBase() {}
cOsdObject(bool FastResponse = false) { needsFastResponse = FastResponse; }
virtual ~cOsdObject() {}
int Width(void) { return Interface->Width(); }
int Height(void) { return Interface->Height(); }
bool NeedsFastResponse(void) { return needsFastResponse; }
virtual eOSState ProcessKey(eKeys Key) = 0;
};
class cOsdMenu : public cOsdBase, public cList<cOsdItem> {
class cOsdMenu : public cOsdObject, public cList<cOsdItem> {
private:
char *title;
int cols[cInterface::MaxCols];

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osdbase.c 1.2 2002/05/13 16:30:59 kls Exp $
* $Id: osdbase.c 1.4 2002/05/18 12:39:16 kls Exp $
*/
#include "osdbase.h"
@ -316,22 +316,22 @@ const char *cWindow::Data(int x, int y)
return cBitmap::Data(x, y);
}
// --- cOsd ------------------------------------------------------------------
// --- cOsdBase --------------------------------------------------------------
cOsd::cOsd(int x, int y)
cOsdBase::cOsdBase(int x, int y)
{
numWindows = 0;
x0 = x;
y0 = y;
}
cOsd::~cOsd()
cOsdBase::~cOsdBase()
{
for (int i = 0; i < numWindows; i++)
delete window[i];
}
tWindowHandle cOsd::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled)
tWindowHandle cOsdBase::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled)
{
if (numWindows < MAXNUMWINDOWS) {
if (x >= 0 && y >= 0 && w > 0 && h > 0 && (Bpp == 1 || Bpp == 2 || Bpp == 4 || Bpp == 8)) {
@ -356,7 +356,7 @@ tWindowHandle cOsd::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBa
return -1;
}
void cOsd::AddColor(eDvbColor Color, tWindowHandle Window)
void cOsdBase::AddColor(eDvbColor Color, tWindowHandle Window)
{
cWindow *w = GetWindow(Window);
if (w) {
@ -365,7 +365,7 @@ void cOsd::AddColor(eDvbColor Color, tWindowHandle Window)
}
}
cWindow *cOsd::GetWindow(int x, int y)
cWindow *cOsdBase::GetWindow(int x, int y)
{
for (int i = 0; i < numWindows; i++) {
if (window[i]->Tiled() && window[i]->Contains(x, y))
@ -374,7 +374,7 @@ cWindow *cOsd::GetWindow(int x, int y)
return NULL;
}
cWindow *cOsd::GetWindow(tWindowHandle Window)
cWindow *cOsdBase::GetWindow(tWindowHandle Window)
{
if (0 <= Window && Window < numWindows)
return window[Window];
@ -383,7 +383,7 @@ cWindow *cOsd::GetWindow(tWindowHandle Window)
return NULL;
}
void cOsd::Flush(void)
void cOsdBase::Flush(void)
{
for (int i = 0; i < numWindows; i++) {
CommitWindow(window[i]);
@ -396,7 +396,7 @@ void cOsd::Flush(void)
}
}
void cOsd::Clear(tWindowHandle Window)
void cOsdBase::Clear(tWindowHandle Window)
{
if (Window == ALL_TILED_WINDOWS || Window == ALL_WINDOWS) {
for (int i = 0; i < numWindows; i++)
@ -410,31 +410,31 @@ void cOsd::Clear(tWindowHandle Window)
}
}
void cOsd::Fill(int x1, int y1, int x2, int y2, eDvbColor Color, tWindowHandle Window)
void cOsdBase::Fill(int x1, int y1, int x2, int y2, eDvbColor Color, tWindowHandle Window)
{
cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x1, y1) : GetWindow(Window);
if (w)
w->Fill(x1, y1, x2, y2, Color);
}
void cOsd::SetBitmap(int x, int y, const cBitmap &Bitmap, tWindowHandle Window)
void cOsdBase::SetBitmap(int x, int y, const cBitmap &Bitmap, tWindowHandle Window)
{
cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window);
if (w)
w->SetBitmap(x, y, Bitmap);
}
int cOsd::Width(unsigned char c)
int cOsdBase::Width(unsigned char c)
{
return numWindows ? window[0]->Width(c) : 0;
}
int cOsd::Width(const char *s)
int cOsdBase::Width(const char *s)
{
return numWindows ? window[0]->Width(s) : 0;
}
eDvbFont cOsd::SetFont(eDvbFont Font)
eDvbFont cOsdBase::SetFont(eDvbFont Font)
{
eDvbFont oldFont = Font;
for (int i = 0; i < numWindows; i++)
@ -442,14 +442,14 @@ eDvbFont cOsd::SetFont(eDvbFont Font)
return oldFont;
}
void cOsd::Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground, tWindowHandle Window)
void cOsdBase::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg, tWindowHandle Window)
{
cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window);
if (w)
w->Text(x, y, s, ColorFg, ColorBg);
}
void cOsd::Relocate(tWindowHandle Window, int x, int y, int NewWidth, int NewHeight)
void cOsdBase::Relocate(tWindowHandle Window, int x, int y, int NewWidth, int NewHeight)
{
cWindow *w = GetWindow(Window);
if (w) {
@ -471,12 +471,12 @@ void cOsd::Relocate(tWindowHandle Window, int x, int y, int NewWidth, int NewHei
}
}
void cOsd::Hide(tWindowHandle Window)
void cOsdBase::Hide(tWindowHandle Window)
{
HideWindow(GetWindow(Window), true);
}
void cOsd::Show(tWindowHandle Window)
void cOsdBase::Show(tWindowHandle Window)
{
HideWindow(GetWindow(Window), false);
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osdbase.h 1.1 2002/05/10 14:26:09 kls Exp $
* $Id: osdbase.h 1.2 2002/05/18 12:38:17 kls Exp $
*/
#ifndef __OSDBASE_H
@ -119,7 +119,7 @@ typedef int tWindowHandle;
#define ALL_TILED_WINDOWS (-3)
#define LAST_CREATED_WINDOW (-4)
class cOsd {
class cOsdBase {
private:
int numWindows;
int x0, y0;
@ -149,9 +149,9 @@ protected:
virtual void CloseWindow(cWindow *Window) = 0;
// Close the window and release any OSD hardware resources allocated for it.
public:
cOsd(int x, int y);
cOsdBase(int x, int y);
// Initializes the OSD, starting at screen coordinates (x, y).
virtual ~cOsd();
virtual ~cOsdBase();
// Destroys all windows and shuts down the OSD.
tWindowHandle Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground = true, bool Tiled = true);
// Creates a window at coordinates (x, y), which are relative to the OSD's

55
player.c Normal file
View File

@ -0,0 +1,55 @@
/*
* player.c: The basic player interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: player.c 1.1 2002/06/16 10:34:50 kls Exp $
*/
#include "player.h"
// --- cPlayer ---------------------------------------------------------------
cPlayer::cPlayer(void)
{
device = NULL;
deviceFileHandle = -1;
}
cPlayer::~cPlayer()
{
Detach();
}
int cPlayer::PlayVideo(const uchar *Data, int Length)
{
if (device)
return device->PlayVideo(Data, Length);
esyslog("ERROR: attempt to use cPlayer::PlayVideo() without attaching to a cDevice!");
return -1;
}
int cPlayer::PlayAudio(const uchar *Data, int Length)
{
if (device)
return device->PlayAudio(Data, Length);
esyslog("ERROR: attempt to use cPlayer::PlayAudio() without attaching to a cDevice!");
return -1;
}
void cPlayer::Detach(void)
{
if (device)
device->Detach(this);
}
// --- cControl --------------------------------------------------------------
cControl::cControl(void)
{
}
cControl::~cControl()
{
}

51
player.h Normal file
View File

@ -0,0 +1,51 @@
/*
* player.h: The basic player interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: player.h 1.1 2002/06/16 11:52:45 kls Exp $
*/
#ifndef __PLAYER_H
#define __PLAYER_H
#include "device.h"
#include "osd.h"
class cPlayer {
friend class cDevice;
private:
cDevice *device;
int deviceFileHandle;
protected:
int DeviceFileHandle(void) { return deviceFileHandle; } //XXX+ needed for polling
void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
void DeviceClear(void) { if (device) device->Clear(); }
void DevicePlay(void) { if (device) device->Play(); }
void DeviceFreeze(void) { if (device) device->Freeze(); }
void DeviceMute(void) { if (device) device->Mute(); }
void DeviceStillPicture(const uchar *Data, int Length) { if (device) device->StillPicture(Data, Length); }
void Detach(void);
virtual void Activate(bool On) {}
// This function is called right after the cPlayer has been attached to
// (On == true) or before it gets detached from (On == false) a cDevice.
// It can be used to do things like starting/stopping a thread.
int PlayVideo(const uchar *Data, int Length);
// Sends the given Data to the video device and returns the number of
// bytes that have actually been accepted by the video device (or a
// negative value in case of an error).
int PlayAudio(const uchar *Data, int Length);
// XXX+ TODO
public:
cPlayer(void);
virtual ~cPlayer();
};
class cControl : public cOsdObject {
public:
cControl(void);
virtual ~cControl();
};
#endif //__PLAYER_H

55
receiver.c Normal file
View File

@ -0,0 +1,55 @@
/*
* receiver.c: The basic receiver interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: receiver.c 1.1 2002/06/08 09:58:29 kls Exp $
*/
#include <stdarg.h>
#include <stdio.h>
#include "receiver.h"
cReceiver::cReceiver(int Ca, int Priority, int NumPids, ...)
{
device = NULL;
ca = Ca;
priority = Priority;
if (NumPids) {
va_list ap;
va_start(ap, NumPids);
int n = 0;
while (n < MAXRECEIVEPIDS && NumPids--) {
if ((pids[n] = va_arg(ap, int)) != 0)
n++;
}
va_end(ap);
}
else
esyslog("ERROR: cReceiver called without a PID!");
}
cReceiver::~cReceiver()
{
Detach();
}
bool cReceiver::WantsPid(int Pid)
{
if (Pid) {
for (int i = 0; i < MAXRECEIVEPIDS; i++) {
if (pids[i] == Pid)
return true;
if (!pids[i])
break;
}
}
return false;
}
void cReceiver::Detach(void)
{
if (device)
device->Detach(this);
}

48
receiver.h Normal file
View File

@ -0,0 +1,48 @@
/*
* receiver.h: The basic receiver interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: receiver.h 1.1 2002/06/08 15:32:51 kls Exp $
*/
#ifndef __RECEIVER_H
#define __RECEIVER_H
#include "device.h"
#define MAXRECEIVEPIDS 16 // the maximum number of PIDs per receiver
class cReceiver {
friend class cDevice;
private:
cDevice *device;
int ca;
int priority;
int pids[MAXRECEIVEPIDS];
bool WantsPid(int Pid);
protected:
void Detach(void);
virtual void Activate(bool On) {}
// This function is called just before the cReceiver gets attached to
// (On == true) or detached from (On == false) a cDevice. It can be used
// to do things like starting/stopping a thread.
// It is guaranteed that Receive() will not be called before Activate(true).
virtual void Receive(uchar *Data, int Length) = 0;
// This function is called from the cDevice we are attached to, and
// delivers one TS packet from the set of PIDs the cReceiver has requested.
// The data packet must be accepted immediately, and the call must return
// as soon as possible, without any unnecessary delay. Each TS packet
// will be delivered only ONCE, so the cReceiver must make sure that
// it will be able to buffer the data if necessary.
public:
cReceiver(int Ca, int Priority, int NumPids, ...);
// Creates a new receiver that requires conditional access Ca and has
// 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.
// The total number of non-zero PIDs must not exceed MAXRECEIVEPIDS.
virtual ~cReceiver();
};
#endif //__RECEIVER_H

149
recorder.c Normal file
View File

@ -0,0 +1,149 @@
/*
* recorder.h: The actual DVB recorder
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recorder.c 1.1 2002/06/16 10:03:25 kls Exp $
*/
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include "recorder.h"
// The size of the array used to buffer video data:
// (must be larger than MINVIDEODATA - see remux.h)
#define VIDEOBUFSIZE MEGABYTE(1)
#define MINFREEDISKSPACE (512) // MB
#define DISKCHECKINTERVAL 100 // seconds
cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(Ca, Priority, 5, VPid, APid1, APid2, DPid1, DPid2)
{
ringBuffer = NULL;
remux = NULL;
fileName = NULL;
index = NULL;
pictureType = NO_PICTURE;
fileSize = 0;
active = false;
lastDiskSpaceCheck = time(NULL);
isyslog("record %s", FileName);
// Create directories if necessary:
if (!MakeDirs(FileName, true))
return;
// Make sure the disk is up and running:
SpinUpDisk(FileName);
ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
fileName = new cFileName(FileName, true);
recordFile = fileName->Open();
if (recordFile < 0)
return;
// Create the index file:
index = new cIndexFile(FileName, true);
if (!index)
esyslog("ERROR: can't allocate index");
// let's continue without index, so we'll at least have the recording
}
cRecorder::~cRecorder()
{
Detach();
delete index;
delete fileName;
delete remux;
delete ringBuffer;
}
void cRecorder::Activate(bool On)
{
if (On) {
if (recordFile >= 0)
Start();
}
else if (active) {
active = false;
Cancel(3);
}
}
bool cRecorder::RunningLowOnDiskSpace(void)
{
if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) {
int Free = FreeDiskSpaceMB(fileName->Name());
lastDiskSpaceCheck = time(NULL);
if (Free < MINFREEDISKSPACE) {
dsyslog("low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE);
return true;
}
}
return false;
}
bool cRecorder::NextFile(void)
{
if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME
if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) {
recordFile = fileName->NextFile();
fileSize = 0;
}
}
return recordFile >= 0;
}
void cRecorder::Receive(uchar *Data, int Length)
{
int p = ringBuffer->Put(Data, Length);
if (p != Length && active)
esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
}
void cRecorder::Action(void)
{
dsyslog("recording thread started (pid=%d)", getpid());
uchar b[MINVIDEODATA];
int r = 0;
active = true;
while (active) {
int g = ringBuffer->Get(b + r, sizeof(b) - r);
if (g > 0)
r += g;
if (r > 0) {
int Count = r, Result;
const uchar *p = remux->Process(b, Count, Result, &pictureType);
if (p) {
//XXX+ active??? see old version (Busy)
if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame
break;
if (NextFile()) {
if (index && pictureType != NO_PICTURE)
index->Write(pictureType, fileName->Number(), fileSize);
if (safe_write(recordFile, p, Result) < 0) {
LOG_ERROR_STR(fileName->Name());
break;
}
fileSize += Result;
}
else
break;
}
if (Count > 0) {
r -= Count;
memmove(b, b + Count, r);
}
}
else
usleep(1); // this keeps the CPU load low
}
dsyslog("recording thread ended (pid=%d)", getpid());
}

43
recorder.h Normal file
View File

@ -0,0 +1,43 @@
/*
* recorder.h: The actual DVB recorder
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recorder.h 1.1 2002/06/08 09:35:03 kls Exp $
*/
#ifndef __RECORDER_H
#define __RECORDER_H
#include "receiver.h"
#include "recording.h"
#include "remux.h"
#include "ringbuffer.h"
#include "thread.h"
class cRecorder : public cReceiver, cThread {
private:
cRingBufferLinear *ringBuffer;
cRemux *remux;
cFileName *fileName;
cIndexFile *index;
uchar pictureType;
int fileSize;
int recordFile;
bool active;
time_t lastDiskSpaceCheck;
bool RunningLowOnDiskSpace(void);
bool NextFile(void);
protected:
virtual void Activate(bool On);
virtual void Receive(uchar *Data, int Length);
virtual void Action(void);
public:
cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2);
// Creates a new recorder that requires conditional access Ca, has
// the given Priority and will record the given PIDs into the file FileName.
virtual ~cRecorder();
};
#endif //__RECORDER_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recording.c 1.62 2002/05/13 16:31:21 kls Exp $
* $Id: recording.c 1.63 2002/06/16 11:29:27 kls Exp $
*/
#include "recording.h"
@ -16,6 +16,7 @@
#include <unistd.h>
#include "i18n.h"
#include "interface.h"
#include "remux.h" //XXX+ I_FRAME
#include "tools.h"
#include "videodir.h"
@ -732,3 +733,350 @@ void cRecordingUserCommand::InvokeCommand(const char *State, const char *Recordi
delete cmd;
}
}
// --- XXX+
//XXX+ somewhere else???
// --- cIndexFile ------------------------------------------------------------
#define INDEXFILESUFFIX "/index.vdr"
// The maximum time to wait before giving up while catching up on an index file:
#define MAXINDEXCATCHUP 2 // seconds
cIndexFile::cIndexFile(const char *FileName, bool Record)
:resumeFile(FileName)
{
f = -1;
fileName = NULL;
size = 0;
last = -1;
index = NULL;
if (FileName) {
fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + 1];
if (fileName) {
strcpy(fileName, FileName);
char *pFileExt = fileName + strlen(fileName);
strcpy(pFileExt, INDEXFILESUFFIX);
int delta = 0;
if (access(fileName, R_OK) == 0) {
struct stat buf;
if (stat(fileName, &buf) == 0) {
delta = buf.st_size % sizeof(tIndex);
if (delta) {
delta = sizeof(tIndex) - delta;
esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, fileName);
}
last = (buf.st_size + delta) / sizeof(tIndex) - 1;
if (!Record && last >= 0) {
size = last + 1;
index = new tIndex[size];
if (index) {
f = open(fileName, O_RDONLY);
if (f >= 0) {
if ((int)safe_read(f, index, buf.st_size) != buf.st_size) {
esyslog("ERROR: can't read from file '%s'", fileName);
delete index;
index = NULL;
close(f);
f = -1;
}
// we don't close f here, see CatchUp()!
}
else
LOG_ERROR_STR(fileName);
}
else
esyslog("ERROR: can't allocate %d bytes for index '%s'", size * sizeof(tIndex), fileName);
}
}
else
LOG_ERROR;
}
else if (!Record)
isyslog("missing index file %s", fileName);
if (Record) {
if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) {
if (delta) {
esyslog("ERROR: padding index file with %d '0' bytes", delta);
while (delta--)
writechar(f, 0);
}
}
else
LOG_ERROR_STR(fileName);
}
}
else
esyslog("ERROR: can't copy file name '%s'", FileName);
}
}
cIndexFile::~cIndexFile()
{
if (f >= 0)
close(f);
delete fileName;
delete index;
}
bool cIndexFile::CatchUp(int Index)
{
if (index && f >= 0) {
for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index >= last); i++) {
struct stat buf;
if (fstat(f, &buf) == 0) {
int newLast = buf.st_size / sizeof(tIndex) - 1;
if (newLast > last) {
if (size <= newLast) {
size *= 2;
if (size <= newLast)
size = newLast + 1;
}
index = (tIndex *)realloc(index, size * sizeof(tIndex));
if (index) {
int offset = (last + 1) * sizeof(tIndex);
int delta = (newLast - last) * sizeof(tIndex);
if (lseek(f, offset, SEEK_SET) == offset) {
if (safe_read(f, &index[last + 1], delta) != delta) {
esyslog("ERROR: can't read from index");
delete index;
index = NULL;
close(f);
f = -1;
break;
}
last = newLast;
}
else
LOG_ERROR_STR(fileName);
}
else
esyslog("ERROR: can't realloc() index");
}
}
else
LOG_ERROR_STR(fileName);
if (Index >= last)
sleep(1);
else
return true;
}
}
return false;
}
bool cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset)
{
if (f >= 0) {
tIndex i = { FileOffset, PictureType, FileNumber, 0 };
if (safe_write(f, &i, sizeof(i)) < 0) {
LOG_ERROR_STR(fileName);
close(f);
f = -1;
return false;
}
last++;
}
return f >= 0;
}
bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length)
{
if (index) {
CatchUp(Index);
if (Index >= 0 && Index <= last) {
*FileNumber = index[Index].number;
*FileOffset = index[Index].offset;
if (PictureType)
*PictureType = index[Index].type;
if (Length) {
int fn = index[Index + 1].number;
int fo = index[Index + 1].offset;
if (fn == *FileNumber)
*Length = fo - *FileOffset;
else
*Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly)
}
return true;
}
}
return false;
}
int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd)
{
if (index) {
CatchUp();
int d = Forward ? 1 : -1;
for (;;) {
Index += d;
if (Index >= 0 && Index < last - ((Forward && StayOffEnd) ? 100 : 0)) {
if (index[Index].type == I_FRAME) {
if (FileNumber)
*FileNumber = index[Index].number;
else
FileNumber = &index[Index].number;
if (FileOffset)
*FileOffset = index[Index].offset;
else
FileOffset = &index[Index].offset;
if (Length) {
// all recordings end with a non-I_FRAME, so the following should be safe:
int fn = index[Index + 1].number;
int fo = index[Index + 1].offset;
if (fn == *FileNumber)
*Length = fo - *FileOffset;
else {
esyslog("ERROR: 'I' frame at end of file #%d", *FileNumber);
*Length = -1;
}
}
return Index;
}
}
else
break;
}
}
return -1;
}
int cIndexFile::Get(uchar FileNumber, int FileOffset)
{
if (index) {
CatchUp();
//TODO implement binary search!
int i;
for (i = 0; i < last; i++) {
if (index[i].number > FileNumber || (index[i].number == FileNumber) && index[i].offset >= FileOffset)
break;
}
return i;
}
return -1;
}
// --- cFileName -------------------------------------------------------------
#include <errno.h>
#include <unistd.h>
#include "videodir.h"
#define MAXFILESPERRECORDING 255
#define RECORDFILESUFFIX "/%03d.vdr"
#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety...
cFileName::cFileName(const char *FileName, bool Record, bool Blocking)
{
file = -1;
fileNumber = 0;
record = Record;
blocking = Blocking;
// Prepare the file name:
fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN];
if (!fileName) {
esyslog("ERROR: can't copy file name '%s'", fileName);
return;
}
strcpy(fileName, FileName);
pFileNumber = fileName + strlen(fileName);
SetOffset(1);
}
cFileName::~cFileName()
{
Close();
delete fileName;
}
int cFileName::Open(void)
{
if (file < 0) {
int BlockingFlag = blocking ? 0 : O_NONBLOCK;
if (record) {
dsyslog("recording to '%s'", fileName);
file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag);
if (file < 0)
LOG_ERROR_STR(fileName);
}
else {
if (access(fileName, R_OK) == 0) {
dsyslog("playing '%s'", fileName);
file = open(fileName, O_RDONLY | BlockingFlag);
if (file < 0)
LOG_ERROR_STR(fileName);
}
else if (errno != ENOENT)
LOG_ERROR_STR(fileName);
}
}
return file;
}
void cFileName::Close(void)
{
if (file >= 0) {
if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0))
LOG_ERROR_STR(fileName);
file = -1;
}
}
int cFileName::SetOffset(int Number, int Offset)
{
if (fileNumber != Number)
Close();
if (0 < Number && Number <= MAXFILESPERRECORDING) {
fileNumber = Number;
sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber);
if (record) {
if (access(fileName, F_OK) == 0) // file exists, let's try next suffix
return SetOffset(Number + 1);
else if (errno != ENOENT) { // something serious has happened
LOG_ERROR_STR(fileName);
return -1;
}
// found a non existing file suffix
}
if (Open() >= 0) {
if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) {
LOG_ERROR_STR(fileName);
return -1;
}
}
return file;
}
esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING);
return -1;
}
int cFileName::NextFile(void)
{
return SetOffset(fileNumber + 1);
}
const char *IndexToHMSF(int Index, bool WithFrame)
{
static char buffer[16];
int f = (Index % FRAMESPERSEC) + 1;
int s = (Index / FRAMESPERSEC);
int m = s / 60 % 60;
int h = s / 3600;
s %= 60;
snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f);
return buffer;
}
int HMSFToIndex(const char *HMSF)
{
int h, m, s, f = 0;
if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f))
return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1;
return 0;
}
int SecondsToFrames(int Seconds)
{
return Seconds * FRAMESPERSEC;
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recording.h 1.22 2002/02/03 11:59:49 kls Exp $
* $Id: recording.h 1.23 2002/06/16 11:29:47 kls Exp $
*/
#ifndef __RECORDING_H
@ -104,4 +104,63 @@ public:
static void InvokeCommand(const char *State, const char *RecordingFileName);
};
//XXX+
#define FRAMESPERSEC 25
// The maximum file size is limited by the range that can be covered
// with 'int'. 4GB might be possible (if the range is considered
// 'unsigned'), 2GB should be possible (even if the range is considered
// 'signed'), so let's use 2000MB for absolute safety (the actual file size
// may be slightly higher because we stop recording only before the next
// 'I' frame, to have a complete Group Of Pictures):
#define MAXVIDEOFILESIZE 2000 // MB
#define MINVIDEOFILESIZE 100 // MB
class cIndexFile {
private:
struct tIndex { int offset; uchar type; uchar number; short reserved; };
int f;
char *fileName;
int size, last;
tIndex *index;
cResumeFile resumeFile;
bool CatchUp(int Index = -1);
public:
cIndexFile(const char *FileName, bool Record);
~cIndexFile();
bool Ok(void) { return index != NULL; }
bool Write(uchar PictureType, uchar FileNumber, int FileOffset);
bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL, int *Length = NULL);
int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL, bool StayOffEnd = false);
int Get(uchar FileNumber, int FileOffset);
int Last(void) { CatchUp(); return last; }
int GetResume(void) { return resumeFile.Read(); }
bool StoreResume(int Index) { return resumeFile.Save(Index); }
};
class cFileName {
private:
int file;
int fileNumber;
char *fileName, *pFileNumber;
bool record;
bool blocking;
public:
cFileName(const char *FileName, bool Record, bool Blocking = false);
~cFileName();
const char *Name(void) { return fileName; }
int Number(void) { return fileNumber; }
int Open(void);
void Close(void);
int SetOffset(int Number, int Offset = 0);
int NextFile(void);
};
const char *IndexToHMSF(int Index, bool WithFrame = false);
// Converts the given index to a string, optionally containing the frame number.
int HMSFToIndex(const char *HMSF);
// Converts the given string (format: "hh:mm:ss.ff") to an index.
int SecondsToFrames(int Seconds); //XXX+ ->player???
// Returns the number of frames corresponding to the given number of seconds.
#endif //__RECORDING_H

View File

@ -6,7 +6,7 @@
*
* Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16.
*
* $Id: remote.c 1.26 2002/05/13 16:31:27 kls Exp $
* $Id: remote.c 1.27 2002/05/18 12:55:39 kls Exp $
*/
#include "remote.h"
@ -24,6 +24,10 @@
#include <sys/un.h>
#endif
#if defined REMOTE_KBD
#include <ncurses.h>
#endif
#include "config.h"
#include "tools.h"

View File

@ -1,5 +1,5 @@
/*
* ringbuffer.c: A threaded ring buffer
* ringbuffer.c: A ring buffer
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
@ -7,50 +7,25 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
* $Id: ringbuffer.c 1.7 2002/05/13 16:31:46 kls Exp $
* $Id: ringbuffer.c 1.9 2002/06/16 11:24:40 kls Exp $
*/
#include "ringbuffer.h"
#include <unistd.h>
#include "tools.h"
// --- cRingBufferInputThread -------------------------------------------------
class cRingBufferInputThread : public cThread {
private:
cRingBuffer *ringBuffer;
protected:
virtual void Action(void) { ringBuffer->Input(); }
public:
cRingBufferInputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
};
// --- cRingBufferOutputThread ------------------------------------------------
class cRingBufferOutputThread : public cThread {
private:
cRingBuffer *ringBuffer;
protected:
virtual void Action(void) { ringBuffer->Output(); }
public:
cRingBufferOutputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
};
// --- cRingBuffer ------------------------------------------------------------
// --- cRingBuffer -----------------------------------------------------------
cRingBuffer::cRingBuffer(int Size, bool Statistics)
{
size = Size;
statistics = Statistics;
inputThread = NULL;
outputThread = NULL;
busy = false;
maxFill = 0;
lastPercent = 0;
}
cRingBuffer::~cRingBuffer()
{
delete inputThread;
delete outputThread;
if (statistics)
dsyslog("buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
}
@ -79,45 +54,13 @@ void cRingBuffer::EnableGet(void)
readyForGet.Broadcast();
}
bool cRingBuffer::Start(void)
{
if (!busy) {
busy = true;
outputThread = new cRingBufferOutputThread(this);
if (!outputThread->Start())
DELETENULL(outputThread);
inputThread = new cRingBufferInputThread(this);
if (!inputThread->Start()) {
DELETENULL(inputThread);
DELETENULL(outputThread);
}
busy = outputThread && inputThread;
}
return busy;
}
bool cRingBuffer::Active(void)
{
return outputThread && outputThread->Active() && inputThread && inputThread->Active();
}
void cRingBuffer::Stop(void)
{
busy = false;
for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
break;
}
DELETENULL(inputThread);
DELETENULL(outputThread);
}
// --- cRingBufferLinear ----------------------------------------------------
// --- cRingBufferLinear -----------------------------------------------------
cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
:cRingBuffer(Size, Statistics)
{
buffer = NULL;
getThreadPid = -1;
if (Size > 1) { // 'Size - 1' must not be 0!
buffer = new uchar[Size];
if (!buffer)
@ -146,6 +89,8 @@ void cRingBufferLinear::Clear(void)
Lock();
head = tail = 0;
Unlock();
EnablePut();
EnableGet();
}
int cRingBufferLinear::Put(const uchar *Data, int Count)
@ -159,11 +104,13 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
int fill = Size() - free - 1 + Count;
if (fill >= Size())
fill = Size() - 1;
if (fill > maxFill) {
if (fill > maxFill)
maxFill = fill;
int percent = maxFill * 100 / (Size() - 1);
int percent = maxFill * 100 / (Size() - 1) / 5 * 5;
if (abs(lastPercent - percent) >= 5) {
if (percent > 75)
dsyslog("buffer usage: %d%%", percent);
dsyslog("buffer usage: %d%% (pid=%d)", percent, getThreadPid);
lastPercent = percent;
}
}
if (free > 0) {
@ -185,6 +132,7 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
else
Count = 0;
Unlock();
EnableGet();
}
return Count;
}
@ -193,6 +141,8 @@ int cRingBufferLinear::Get(uchar *Data, int Count)
{
if (Count > 0) {
Lock();
if (getThreadPid < 0)
getThreadPid = getpid();
int rest = Size() - tail;
int diff = head - tail;
int cont = (diff >= 0) ? diff : Size() + diff;
@ -213,6 +163,8 @@ int cRingBufferLinear::Get(uchar *Data, int Count)
else
Count = 0;
Unlock();
if (Count == 0)
WaitForGet();
}
return Count;
}
@ -239,7 +191,7 @@ cFrame::~cFrame()
// --- cRingBufferFrame ------------------------------------------------------
cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics = false)
cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics)
:cRingBuffer(Size, Statistics)
{
head = NULL;
@ -255,7 +207,7 @@ void cRingBufferFrame::Clear(void)
{
Lock();
const cFrame *p;
while ((p = Get(false)) != NULL)
while ((p = Get()) != NULL)
Drop(p);
Unlock();
EnablePut();
@ -279,17 +231,14 @@ bool cRingBufferFrame::Put(cFrame *Frame)
EnableGet();
return true;
}
WaitForPut();
return false;
}
const cFrame *cRingBufferFrame::Get(bool Wait)
const cFrame *cRingBufferFrame::Get(void)
{
Lock();
cFrame *p = head ? head->next : NULL;
Unlock();
if (!p && Wait)
WaitForGet();
return p;
}

View File

@ -1,10 +1,10 @@
/*
* ringbuffer.h: A threaded ring buffer
* ringbuffer.h: A ring buffer
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ringbuffer.h 1.5 2001/11/03 10:41:33 kls Exp $
* $Id: ringbuffer.h 1.6 2002/06/16 11:30:07 kls Exp $
*/
#ifndef __RINGBUFFER_H
@ -12,24 +12,17 @@
#include "thread.h"
typedef unsigned char uchar;
class cRingBufferInputThread;
class cRingBufferOutputThread;
typedef unsigned char uchar;//XXX+
class cRingBuffer {
friend class cRingBufferInputThread;
friend class cRingBufferOutputThread;
private:
cRingBufferInputThread *inputThread;
cRingBufferOutputThread *outputThread;
cMutex mutex;
cCondVar readyForPut, readyForGet;
cMutex putMutex, getMutex;
int size;
bool busy;
protected:
int maxFill;//XXX
int lastPercent;
bool statistics;//XXX
void WaitForPut(void);
void WaitForGet(void);
@ -41,26 +34,19 @@ protected:
void Lock(void) { mutex.Lock(); }
void Unlock(void) { mutex.Unlock(); }
int Size(void) { return size; }
bool Busy(void) { return busy; }
virtual void Input(void) = 0;
// Runs as a separate thread and shall continuously read data from
// a source and call Put() to store the data in the ring buffer.
virtual void Output(void) = 0;
// Runs as a separate thread and shall continuously call Get() to
// retrieve data from the ring buffer and write it to a destination.
public:
cRingBuffer(int Size, bool Statistics = false);
virtual ~cRingBuffer();
bool Start(void);
bool Active(void);
void Stop(void);
};
class cRingBufferLinear : public cRingBuffer {
private:
int head, tail;
uchar *buffer;
protected:
pid_t getThreadPid;
public:
cRingBufferLinear(int Size, bool Statistics = false);
virtual ~cRingBufferLinear();
virtual int Available(void);
virtual void Clear(void);
// Immediately clears the ring buffer.
@ -70,9 +56,6 @@ protected:
int Get(uchar *Data, int Count);
// Gets at most Count bytes of Data from the ring buffer.
// Returns the number of bytes actually retrieved.
public:
cRingBufferLinear(int Size, bool Statistics = false);
virtual ~cRingBufferLinear();
};
enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby };
@ -99,21 +82,20 @@ private:
cFrame *head;
int currentFill;
void Delete(const cFrame *Frame);
protected:
public:
cRingBufferFrame(int Size, bool Statistics = false);
virtual ~cRingBufferFrame();
virtual int Available(void);
virtual void Clear(void);
// Immediately clears the ring buffer.
bool Put(cFrame *Frame);
// Puts the Frame into the ring buffer.
// Returns true if this was possible.
const cFrame *Get(bool Wait = true);
const cFrame *Get(void);
// Gets the next frame from the ring buffer.
// The actual data still remains in the buffer until Drop() is called.
void Drop(const cFrame *Frame);
// Drops the Frame that has just been fetched with Get().
public:
cRingBufferFrame(int Size, bool Statistics = false);
virtual ~cRingBufferFrame();
};
#endif // __RINGBUFFER_H

96
status.c Normal file
View File

@ -0,0 +1,96 @@
/*
* status.c: Status monitoring
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: status.c 1.3 2002/06/16 13:24:36 kls Exp $
*/
#include "status.h"
// --- cStatus ---------------------------------------------------------------
cList<cStatus> cStatus::statusMonitors;
cStatus::cStatus(void)
{
statusMonitors.Add(this);
}
cStatus::~cStatus()
{
statusMonitors.Del(this, false);
}
void cStatus::MsgChannelSwitch(const cDevice *Device, int ChannelNumber)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->ChannelSwitch(Device, ChannelNumber);
}
void cStatus::MsgRecording(const cDevice *Device, const char *Name)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->Recording(Device, Name);
}
void cStatus::MsgReplaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->Replaying(DvbPlayerControl, Name);
}
void cStatus::MsgSetVolume(int Volume, bool Absolute)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->SetVolume(Volume, Absolute);
}
void cStatus::MsgOsdClear(void)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdClear();
}
void cStatus::MsgOsdTitle(const char *Title)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdTitle(Title);
}
void cStatus::MsgOsdStatusMessage(const char *Message)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdStatusMessage(Message);
}
void cStatus::MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdHelpKeys(Red, Green, Yellow, Blue);
}
void cStatus::MsgOsdCurrentItem(const char *Text)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdCurrentItem(Text);
}
void cStatus::MsgOsdTextItem(const char *Text, bool Scroll)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdTextItem(Text, Scroll);
}
void cStatus::MsgOsdChannel(const char *Text)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdChannel(Text);
}
void cStatus::MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle);
}

75
status.h Normal file
View File

@ -0,0 +1,75 @@
/*
* status.h: Status monitoring
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: status.h 1.3 2002/06/16 13:24:50 kls Exp $
*/
#ifndef __STATUS_H
#define __STATUS_H
#include "config.h"
#include "device.h"
#include "dvbplayer.h"
#include "tools.h"
class cStatus : public cListObject {
private:
static cList<cStatus> statusMonitors;
protected:
// These functions can be implemented by derived classes to receive status information:
virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {}
// Indicates a channel switch on the given DVB device.
// If ChannelNumber is 0, this is before the channel is being switched,
// otherwise ChannelNumber is the number of the channel that has been switched to.
virtual void Recording(const cDevice *Device, const char *Name) {}
// The given DVB device has started recording Name. Name is the full directory
// name of the recording. If Name is NULL, the recording has ended.
virtual void Replaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name) {}
// The given player control has started replaying Name. Name is the full directory
// name of the recording. If Name is NULL, the replay has ended.
virtual void SetVolume(int Volume, bool Absolute) {}
// The volume has been set to the given value, either
// absolutely or relative to the current volume.
virtual void OsdClear(void) {}
// The OSD has been cleared.
virtual void OsdTitle(const char *Title) {}
// Title has been displayed in the title line of the menu.
virtual void OsdStatusMessage(const char *Message) {}
// Message has been displayed in the status line of the menu.
// If Message is NULL, the status line has been cleared.
virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue) {}
// The help keys have been set to the given values (may be NULL).
virtual void OsdCurrentItem(const char *Text) {}
// The OSD displays the given single line Text as the current menu item.
virtual void OsdTextItem(const char *Text, bool Scroll) {}
// The OSD displays the given multi line text. If Text points to an
// actual string, that text shall be displayed and Scroll has no
// meaning. If Text is NULL, Scroll defines whether the previously
// received text shall be scrolled up (true) or down (false) and
// the text shall be redisplayed with the new offset.
virtual void OsdChannel(const char *Text) {}
// The OSD displays the single line Text with the current channel information.
virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {}
// The OSD displays the given programme information.
public:
cStatus(void);
virtual ~cStatus();
// These functions are called whenever the related status information changes:
static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber);
static void MsgRecording(const cDevice *Device, const char *Name);
static void MsgReplaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name);
static void MsgSetVolume(int Volume, bool Absolute);
static void MsgOsdClear(void);
static void MsgOsdTitle(const char *Title);
static void MsgOsdStatusMessage(const char *Message);
static void MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue);
static void MsgOsdCurrentItem(const char *Text);
static void MsgOsdTextItem(const char *Text, bool Scroll = false);
static void MsgOsdChannel(const char *Text);
static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle);
};
#endif //__STATUS_H

26
svdrp.c
View File

@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
* $Id: svdrp.c 1.37 2002/05/13 16:32:05 kls Exp $
* $Id: svdrp.c 1.38 2002/06/09 15:56:54 kls Exp $
*/
#include "svdrp.h"
@ -27,7 +27,7 @@
#include <sys/time.h>
#include <unistd.h>
#include "config.h"
#include "dvbapi.h"
#include "device.h"
#include "interface.h"
#include "tools.h"
@ -390,12 +390,12 @@ void cSVDRP::CmdCHAN(const char *Option)
n = o;
}
else if (strcmp(Option, "-") == 0) {
n = cDvbApi::CurrentChannel();
n = cDevice::CurrentChannel();
if (n > 1)
n--;
}
else if (strcmp(Option, "+") == 0) {
n = cDvbApi::CurrentChannel();
n = cDevice::CurrentChannel();
if (n < Channels.MaxNumber())
n++;
}
@ -430,11 +430,11 @@ void cSVDRP::CmdCHAN(const char *Option)
return;
}
}
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
if (channel)
Reply(250, "%d %s", channel->number, channel->name);
else
Reply(550, "Unable to find channel \"%d\"", cDvbApi::CurrentChannel());
Reply(550, "Unable to find channel \"%d\"", cDevice::CurrentChannel());
}
void cSVDRP::CmdDELC(const char *Option)
@ -541,7 +541,7 @@ void cSVDRP::CmdGRAB(const char *Option)
Reply(501, "Unexpected parameter \"%s\"", p);
return;
}
if (cDvbApi::PrimaryDvbApi->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY))
if (cDevice::PrimaryDevice()->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY))
Reply(250, "Grabbed image %s", Option);
else
Reply(451, "Grab image failed");
@ -926,22 +926,22 @@ void cSVDRP::CmdVOLU(const char *Option)
{
if (*Option) {
if (isnumber(Option))
cDvbApi::PrimaryDvbApi->SetVolume(strtol(Option, NULL, 10), true);
cDevice::PrimaryDevice()->SetVolume(strtol(Option, NULL, 10), true);
else if (strcmp(Option, "+") == 0)
cDvbApi::PrimaryDvbApi->SetVolume(VOLUMEDELTA);
cDevice::PrimaryDevice()->SetVolume(VOLUMEDELTA);
else if (strcmp(Option, "-") == 0)
cDvbApi::PrimaryDvbApi->SetVolume(-VOLUMEDELTA);
cDevice::PrimaryDevice()->SetVolume(-VOLUMEDELTA);
else if (strcasecmp(Option, "MUTE") == 0)
cDvbApi::PrimaryDvbApi->ToggleMute();
cDevice::PrimaryDevice()->ToggleMute();
else {
Reply(501, "Unknown option: \"%s\"", Option);
return;
}
}
if (cDvbApi::PrimaryDvbApi->IsMute())
if (cDevice::PrimaryDevice()->IsMute())
Reply(250, "Audio is mute");
else
Reply(250, "Audio volume is %d", cDvbApi::CurrentVolume());
Reply(250, "Audio volume is %d", cDevice::CurrentVolume());
}
#define CMD(c) (strcasecmp(Cmd, c) == 0)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 1.20 2002/05/13 16:32:09 kls Exp $
* $Id: thread.c 1.21 2002/06/01 15:28:46 kls Exp $
*/
#include "thread.h"
@ -147,6 +147,7 @@ bool cThread::Active(void)
void cThread::Cancel(int WaitSeconds)
{
running = false;
if (WaitSeconds > 0) {
for (time_t t0 = time(NULL) + WaitSeconds; time(NULL) < t0; ) {
if (!Active())

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.h 1.12 2002/02/23 13:53:38 kls Exp $
* $Id: thread.h 1.13 2002/06/01 14:55:31 kls Exp $
*/
#ifndef __THREAD_H
@ -54,9 +54,9 @@ private:
static bool signalHandlerInstalled;
static void SignalHandler(int signum);
static void *StartThread(cThread *Thread);
protected:
void Lock(void) { mutex.Lock(); }
void Unlock(void) { mutex.Unlock(); }
protected:
void WakeUp(void);
virtual void Action(void) = 0;
void Cancel(int WaitSeconds = 0);

118
tmp.dif Normal file
View File

@ -0,0 +1,118 @@
--- dvb.c
+++ dvb.c Wed May 29 17:41:53 2002
@@ -444,6 +444,8 @@
break;
if (!dvb->arm_ready)
continue;
+ if (down_interruptible(&dvb->dcomlock))
+ continue;
newloops=rdebi(dvb, DEBINOSWAP, STATUS_LOOPS, 0, 2);
if (newloops==dvb->arm_loops) {
printk("dvb%d: ARM crashed!\n", dvb->num);
@@ -451,6 +453,7 @@
newloops=rdebi(dvb, DEBINOSWAP, STATUS_LOOPS, 0, 2)-1;
}
dvb->arm_loops=newloops;
+ up(&dvb->dcomlock);
}
dvb->arm_thread = NULL;
return 0;
@@ -1158,6 +1161,31 @@
return blen;
}
+/* Timer to avoid broken data transfer in gpioirq() */
+
+#define GPIO_RXTIME_FRAME ((32*HZ)/1000)
+
+static void gpio_receive_timeout(unsigned long data)
+{
+ struct dvb_struct *dvb = (struct dvb_struct *)data;
+ dvb->debitimer.expires = 0;
+}
+
+static void gpio_receive_timer(struct dvb_struct *dvb, unsigned long ticks)
+{
+ dvb_demux_filter_t *dvbdmxfilter = dvb->handle2filter[((dvb->debitype)>>8)&0x1f];
+
+ if (!dvbdmxfilter || dvbdmxfilter->type != DMX_TYPE_TS)
+ return;
+ mod_timer(&dvb->debitimer, jiffies + ticks);
+}
+
+static inline int gpio_rx_pending(struct dvb_struct *dvb)
+{
+ return !timer_pending(&dvb->debitimer) && \
+ dvb->debitimer.expires == 0;
+}
+
static void
gpioirq(struct saa7146* saa, void *data)
{
@@ -1313,6 +1341,7 @@
iwdebi(dvb, DEBINOSWAP, RX_BUFF, 0, 2);
break;
} /* yes, fall through */
+ gpio_receive_timer(dvb, GPIO_RXTIME_FRAME);
case DATA_TS_RECORD:
case DATA_PES_RECORD:
saa7146_write(dvb->saa_mem, IER,
@@ -1843,7 +1872,7 @@
bpp=dvb->osdbpp[dvb->osdwin]+1;
bpl=((w*bpp+7)&~7)/8;
size=h*bpl;
- lpb=(32*1024)/bpl;
+ lpb=(16*1024)/bpl;
bnum=size/(lpb*bpl);
brest=size-bnum*lpb*bpl;
@@ -1851,6 +1880,10 @@
LoadBitmap(dvb, bpp2bit[dvb->osdbpp[dvb->osdwin]], w, lpb, inc, data);
BlitBitmap(dvb, dvb->osdwin, x0, y0+i*lpb, 0);
data+=lpb*inc;
+ if (gpio_rx_pending(dvb)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(GPIO_RXTIME_FRAME);
+ }
}
if (brest) {
LoadBitmap(dvb, bpp2bit[dvb->osdbpp[dvb->osdwin]], w, brest/bpl, inc, data);
@@ -3819,6 +3852,7 @@
return TTBStop(dvb);
if (dvbdmxfeed->type == DMX_TYPE_TS) {
+ del_timer(&dvb->debitimer);
if (dvbdmxfeed->ts_type & TS_DECODER) {
if (dvbdmxfeed->pes_type>=DMX_TS_PES_OTHER ||
!dvbdmx->pesfilter[dvbdmxfeed->pes_type])
@@ -5472,8 +5506,12 @@
spin_lock_init (&dvb->debilock);
sema_init(&dvb->dcomlock, 1);
init_waitqueue_head(&dvb->debiq);
+ init_timer(&dvb->debitimer);
dvb->debilock=SPIN_LOCK_UNLOCKED;
dvb->debitype=-1;
+ dvb->debitimer.function = gpio_receive_timeout;
+ dvb->debitimer.data = (unsigned long) dvb;
+ dvb->debitimer.expires = jiffies;
dvb->num=num;
dvb->i2cbus=adap;
@@ -5741,6 +5779,7 @@
/* release the saa7146s */
for( i = 0; i < num_dvb; i++) {
+ del_timer_sync(&(dvbs[i].debitimer));
dvbs[i].arm_rmmod=1;
wake_up_interruptible(&dvbs[i].arm_wait);
while (dvbs[i].arm_thread)
--- dvb.h
+++ dvb.h Wed May 29 17:41:08 2002
@@ -566,6 +566,7 @@
spinlock_t debilock;
struct semaphore dcomlock;
WAIT_QUEUE debiq;
+ struct timer_list debitimer;
int debitype;
int debilen;
int debibuf;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 1.66 2002/05/13 17:56:17 kls Exp $
* $Id: tools.c 1.67 2002/05/18 15:10:45 kls Exp $
*/
#include "tools.h"
@ -793,14 +793,15 @@ void cListBase::Ins(cListObject *Object, cListObject *Before)
}
}
void cListBase::Del(cListObject *Object)
void cListBase::Del(cListObject *Object, bool DeleteObject)
{
if (Object == objects)
objects = Object->Next();
if (Object == lastObject)
lastObject = Object->Prev();
Object->Unlink();
delete Object;
if (DeleteObject)
delete Object;
}
void cListBase::Move(int From, int To)

11
tools.h
View File

@ -4,13 +4,13 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 1.45 2002/05/13 16:21:55 kls Exp $
* $Id: tools.h 1.47 2002/06/09 11:09:10 kls Exp $
*/
#ifndef __TOOLS_H
#define __TOOLS_H
//#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
@ -18,6 +18,8 @@
#include <sys/stat.h>
#include <sys/types.h>
typedef unsigned char uchar;
extern int SysLogLevel;
#define esyslog(a...) void( (SysLogLevel > 0) ? syslog(LOG_ERR, a) : void() )
@ -36,6 +38,9 @@ extern int SysLogLevel;
#define DELETENULL(p) (delete (p), p = NULL)
#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
#define FATALERRNO (errno != EAGAIN && errno != EINTR)
template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
@ -135,7 +140,7 @@ public:
virtual ~cListBase();
void Add(cListObject *Object, cListObject *After = NULL);
void Ins(cListObject *Object, cListObject *Before = NULL);
void Del(cListObject *Object);
void Del(cListObject *Object, bool DeleteObject = true);
virtual void Move(int From, int To);
void Move(cListObject *From, cListObject *To);
virtual void Clear(void);

70
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
* $Id: vdr.c 1.109 2002/05/13 16:32:49 kls Exp $
* $Id: vdr.c 1.114 2002/06/16 11:30:28 kls Exp $
*/
#include <getopt.h>
@ -31,11 +31,12 @@
#include <stdlib.h>
#include <unistd.h>
#include "config.h"
#include "dvbapi.h"
#include "eit.h"
#include "device.h"
#include "eitscan.h"
#include "i18n.h"
#include "interface.h"
#include "menu.h"
#include "osd.h"
#include "plugin.h"
#include "recording.h"
#include "tools.h"
@ -117,15 +118,17 @@ int main(int argc, char *argv[])
int c;
while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:L:mp:P:r:s:t:v:Vw:", long_options, NULL)) != -1) {
switch (c) {
case 'a': cDvbApi::SetAudioCommand(optarg);
/*XXX+
case 'a': cDevice::SetAudioCommand(optarg);
break;
XXX*/
case 'c': ConfigDirectory = optarg;
break;
case 'd': DaemonMode = true; break;
case 'D': if (isnumber(optarg)) {
int n = atoi(optarg);
if (0 <= n && n < MAXDVBAPI) {
cDvbApi::SetUseDvbApi(n);
if (0 <= n && n < MAXDEVICES) {
cDevice::SetUseDevice(n);
break;
}
}
@ -146,7 +149,12 @@ int main(int argc, char *argv[])
fprintf(stderr, "vdr: invalid log level: %s\n", optarg);
return 2;
break;
case 'L': PluginManager.SetDirectory(optarg);
case 'L': if (access(optarg, R_OK | X_OK) == 0)
PluginManager.SetDirectory(optarg);
else {
fprintf(stderr, "vdr: can't access plugin directory: %s\n", optarg);
return 2;
}
break;
case 'm': MuteAudio = true;
break;
@ -317,10 +325,10 @@ int main(int argc, char *argv[])
// DVB interfaces:
if (!cDvbApi::Init())
if (!cDevice::Initialize())
return 2;
cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB);
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
cSIProcessor::Read();
@ -329,13 +337,17 @@ int main(int argc, char *argv[])
if (!PluginManager.StartPlugins())
return 2;
// OSD:
cOsd::Initialize();
// Channel:
Channels.SwitchTo(Setup.CurrentChannel);
if (MuteAudio)
cDvbApi::PrimaryDvbApi->ToggleMute();
cDevice::PrimaryDevice()->ToggleMute();
else
cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true);
cDevice::PrimaryDevice()->SetVolume(Setup.CurrentVolume, true);
cEITScanner EITScanner;
@ -358,10 +370,10 @@ int main(int argc, char *argv[])
// Main program loop:
cOsdBase *Menu = NULL;
cOsdObject *Menu = NULL;
cReplayControl *ReplayControl = NULL;
int LastChannel = -1;
int PreviousChannel = cDvbApi::CurrentChannel();
int PreviousChannel = cDevice::CurrentChannel();
time_t LastActivity = 0;
int MaxLatencyTime = 0;
bool ForceShutdown = false;
@ -386,12 +398,12 @@ int main(int argc, char *argv[])
}
}
// Channel display:
if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) {
if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
if (!Menu)
Menu = new cDisplayChannel(cDvbApi::CurrentChannel(), LastChannel > 0);
Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel > 0);
if (LastChannel > 0)
PreviousChannel = LastChannel;
LastChannel = cDvbApi::CurrentChannel();
LastChannel = cDevice::CurrentChannel();
}
// Timers and Recordings:
if (!Menu) {
@ -404,7 +416,7 @@ int main(int argc, char *argv[])
}
}
// User Input:
cOsdBase **Interact = Menu ? &Menu : (cOsdBase **)&ReplayControl;
cOsdObject **Interact = Menu ? &Menu : (cOsdObject **)&ReplayControl;
eKeys key = Interface->GetKey(!*Interact || !(*Interact)->NeedsFastResponse());
if (NORMALKEY(key) != kNone) {
EITScanner.Activity();
@ -419,11 +431,11 @@ int main(int argc, char *argv[])
case kVolDn:
case kMute:
if (key == kMute) {
if (!cDvbApi::PrimaryDvbApi->ToggleMute() && !Menu)
if (!cDevice::PrimaryDevice()->ToggleMute() && !Menu)
break; // no need to display "mute off"
}
else
cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
cDevice::PrimaryDevice()->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
if (!Menu && (!ReplayControl || !ReplayControl->Visible()))
Menu = cDisplayVolume::Create();
cDisplayVolume::Process(key);
@ -467,7 +479,7 @@ int main(int argc, char *argv[])
case osSwitchDvb:
DELETENULL(*Interact);
Interface->Info(tr("Switching primary DVB..."));
cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB);
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
break;
case osBack:
case osEnd: DELETENULL(*Interact);
@ -480,7 +492,7 @@ int main(int argc, char *argv[])
switch (key) {
// Toggle channels:
case k0: {
int CurrentChannel = cDvbApi::CurrentChannel();
int CurrentChannel = cDevice::CurrentChannel();
Channels.SwitchTo(PreviousChannel);
PreviousChannel = CurrentChannel;
break;
@ -501,7 +513,7 @@ int main(int argc, char *argv[])
case kUp:
case kDown|k_Repeat:
case kDown: {
int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1);
int n = cDevice::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1);
cChannel *channel = Channels.GetByNumber(n);
if (channel)
channel->Switch();
@ -517,14 +529,16 @@ int main(int argc, char *argv[])
}
if (!Menu) {
EITScanner.Process();
/*XXX+
if (!cVideoCutter::Active() && cVideoCutter::Ended()) {
if (cVideoCutter::Error())
Interface->Error(tr("Editing process failed!"));
else
Interface->Info(tr("Editing process finished"));
}
XXX*/
}
if (!*Interact && ((!cRecordControls::Active() && !cVideoCutter::Active()) || ForceShutdown)) {
if (!*Interact && ((!cRecordControls::Active() /*XXX+&& !cVideoCutter::Active()XXX*/) || ForceShutdown)) {
time_t Now = time(NULL);
if (Now - LastActivity > ACTIVITYTIMEOUT) {
// Shutdown:
@ -583,15 +597,17 @@ int main(int argc, char *argv[])
}
if (Interrupted)
isyslog("caught signal %d", Interrupted);
cVideoCutter::Stop();
cRecordControls::Shutdown();
//XXX+cVideoCutter::Stop();
delete Menu;
delete ReplayControl;
delete Interface;
cOsd::Shutdown();
PluginManager.Shutdown(true);
Setup.CurrentChannel = cDvbApi::CurrentChannel();
Setup.CurrentVolume = cDvbApi::CurrentVolume();
Setup.CurrentChannel = cDevice::CurrentChannel();
Setup.CurrentVolume = cDevice::CurrentVolume();
Setup.Save();
cDvbApi::Cleanup();
cDevice::Shutdown();
if (WatchdogTimeout > 0)
dsyslog("max. latency time %d seconds", MaxLatencyTime);
isyslog("exiting");