mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
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:
parent
d07e3829f7
commit
f06d2c27fc
24
CONTRIBUTORS
24
CONTRIBUTORS
@ -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
71
HISTORY
@ -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.
|
||||
|
21
Makefile
21
Makefile
@ -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:
|
||||
|
125
PLUGINS.html
125
PLUGINS.html
@ -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> </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> </td><td width=100%>
|
||||
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime> </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> </td><td width=100%>
|
||||
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan> </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> </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> </td><td width=100%>
|
||||
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan> </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> </td><td width=100%>
|
||||
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan> </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> </td><td width=100%>
|
||||
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime> </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> </td><td width=100%>
|
||||
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan> </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> </td><td width=100%>
|
||||
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan> </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> </td><td width=100%>
|
||||
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan> </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> </td><td width=100%>
|
||||
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime> </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> </td><td width=100%>
|
||||
<!--X1.1.1--><table width=100%><tr><td bgcolor=lime> </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> </td><td width=100%>
|
||||
<!--X1.1.2--><table width=100%><tr><td bgcolor=cyan> </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> </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> </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 <vdr/status.h>
|
||||
|
||||
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->CardIndex());
|
||||
else
|
||||
dsyslog("about to switch channel on DVB %d", Device->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 <vdr/plugin.h>
|
||||
|
||||
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>
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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
340
PLUGINS/SRC/status/COPYING
Normal 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.
|
6
PLUGINS/SRC/status/HISTORY
Normal file
6
PLUGINS/SRC/status/HISTORY
Normal file
@ -0,0 +1,6 @@
|
||||
VDR Plugin 'status' Revision History
|
||||
------------------------------------
|
||||
|
||||
2002-05-18: Version 0.0.1
|
||||
|
||||
- Initial revision.
|
79
PLUGINS/SRC/status/Makefile
Normal file
79
PLUGINS/SRC/status/Makefile
Normal 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
11
PLUGINS/SRC/status/README
Normal 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
179
PLUGINS/SRC/status/status.c
Normal 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
11
audio.c
Normal 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
13
audio.h
Normal 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
|
29
config.c
29
config.c
@ -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) {
|
||||
|
12
config.h
12
config.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.h 1.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__;
|
||||
|
199
device.h
Normal file
199
device.h
Normal 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
12
dmxdev.c.diff
Normal 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);
|
335
dvbapi.h
335
dvbapi.h
@ -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
|
16
dvbosd.c
16
dvbosd.c
@ -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).
|
||||
|
8
dvbosd.h
8
dvbosd.h
@ -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
733
dvbplayer.c
Normal 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
60
dvbplayer.h
Normal 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
3
eit.c
@ -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
84
eitscan.c
Normal 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
33
eitscan.h
Normal 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
|
@ -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 (<>) {
|
||||
|
4
i18n.h
4
i18n.h
@ -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];
|
||||
|
||||
|
40
interface.c
40
interface.c
@ -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();
|
||||
}
|
||||
|
@ -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
225
menu.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menu.c 1.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
25
menu.h
@ -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;
|
||||
|
18
menuitems.c
18
menuitems.c
@ -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);
|
||||
|
12
newplugin
12
newplugin
@ -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
243
osd.c
@ -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
47
osd.h
@ -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];
|
||||
|
38
osdbase.c
38
osdbase.c
@ -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);
|
||||
}
|
||||
|
@ -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
55
player.c
Normal 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
51
player.h
Normal 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
55
receiver.c
Normal 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
48
receiver.h
Normal 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
149
recorder.c
Normal 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
43
recorder.h
Normal 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
|
350
recording.c
350
recording.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: recording.c 1.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;
|
||||
}
|
||||
|
61
recording.h
61
recording.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: recording.h 1.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
|
||||
|
6
remote.c
6
remote.c
@ -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"
|
||||
|
||||
|
95
ringbuffer.c
95
ringbuffer.c
@ -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;
|
||||
}
|
||||
|
||||
|
42
ringbuffer.h
42
ringbuffer.h
@ -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
96
status.c
Normal 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
75
status.h
Normal 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
26
svdrp.c
@ -10,7 +10,7 @@
|
||||
* and interact with the Video Disk Recorder - or write a full featured
|
||||
* graphical interface that sits on top of an SVDRP connection.
|
||||
*
|
||||
* $Id: svdrp.c 1.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)
|
||||
|
3
thread.c
3
thread.c
@ -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())
|
||||
|
4
thread.h
4
thread.h
@ -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
118
tmp.dif
Normal 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;
|
7
tools.c
7
tools.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: tools.c 1.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
11
tools.h
@ -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
70
vdr.c
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user