Version 1.3.38

- Fixed handling second audio and Dolby Digital PIDs for encrypted channels
  (was broken in version 1.3.37).
- Improved TS/PES conversion to better handle lost TS packets (thanks to
  Reinhard Nissl).
- Limited the frequency of log messages from the cRepackers.
- Now using the gettid() syscall to get a thread's pid, so that we get a
  useful value on NPTL systems (suggested by Johannes Stezenbach).
- Fixed the RCU remote control handling to avoid problems with NPTL (thanks
  to Andreas Share for reporting a lockup with the RCU on NPTL systems).
- When displaying the amount of free disk space, the space consumed by
  recordings that have been "deleted" but not yet actually "removed" is now
  taken into account (suggested by Christian Vogt).
- Now avoiding unnecessary disk access when checking if there are deleted
  recordings that need to be removed (reported by Carsten Koch).
- Fixed handling the DELETEDLIFETIME when removing deleted recordings. Now
  a deleted recording is retained at least DELETEDLIFETIME seconds before
  actually removing it.
  The value of DELETEDLIFETIME has been changed to 300. So after (possibly
  inadvertently) deleting a recording, there will be at least 5 minutes
  in which it can be recovered (unless a new recording immediately requires
  the disk space). The count starts again at 0 every time VDR is started.
- Fixed a possible crash when displaying the "Low disk space!" message from
  a background thread (thanks to Christof Steininger).
- Fixed handling OSD areas that have invalid sizes (thanks to Marco Schlüßler).
- Added a mutex to AssertFreeDiskSpace() to make sure calls from foreground
  and background threads won't interfere.
- The main menu now dynamically updates its contents in case an instant
  recording or replay stops, etc.
- The version number of EPG events is now also stored in the epg.data file
  (thanks to Kendy Kutzner).
- EPG events that are no longer in the currently broadcasted data stream are
  now automatically deleted.
- Removed an invalid access to Event->schedule in cSchedule::DelEvent().
- Modified cSchedule::Cleanup() (events are always sorted by time).
- Schedules are now cleaned up once every hour (not only at 05:00).
- The "Schedule" and "What's on now/next?" menus are now updated if a timer
  is set or modified.
- cTimer no longer has its own 'schedule' member, it rather uses that of the
  event it has been set to.
- The "Red" button in the "Schedule", "What's on now/next?" and "Event" menus
  now immediately creates a timer for the selected event and marks it with 'T'.
  If the event is already marked with 'T', the "Red" button opens the "Edit
  timer" menu for that timer.
- Removing deleted recordings is now done in a separate thread.
- Dropped the unused "stop recording on primary interface" stuff.
- Converting a grabbed image to JPEG is now done with the new function
  RgbToJpeg() (see tools.h).
- The SVDRP command GRAB now determines the image type (JPEG or PNM) from the
  extension (".jpg", ".jpeg" or ".pnm") of the given file name. The explicit
  'jpeg' or 'pnm' parameter is still accepted for backward compatibility, but
  has no meaning any more.
- The function cDevice::GrabImage() no longer writes the grabbed image to a
  file, but rather returns a pointer to the image in memory. The wrapper
  function cDevice::GrabImageFile() can be used to write the grabbed image
  directly to a file. Plugins that used the old version of cDevice::GrabImage()
  need to be adapted to the new interface.
- The new class cBase64Encoder (see tools.h) can be used to encode data in
  base64 (thanks to Bob Withers for publishing his Base64 class).
- The SVDRP command GRAB now writes the image data to the SVDRP connection
  (encoded in base64) if the given file name consists of only the file
  extension (".jpg", ".jpeg" or ".pnm"), or if only "-" is given as file
  name (based on a suggestion from Darren Salt).
  A simple way of viewing a grabbed image on a remote host is:

  svdrpsend.pl -d <hostname> 'grab -' | sed -n -e 's/^216-//p' -e '1ibegin-base64 644 -' -e '$a====' | uudecode | display -

- The new command line option '-g' must be given if the SVDRP command GRAB
  shall be allowed to write image files to disk. The parameter to this option
  must be the full path name of an existing directory, without any "..", double
  '/' or symlinks. By default, or if "-g- is given, grabbing to files is
  not allowed any more because of potential security risks.
- Modified the way the SVDRP command GRAB writes the grabbed image to a file
  to avoid a security hole (CAN-2005-0071, reported by Javier Fernández-Sanguino
  Peña):
  + The file handle is now opened in a way that it won't follow symbolic links
    (suggested by Darren Salt).
  + The given file name is now canonicalized, so that it won't contain any
    ".." or symlinks (suggested by Darren Salt).
  + Grabbing to files is limited to the directory given in the the command
    line option '-g'. By default grabbing to files is not allowed any more.
- Updated the Greek OSD texts (thanks to Dimitrios Dimitrakos).
- Changed all "illegal" to "invalid" in error messages (there's nothing "illegal"
  in VDR ;-).
- When started as user 'root' VDR now switches to a lesser privileged user id,
  keeping the capability to set the system time (based on a patch from Ludwig
  Nussel). By default the user id 'vdr' is used, which can be changed through
  the new command line option '-u'. Note that for security reasons VDR will no
  longer run as user 'root' (unless you explicitly start it with '-u root',
  but this is not recommended!). The 'runvdr' script has been changed to
  use the '-u' option.
- Changed the API of the functions cStatus::Recording() and cStatus::Replaying(),
  so that they can provide the full file name of the recording. Plugins that use
  these (or the related cStatus::Msg...() functions) need to be adapted
  (suggested by Andreas Brugger).
- The DVB devices now retune (and, if applicable, resend the DiSEqC data) if
  the lock is lost (based on a patch from Reinhard Nissl).
- Fixed handling multi byte key sequences in cKbdRemote (based on a patch from
  Jürgen Schneider).
- Removed unused variables in skinclassic.c and skinsttng.c (thanks to Marco
  Schlüßler).
- Made the static cControl functions thread safe (thanks to Patrick Fischer).
- Fixed initializing pthread_mutexattr_t and pthread_rwlockattr_t to avoid
  warnings with g++ 4.1.0 (thanks to Ville Skyttä).
- Fixed incrementing the 'state' variables in the repacker classes in remux.c
  to avoid warnings with g++ 4.1.0 (reported by Ville Skyttä).
- The Makefile now reports a summary of failed plugins (thanks to Udo Richter).
- The cTimer constructor can now take an optional cChannel (suggested by
  Patrick Fischer).
- Fixed setting the main thread id if VDR is running as a daemon.
- Fixed handling TS packets in cTS2PES (thanks to Reinhard Nissl).
- Added cTimer::SetPriority() to set a timer's priority (suggested by Kendy Kutzner).
- Added cMenuEditStrItem::InEditMode() (suggested by Christian Wieninger).
- Now using FE_READ_STATUS to read the current frontend status (suggested by
  Holger Wächtler).
- The "Menu" key now behaves consistently. If there is anything on the OSD, it
  is closed when the "Menu" key is pressed, and if there is nothing on the OSD,
  the "Menu" key opens the main menu (suggested by Luca Olivetti).
- The new option "Setup/OSD/Timeout requested channel info" can be used to turn
  off the automatic timeout of the channel display in case it was invoked by
  a press of the "Ok" key (suggested by Thiemo Gehrke).
- A message is now given when an instant recording is started (suggested by
  Helmut Auer). Actually the code was already there, just commented out - don't
  remember why it wasn't active...
- Removed an obsolete "Summary" text from i18n.c and preceded all key definition
  texts with "Key$" to avoid duplicates (reported by Lucian Muresan).
- Preceded all button texts with "Button$".
- Removed obsolete "Eject", "Language" and "scanning recordings..." texts.
- Added missing #include "thread.h" to dvbspu.c (reported by Gavin Hamill).
- Disabled the use of "fadvise" in cUnbufferedFile because there have been
  several reports that it causes more problems than it solves (suggested by
  Petri Hintukainen). If you want to use "fadvise", you can activate the line
  //#define USE_FADVISE
  in tools.c.
- Removed unused 'offset' member from cOsdItem.
- In the "Channels" menu the numeric keys now position the cursor to the channel
  with the given number (see MANUAL, section "Remote Control Keys", note (3) for
  details).
- The "Mark/Move" function in the "Channels" menu now also works in the non-numeric
  sort modes.
- The default cOsdObject::Show() now automatically calls cOsdMenu::Display() if
  this is a menu.
- The new "Info" key brings up information on the currently viewed programme
  or recording. For a live programme this is the same as "Schedule/Ok", i.e. the
  description of the current EPG event. For a recording this is the same as shown
  by the "Info" button in the "Recordings" menu. Plugins that implement players
  can overwrite their cControl::GetInfo() function to show their own info (see
  PLUGINS.html for details). Pressing the "Info" key again while the info is
  displayed will close the OSD. In order to assign this new key to an existing
  remote control setup, the remote.conf file needs to be deleted and VDR has
  to be restarted to go through the process of learning the remote control keys.
- Any cReceivers still attached to a cDevice when that device switches to a
  different transponder are now automatically detached (suggested by Patrick
  Fischer).
- The "flags" of a timer are now handled as an unsigned integer value. In order
  to do this, the interface of cMenuEditBitItem also had to be changed.
- In string entry fields (like, e.g., the file name of a recording) the characters
  can now be entered by pressing the numeric keys, the same way as on a
  telephone keypad (based on the "Easy Input" patch from Marcel Schaeben).
- Fixed the "Day" field of the "Edit timer" menu when pressing '0' to switch
  from "single shot" to "weekly", followed by the "Right" key (reported by
  Andreas Böttger).
- The file 'ca.conf' is obsolete and has been removed.
- Revised all descriptions regarding CICAM.
- Adapted c(Dvb)Device::ProvidesCa() to the dynamic CA handling.
- Added a mutex to synchronize cDevice::PlayPesPacket() and SetCurrentAudioTrack()
  (thanks to Reinhard Nissl).
- Added a SleepMs() in cRecorder::Action() to avoid a busy loop (thanks to Ingo
  Schneider).
- Cleaned up some trailing white space.
This commit is contained in:
Klaus Schmidinger 2006-01-08 18:00:00 +01:00
parent 8c63e0fd96
commit da948a50d2
77 changed files with 2409 additions and 1136 deletions

View File

@ -16,6 +16,8 @@ Carsten Koch <Carsten.Koch@icem.de>
for fixing converting summary.vdr files that would result in a very long 'short text' for fixing converting summary.vdr files that would result in a very long 'short text'
for his help in testing and debugging reading the list of recordings in a for his help in testing and debugging reading the list of recordings in a
separate thread separate thread
for reporting some unnecessary disk access when checking if there are deleted
recordings that need to be removed
Plamen Ganev <pganev@com-it.net> Plamen Ganev <pganev@com-it.net>
for fixing the frequency offset for Hotbird channels for fixing the frequency offset for Hotbird channels
@ -310,6 +312,7 @@ Andreas Share <a.share@t-online.de>
for his support in keeping the Premiere World channels up to date in 'channels.conf' for his support in keeping the Premiere World channels up to date in 'channels.conf'
for pointing out that section filters should only be set if the device actually has for pointing out that section filters should only be set if the device actually has
a lock a lock
for reporting a lockup with the RCU on NPTL systems
Simon Bauschulte <SemiSchwabe@Brutzel.de> Simon Bauschulte <SemiSchwabe@Brutzel.de>
for his support in keeping the Premiere World channels up to date in 'channels.conf' for his support in keeping the Premiere World channels up to date in 'channels.conf'
@ -480,6 +483,8 @@ Oliver Lorei <oliverlorei@cityweb.de>
Andreas Böttger <fboettger@t-online.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 for reporting a bug in skipping forward in time shift mode near the end of the recording
for fixing setting system time to avoid time jumps in case of faulty data for fixing setting system time to avoid time jumps in case of faulty data
for reporting a bug in the "Day" field of the "Edit timer" menu when pressing
'0' to switch from "single shot" to "weekly", followed by the "Right" key
Onno Kreuzinger <ok@solutas.net> Onno Kreuzinger <ok@solutas.net>
for reporting leftover references to the file FORMATS in MANUAL and svdrp.c for reporting leftover references to the file FORMATS in MANUAL and svdrp.c
@ -517,8 +522,9 @@ Christian Rienecker <C.Rienecker@gmx.net>
Joerg Riechardt <J.Riechardt@gmx.de> Joerg Riechardt <J.Riechardt@gmx.de>
for filling in some missing teletext PIDs for filling in some missing teletext PIDs
Holger Wächtler <holger@convergence.de> Holger Wächtler <holger@qanu.de>
for some valuable advice during adapting to the NEWSTRUCT driver for some valuable advice during adapting to the NEWSTRUCT driver
for suggesting to use FE_READ_STATUS to read the current frontend status
Jürgen Zimmermann <jnzimmer@informatik.uni-kl.de> Jürgen Zimmermann <jnzimmer@informatik.uni-kl.de>
for adding some missing #includes to files in libdtv for gcc 3.2 for adding some missing #includes to files in libdtv for gcc 3.2
@ -531,6 +537,7 @@ Helmut Auer <vdr@helmutauer.de>
for implementing a default cRemote::Initialize() for implementing a default cRemote::Initialize()
for suggesting to increase the default value for 'Min. user inactivity' to 300 minutes for suggesting to increase the default value for 'Min. user inactivity' to 300 minutes
for suggesting to add cChannel::LinkChannels() and cChannel::RefChannel() for suggesting to add cChannel::LinkChannels() and cChannel::RefChannel()
for suggesting to give a message when an instant recording is started
Jeremy Hall <jhall@UU.NET> Jeremy Hall <jhall@UU.NET>
for fixing an incomplete initialization of the filter parameters in eit.c for fixing an incomplete initialization of the filter parameters in eit.c
@ -821,6 +828,7 @@ Ludwig Nussel <ludwig.nussel@web.de>
cThread::Start() cThread::Start()
for removing the LOCK_THREAD from the LIRC thread for removing the LOCK_THREAD from the LIRC thread
for making the Makefile patch friendlier for making the Makefile patch friendlier
for a patch that was used for implementing setting the user id
Thomas Koch <tom@harhar.net> Thomas Koch <tom@harhar.net>
for his support in keeping the Premiere World channels up to date in 'channels.conf' for his support in keeping the Premiere World channels up to date in 'channels.conf'
@ -1007,6 +1015,11 @@ Reinhard Nissl <rnissl@gmx.de>
for suggesting to always use stream id 0xE0 for the video stream, to avoid problems for suggesting to always use stream id 0xE0 for the video stream, to avoid problems
with post processing tools that choke on different ids with post processing tools that choke on different ids
for fixing cDvbPlayer::SkipFrames() to properly handle radio recordings for fixing cDvbPlayer::SkipFrames() to properly handle radio recordings
for improving TS/PES conversion to better handle lost TS packets
for suggesting to make the DVB devices retune (and, if applicable, resend the
DiSEqC data) if the lock is lost
for fixing handling TS packets in cTS2PES
for adding a mutex to synchronize cDevice::PlayPesPacket() and SetCurrentAudioTrack()
Richard Robson <richard_robson@beeb.net> Richard Robson <richard_robson@beeb.net>
for reporting freezing replay if a timer starts while in Transfer Mode from the for reporting freezing replay if a timer starts while in Transfer Mode from the
@ -1252,6 +1265,8 @@ Marco Schl
for fixing initializing the day index when editing the weekday parameter of a for fixing initializing the day index when editing the weekday parameter of a
repeating timer repeating timer
for figuring out some obscure length bytes the the CA PMT Reply data of AlphaCrypt CAMs for figuring out some obscure length bytes the the CA PMT Reply data of AlphaCrypt CAMs
for fixing handling OSD areas that have invalid sizes
for removing unused variables in skinclassic.c and skinsttng.c
Jürgen Schmitz <j.schmitz@web.de> Jürgen Schmitz <j.schmitz@web.de>
for reporting a bug in displaying the current channel when switching via the SVDRP for reporting a bug in displaying the current channel when switching via the SVDRP
@ -1307,6 +1322,7 @@ Udo Richter <udo_richter@gmx.de>
for reporting a bug in opening recording folders in case the last replayed recording for reporting a bug in opening recording folders in case the last replayed recording
no longer exists no longer exists
for reporting a missing check against MAXOSDAREAS in cOsd::CanHandleAreas() for reporting a missing check against MAXOSDAREAS in cOsd::CanHandleAreas()
for making the Makefile report a summary of failed plugins
Sven Kreiensen <svenk@kammer.uni-hannover.de> Sven Kreiensen <svenk@kammer.uni-hannover.de>
for his help in keeping 'channels.conf.terr' up to date for his help in keeping 'channels.conf.terr' up to date
@ -1318,6 +1334,7 @@ Lucian Muresan <lucianm@users.sourceforge.net>
for updating the Romanian language texts and the iso8859-2 fonts for updating the Romanian language texts and the iso8859-2 fonts
for making VDR actually use the iso8859-15 fonts for making VDR actually use the iso8859-15 fonts
for suggesting to make the function ExchangeChars() for suggesting to make the function ExchangeChars()
for reporting duplicate texts in i18n.c
Mattias Grönlund <Mattias@Gronlund.net> Mattias Grönlund <Mattias@Gronlund.net>
for pointing out a missing cleanup at program exit in case there is a problem for pointing out a missing cleanup at program exit in case there is a problem
@ -1346,6 +1363,8 @@ Andreas Brugger <brougs78@gmx.net>
for reporting the missing Euro sign in iso8859-1 for reporting the missing Euro sign in iso8859-1
for reporting a problem with making changes to timers through SVDRP while they for reporting a problem with making changes to timers through SVDRP while they
are being edited via the menu are being edited via the menu
for suggesting to change the API of the functions cStatus::Recording() and
cStatus::Replaying(), so that they can provide the full file name of the recording
Dino Ravnic <dino.ravnic@fer.hr> Dino Ravnic <dino.ravnic@fer.hr>
for fixing some characters in the iso8859-2 font file for fixing some characters in the iso8859-2 font file
@ -1364,6 +1383,9 @@ Darren Salt <linux@youmustbejoking.demon.co.uk>
for a patch that was used to add the command line options '--lirc', '--rcu' and for a patch that was used to add the command line options '--lirc', '--rcu' and
'--no-kbd' '--no-kbd'
for adding '__attribute__' to functions that use printf() like parameters for adding '__attribute__' to functions that use printf() like parameters
for suggesting to write grabbed images to the SVDRP connection encoded in base64
for suggesting to open the file handle in the SVDRP GRAB command in a way that
it won't follow symbolic links, and to canonicalize the file name
Sean Carlos <seanc@libero.it> Sean Carlos <seanc@libero.it>
for translating OSD texts to the Italian language for translating OSD texts to the Italian language
@ -1416,6 +1438,7 @@ Chris Warren <dvb@ixalon.net>
Luca Olivetti <luca@ventoso.org> Luca Olivetti <luca@ventoso.org>
for making cDevice::AttachPlayer() keep the track language codes and descriptions for making cDevice::AttachPlayer() keep the track language codes and descriptions
in Transfer Mode in Transfer Mode
for suggesting to make the "Menu" key behave consistently
Mikko Salo <mikko.salo@ppe.inet.fi> Mikko Salo <mikko.salo@ppe.inet.fi>
for suggesting to make the setup option "DVB/Video display format" available only for suggesting to make the setup option "DVB/Video display format" available only
@ -1432,6 +1455,10 @@ Ville Skytt
for making LIRC command parsing more robust for making LIRC command parsing more robust
for fixing some typos in MANUAL for fixing some typos in MANUAL
for reporting that the default value for "Setup/EPG bugfix level" was wrong for reporting that the default value for "Setup/EPG bugfix level" was wrong
for fixing initializing pthread_mutexattr_t and pthread_rwlockattr_t to avoid
warnings with g++ 4.1.0
for reporting warnings with g++ 4.1.0 regarding incrementing the 'state' variables
in the repacker classes in remux.c
Steffen Beyer <cpunk@reactor.de> Steffen Beyer <cpunk@reactor.de>
for fixing setting the colored button help after deleting a recording in case the next for fixing setting the colored button help after deleting a recording in case the next
@ -1453,6 +1480,8 @@ Michael Reinelt <reinelt@eunet.at>
Johannes Stezenbach <js@linuxtv.org> Johannes Stezenbach <js@linuxtv.org>
for pointing out that the byte swap for big endian systems in cDvbOsd::Flush() for pointing out that the byte swap for big endian systems in cDvbOsd::Flush()
is wrong is wrong
for suggesting to use gettid() syscall to get a thread's pid, so that we get a
useful value on NPTL systems
Paavo Hartikainen <pahartik@sci.fi> Paavo Hartikainen <pahartik@sci.fi>
for verifying that the byte swap for big endian systems in cDvbOsd::Flush() was for verifying that the byte swap for big endian systems in cDvbOsd::Flush() was
@ -1538,6 +1567,10 @@ Nicolas Huillard <nhuillard@e-dition.fr>
Patrick Fischer <patrick_fischer@gmx.de> Patrick Fischer <patrick_fischer@gmx.de>
for reporting an error in the cFilter example in PLUGINS.html for reporting an error in the cFilter example in PLUGINS.html
for making the static cControl functions thread safe
for suggesting that the cTimer constructor should take an optional cChannel
for suggesting that any cReceivers still attached to a cDevice when that device
switches to a different transponder shall be automatically detached
Ralf Müller <ralf@bj-ig.de> Ralf Müller <ralf@bj-ig.de>
for a patch that was used to implement cUnbufferedFile for a patch that was used to implement cUnbufferedFile
@ -1547,3 +1580,48 @@ Maarten Wisse <Maarten.Wisse@urz.uni-hd.de>
Holger Brunn <holger.brunn@stud.uni-karlsruhe.de> Holger Brunn <holger.brunn@stud.uni-karlsruhe.de>
for adding a copy constructor to cString and fixing its assignment operator for adding a copy constructor to cString and fixing its assignment operator
Christian Vogt <c.v@nexgo.de>
for suggesting to take deleted recordings into account when displaying the
amount of free disk space
Christof Steininger <christof.steininger@t-online.de>
for fixing a possible crash when displaying the "Low disk space!" message from
a background thread
Kendy Kutzner <kutzner@ira.uka.de>
for making the version number of EPG events be stored in the epg.data file
for suggesting to add cTimer::SetPriority() to set a timer's priority
Bob Withers <bwit@pobox.com>
for publishing a Base64 encoder at http://www.ruffboy.com/download.htm
(http://www.ruffboy.com/code/Base64.zip), part of which was used when writing
the cBase64Encoder class
Javier Fernández-Sanguino Peña <jfs@computer.org>
for reporting a security hole in the way the SVDRP command GRAB writes the
image file
Jürgen Schneider <ivory7@gmx.de>
for a patch that was used as a base to fix handling multi byte key sequences
in cKbdRemote
Christian Wieninger <cwieninger@gmx.de>
for suggesting to add cMenuEditStrItem::InEditMode()
Thiemo Gehrke <tgehrke@reel-multimedia.com>
for suggesting to add a setup option to turn off the automatic timeout of the
channel display in case it was invoked by a press of the "Ok" key
Gavin Hamill <gdh@acentral.co.uk>
for reporting a missing #include "thread.h" in dvbspu.c
Petri Hintukainen <Petri.Hintukainen@hut.fi>
for suggesting to disable the use of "fadvise" in cUnbufferedFile because there
have been several reports that it causes more problems than it solves
Marcel Schaeben <mts280@gmx.de>
for his "Easy Input" patch
Ingo Schneider <mail@ingo-schneider.de>
for adding a SleepMs() in cRecorder::Action() to avoid a busy loop

186
HISTORY
View File

@ -1491,9 +1491,9 @@ Video Disk Recorder Revision History
--- Makefile 2002/06/10 16:24:06 1.4 --- Makefile 2002/06/10 16:24:06 1.4
+++ Makefile 2002/09/17 15:36:36 1.5 +++ Makefile 2002/09/17 15:36:36 1.5
@@ -15,7 +15,12 @@ @@ -15,7 +15,12 @@
### The directory environment: ### The directory environment:
+ifdef NEWSTRUCT +ifdef NEWSTRUCT
+DVBDIR = ../../../../DVB/include +DVBDIR = ../../../../DVB/include
+DEFINES += -DNEWSTRUCT +DEFINES += -DNEWSTRUCT
@ -1504,12 +1504,12 @@ Video Disk Recorder Revision History
VDRINC = $(VDRDIR)/include VDRINC = $(VDRDIR)/include
LIBDIR = ../../lib LIBDIR = ../../lib
@@ -34,7 +39,7 @@ @@ -34,7 +39,7 @@
INCLUDES = -I$(VDRINC) -I$(DVBDIR) INCLUDES = -I$(VDRINC) -I$(DVBDIR)
-DEFINES = -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DEFINES = -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here): ### The object files (add further files here):
------------------------------------------------------- -------------------------------------------------------
@ -2705,7 +2705,7 @@ Video Disk Recorder Revision History
- Timers can now be set to use the VPS information to control recording a programme. - Timers can now be set to use the VPS information to control recording a programme.
The new setup options "Recording/Use VPS" and "Recording/VPS margin", as well as The new setup options "Recording/Use VPS" and "Recording/VPS margin", as well as
the "VPS" option in the individual timers, can be used to control this feature the "VPS" option in the individual timers, can be used to control this feature
(see MANUAL for details). (see MANUAL for details).
Note that this feature will certainly need a lot of testing before it can be Note that this feature will certainly need a lot of testing before it can be
called "safe"! called "safe"!
- The "Schedule" and "What's on now/next?" menus now have an additional column - The "Schedule" and "What's on now/next?" menus now have an additional column
@ -3270,7 +3270,7 @@ Video Disk Recorder Revision History
botton left side. botton left side.
- The new setup option "DVB/Audio languages" can be used to control which audio - The new setup option "DVB/Audio languages" can be used to control which audio
language shall be selected in case a channel broadcasts in different languages language shall be selected in case a channel broadcasts in different languages
(see MANUAL for details). (see MANUAL for details).
- The "Left" and "Right" keys in the "Audio" menu can be used to switch between - The "Left" and "Right" keys in the "Audio" menu can be used to switch between
the left and right stereo channels in case there are different audio tracks the left and right stereo channels in case there are different audio tracks
in these channels (see MANUAL for details). in these channels (see MANUAL for details).
@ -3962,3 +3962,175 @@ Video Disk Recorder Revision History
- The SVDRP command MESG uses the new message queueing facility, so MESG - The SVDRP command MESG uses the new message queueing facility, so MESG
commands may now be executed at any time, and the message will be displayed commands may now be executed at any time, and the message will be displayed
(no more "pending message"). (no more "pending message").
2006-01-08: Version 1.3.38
- Fixed handling second audio and Dolby Digital PIDs for encrypted channels
(was broken in version 1.3.37).
- Improved TS/PES conversion to better handle lost TS packets (thanks to
Reinhard Nissl).
- Limited the frequency of log messages from the cRepackers.
- Now using the gettid() syscall to get a thread's pid, so that we get a
useful value on NPTL systems (suggested by Johannes Stezenbach).
- Fixed the RCU remote control handling to avoid problems with NPTL (thanks
to Andreas Share for reporting a lockup with the RCU on NPTL systems).
- When displaying the amount of free disk space, the space consumed by
recordings that have been "deleted" but not yet actually "removed" is now
taken into account (suggested by Christian Vogt).
- Now avoiding unnecessary disk access when checking if there are deleted
recordings that need to be removed (reported by Carsten Koch).
- Fixed handling the DELETEDLIFETIME when removing deleted recordings. Now
a deleted recording is retained at least DELETEDLIFETIME seconds before
actually removing it.
The value of DELETEDLIFETIME has been changed to 300. So after (possibly
inadvertently) deleting a recording, there will be at least 5 minutes
in which it can be recovered (unless a new recording immediately requires
the disk space). The count starts again at 0 every time VDR is started.
- Fixed a possible crash when displaying the "Low disk space!" message from
a background thread (thanks to Christof Steininger).
- Fixed handling OSD areas that have invalid sizes (thanks to Marco Schlüßler).
- Added a mutex to AssertFreeDiskSpace() to make sure calls from foreground
and background threads won't interfere.
- The main menu now dynamically updates its contents in case an instant
recording or replay stops, etc.
- The version number of EPG events is now also stored in the epg.data file
(thanks to Kendy Kutzner).
- EPG events that are no longer in the currently broadcasted data stream are
now automatically deleted.
- Removed an invalid access to Event->schedule in cSchedule::DelEvent().
- Modified cSchedule::Cleanup() (events are always sorted by time).
- Schedules are now cleaned up once every hour (not only at 05:00).
- The "Schedule" and "What's on now/next?" menus are now updated if a timer
is set or modified.
- cTimer no longer has its own 'schedule' member, it rather uses that of the
event it has been set to.
- The "Red" button in the "Schedule", "What's on now/next?" and "Event" menus
now immediately creates a timer for the selected event and marks it with 'T'.
If the event is already marked with 'T', the "Red" button opens the "Edit
timer" menu for that timer.
- Removing deleted recordings is now done in a separate thread.
- Dropped the unused "stop recording on primary interface" stuff.
- Converting a grabbed image to JPEG is now done with the new function
RgbToJpeg() (see tools.h).
- The SVDRP command GRAB now determines the image type (JPEG or PNM) from the
extension (".jpg", ".jpeg" or ".pnm") of the given file name. The explicit
'jpeg' or 'pnm' parameter is still accepted for backward compatibility, but
has no meaning any more.
- The function cDevice::GrabImage() no longer writes the grabbed image to a
file, but rather returns a pointer to the image in memory. The wrapper
function cDevice::GrabImageFile() can be used to write the grabbed image
directly to a file. Plugins that used the old version of cDevice::GrabImage()
need to be adapted to the new interface.
- The new class cBase64Encoder (see tools.h) can be used to encode data in
base64 (thanks to Bob Withers for publishing his Base64 class).
- The SVDRP command GRAB now writes the image data to the SVDRP connection
(encoded in base64) if the given file name consists of only the file
extension (".jpg", ".jpeg" or ".pnm"), or if only "-" is given as file
name (based on a suggestion from Darren Salt).
A simple way of viewing a grabbed image on a remote host is:
svdrpsend.pl -d <hostname> 'grab -' | sed -n -e 's/^216-//p' -e '1ibegin-base64 644 -' -e '$a====' | uudecode | display
- The new command line option '-g' must be given if the SVDRP command GRAB
shall be allowed to write image files to disk. The parameter to this option
must be the full path name of an existing directory, without any "..", double
'/' or symlinks. By default, or if "-g- is given, grabbing to files is
not allowed any more because of potential security risks.
- Modified the way the SVDRP command GRAB writes the grabbed image to a file
to avoid a security hole (CAN-2005-0071, reported by Javier Fernández-Sanguino
Peña):
+ The file handle is now opened in a way that it won't follow symbolic links
(suggested by Darren Salt).
+ The given file name is now canonicalized, so that it won't contain any
".." or symlinks (suggested by Darren Salt).
+ Grabbing to files is limited to the directory given in the the command
line option '-g'. By default grabbing to files is not allowed any more.
- Updated the Greek OSD texts (thanks to Dimitrios Dimitrakos).
- Changed all "illegal" to "invalid" in error messages (there's nothing "illegal"
in VDR ;-).
- When started as user 'root' VDR now switches to a lesser privileged user id,
keeping the capability to set the system time (based on a patch from Ludwig
Nussel). By default the user id 'vdr' is used, which can be changed through
the new command line option '-u'. Note that for security reasons VDR will no
longer run as user 'root' (unless you explicitly start it with '-u root',
but this is not recommended!). The 'runvdr' script has been changed to
use the '-u' option.
- Changed the API of the functions cStatus::Recording() and cStatus::Replaying(),
so that they can provide the full file name of the recording. Plugins that use
these (or the related cStatus::Msg...() functions) need to be adapted
(suggested by Andreas Brugger).
- The DVB devices now retune (and, if applicable, resend the DiSEqC data) if
the lock is lost (based on a patch from Reinhard Nissl).
- Fixed handling multi byte key sequences in cKbdRemote (based on a patch from
Jürgen Schneider).
- Removed unused variables in skinclassic.c and skinsttng.c (thanks to Marco
Schlüßler).
- Made the static cControl functions thread safe (thanks to Patrick Fischer).
- Fixed initializing pthread_mutexattr_t and pthread_rwlockattr_t to avoid
warnings with g++ 4.1.0 (thanks to Ville Skyttä).
- Fixed incrementing the 'state' variables in the repacker classes in remux.c
to avoid warnings with g++ 4.1.0 (reported by Ville Skyttä).
- The Makefile now reports a summary of failed plugins (thanks to Udo Richter).
- The cTimer constructor can now take an optional cChannel (suggested by
Patrick Fischer).
- Fixed setting the main thread id if VDR is running as a daemon.
- Fixed handling TS packets in cTS2PES (thanks to Reinhard Nissl).
- Added cTimer::SetPriority() to set a timer's priority (suggested by Kendy Kutzner).
- Added cMenuEditStrItem::InEditMode() (suggested by Christian Wieninger).
- Now using FE_READ_STATUS to read the current frontend status (suggested by
Holger Wächtler).
- The "Menu" key now behaves consistently. If there is anything on the OSD, it
is closed when the "Menu" key is pressed, and if there is nothing on the OSD,
the "Menu" key opens the main menu (suggested by Luca Olivetti).
- The new option "Setup/OSD/Timeout requested channel info" can be used to turn
off the automatic timeout of the channel display in case it was invoked by
a press of the "Ok" key (suggested by Thiemo Gehrke).
- A message is now given when an instant recording is started (suggested by
Helmut Auer). Actually the code was already there, just commented out - don't
remember why it wasn't active...
- Removed an obsolete "Summary" text from i18n.c and preceded all key definition
texts with "Key$" to avoid duplicates (reported by Lucian Muresan).
- Preceded all button texts with "Button$".
- Removed obsolete "Eject", "Language" and "scanning recordings..." texts.
- Added missing #include "thread.h" to dvbspu.c (reported by Gavin Hamill).
- Disabled the use of "fadvise" in cUnbufferedFile because there have been
several reports that it causes more problems than it solves (suggested by
Petri Hintukainen). If you want to use "fadvise", you can activate the line
//#define USE_FADVISE
in tools.c.
- Removed unused 'offset' member from cOsdItem.
- In the "Channels" menu the numeric keys now position the cursor to the channel
with the given number (see MANUAL, section "Remote Control Keys", note (3) for
details).
- The "Mark/Move" function in the "Channels" menu now also works in the non-numeric
sort modes.
- The default cOsdObject::Show() now automatically calls cOsdMenu::Display() if
this is a menu.
- The new "Info" key brings up information on the currently viewed programme
or recording. For a live programme this is the same as "Schedule/Ok", i.e. the
description of the current EPG event. For a recording this is the same as shown
by the "Info" button in the "Recordings" menu. Plugins that implement players
can overwrite their cControl::GetInfo() function to show their own info (see
PLUGINS.html for details). Pressing the "Info" key again while the info is
displayed will close the OSD. In order to assign this new key to an existing
remote control setup, the remote.conf file needs to be deleted and VDR has
to be restarted to go through the process of learning the remote control keys.
- Any cReceivers still attached to a cDevice when that device switches to a
different transponder are now automatically detached (suggested by Patrick
Fischer).
- The "flags" of a timer are now handled as an unsigned integer value. In order
to do this, the interface of cMenuEditBitItem also had to be changed.
- In string entry fields (like, e.g., the file name of a recording) the characters
can now be entered by pressing the numeric keys, the same way as on a
telephone keypad (based on the "Easy Input" patch from Marcel Schaeben).
- Fixed the "Day" field of the "Edit timer" menu when pressing '0' to switch
from "single shot" to "weekly", followed by the "Right" key (reported by
Andreas Böttger).
- The file 'ca.conf' is obsolete and has been removed.
- Revised all descriptions regarding CICAM.
- Adapted c(Dvb)Device::ProvidesCa() to the dynamic CA handling.
- Added a mutex to synchronize cDevice::PlayPesPacket() and SetCurrentAudioTrack()
(thanks to Reinhard Nissl).
- Added a SleepMs() in cRecorder::Action() to avoid a busy loop (thanks to Ingo
Schneider).
- Cleaned up some trailing white space.

13
INSTALL
View File

@ -132,6 +132,19 @@ call to the VDR program, be sure to NOT use the '-d' option! Otherwise
VDR will go into 'deamon' mode and the initial program call will return VDR will go into 'deamon' mode and the initial program call will return
immediately! immediately!
Setting the system time:
------------------------
If you want VDR to set the system time according to the data received
from the transponder, you need to start VDR as user 'root'. VDR will
then only keep the capability to set the system time, and set its
user id to a lesser privileged one ('vdr' by default, can be set
to a different value with the '-u' option).
You also need to enable the "EPG/Set system time" option in VDR's
Setup menu, and select a transponder from which you want to receive
the time in "Use time from transponder". Make sure you select a transponder
that has a reliable clock - some transponders are quite off.
Automatic shutdown: Automatic shutdown:
------------------- -------------------

47
MANUAL
View File

@ -1,7 +1,7 @@
Video Disk Recorder User's Manual Video Disk Recorder User's Manual
--------------------------------- ---------------------------------
Version 1.2 Version 1.3
----------- -----------
* Remote Control Keys * Remote Control Keys
@ -18,7 +18,7 @@ Version 1.2
Left Prev group - Page up Page up Decrement Page up Search back Sel. channel Left Prev group - Page up Page up Decrement Page up Search back Sel. channel
Right Next group - Page down Page down Increment Page down Search forward Sel. channel Right Next group - Page down Page down Increment Page down Search forward Sel. channel
Ok Ch display Select Switch Edit Accept Play Progress disp. Switch & Close Ok Ch display Select Switch Edit Accept Play Progress disp. Switch & Close
Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Menu on Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu off Menu off
Back - Menu off VDR menu VDR menu Discard VDR menu Recordings menu Close Back - Menu off VDR menu VDR menu Discard VDR menu Recordings menu Close
Red - Record Edit Edit ABC/abc Play/Commands(2) Jump - Red - Record Edit Edit ABC/abc Play/Commands(2) Jump -
Green - Audio New New Ins/Ovr Rewind Skip -60s - Green - Audio New New Ins/Ovr Rewind Skip -60s -
@ -30,9 +30,14 @@ Version 1.2
are used to enter the data, and the Left key can be used to delete the last are used to enter the data, and the Left key can be used to delete the last
entered digit. entered digit.
In a text input field (like, e.g., the file name of a recording) the characters
can be entered by pressing the numeric keys, the same way as on a telephone
keypad.
If your remote control provides additional keys, they can be used for the If your remote control provides additional keys, they can be used for the
following functions: following functions:
Info display information on the currently viewed programme or recording
Play resume normal replay Play resume normal replay
Pause pause replay or live video Pause pause replay or live video
Stop stop replay Stop stop replay
@ -74,7 +79,12 @@ Version 1.2
to "mark" a timer for moving. to "mark" a timer for moving.
(2) See "Processing Recordings" below. (2) See "Processing Recordings" below.
(3) In the "Channels" menu the '0' key switches the sort mode through "by number", (3) In the "Channels" menu the '0' key switches the sort mode through "by number",
"by name" and "by provider". "by name" and "by provider". Other numeric input positions the cursor to
the channel with the number entered so far. If there is no channel with that
number, nothing happens. While entering a channel number, the '0' key will
be treated as part of that number, not as a sort mode toggle. If no numeric
key has been pressed for more than one second, the number is reset and '0'
functions as sort mode toggle again.
(4) In the "Timers" menu, when on the "Day" item, the '0' key toggles between (4) In the "Timers" menu, when on the "Day" item, the '0' key toggles between
a single shot and a repeating timer. If "Day" indicates a repeating timer, a single shot and a repeating timer. If "Day" indicates a repeating timer,
the keys '1'...'7' can be used to toggle the individual days ('1' is Monday). the keys '1'...'7' can be used to toggle the individual days ('1' is Monday).
@ -141,14 +151,17 @@ Version 1.2
"Schedule" menu of the current channel in the list. "Schedule" menu of the current channel in the list.
The "Red" button allows you to instantly program a timer to record the The "Red" button allows you to instantly program a timer to record the
selected programme. You will get into the "Edit Timer" menu in which selected programme. After pressing this button, the current event will
everything has already been filled in, and you can make any modifications be marked with 'T', and the function of the "Red" button will change from
"Record" to "Timer". Pressing "Red" on an event marked with 'T' will open
the "Edit timer" menu for this timer, where you can make any modifications
you may want to apply. Note that the Start and Stop time are offset by the you may want to apply. Note that the Start and Stop time are offset by the
MarginStart and MarginStop parameters (see Setup) in order to make sure the MarginStart and MarginStop parameters (see Setup) in order to make sure the
entire programme is recorded in case it doesn't exactly adhere to its entire programme is recorded in case it doesn't exactly adhere to its
published start/stop times. Of course, no guarantee can be given that the published start/stop times. Of course, no guarantee can be given that the
default margin values will be sufficient, so in case this recording is default margin values will be sufficient, so in case this recording is
really important you may want to add an extra margin ;-) really important you may want to add an extra margin ;-). VPS recordings
will use the exact Start (or VPS) and Stop times as given in the event.
The "Blue" button can be pressed to switch to the channel with the selected The "Blue" button can be pressed to switch to the channel with the selected
programme. programme.
@ -373,7 +386,7 @@ Version 1.2
* Programming the Timer * Programming the Timer
Use the "Timer" menu to maintain your list of timer controlled recordings. Use the "Timer" menu to maintain your list of timer controlled recordings.
The parameters in the "Edit Timer" menu have the following meanings: The parameters in the "Edit timer" menu have the following meanings:
Active: Defines whether the timer will be processed (set it to 'no' to Active: Defines whether the timer will be processed (set it to 'no' to
temporarily disable a timer). temporarily disable a timer).
@ -493,6 +506,10 @@ Version 1.2
always displayed when pressing the "Ok" button in always displayed when pressing the "Ok" button in
normal viewing mode. normal viewing mode.
Timeout requested channel info = yes
Turns the automatic timeout of the channel display (when
invoked by a press of the "Ok" key) on or off.
Scroll pages = yes no = when pressing the "Down" ("Up") key while the cursor Scroll pages = yes no = when pressing the "Down" ("Up") key while the cursor
is on the last (first) line of a list page, the is on the last (first) line of a list page, the
list is scrolled down (up) a single line and the cursor will list is scrolled down (up) a single line and the cursor will
@ -639,17 +656,11 @@ Version 1.2
CICAM: CICAM:
CICAM DVBn m Defines the "Conditional Access" capabilities of the DVB CICAM DVBn m Shows the CAMs that each device contains, where 'n' is
card 'n'. Each DVB card can provide up to two CICAM the number of the device, and 'm' is the number of the
methods ('m' = [1, 2]). Common Interface slot of that device. The "Red" key
can be pressed to enter the CAM menu, and the "Green" key
In the 'setup.conf' file the value consists of the card triggers a reset of the selected CAM.
number, followed by a list of decryption method values
(defined in 'ca.conf').
For instance
CaCaps = 3 101 102
would define that card number 3 is able to decrypt
"Premiere World" and the "ORF".
Recording: Recording:

View File

@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and # See the main source file 'vdr.c' for copyright information and
# how to reach the author. # how to reach the author.
# #
# $Id: Makefile 1.79 2005/09/02 14:23:38 kls Exp $ # $Id: Makefile 1.81 2006/01/01 15:12:05 kls Exp $
.DELETE_ON_ERROR: .DELETE_ON_ERROR:
@ -27,7 +27,7 @@ endif
LSIDIR = ./libsi LSIDIR = ./libsi
MANDIR = /usr/local/man MANDIR = /usr/local/man
BINDIR = /usr/local/bin BINDIR = /usr/local/bin
LIBS = -ljpeg -lpthread -ldl LIBS = -ljpeg -lpthread -ldl -lcap
INCLUDES = INCLUDES =
PLUGINDIR= ./PLUGINS PLUGINDIR= ./PLUGINS
@ -183,7 +183,12 @@ include-dir:
# Plugins: # Plugins:
plugins: include-dir plugins: include-dir
@for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/src/$$i" all; done @failed="";\
for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do\
echo "Plugin $$i:";\
$(MAKE) -C "$(PLUGINDIR)/src/$$i" all || failed="$$failed $$i";\
done;\
if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; fi
plugins-clean: 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

View File

@ -9,23 +9,23 @@
<center><b>Version 1.3</b></center> <center><b>Version 1.3</b></center>
<p> <p>
<center> <center>
Copyright &copy; 2005 Klaus Schmidinger<br> Copyright &copy; 2006 Klaus Schmidinger<br>
<a href="mailto:kls@cadsoft.de">kls@cadsoft.de</a><br> <a href="mailto:kls@cadsoft.de">kls@cadsoft.de</a><br>
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a> <a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
</center> </center>
<p> <p>
<!--X1.3.21--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%> <!--X1.3.30--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.21 are marked like this.
<!--X1.3.21--></td></tr></table>
<!--X1.3.30--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.30 are marked like this. Important modifications introduced in version 1.3.30 are marked like this.
<!--X1.3.30--></td></tr></table> <!--X1.3.30--></td></tr></table>
<!--X1.3.31--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%> <!--X1.3.31--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.31 are marked like this. Important modifications introduced in version 1.3.31 are marked like this.
<!--X1.3.31--></td></tr></table> <!--X1.3.31--></td></tr></table>
<!--X1.3.37--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%> <!--X1.3.37--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.37 are marked like this. Important modifications introduced in version 1.3.37 are marked like this.
<!--X1.3.37--></td></tr></table> <!--X1.3.37--></td></tr></table>
<!--X1.3.38--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.38 are marked like this.
<!--X1.3.38--></td></tr></table>
<p> <p>
VDR provides an easy to use plugin interface that allows additional functionality 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. to be added to the program by implementing a dynamically loadable library file.
@ -66,10 +66,10 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#The Setup menu">The Setup menu</a> <li><a href="#The Setup menu">The Setup menu</a>
<li><a href="#Configuration files">Configuration files</a> <li><a href="#Configuration files">Configuration files</a>
<li><a href="#Internationalization">Internationalization</a> <li><a href="#Internationalization">Internationalization</a>
<!--X1.3.30--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%> <!--X1.3.30--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<li><a href="#Custom services">Custom services</a> <li><a href="#Custom services">Custom services</a>
<!--X1.3.30--></td></tr></table> <!--X1.3.30--></td></tr></table>
<!--X1.3.31--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%> <!--X1.3.31--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<li><a href="#SVDRP commands">SVDRP commands</a> <li><a href="#SVDRP commands">SVDRP commands</a>
<!--X1.3.31--></td></tr></table> <!--X1.3.31--></td></tr></table>
<li><a href="#Loading plugins into VDR">Loading plugins into VDR</a> <li><a href="#Loading plugins into VDR">Loading plugins into VDR</a>
@ -85,9 +85,7 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#Skins">Skins</a> <li><a href="#Skins">Skins</a>
<li><a href="#Themes">Themes</a> <li><a href="#Themes">Themes</a>
<li><a href="#Devices">Devices</a> <li><a href="#Devices">Devices</a>
<!--X1.3.21--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<li><a href="#Audio">Audio</a> <li><a href="#Audio">Audio</a>
<!--X1.3.21--></td></tr></table>
<li><a href="#Remote Control">Remote Control</a> <li><a href="#Remote Control">Remote Control</a>
</ul> </ul>
</ul> </ul>
@ -520,7 +518,7 @@ virtual void Stop(void);
in which it shall stop them. in which it shall stop them.
<p> <p>
The <tt>Stop()</tt> function will only be called if a previous call to the The <tt>Stop()</tt> function will only be called if a previous call to the
<a href="#Getting started"><tt>Start()</tt></a> function of that plugin has <a href="#Getting started"><tt>Start()</tt></a> function of that plugin has
returned <i>true</i>. The <tt>Stop()</tt> functions are called in the reverse order returned <i>true</i>. The <tt>Stop()</tt> functions are called in the reverse order
as the <a href="#Getting started"><tt>Start()</tt></a> functions were called. as the <a href="#Getting started"><tt>Start()</tt></a> functions were called.
@ -866,7 +864,7 @@ Texts are first searched for in the <i>Phrases</i> registered for this plugin (i
and then in the global VDR texts. So a plugin can make use of texts defined by the and then in the global VDR texts. So a plugin can make use of texts defined by the
core VDR code. core VDR code.
<!--X1.3.30--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%> <!--X1.3.30--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<a name="Custom services"><hr><h2>Custom services</h2> <a name="Custom services"><hr><h2>Custom services</h2>
<center><i><b>What can I do for you?</b></i></center><p> <center><i><b>What can I do for you?</b></i></center><p>
@ -937,7 +935,7 @@ any plugin handled the request, or <tt>false</tt> if no plugin handled the reque
<!--X1.3.30--></td></tr></table> <!--X1.3.30--></td></tr></table>
<!--X1.3.31--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%> <!--X1.3.31--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<a name="SVDRP commands"><hr><h2>SVDRP commands</h2> <a name="SVDRP commands"><hr><h2>SVDRP commands</h2>
<center><i><b>Infinite Diversity in Infinite Combinations</b></i></center><p> <center><i><b>Infinite Diversity in Infinite Combinations</b></i></center><p>
@ -1264,6 +1262,9 @@ public:
cMyControl(void); cMyControl(void);
virtual ~cMyControl(); virtual ~cMyControl();
virtual void Hide(void); virtual void Hide(void);
<!--X1.3.38--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
virtual cOsdObject *GetInfo(void);
<!--X1.3.38--></td></tr></table>
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
</pre></td></tr></table><p> </pre></td></tr></table><p>
@ -1292,8 +1293,14 @@ to make the main program loop shut down the player control.
A derived <tt>cControl</tt> <b>must</b> implement the <tt>Hide()</tt> function, in which A derived <tt>cControl</tt> <b>must</b> implement the <tt>Hide()</tt> function, in which
it has to hide itself from the OSD, in case it uses it. <tt>Hide()</tt> may be called at it has to hide itself from the OSD, in case it uses it. <tt>Hide()</tt> may be called at
any time, and it may be called even if the <tt>cControl</tt> is not visible at the moment. any time, and it may be called even if the <tt>cControl</tt> is not visible at the moment.
The reason for this is that the <tt>Menu</tt> button shall always bring up the main VDR <p>
menu, so any active <tt>cControl</tt> needs to be hidden when that button is pressed. <!--X1.3.38--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
The <tt>GetInfo()</tt> function is called when the user presses the <tt>Info</tt> button,
and shall return a pointer to a <tt>cOsdObject</tt> that contains information
about the currently played programme. The caller takes ownership of the returned
pointer and will delete it when it is no longer used. If no information is available,
<tt>NULL</tt> shall be returned.
<!--X1.3.38--></td></tr></table>
<p> <p>
Finally, to get things going, a plugin that implements a player (and the surrounding Finally, to get things going, a plugin that implements a player (and the surrounding
infrastructure like displaying a list of playable stuff etc) simply has to call the infrastructure like displaying a list of playable stuff etc) simply has to call the
@ -1515,7 +1522,7 @@ with the full required resolution. Only if this fails shall it use alternate
areas. Drawing areas are always rectangular and may not overlap (but do not need areas. Drawing areas are always rectangular and may not overlap (but do not need
to be adjacent). to be adjacent).
<!--X1.3.37--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%> <!--X1.3.37--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
<p> <p>
Directly accessing the OSD is only allowed from the foreground thread, which Directly accessing the OSD is only allowed from the foreground thread, which
restricts this to a <tt>cOsdObject</tt> returned from the plugin's <tt>MainMenuAction()</tt> restricts this to a <tt>cOsdObject</tt> returned from the plugin's <tt>MainMenuAction()</tt>
@ -1840,9 +1847,7 @@ private:
virtual void Action(void); virtual void Action(void);
public: public:
cMyAudio(void); cMyAudio(void);
<!--X1.3.21--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
virtual void Play(const uchar *Data, int Length, uchar Id); virtual void Play(const uchar *Data, int Length, uchar Id);
<!--X1.3.21--></td></tr></table>
virtual void Mute(bool On); virtual void Mute(bool On);
virtual void Clear(void); virtual void Clear(void);
}; };

View File

@ -17,7 +17,7 @@
# page exists, 'x' is entered. # page exists, 'x' is entered.
# #
S28.2E-2-2027-4705:106:sky_one S28.2E-2-2027-4705:106:sky_one
S28.2E-2-2027-5104:107:sky_one_mix S28.2E-2-2027-5104:107:sky_two
S28.2E-2-2044-10070:118:itv2 S28.2E-2-2044-10070:118:itv2
S28.2E-2-2023-4905:130:scifi S28.2E-2-2023-4905:130:scifi
S28.2E-2-2025-5904:127:paramount S28.2E-2-2025-5904:127:paramount

View File

@ -8,7 +8,7 @@
# #
# See the README file for copyright information and how to reach the author. # See the README file for copyright information and how to reach the author.
# #
# $Id: getskyepg.pl 1.3 2004/02/15 13:35:52 kls Exp $ # $Id: getskyepg.pl 1.4 2006/01/08 10:21:32 kls Exp $
use Getopt::Std; use Getopt::Std;
use Time::Local; use Time::Local;
@ -151,7 +151,7 @@ sub GetEpgData
$gmt[1] = $m; # minutes $gmt[1] = $m; # minutes
$gmt[2] = $h; # hours $gmt[2] = $h; # hours
$time = timegm(@gmt) + ($day - 1) * $SecsInDay + ($h < 12 ? $dt : 0); $time = timegm(@gmt) + ($day - 1) * $SecsInDay + ($h < 12 ? $dt : 0);
# comensate for DST: # compensate for DST:
$time += $DST if (localtime($time))[8]; $time += $DST if (localtime($time))[8];
# create EPG data: # create EPG data:
if ($Time) { if ($Time) {

View File

@ -31,3 +31,7 @@ VDR Plugin 'status' Revision History
2002-12-13: Version 0.1.0 2002-12-13: Version 0.1.0
- Changed setting of CXX and CXXFLAGS variables in Makefile. - Changed setting of CXX and CXXFLAGS variables in Makefile.
2005-12-31: Version 0.2.0
- API change in cStatus.

View File

@ -3,13 +3,13 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: status.c 1.7 2002/12/13 15:01:53 kls Exp $ * $Id: status.c 1.8 2005/12/31 15:19:45 kls Exp $
*/ */
#include <vdr/plugin.h> #include <vdr/plugin.h>
#include <vdr/status.h> #include <vdr/status.h>
static const char *VERSION = "0.1.0"; static const char *VERSION = "0.2.0";
static const char *DESCRIPTION = "Status monitor test"; static const char *DESCRIPTION = "Status monitor test";
static const char *MAINMENUENTRY = NULL; static const char *MAINMENUENTRY = NULL;
@ -18,8 +18,8 @@ static const char *MAINMENUENTRY = NULL;
class cStatusTest : public cStatus { class cStatusTest : public cStatus {
protected: protected:
virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
virtual void Recording(const cDevice *Device, const char *Name); virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On);
virtual void Replaying(const cControl *Control, const char *Name); virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On);
virtual void SetVolume(int Volume, bool Absolute); virtual void SetVolume(int Volume, bool Absolute);
virtual void OsdClear(void); virtual void OsdClear(void);
virtual void OsdTitle(const char *Title); virtual void OsdTitle(const char *Title);
@ -36,14 +36,14 @@ void cStatusTest::ChannelSwitch(const cDevice *Device, int ChannelNumber)
dsyslog("status: cStatusTest::ChannelSwitch %d %d", Device->CardIndex(), ChannelNumber); dsyslog("status: cStatusTest::ChannelSwitch %d %d", Device->CardIndex(), ChannelNumber);
} }
void cStatusTest::Recording(const cDevice *Device, const char *Name) void cStatusTest::Recording(const cDevice *Device, const char *Name, const char *FileName, bool On)
{ {
dsyslog("status: cStatusTest::Recording %d %s", Device->CardIndex(), Name); dsyslog("status: cStatusTest::Recording %d %s %s %d", Device->CardIndex(), Name, FileName, On);
} }
void cStatusTest::Replaying(const cControl *Control, const char *Name) void cStatusTest::Replaying(const cControl *Control, const char *Name, const char *FileName, bool On)
{ {
dsyslog("status: cStatusTest::Replaying %s", Name); dsyslog("status: cStatusTest::Replaying %s %s %d", Name, FileName, On);
} }
void cStatusTest::SetVolume(int Volume, bool Absolute) void cStatusTest::SetVolume(int Volume, bool Absolute)

17
ca.conf
View File

@ -1,17 +0,0 @@
# Conditional Access configuration for VDR
#
# Format:
#
# number description
#
# Please contact kls@cadsoft.de before assigning a new number
# to a description, in order to keep them unique.
0 Free To Air
# Special values to "hard code" a channel to a specific DVB card:
1 DVB 1
2 DVB 2
3 DVB 3
4 DVB 4

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: channels.c 1.46 2005/09/11 14:22:24 kls Exp $ * $Id: channels.c 1.47 2005/12/30 15:41:24 kls Exp $
*/ */
#include "channels.h" #include "channels.h"
@ -586,7 +586,7 @@ static const char *ParseParameter(const char *s, int &Value, const tChannelParam
return p; return p;
} }
} }
esyslog("ERROR: illegal value for parameter '%c'", *(s - 1)); esyslog("ERROR: invalid value for parameter '%c'", *(s - 1));
return NULL; return NULL;
} }

View File

@ -2,18 +2,18 @@ RTL Television,RTL;RTL World:12187:hC34:S19.2E:27500:163:104=deu:105:0:12003:1:1
SAT.1;ProSiebenSat.1:12480:vC34:S19.2E:27500:1791:1792=deu;1795=deu:34:0:46:133:33:0 SAT.1;ProSiebenSat.1:12480:vC34:S19.2E:27500:1791:1792=deu;1795=deu:34:0:46:133:33:0
ProSieben;ProSiebenSat.1:12480:vC34:S19.2E:27500:255:256=deu;257=deu:32:0:898:133:33:0 ProSieben;ProSiebenSat.1:12480:vC34:S19.2E:27500:255:256=deu;257=deu:32:0:898:133:33:0
RTL2;RTL World:12187:hC34:S19.2E:27500:166:128=deu:68:0:12020:1:1089:0 RTL2;RTL World:12187:hC34:S19.2E:27500:166:128=deu:68:0:12020:1:1089:0
Das Erste;ARD:11836:hC34:S19.2E:27500:101:102=deu:104:0:28106:1:1101:0 Das Erste;ARD:11836:hC34:S19.2E:27500:101:102=deu;106=deu:104:0:28106:1:1101:0
Bayerisches FS;ARD:11836:hC34:S19.2E:27500:201:202=deu:204:0:28107:1:1101:0 Bayerisches FS;ARD:11836:hC34:S19.2E:27500:201:202=deu:204:0:28107:1:1101:0
hr-fernsehen;ARD:11836:hC34:S19.2E:27500:301:302=deu:304:0:28108:1:1101:0 hr-fernsehen;ARD:11836:hC34:S19.2E:27500:301:302=deu:304:0:28108:1:1101:0
NDR FS MV;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28224:1:1073:0 NDR FS MV;ARD:12109:hC34:S19.2E:27500:2401:2402=deu:2404:0:28224:1:1073:0
SR SÜDWEST Ferns.;ARD:12265:hC34:S19.2E:27500:1301:1302=deu:1304:0:28486:1:1093:0 SR SÜDWEST Ferns.;ARD:12265:hC34:S19.2E:27500:1301:1302=deu:1304:0:28486:1:1093:0
WDR Köln;ARD:11836:hC34:S19.2E:27500:601:602=deu:604:0:28111:1:1101:0 WDR Köln;ARD:11836:hC34:S19.2E:27500:601:602=deu:604:0:28111:1:1101:0
BR-alpha;ARD:11836:hC34:S19.2E:27500:701:702=deu;703:704:0:28112:1:1101:0 BR-alpha;ARD:11836:hC34:S19.2E:27500:701:702=deu:704:0:28112:1:1101:0
SÜDWEST Ferns. BW;ARD:11836:hC34:S19.2E:27500:801:802=deu:804:0:28113:1:1101:0 SÜDWEST Ferns. BW;ARD:11836:hC34:S19.2E:27500:801:802=deu:804:0:28113:1:1101:0
Phoenix;ARD:11836:hC34:S19.2E:27500:901:902=deu:904:0:28114:1:1101:0 Phoenix;ARD:11836:hC34:S19.2E:27500:901:902=deu:904:0:28114:1:1101:0
ZDF;ZDFvision:11953:hC34:S19.2E:27500:110:120=deu,121=2ch;125=dd:130:0:28006:1:1079:0 ZDF;ZDFvision:11953:hC34:S19.2E:27500:110:120=deu,121=2ch;125=dd:130:0:28006:1:1079:0
3sat;ZDFvision:11953:hC34:S19.2E:27500:210:220=deu,221=2ch;225=dd:230:0:28007:1:1079:0 3sat;ZDFvision:11953:hC34:S19.2E:27500:210:220=deu,221=2ch;225=dd:230:0:28007:1:1079:0
KiKa;ZDFvision:11953:hC34:S19.2E:27500:310:320:0:0:28008:1:1079:0 KiKa;ZDFvision:11953:hC34:S19.2E:27500:310:320=deu:330:0:28008:1:1079:0
arte;ARD:11836:hC34:S19.2E:27500:401:402=deu,403=fra:404:0:28109:1:1101:0 arte;ARD:11836:hC34:S19.2E:27500:401:402=deu,403=fra:404:0:28109:1:1101:0
ORF1;ORF:12692:hC56:S19.2E:22000:160:161=deu;163=deu:165:1762,D05,1702,1801:13001:1:1117:0 ORF1;ORF:12692:hC56:S19.2E:22000:160:161=deu;163=deu:165:1762,D05,1702,1801:13001:1:1117:0
ORF2;ORF:12692:hC56:S19.2E:22000:500:501=deu;503=deu:505:1762,D05,1702,1801:13002:1:1117:0 ORF2;ORF:12692:hC56:S19.2E:22000:500:501=deu;503=deu:505:1762,D05,1702,1801:13002:1:1117:0
@ -28,14 +28,14 @@ DSF;BetaDigital:12480:vC34:S19.2E:27500:1023:1024=deu:39:0:900:133:33:0
HSE24,HSE24;BetaDigital:12480:vC34:S19.2E:27500:1279:1280=deu:37:0:40:133:33:0 HSE24,HSE24;BetaDigital:12480:vC34:S19.2E:27500:1279:1280=deu:37:0:40:133:33:0
Bloomberg TV Germany;Bloomberg:12551:vC56:S19.2E:22000:162:99=deu:0:0:12160:1:1108:0 Bloomberg TV Germany;Bloomberg:12551:vC56:S19.2E:22000:162:99=deu:0:0:12160:1:1108:0
EURONEWS;CSAT:11817:vC34:S19.2E:27500:163:92=fra,93=eng,94=ita,95=esl,91=rus,98=por,99=deu:0:0:8004:1:1070:0 EURONEWS;CSAT:11817:vC34:S19.2E:27500:163:92=fra,93=eng,94=ita,95=esl,91=rus,98=por,99=deu:0:0:8004:1:1070:0
rbb Brandenburg;ARD:12109:hC34:S19.2E:27500:501:502=deu:504:0:28205:1:1073:0 rbb Brandenburg;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28205:1:1073:0
Sky News:11597:vC56:S19.2E:22000:305+131:306=eng:0:0:28707:1:1026:0 Sky News:11597:vC56:S19.2E:22000:305+131:306=eng:0:0:28707:1:1026:0
Veronica/JETIX;CANALDIGITAAL:12574:hC56:S19.2E:22000:518+8190:92=dut:38:622,100:5020:53:1109:0 Veronica/JETIX;CANALDIGITAAL:12574:hC56:S19.2E:22000:518+8190:92=dut:38:622,100:5020:53:1109:0
BVN;CANALDIGITAAL:12574:hC56:S19.2E:22000:515+8190:96=dut:36:0:5025:53:1109:0 BVN;CANALDIGITAAL:12574:hC56:S19.2E:22000:515+8190:96=dut:36:0:5025:53:1109:0
n-tv;RTL World:12187:hC34:S19.2E:27500:169:73=deu:80:0:12090:1:1089:0 n-tv;RTL World:12187:hC34:S19.2E:27500:169:73=deu:80:0:12090:1:1089:0
Al Jazeera;CANALSATELLITE:11567:vC56:S19.2E:22000:55:56=ara:0:0:9021:1:1024:0 Al Jazeera;CANALSATELLITE:11567:vC56:S19.2E:22000:55:56=ara:0:0:9021:1:1024:0
TW1;ORF:12662:hC56:S19.2E:22000:1010:1011=deu:1013:0:13101:1:1115:0 TW1;ORF:12662:hC56:S19.2E:22000:1010:1011=deu:1013:0:13101:1:1115:0
Eurosport;ZDFvision:11953:hC34:S19.2E:27500:410:420=deu:430:0:28009:1:1079:0 Eurosport;SES Astra:12226:hC34:S19.2E:27500:101+8190:103=deu:102:0:31200:1:1091:0
EinsExtra;ARD:12109:hC34:S19.2E:27500:101:102=deu:0:0:28201:1:1073:0 EinsExtra;ARD:12109:hC34:S19.2E:27500:101:102=deu:0:0:28201:1:1073:0
EinsFestival;ARD:12109:hC34:S19.2E:27500:201:202=deu:0:0:28202:1:1073:0 EinsFestival;ARD:12109:hC34:S19.2E:27500:201:202=deu:0:0:28202:1:1073:0
EinsPlus;ARD:12109:hC34:S19.2E:27500:301:302=deu:0:0:28203:1:1073:0 EinsPlus;ARD:12109:hC34:S19.2E:27500:301:302=deu:0:0:28203:1:1073:0
@ -44,11 +44,11 @@ ZDFdokukanal;ZDFvision:11953:hC34:S19.2E:27500:660:670=deu:130:0:28014:1:1079:0
MDR FERNSEHEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28204:1:1073:0 MDR FERNSEHEN;ARD:12109:hC34:S19.2E:27500:401:402=deu:404:0:28204:1:1073:0
rbb Berlin;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0 rbb Berlin;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0
:Premiere World :Premiere World
PREMIERE START,START;PREMIERE:11797:hC34:S19.2E:27500:255:256=deu:32:1:8:133:2:0 PREMIERE START,START;PREMIERE:11797:hC34:S19.2E:27500:255:256=deu:32:1801,1722,1702:8:133:2:0
PREMIERE 1,PREM 1;PREMIERE:11797:hC34:S19.2E:27500:511:512=deu,513=deu;515=deu:32:1702,1722,1801:10:133:2:0 PREMIERE 1,PREM 1;PREMIERE:11797:hC34:S19.2E:27500:511:512=deu,513=deu;515=deu:32:1801,1722,1702:10:133:2:0
PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:32:1702,1801,1722:11:133:2:0 PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:32:1801,1722,1702:11:133:2:0
PREMIERE 3,PREM 3;PREMIERE:11797:hC34:S19.2E:27500:2303:2304=deu,2305=deu:32:1722,1702,1801:43:133:2:0 PREMIERE 3,PREM 3;PREMIERE:11797:hC34:S19.2E:27500:2303:2304=deu,2305=deu:32:1722,1702,1801:43:133:2:0
PREMIERE 4,PREM 4;PREMIERE:11797:hC34:S19.2E:27500:767:768=deu:32:1801,1722,1702:9:133:2:0 PREMIERE 4,PREM 4;PREMIERE:11797:hC34:S19.2E:27500:767:768=deu,769=deu:32:1801,1722,1702:9:133:2:0
PREMIERE 5,PREM 5;PREMIERE:11797:hC34:S19.2E:27500:1279:1280=deu,1281=deu:32:1722,1702,1801:29:133:2:0 PREMIERE 5,PREM 5;PREMIERE:11797:hC34:S19.2E:27500:1279:1280=deu,1281=deu:32:1722,1702,1801:29:133:2:0
PREMIERE 6,PREM 6;PREMIERE:11797:hC34:S19.2E:27500:1535:1536=deu:32:1702,1722,1801:41:133:2:0 PREMIERE 6,PREM 6;PREMIERE:11797:hC34:S19.2E:27500:1535:1536=deu:32:1702,1722,1801:41:133:2:0
PREMIERE 7,PREM 7;PREMIERE:11797:hC34:S19.2E:27500:1023:1024=deu:32:1801,1702,1722:20:133:2:0 PREMIERE 7,PREM 7;PREMIERE:11797:hC34:S19.2E:27500:1023:1024=deu:32:1801,1702,1722:20:133:2:0
@ -57,10 +57,10 @@ DISNEY CHANNEL,DISNEY;PREMIERE:11758:hC34:S19.2E:27500:2559:2560=deu:32:1801,170
PREMIERE DIREKT,DIREKT;PREMIERE:12031:hC34:S19.2E:27500:2815:2816=deu,2817=deu;2819=deu:0:0:18:133:4:0 PREMIERE DIREKT,DIREKT;PREMIERE:12031:hC34:S19.2E:27500:2815:2816=deu,2817=deu;2819=deu:0:0:18:133:4:0
:PW Erotic :PW Erotic
BEATE-UHSE.TV,B-UHSE;PREMIERE:11758:hC34:S19.2E:27500:1791:1792=deu:32:1722,1702,1801:21:133:17:0 BEATE-UHSE.TV,B-UHSE;PREMIERE:11758:hC34:S19.2E:27500:1791:1792=deu:32:1722,1702,1801:21:133:17:0
EROTIK - AB 18!,AB 18!;PREMIERE:12031:hC34:S19.2E:27500:1279:1280=deu:0:1810,1801,1702,1722:513:133:4:0 EROTIK - AB 18!,AB 18!;PREMIERE:12031:hC34:S19.2E:27500:1279:1280=deu:0:1722,1801,1702,1810:513:133:4:0
:Sportsworld :Sportsworld
PREMIERE SPORT PORTAL,SPORT PORTAL;PREMIERE:11719:hC34:S19.2E:27500:255:256=deu,257=deu:32:1702,1722,1801:17:133:3:0 PREMIERE SPORT PORTAL,SPORT PORTAL;PREMIERE:11719:hC34:S19.2E:27500:255:256=deu,257=deu:32:1722,1801,1702:17:133:3:0
PREMIERE WIN,WIN;PREMIERE:12031:hC34:S19.2E:27500:3839:3840=deu:32:0:27:133:4:0 PREMIERE WIN,WIN;PREMIERE:12031:hC34:S19.2E:27500:3839:3840=deu:33:0:27:133:4:0
:Beta Digital :Beta Digital
N24;ProSiebenSat.1:12480:vC34:S19.2E:27500:2047:2048=deu:36:0:47:133:33:0 N24;ProSiebenSat.1:12480:vC34:S19.2E:27500:2047:2048=deu:36:0:47:133:33:0
LibertyTV FR;LibertyTV.com:12610:vC56:S19.2E:22000:941:943=deu:0:0:12199:1:1112:0 LibertyTV FR;LibertyTV.com:12610:vC56:S19.2E:22000:941:943=deu:0:0:12199:1:1112:0
@ -92,9 +92,9 @@ Sky One;BSkyB:12226:hC23:S28.2E:27500:515+8190:643=eng:579:960,961:4705:2:2027:0
Sky Two;BSkyB:12226:hC23:S28.2E:27500:514+8190:642=eng,662=NAR:578:960,961:5104:2:2027:0 Sky Two;BSkyB:12226:hC23:S28.2E:27500:514+8190:642=eng,662=NAR:578:960,961:5104:2:2027:0
ITV2;BSkyB:10758:vC56:S28.2E:22000:2314:2315=eng,2363=NAR:2317:0:10070:2:2044:0 ITV2;BSkyB:10758:vC56:S28.2E:22000:2314:2315=eng,2363=NAR:2317:0:10070:2:2044:0
Sci-Fi;BSkyB:12148:hC23:S28.2E:27500:512+8190:640=eng:576:960,961:4905:2:2023:0 Sci-Fi;BSkyB:12148:hC23:S28.2E:27500:512+8190:640=eng:576:960,961:4905:2:2023:0
Paramount;BSkyB:12187:hC23:S28.2E:27500:518+8190:666=eng,686=NAR:582:960,961:5904:2:2025:0 ParaComedy 1;BSkyB:12187:hC23:S28.2E:27500:518+8190:666=eng,686=NAR:582:960,961:5904:2:2025:0
Paramount;BSkyB:11526:vC23:S28.2E:27500:2317+2306:2318=eng:2319:960,961:50305:2:2404:0 Paramount;BSkyB:11526:vC23:S28.2E:27500:2317+2306:2318=eng:2319:960,961:50305:2:2404:0
Paramount 2;BSkyB:11914:hC23:S28.2E:27500:514+8190:642=eng,662=NAR:578:960,961:4504:2:2011:0 ParaComedy 2;BSkyB:11914:hC23:S28.2E:27500:514+8190:642=eng,662=NAR:578:960,961:4504:2:2011:0
Discovery;BSkyB:11875:hC23:S28.2E:27500:2308:2310=eng,2311=NAR:2309:960,961:6201:2:2009:0 Discovery;BSkyB:11875:hC23:S28.2E:27500:2308:2310=eng,2311=NAR:2309:960,961:6201:2:2009:0
Sky Movies 1;BSkyB:11836:hC23:S28.2E:27500:518+8190:646=eng,653=NAR;686=eng:582:960,961:4303:2:2007:0 Sky Movies 1;BSkyB:11836:hC23:S28.2E:27500:518+8190:646=eng,653=NAR;686=eng:582:960,961:4303:2:2007:0
Sky Movies 2;BSkyB:11836:hC23:S28.2E:27500:519+8190:647=eng,667=NAR;687=eng:583:960,961:4302:2:2007:0 Sky Movies 2;BSkyB:11836:hC23:S28.2E:27500:519+8190:647=eng,667=NAR;687=eng:583:960,961:4302:2:2007:0
@ -115,8 +115,11 @@ S1T;BSkyB:12285:vC23:S28.2E:27500:513+8190:641=eng,661=NAR:577:960,961:4409:2:20
CNN;BSkyB:12051:vC23:S28.2E:27500:2313:2315=eng:2314:0:7140:2:2018:0 CNN;BSkyB:12051:vC23:S28.2E:27500:2313:2315=eng:2314:0:7140:2:2018:0
BBC PARL'MNT;BSkyB:10847:vC56:S28.2E:22000:2327:2328=eng:2331:0:6902:2:2050:0 BBC PARL'MNT;BSkyB:10847:vC56:S28.2E:22000:2327:2328=eng:2331:0:6902:2:2050:0
IGLESIA MME;T-Systems/MTI:11200:vC56:S13.0E:27500:4097:4098:0:0:4733:318:13400:0 IGLESIA MME;T-Systems/MTI:11200:vC56:S13.0E:27500:4097:4098:0:0:4733:318:13400:0
Euro1080;EURO1080:12168:vC56:S19.2E:27500:308:256:0:FF:21100:1:1088:0 Euro1080 HD-5;Euro1080:10758:vC78:S23.5E:22000:34:160=eng:0:0:1085:9999:3104:0
Astra HD:12441:vC34:S19.2E:27500:133+80:134=eng:0:FF:29700:0:0:0 Euro1080;EURO1080:12168:vC56:S19.2E:27500:308:256:0:0:21100:1:1088:0
SMD HD;SES ASTRA:12699:vC56:S19.2E:22000:133+80:234=eng:0:0:29700:0:0:0
Astra HD:12441:vC34:S19.2E:27500:133+80:134=eng:0:0:29700:0:0:0
eng-WRN-multi;WRN:12597:vC34:S13.0E:27500:0:2132:0:0:8230:318:9400:0 eng-WRN-multi;WRN:12597:vC34:S13.0E:27500:0:2132:0:0:8230:318:9400:0
TVS Teleport Bonn;DMV:11535:vC34:S1.0W:5632:308+8190:256=eng,257=eng:0:2:1:65535:1:0 Challenger Tv;Telespazio:11304:hC34:S13.0E:27500:490:491:0:0:8409:318:500:0
TVS Teleport Bonn;DMV:11535:vC34:S1.0W:5632:308+8190:256=eng,257=eng:0:3:1:65535:1:0
:@1000 New channels :@1000 New channels

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: channels.h 1.36 2005/09/17 09:59:14 kls Exp $ * $Id: channels.h 1.37 2006/01/07 13:00:43 kls Exp $
*/ */
#ifndef __CHANNELS_H #ifndef __CHANNELS_H
@ -39,6 +39,14 @@
#define MAXLANGCODE1 4 // a 3 letter language code, zero terminated #define MAXLANGCODE1 4 // a 3 letter language code, zero terminated
#define MAXLANGCODE2 8 // up to two 3 letter language codes, separated by '+' and zero terminated #define MAXLANGCODE2 8 // up to two 3 letter language codes, separated by '+' and zero terminated
#define CA_FTA 0x0000
#define CA_DVB_MIN 0x0001
#define CA_DVB_MAX 0x000F
#define CA_USER_MIN 0x0010
#define CA_USER_MAX 0x00FF
#define CA_ENCRYPTED_MIN 0x0100
#define CA_ENCRYPTED_MAX 0xFFFF
struct tChannelParameterMap { struct tChannelParameterMap {
int userValue; int userValue;
int driverValue; int driverValue;

15
ci.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: ci.c 1.40 2005/11/26 13:36:51 kls Exp $ * $Id: ci.c 1.42 2006/01/07 15:07:16 kls Exp $
*/ */
#include "ci.h" #include "ci.h"
@ -185,7 +185,7 @@ cTPDU::cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length, const uint8_t
size = 6; size = 6;
} }
else else
esyslog("ERROR: illegal data length for TPDU tag 0x%02X: %d", Tag, Length); esyslog("ERROR: invalid data length for TPDU tag 0x%02X: %d", Tag, Length);
break; break;
case T_DATA_LAST: case T_DATA_LAST:
case T_DATA_MORE: case T_DATA_MORE:
@ -198,7 +198,7 @@ cTPDU::cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length, const uint8_t
size = Length + (p - data); size = Length + (p - data);
} }
else else
esyslog("ERROR: illegal data length for TPDU tag 0x%02X: %d", Tag, Length); esyslog("ERROR: invalid data length for TPDU tag 0x%02X: %d", Tag, Length);
break; break;
default: default:
esyslog("ERROR: unknown TPDU tag: 0x%02X", Tag); esyslog("ERROR: unknown TPDU tag: 0x%02X", Tag);
@ -1639,6 +1639,15 @@ int cCiHandler::CloseAllSessions(int Slot)
return result; return result;
} }
int cCiHandler::NumCams(void)
{
int result = 0;
for (int i = 0; i < MAX_CI_SLOT; i++)
if (moduleReady[i])
result++;
return result;
}
bool cCiHandler::Ready(void) bool cCiHandler::Ready(void)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);

31
ci.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: ci.h 1.19 2005/11/26 13:37:42 kls Exp $ * $Id: ci.h 1.21 2006/01/07 15:03:05 kls Exp $
*/ */
#ifndef __CI_H #ifndef __CI_H
@ -112,6 +112,7 @@ private:
cList<cCiCaProgramData> caProgramList; cList<cCiCaProgramData> caProgramList;
int ResourceIdToInt(const uint8_t *Data); int ResourceIdToInt(const uint8_t *Data);
bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1); bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1);
const unsigned short *GetCaSystemIds(int Slot);
cCiSession *GetSessionBySessionId(int SessionId); cCiSession *GetSessionBySessionId(int SessionId);
cCiSession *GetSessionByResourceId(int ResourceId, int Slot); cCiSession *GetSessionByResourceId(int ResourceId, int Slot);
cCiSession *CreateSession(int ResourceId); cCiSession *CreateSession(int ResourceId);
@ -123,18 +124,35 @@ private:
public: public:
~cCiHandler(); ~cCiHandler();
static cCiHandler *CreateCiHandler(const char *FileName); static cCiHandler *CreateCiHandler(const char *FileName);
///< Creates a new cCiHandler for the given CA device.
int NumSlots(void) { return numSlots; } int NumSlots(void) { return numSlots; }
///< Returns the number of CAM slots provided by this CA device.
int NumCams(void);
///< Returns the number of actual CAMs inserted into this CA device.
bool Ready(void); bool Ready(void);
///< Returns true if all CAMs in this CA device are ready.
bool Process(int Slot = -1); bool Process(int Slot = -1);
///< Processes the given Slot. If Slot is -1, all slots are processed. ///< Processes the given Slot. If Slot is -1, all slots are processed.
///< Returns false in case of an error. ///< Returns false in case of an error.
bool HasUserIO(void) { return hasUserIO; } bool HasUserIO(void) { return hasUserIO; }
///< Returns true if there is a pending user interaction, which shall
///< be retrieved via GetMenu() or GetEnquiry().
bool EnterMenu(int Slot); bool EnterMenu(int Slot);
///< Requests the CAM in the given Slot to start its menu.
cCiMenu *GetMenu(void); cCiMenu *GetMenu(void);
///< Gets a pending menu, or NULL if there is no menu.
cCiEnquiry *GetEnquiry(void); cCiEnquiry *GetEnquiry(void);
///< Gets a pending enquiry, or NULL if there is no enquiry.
const char *GetCamName(int Slot); const char *GetCamName(int Slot);
const unsigned short *GetCaSystemIds(int Slot); ///< Returns the name of the CAM in the given Slot, or NULL if there
///< is no CAM in that slot.
bool ProvidesCa(const unsigned short *CaSystemIds); //XXX Slot??? bool ProvidesCa(const unsigned short *CaSystemIds); //XXX Slot???
///< Returns true if any of the CAMs can provide one of the given
///< CaSystemIds. This doesn't necessarily mean that it will be
///< possible to actually decrypt such a programme, since CAMs
///< usually advertise several CA system ids, while the actual
///< decryption is controlled by the smart card inserted into
///< the CAM.
void SetSource(int Source, int Transponder); void SetSource(int Source, int Transponder);
///< Sets the Source and Transponder of the device this cCiHandler is ///< Sets the Source and Transponder of the device this cCiHandler is
///< currently tuned to. If Source or Transponder are different than ///< currently tuned to. If Source or Transponder are different than
@ -145,11 +163,14 @@ public:
///< to SetPid() will (de)activate one of these entries. ///< to SetPid() will (de)activate one of these entries.
void SetPid(int Pid, bool Active); void SetPid(int Pid, bool Active);
///< Sets the given Pid (which has previously been added through a ///< Sets the given Pid (which has previously been added through a
///< call to AddPid()) to Active. If Active is true, a later call to ///< call to AddPid()) to Active. A later call to StartDecrypting() will
///< StartDecrypting() will send the full list of currently active CA_PMT ///< send the full list of currently active CA_PMT entries to the CAM.
///< entries to the CAM, including this one.
bool CanDecrypt(int ProgramNumber); bool CanDecrypt(int ProgramNumber);
///< XXX ///< XXX
///< Returns true if there is a CAM in this CA device that is able
///< to decrypt the programme with the given ProgramNumber. The PIDs
///< for this ProgramNumber must have been set through previous calls
///< to SetPid().
void StartDecrypting(void); void StartDecrypting(void);
///< Triggers sending all currently active CA_PMT entries to the CAM, ///< Triggers sending all currently active CA_PMT entries to the CAM,
///< so that it will start decrypting. ///< so that it will start decrypting.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.138 2005/09/09 15:08:59 kls Exp $ * $Id: config.c 1.140 2006/01/07 12:28:49 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -120,24 +120,6 @@ bool cSVDRPhost::Accepts(in_addr_t Address)
return (Address & mask) == addr.s_addr; return (Address & mask) == addr.s_addr;
} }
// -- cCaDefinition ----------------------------------------------------------
cCaDefinition::cCaDefinition(void)
{
number = 0;
description = NULL;
}
cCaDefinition::~cCaDefinition()
{
free(description);
}
bool cCaDefinition::Parse(const char *s)
{
return 2 == sscanf(s, "%d %a[^\n]", &number, &description) && description && *description;
}
// -- cCommands -------------------------------------------------------------- // -- cCommands --------------------------------------------------------------
cCommands Commands; cCommands Commands;
@ -158,21 +140,6 @@ bool cSVDRPhosts::Acceptable(in_addr_t Address)
return false; return false;
} }
// -- cCaDefinitions ---------------------------------------------------------
cCaDefinitions CaDefinitions;
const cCaDefinition *cCaDefinitions::Get(int Number)
{
cCaDefinition *p = First();
while (p) {
if (p->Number() == Number)
return p;
p = (cCaDefinition *)p->Next();
}
return NULL;
}
// -- cSetupLine ------------------------------------------------------------- // -- cSetupLine -------------------------------------------------------------
cSetupLine::cSetupLine(void) cSetupLine::cSetupLine(void)
@ -250,6 +217,7 @@ cSetup::cSetup(void)
strcpy(OSDTheme, "default"); strcpy(OSDTheme, "default");
PrimaryDVB = 1; PrimaryDVB = 1;
ShowInfoOnChSwitch = 1; ShowInfoOnChSwitch = 1;
TimeoutRequChInfo = 1;
MenuScrollPage = 1; MenuScrollPage = 1;
MenuScrollWrap = 0; MenuScrollWrap = 0;
MarkInstantRecord = 1; MarkInstantRecord = 1;
@ -408,6 +376,7 @@ bool cSetup::Parse(const char *Name, const char *Value)
else if (!strcasecmp(Name, "OSDTheme")) strn0cpy(OSDTheme, Value, MaxThemeName); else if (!strcasecmp(Name, "OSDTheme")) strn0cpy(OSDTheme, Value, MaxThemeName);
else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value);
else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value);
else if (!strcasecmp(Name, "TimeoutRequChInfo")) TimeoutRequChInfo = atoi(Value);
else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value);
else if (!strcasecmp(Name, "MenuScrollWrap")) MenuScrollWrap = atoi(Value); else if (!strcasecmp(Name, "MenuScrollWrap")) MenuScrollWrap = atoi(Value);
else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value);
@ -473,6 +442,7 @@ bool cSetup::Save(void)
Store("OSDTheme", OSDTheme); Store("OSDTheme", OSDTheme);
Store("PrimaryDVB", PrimaryDVB); Store("PrimaryDVB", PrimaryDVB);
Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch);
Store("TimeoutRequChInfo", TimeoutRequChInfo);
Store("MenuScrollPage", MenuScrollPage); Store("MenuScrollPage", MenuScrollPage);
Store("MenuScrollWrap", MenuScrollWrap); Store("MenuScrollWrap", MenuScrollWrap);
Store("MarkInstantRecord", MarkInstantRecord); Store("MarkInstantRecord", MarkInstantRecord);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.235 2005/11/11 13:22:02 kls Exp $ * $Id: config.h 1.238 2006/01/07 12:57:42 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -19,8 +19,8 @@
#include "i18n.h" #include "i18n.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "1.3.37" #define VDRVERSION "1.3.38"
#define VDRVERSNUM 10337 // Version * 10000 + Major * 100 + Minor #define VDRVERSNUM 10338 // Version * 10000 + Major * 100 + Minor
#define MAXPRIORITY 99 #define MAXPRIORITY 99
#define MAXLIFETIME 99 #define MAXLIFETIME 99
@ -61,20 +61,6 @@ public:
bool Accepts(in_addr_t Address); bool Accepts(in_addr_t Address);
}; };
#define CACONFBASE 100
class cCaDefinition : public cListObject {
private:
int number;
char *description;
public:
cCaDefinition(void);
~cCaDefinition();
bool Parse(const char *s);
int Number(void) const { return number; }
const char *Description(void) const { return description; }
};
template<class T> class cConfig : public cList<T> { template<class T> class cConfig : public cList<T> {
private: private:
char *fileName; char *fileName;
@ -166,15 +152,9 @@ public:
bool Acceptable(in_addr_t Address); bool Acceptable(in_addr_t Address);
}; };
class cCaDefinitions : public cConfig<cCaDefinition> {
public:
const cCaDefinition *Get(int Number);
};
extern cCommands Commands; extern cCommands Commands;
extern cCommands RecordingCommands; extern cCommands RecordingCommands;
extern cSVDRPhosts SVDRPhosts; extern cSVDRPhosts SVDRPhosts;
extern cCaDefinitions CaDefinitions;
class cSetupLine : public cListObject { class cSetupLine : public cListObject {
private: private:
@ -210,6 +190,7 @@ public:
char OSDTheme[MaxThemeName]; char OSDTheme[MaxThemeName];
int PrimaryDVB; int PrimaryDVB;
int ShowInfoOnChSwitch; int ShowInfoOnChSwitch;
int TimeoutRequChInfo;
int MenuScrollPage; int MenuScrollPage;
int MenuScrollWrap; int MenuScrollWrap;
int MarkInstantRecord; int MarkInstantRecord;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.c 1.112 2005/11/26 12:56:09 kls Exp $ * $Id: device.c 1.121 2006/01/08 11:39:37 kls Exp $
*/ */
#include "device.h" #include "device.h"
@ -222,7 +222,7 @@ int cDevice::NextCardIndex(int n)
esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex); esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
} }
else if (n < 0) else if (n < 0)
esyslog("ERROR: illegal value in IncCardIndex(%d)", n); esyslog("ERROR: invalid value in IncCardIndex(%d)", n);
return nextCardIndex; return nextCardIndex;
} }
@ -302,7 +302,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDe
pri = 6; // receiving with same priority but fewer Ca's pri = 6; // receiving with same priority but fewer Ca's
else else
pri = 7; // all others pri = 7; // all others
if (pri < select) { if (pri <= select) {
select = pri; select = pri;
d = device[i]; d = device[i];
if (NeedsDetachReceivers) if (NeedsDetachReceivers)
@ -322,9 +322,36 @@ void cDevice::Shutdown(void)
} }
} }
bool cDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
{ {
return false; return NULL;
}
bool cDevice::GrabImageFile(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{
int result = 0;
int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE);
if (fd >= 0) {
int ImageSize;
uchar *Image = GrabImage(ImageSize, Jpeg, Quality, SizeX, SizeY);
if (Image) {
if (safe_write(fd, Image, ImageSize) == ImageSize)
isyslog("grabbed image to %s", FileName);
else {
LOG_ERROR_STR(FileName);
result |= 1;
}
free(Image);
}
else
result |= 1;
close(fd);
}
else {
LOG_ERROR_STR(FileName);
result |= 1;
}
return result == 0;
} }
void cDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) void cDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
@ -577,10 +604,14 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
if (LiveView) if (LiveView)
StopReplay(); StopReplay();
// If this card is switched to an other transponder, any receivers still
// attached to it ineed to be automatically detached:
bool NeedsDetachReceivers = false;
// If this card can't receive this channel, we must not actually switch // If this card can't receive this channel, we must not actually switch
// the channel here, because that would irritate the driver when we // the channel here, because that would irritate the driver when we
// start replaying in Transfer Mode immediately after switching the channel: // start replaying in Transfer Mode immediately after switching the channel:
bool NeedsTransferMode = (LiveView && IsPrimaryDevice() && !ProvidesChannel(Channel, Setup.PrimaryLimit)); bool NeedsTransferMode = (LiveView && IsPrimaryDevice() && !ProvidesChannel(Channel, Setup.PrimaryLimit, &NeedsDetachReceivers));
eSetChannelResult Result = scrOk; eSetChannelResult Result = scrOk;
@ -588,11 +619,14 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
// use the card that actually can receive it and transfer data from there: // use the card that actually can receive it and transfer data from there:
if (NeedsTransferMode) { if (NeedsTransferMode) {
cDevice *CaDevice = GetDevice(Channel, 0); cDevice *CaDevice = GetDevice(Channel, 0, &NeedsDetachReceivers);
if (CaDevice && CanReplay()) { if (CaDevice && CanReplay()) {
cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
if (CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! if (CaDevice->SetChannel(Channel, false) == scrOk) { // calling SetChannel() directly, not SwitchChannel()!
if (NeedsDetachReceivers)
CaDevice->DetachAllReceivers();
cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids())); cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids()));
}
else else
Result = scrNoTransfer; Result = scrNoTransfer;
} }
@ -613,7 +647,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
ciHandler->SetSource(Channel->Source(), Channel->Transponder()); ciHandler->SetSource(Channel->Source(), Channel->Transponder());
// Men at work - please stand clear! ;-) // Men at work - please stand clear! ;-)
#ifdef XXX_DO_MULTIPLE_CA_CHANNELS #ifdef XXX_DO_MULTIPLE_CA_CHANNELS
if (Channel->Ca() > CACONFBASE) { if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
#endif #endif
ciHandler->AddPid(Channel->Sid(), Channel->Vpid(), 2); ciHandler->AddPid(Channel->Sid(), Channel->Vpid(), 2);
for (const int *Apid = Channel->Apids(); *Apid; Apid++) for (const int *Apid = Channel->Apids(); *Apid; Apid++)
@ -626,13 +660,15 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
} }
#endif #endif
} }
if (NeedsDetachReceivers)
DetachAllReceivers();
if (SetChannelDevice(Channel, LiveView)) { if (SetChannelDevice(Channel, LiveView)) {
// Start section handling: // Start section handling:
if (sectionHandler) { if (sectionHandler) {
sectionHandler->SetChannel(Channel); sectionHandler->SetChannel(Channel);
sectionHandler->SetStatus(true); sectionHandler->SetStatus(true);
} }
// Start decrypting any PIDs the might have been set in SetChannelDevice(): // Start decrypting any PIDs that might have been set in SetChannelDevice():
if (ciHandler) if (ciHandler)
ciHandler->StartDecrypting(); ciHandler->StartDecrypting();
} }
@ -794,6 +830,7 @@ int cDevice::NumAudioTracks(void) const
bool cDevice::SetCurrentAudioTrack(eTrackType Type) bool cDevice::SetCurrentAudioTrack(eTrackType Type)
{ {
if (ttNone < Type && Type < ttDolbyLast) { if (ttNone < Type && Type < ttDolbyLast) {
cMutexLock MutexLock(&mutexCurrentAudioTrack);
if (IS_DOLBY_TRACK(Type)) if (IS_DOLBY_TRACK(Type))
SetDigitalAudioDevice(true); SetDigitalAudioDevice(true);
currentAudioTrack = Type; currentAudioTrack = Type;
@ -947,6 +984,7 @@ int cDevice::PlayAudio(const uchar *Data, int Length)
int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly) int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
{ {
cMutexLock MutexLock(&mutexCurrentAudioTrack);
bool FirstLoop = true; bool FirstLoop = true;
uchar c = Data[3]; uchar c = Data[3];
const uchar *Start = Data; const uchar *Start = Data;
@ -972,7 +1010,7 @@ int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
uchar SubStreamId = Data[PayloadOffset]; uchar SubStreamId = Data[PayloadOffset];
uchar SubStreamType = SubStreamId & 0xF0; uchar SubStreamType = SubStreamId & 0xF0;
uchar SubStreamIndex = SubStreamId & 0x1F; uchar SubStreamIndex = SubStreamId & 0x1F;
// Compatibility mode for old VDR recordings, where 0xBD was only AC3: // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
pre_1_3_19_PrivateStreamDeteced: pre_1_3_19_PrivateStreamDeteced:
if (pre_1_3_19_PrivateStream) { if (pre_1_3_19_PrivateStream) {
@ -1111,7 +1149,7 @@ int cDevice::ProvidesCa(const cChannel *Channel) const
int Ca = Channel->Ca(); int Ca = Channel->Ca();
if (Ca == CardIndex() + 1) if (Ca == CardIndex() + 1)
return 1; // exactly _this_ card was requested return 1; // exactly _this_ card was requested
if (Ca && Ca <= MAXDEVICES) if (Ca && Ca <= CA_DVB_MAX)
return 0; // a specific card was requested, but not _this_ one return 0; // a specific card was requested, but not _this_ one
return !Ca; // by default every card can provide FTA return !Ca; // by default every card can provide FTA
} }
@ -1242,6 +1280,15 @@ void cDevice::DetachAll(int Pid)
} }
} }
void cDevice::DetachAllReceivers(void)
{
cMutexLock MutexLock(&mutexReceiver);
for (int i = 0; i < MAXRECEIVERS; i++) {
if (receiver[i])
Detach(receiver[i]);
}
}
// --- cTSBuffer ------------------------------------------------------------- // --- cTSBuffer -------------------------------------------------------------
cTSBuffer::cTSBuffer(int File, int Size, int CardIndex) cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.h 1.66 2005/11/05 15:25:41 kls Exp $ * $Id: device.h 1.70 2006/01/08 10:10:26 kls Exp $
*/ */
#ifndef __DEVICE_H #ifndef __DEVICE_H
@ -170,14 +170,16 @@ public:
///< Returns the card index of this device (0 ... MAXDEVICES - 1). ///< Returns the card index of this device (0 ... MAXDEVICES - 1).
int DeviceNumber(void) const; int DeviceNumber(void) const;
///< Returns the number of this device (0 ... MAXDEVICES - 1). ///< Returns the number of this device (0 ... MAXDEVICES - 1).
virtual int ProvidesCa(const cChannel *Channel) const;//XXX PLUGINS.html!!! virtual int ProvidesCa(const cChannel *Channel) const;
//XXX describe changed functionality!!! ///< Checks whether this device provides the conditional access
///< Checks whether this device provides the given value in its ///< facilities to decrypt the given Channel.
///< caCaps. Returns 0 if the value is not provided, 1 if only this ///< Returns 0 if the Channel can't be decrypted, 1 if this is a
///< value is provided, and > 1 if this and other values are provided. ///< Free To Air channel or only exactly this device can decrypt it,
///< If the given value is equal to the number of this device, ///< and > 1 if this device can decrypt the Channel.
///< 1 is returned. If it is 0 (FTA), 1 plus the number of other values ///< If the result is greater than 1 and the device has more than one
///< in caCaps is returned. ///< CAM, the value will be increased by the number of CAMs, which
///< allows to select the device with the smallest number of CAMs
///< in order to preserve resources for other recordings.
virtual bool HasDecoder(void) const; virtual bool HasDecoder(void) const;
///< Tells whether this device has an MPEG decoder. ///< Tells whether this device has an MPEG decoder.
@ -305,11 +307,9 @@ public:
// Image Grab facilities // Image Grab facilities
public: public:
virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
///< Capture a single frame as an image. ///< Grabs the currently visible screen image.
///< Grabs the currently visible screen image into the given file, with the ///< \param Size The size of the returned data block.
///< given parameters.
///< \param FileName The name of the file to write. Should include the proper extension.
///< \param Jpeg If true will write a JPEG file. Otherwise a PNM file will be written. ///< \param Jpeg If true will write a JPEG file. Otherwise a PNM file will be written.
///< \param Quality The compression factor for JPEG. 1 will create a very blocky ///< \param Quality The compression factor for JPEG. 1 will create a very blocky
///< and small image, 70..80 will yield reasonable quality images while keeping the ///< and small image, 70..80 will yield reasonable quality images while keeping the
@ -317,7 +317,13 @@ public:
///< but very high quality image. ///< but very high quality image.
///< \param SizeX The number of horizontal pixels in the frame (default is the current screen width). ///< \param SizeX The number of horizontal pixels in the frame (default is the current screen width).
///< \param SizeY The number of vertical pixels in the frame (default is the current screen height). ///< \param SizeY The number of vertical pixels in the frame (default is the current screen height).
///< \return True if all went well. */ ///< \return A pointer to the grabbed image data, or NULL in case of an error.
///< The caller takes ownership of the returned memory and must free() it once it isn't needed any more.
bool GrabImageFile(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
///< Calls GrabImage() and stores the resulting image in a file with the given name.
///< \return True if all went well.
///< The caller is responsible for making sure that the given file name
///< doesn't lead to overwriting any important other file.
// Video format facilities // Video format facilities
@ -338,6 +344,7 @@ public:
private: private:
tTrackId availableTracks[ttMaxTrackTypes]; tTrackId availableTracks[ttMaxTrackTypes];
eTrackType currentAudioTrack; eTrackType currentAudioTrack;
cMutex mutexCurrentAudioTrack;
int currentAudioTrackMissingCount; int currentAudioTrackMissingCount;
bool pre_1_3_19_PrivateStream; bool pre_1_3_19_PrivateStream;
protected: protected:
@ -516,6 +523,8 @@ public:
///< Detaches the given receiver from this device. ///< Detaches the given receiver from this device.
void DetachAll(int Pid); void DetachAll(int Pid);
///< Detaches all receivers from this device for this pid. ///< Detaches all receivers from this device for this pid.
void DetachAllReceivers(void);
///< Detaches all receivers from this device.
}; };
/// Derived cDevice classes that can receive channels will have to provide /// Derived cDevice classes that can receive channels will have to provide

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: diseqc.c 1.4 2005/01/09 13:05:11 kls Exp $ * $Id: diseqc.c 1.5 2005/12/30 15:41:48 kls Exp $
*/ */
#include "diseqc.h" #include "diseqc.h"
@ -65,7 +65,7 @@ char *cDiseqc::Wait(char *s)
cCondWait::SleepMs(n); cCondWait::SleepMs(n);
return p; return p;
} }
esyslog("ERROR: illegal value for wait time in '%s'", s - 1); esyslog("ERROR: invalid value for wait time in '%s'", s - 1);
return NULL; return NULL;
} }
@ -85,7 +85,7 @@ char *cDiseqc::Codes(char *s)
t = skipspace(p); t = skipspace(p);
} }
else { else {
esyslog("ERROR: illegal code at '%s'", t); esyslog("ERROR: invalid code at '%s'", t);
return NULL; return NULL;
} }
} }

View File

@ -4,18 +4,11 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbdevice.c 1.138 2005/11/26 13:23:11 kls Exp $ * $Id: dvbdevice.c 1.149 2006/01/07 15:15:01 kls Exp $
*/ */
#include "dvbdevice.h" #include "dvbdevice.h"
#include <errno.h> #include <errno.h>
extern "C" {
#ifdef boolean
#define HAVE_BOOLEAN
#endif
#include <jpeglib.h>
#undef boolean
}
#include <limits.h> #include <limits.h>
#include <linux/videodev.h> #include <linux/videodev.h>
#include <linux/dvb/audio.h> #include <linux/dvb/audio.h>
@ -47,6 +40,13 @@ extern "C" {
#define DEV_DVB_AUDIO "audio" #define DEV_DVB_AUDIO "audio"
#define DEV_DVB_CA "ca" #define DEV_DVB_CA "ca"
#define DVBS_TUNE_TIMEOUT 2000 //ms
#define DVBS_LOCK_TIMEOUT 2000 //ms
#define DVBC_TUNE_TIMEOUT 5000 //ms
#define DVBC_LOCK_TIMEOUT 2000 //ms
#define DVBT_TUNE_TIMEOUT 9000 //ms
#define DVBT_LOCK_TIMEOUT 2000 //ms
class cDvbName { class cDvbName {
private: private:
char buffer[PATH_MAX]; char buffer[PATH_MAX];
@ -73,6 +73,9 @@ private:
enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked }; enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
int fd_frontend; int fd_frontend;
int cardIndex; int cardIndex;
int tuneTimeout;
int lockTimeout;
time_t lastTimeoutReport;
fe_type_t frontendType; fe_type_t frontendType;
cCiHandler *ciHandler; cCiHandler *ciHandler;
cChannel channel; cChannel channel;
@ -81,7 +84,7 @@ private:
cMutex mutex; cMutex mutex;
cCondVar locked; cCondVar locked;
cCondVar newSet; cCondVar newSet;
bool GetFrontendEvent(dvb_frontend_event &Event, int TimeoutMs = 0); bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0);
bool SetFrontend(void); bool SetFrontend(void);
virtual void Action(void); virtual void Action(void);
public: public:
@ -98,6 +101,9 @@ cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCi
cardIndex = CardIndex; cardIndex = CardIndex;
frontendType = FrontendType; frontendType = FrontendType;
ciHandler = CiHandler; ciHandler = CiHandler;
tuneTimeout = 0;
lockTimeout = 0;
lastTimeoutReport = 0;
diseqcCommands = NULL; diseqcCommands = NULL;
tunerStatus = tsIdle; tunerStatus = tsIdle;
if (frontendType == FE_QPSK) if (frontendType == FE_QPSK)
@ -125,6 +131,7 @@ void cDvbTuner::Set(const cChannel *Channel, bool Tune)
if (Tune) if (Tune)
tunerStatus = tsSet; tunerStatus = tsSet;
channel = *Channel; channel = *Channel;
lastTimeoutReport = 0;
newSet.Broadcast(); newSet.Broadcast();
} }
@ -140,26 +147,18 @@ bool cDvbTuner::Locked(int TimeoutMs)
return tunerStatus >= tsLocked; return tunerStatus >= tsLocked;
} }
bool cDvbTuner::GetFrontendEvent(dvb_frontend_event &Event, int TimeoutMs) bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs)
{ {
if (TimeoutMs) { if (TimeoutMs) {
struct pollfd pfd; cPoller Poller(fd_frontend);
pfd.fd = fd_frontend; if (Poller.Poll(TimeoutMs)) {
pfd.events = POLLIN | POLLPRI; dvb_frontend_event Event;
do { while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
int stat = poll(&pfd, 1, TimeoutMs); ; // just to clear the event queue - we'll read the actual status below
if (stat == 1) }
break;
if (stat < 0) {
if (errno == EINTR)
continue;
esyslog("ERROR: frontend %d poll failed: %m", cardIndex);
}
return false;
} while (0);
} }
do { do {
int stat = ioctl(fd_frontend, FE_GET_EVENT, &Event); int stat = ioctl(fd_frontend, FE_READ_STATUS, &Status);
if (stat == 0) if (stat == 0)
return true; return true;
if (stat < 0) { if (stat < 0) {
@ -245,6 +244,9 @@ bool cDvbTuner::SetFrontend(void)
Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); Frontend.inversion = fe_spectral_inversion_t(channel.Inversion());
Frontend.u.qpsk.symbol_rate = channel.Srate() * 1000UL; Frontend.u.qpsk.symbol_rate = channel.Srate() * 1000UL;
Frontend.u.qpsk.fec_inner = fe_code_rate_t(channel.CoderateH()); Frontend.u.qpsk.fec_inner = fe_code_rate_t(channel.CoderateH());
tuneTimeout = DVBS_TUNE_TIMEOUT;
lockTimeout = DVBS_LOCK_TIMEOUT;
} }
break; break;
case FE_QAM: { // DVB-C case FE_QAM: { // DVB-C
@ -256,6 +258,9 @@ bool cDvbTuner::SetFrontend(void)
Frontend.u.qam.symbol_rate = channel.Srate() * 1000UL; Frontend.u.qam.symbol_rate = channel.Srate() * 1000UL;
Frontend.u.qam.fec_inner = fe_code_rate_t(channel.CoderateH()); Frontend.u.qam.fec_inner = fe_code_rate_t(channel.CoderateH());
Frontend.u.qam.modulation = fe_modulation_t(channel.Modulation()); Frontend.u.qam.modulation = fe_modulation_t(channel.Modulation());
tuneTimeout = DVBC_TUNE_TIMEOUT;
lockTimeout = DVBC_LOCK_TIMEOUT;
} }
break; break;
case FE_OFDM: { // DVB-T case FE_OFDM: { // DVB-T
@ -271,6 +276,9 @@ bool cDvbTuner::SetFrontend(void)
Frontend.u.ofdm.transmission_mode = fe_transmit_mode_t(channel.Transmission()); Frontend.u.ofdm.transmission_mode = fe_transmit_mode_t(channel.Transmission());
Frontend.u.ofdm.guard_interval = fe_guard_interval_t(channel.Guard()); Frontend.u.ofdm.guard_interval = fe_guard_interval_t(channel.Guard());
Frontend.u.ofdm.hierarchy_information = fe_hierarchy_t(channel.Hierarchy()); Frontend.u.ofdm.hierarchy_information = fe_hierarchy_t(channel.Hierarchy());
tuneTimeout = DVBT_TUNE_TIMEOUT;
lockTimeout = DVBT_LOCK_TIMEOUT;
} }
break; break;
default: default:
@ -286,30 +294,54 @@ bool cDvbTuner::SetFrontend(void)
void cDvbTuner::Action(void) void cDvbTuner::Action(void)
{ {
dvb_frontend_event event; cTimeMs Timer;
bool LostLock = false;
fe_status_t Status = (fe_status_t)0;
while (Running()) { while (Running()) {
bool hasEvent = GetFrontendEvent(event, 1); fe_status_t NewStatus;
if (GetFrontendStatus(NewStatus, 10))
Status = NewStatus;
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
switch (tunerStatus) { switch (tunerStatus) {
case tsIdle: case tsIdle:
break; break;
case tsSet: case tsSet:
if (hasEvent)
continue;
tunerStatus = SetFrontend() ? tsTuned : tsIdle; tunerStatus = SetFrontend() ? tsTuned : tsIdle;
Timer.Set(tuneTimeout);
continue; continue;
case tsTuned: case tsTuned:
if (Timer.TimedOut()) {
tunerStatus = tsSet;
diseqcCommands = NULL;
if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
esyslog("ERROR: frontend %d timed out while tuning to channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
lastTimeoutReport = time(NULL);
}
continue;
}
case tsLocked: case tsLocked:
if (hasEvent) { if (Status & FE_REINIT) {
if (event.status & FE_REINIT) { tunerStatus = tsSet;
tunerStatus = tsSet; diseqcCommands = NULL;
esyslog("ERROR: frontend %d was reinitialized - re-tuning", cardIndex); esyslog("ERROR: frontend %d was reinitialized", cardIndex);
} lastTimeoutReport = 0;
if (event.status & FE_HAS_LOCK) { continue;
tunerStatus = tsLocked; }
locked.Broadcast(); else if (Status & FE_HAS_LOCK) {
if (LostLock) {
esyslog("frontend %d regained lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
LostLock = false;
} }
tunerStatus = tsLocked;
locked.Broadcast();
lastTimeoutReport = 0;
}
else if (tunerStatus == tsLocked) {
LostLock = true;
esyslog("ERROR: frontend %d lost lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
tunerStatus = tsTuned;
Timer.Set(lockTimeout);
lastTimeoutReport = 0;
continue; continue;
} }
} }
@ -471,13 +503,21 @@ bool cDvbDevice::Ready(void)
int cDvbDevice::ProvidesCa(const cChannel *Channel) const int cDvbDevice::ProvidesCa(const cChannel *Channel) const
{ {
if (Channel->Ca() >= 0x0100 && ciHandler) { int NumCams = 0;
unsigned short ids[MAXCAIDS + 1]; if (ciHandler) {
for (int i = 0; i <= MAXCAIDS; i++) // '<=' copies the terminating 0! NumCams = ciHandler->NumCams();
ids[i] = Channel->Ca(i); if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
return ciHandler->ProvidesCa(ids); unsigned short ids[MAXCAIDS + 1];
for (int i = 0; i <= MAXCAIDS; i++) // '<=' copies the terminating 0!
ids[i] = Channel->Ca(i);
if (ciHandler->ProvidesCa(ids))
return NumCams + 1;
}
} }
return cDevice::ProvidesCa(Channel); int result = cDevice::ProvidesCa(Channel);
if (result > 0)
result += NumCams;
return result;
} }
cSpuDecoder *cDvbDevice::GetSpuDecoder(void) cSpuDecoder *cDvbDevice::GetSpuDecoder(void)
@ -487,103 +527,84 @@ cSpuDecoder *cDvbDevice::GetSpuDecoder(void)
return spuDecoder; return spuDecoder;
} }
bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) uchar *cDvbDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
{ {
if (devVideoIndex < 0) if (devVideoIndex < 0)
return false; return NULL;
char buffer[PATH_MAX]; char buffer[PATH_MAX];
snprintf(buffer, sizeof(buffer), "%s%d", DEV_VIDEO, devVideoIndex); snprintf(buffer, sizeof(buffer), "%s%d", DEV_VIDEO, devVideoIndex);
int videoDev = open(buffer, O_RDWR); int videoDev = open(buffer, O_RDWR);
if (videoDev < 0)
LOG_ERROR_STR(buffer);
if (videoDev >= 0) { if (videoDev >= 0) {
int result = 0; uchar *result = NULL;
struct video_mbuf mbuf; struct video_mbuf mbuf;
result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf); if (ioctl(videoDev, VIDIOCGMBUF, &mbuf) == 0) {
if (result == 0) {
int msize = mbuf.size; int msize = mbuf.size;
unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
if (mem && mem != (unsigned char *)-1) { if (mem && mem != (unsigned char *)-1) {
// set up the size and RGB // set up the size and RGB
struct video_capability vc; struct video_capability vc;
result |= ioctl(videoDev, VIDIOCGCAP, &vc); if (ioctl(videoDev, VIDIOCGCAP, &vc) == 0) {
struct video_mmap vm; struct video_mmap vm;
vm.frame = 0; vm.frame = 0;
if ((SizeX > 0) && (SizeX <= vc.maxwidth) && if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
(SizeY > 0) && (SizeY <= vc.maxheight)) { (SizeY > 0) && (SizeY <= vc.maxheight)) {
vm.width = SizeX; vm.width = SizeX;
vm.height = SizeY; vm.height = SizeY;
}
else {
vm.width = vc.maxwidth;
vm.height = vc.maxheight;
}
vm.format = VIDEO_PALETTE_RGB24;
result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
// make RGB out of BGR:
int memsize = vm.width * vm.height;
unsigned char *mem1 = mem;
for (int i = 0; i < memsize; i++) {
unsigned char tmp = mem1[2];
mem1[2] = mem1[0];
mem1[0] = tmp;
mem1 += 3;
}
if (Quality < 0)
Quality = 100;
isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
FILE *f = fopen(FileName, "wb");
if (f) {
if (Jpeg) {
// write JPEG file:
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, f);
cinfo.image_width = vm.width;
cinfo.image_height = vm.height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, Quality, true);
jpeg_start_compress(&cinfo, true);
int rs = vm.width * 3;
JSAMPROW rp[vm.height];
for (int k = 0; k < vm.height; k++)
rp[k] = &mem[rs * k];
jpeg_write_scanlines(&cinfo, rp, vm.height);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
} }
else { else {
// write PNM file: vm.width = vc.maxwidth;
if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 || vm.height = vc.maxheight;
fwrite(mem, vm.width * vm.height * 3, 1, f) != 1) { }
LOG_ERROR_STR(FileName); vm.format = VIDEO_PALETTE_RGB24;
result |= 1; if (ioctl(videoDev, VIDIOCMCAPTURE, &vm) == 0 && ioctl(videoDev, VIDIOCSYNC, &vm.frame) == 0) {
// make RGB out of BGR:
int memsize = vm.width * vm.height;
unsigned char *mem1 = mem;
for (int i = 0; i < memsize; i++) {
unsigned char tmp = mem1[2];
mem1[2] = mem1[0];
mem1[0] = tmp;
mem1 += 3;
}
if (Quality < 0)
Quality = 100;
isyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
if (Jpeg) {
// convert to JPEG:
result = RgbToJpeg(mem, vm.width, vm.height, Size, Quality);
if (!result)
esyslog("ERROR: failed to convert image to JPEG");
}
else {
// convert to PNM:
char buf[32];
snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", vm.width, vm.height);
int l = strlen(buf);
int bytes = memsize * 3;
Size = l + bytes;
result = MALLOC(uchar, Size);
if (result) {
memcpy(result, buf, l);
memcpy(result + l, mem, bytes);
}
else
esyslog("ERROR: failed to convert image to PNM");
} }
} }
fclose(f);
}
else {
LOG_ERROR_STR(FileName);
result |= 1;
} }
munmap(mem, msize); munmap(mem, msize);
} }
else else
result |= 1; esyslog("ERROR: failed to memmap video device");
} }
close(videoDev); close(videoDev);
return result == 0; return result;
} }
return false; else
LOG_ERROR_STR(buffer);
return NULL;
} }
void cDvbDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) void cDvbDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
@ -754,7 +775,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) { if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
#ifdef DO_MULTIPLE_RECORDINGS #ifdef DO_MULTIPLE_RECORDINGS
#ifndef DO_MULTIPLE_CA_CHANNELS #ifndef DO_MULTIPLE_CA_CHANNELS
if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE) if (Ca() >= CA_ENCRYPTED_MIN || Channel->Ca() >= CA_ENCRYPTED_MIN)
needsDetachReceivers = Ca() != Channel->Ca(); needsDetachReceivers = Ca() != Channel->Ca();
else else
#endif #endif
@ -825,6 +846,11 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1); esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
return false; return false;
} }
//XXX quick workaround for additional live audio PIDs:
if (ciHandler) {
ciHandler->SetPid(Channel->Apid(1), true);
ciHandler->SetPid(Channel->Dpid(0), true);
}
if (IsPrimaryDevice()) if (IsPrimaryDevice())
AddPid(Channel->Tpid(), ptTeletext); AddPid(Channel->Tpid(), ptTeletext);
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schlüßler <marco@lordzodiac.de> this works CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schlüßler <marco@lordzodiac.de> this works

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbdevice.h 1.36 2005/11/11 14:51:38 kls Exp $ * $Id: dvbdevice.h 1.37 2005/12/29 13:33:12 kls Exp $
*/ */
#ifndef __DVBDEVICE_H #ifndef __DVBDEVICE_H
@ -85,7 +85,7 @@ private:
static int devVideoOffset; static int devVideoOffset;
int devVideoIndex; int devVideoIndex;
public: public:
virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
// Video format facilities // Video format facilities

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbosd.c 1.27 2005/05/22 10:57:45 kls Exp $ * $Id: dvbosd.c 1.29 2005/12/30 15:41:54 kls Exp $
*/ */
#include "dvbosd.h" #include "dvbosd.h"
@ -39,7 +39,7 @@ cDvbOsd::cDvbOsd(int Left, int Top, int OsdDev)
osdDev = OsdDev; osdDev = OsdDev;
shown = false; shown = false;
if (osdDev < 0) if (osdDev < 0)
esyslog("ERROR: illegal OSD device handle (%d)!", osdDev); esyslog("ERROR: invalid OSD device handle (%d)!", osdDev);
else { else {
osdMem = MAXOSDMEMORY; osdMem = MAXOSDMEMORY;
#ifdef OSD_CAP_MEMSIZE #ifdef OSD_CAP_MEMSIZE
@ -88,6 +88,8 @@ eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
return oeBppNotSupported; return oeBppNotSupported;
if ((Areas[i].Width() & (8 / Areas[i].bpp - 1)) != 0) if ((Areas[i].Width() & (8 / Areas[i].bpp - 1)) != 0)
return oeWrongAlignment; return oeWrongAlignment;
if (Areas[i].Width() < 1 || Areas[i].Height() < 1 || Areas[i].Width() > 720 || Areas[i].Height() > 576)
return oeWrongAreaSize;
TotalMemory += Areas[i].Width() * Areas[i].Height() / (8 / Areas[i].bpp); TotalMemory += Areas[i].Width() * Areas[i].Height() / (8 / Areas[i].bpp);
} }
if (TotalMemory > osdMem) if (TotalMemory > osdMem)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbplayer.c 1.41 2005/10/31 12:33:48 kls Exp $ * $Id: dvbplayer.c 1.42 2006/01/08 11:39:41 kls Exp $
*/ */
#include "dvbplayer.h" #include "dvbplayer.h"
@ -621,7 +621,7 @@ int cDvbPlayer::SkipFrames(int Frames)
int Current, Total; int Current, Total;
GetIndex(Current, Total, true); GetIndex(Current, Total, true);
int OldCurrent = Current; int OldCurrent = Current;
// As GetNextIFrame() increments/decrements at least once, the // As GetNextIFrame() increments/decrements at least once, the
// destination frame (= Current + Frames) must be adjusted by // destination frame (= Current + Frames) must be adjusted by
// -1/+1 respectively. // -1/+1 respectively.
Current = index->GetNextIFrame(Current + Frames + (Frames > 0 ? -1 : 1), Frames > 0); Current = index->GetNextIFrame(Current + Frames + (Frames > 0 ? -1 : 1), Frames > 0);

View File

@ -8,16 +8,15 @@
* *
* parts of this file are derived from the OMS program. * parts of this file are derived from the OMS program.
* *
* $Id: dvbspu.c 1.17 2005/11/05 12:08:15 kls Exp $ * $Id: dvbspu.c 1.19 2006/01/08 11:39:46 kls Exp $
*/ */
#include "dvbspu.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <inttypes.h> #include <inttypes.h>
#include <math.h> #include <math.h>
#include "device.h" #include "device.h"
#include "dvbspu.h"
/* /*
* cDvbSpubitmap: * cDvbSpubitmap:
@ -28,7 +27,7 @@
* Inputs: * Inputs:
* - a SPU rle encoded image on creation, which will be decoded into * - a SPU rle encoded image on creation, which will be decoded into
* the full screen indexed bitmap * the full screen indexed bitmap
* *
* Output: * Output:
* - a minimal sized cDvbSpuBitmap a given palette, the indexed bitmap * - a minimal sized cDvbSpuBitmap a given palette, the indexed bitmap
* will be scanned to get the smallest possible resulting bitmap considering * will be scanned to get the smallest possible resulting bitmap considering
@ -436,7 +435,7 @@ int cDvbSpuDecoder::setTime(uint32_t pts)
prev_DCSQ_offset = DCSQ_offset; prev_DCSQ_offset = DCSQ_offset;
DCSQ_offset = spuU32(i); DCSQ_offset = spuU32(i);
DEBUG("offs = %d, DCSQ = %d, prev_DCSQ = %d\n", DEBUG("offs = %d, DCSQ = %d, prev_DCSQ = %d\n",
i, DCSQ_offset, prev_DCSQ_offset); i, DCSQ_offset, prev_DCSQ_offset);
i += 2; i += 2;

View File

@ -8,16 +8,16 @@
* *
* parts of this file are derived from the OMS program. * parts of this file are derived from the OMS program.
* *
* $Id: dvbspu.h 1.10 2005/11/05 12:08:47 kls Exp $ * $Id: dvbspu.h 1.11 2006/01/05 10:18:31 kls Exp $
*/ */
#ifndef __DVBSPU_H #ifndef __DVBSPU_H
#define __DVBSPU_H #define __DVBSPU_H
#include <inttypes.h> #include <inttypes.h>
#include "osd.h" #include "osd.h"
#include "spu.h" #include "spu.h"
#include "thread.h"
typedef struct sDvbSpuPalDescr { typedef struct sDvbSpuPalDescr {
uint8_t index; uint8_t index;

8
eit.c
View File

@ -8,7 +8,7 @@
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>. * Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
* *
* $Id: eit.c 1.112 2005/11/04 14:19:16 kls Exp $ * $Id: eit.c 1.113 2005/12/26 11:50:09 kls Exp $
*/ */
#include "eit.h" #include "eit.h"
@ -43,6 +43,8 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
bool Empty = true; bool Empty = true;
bool Modified = false; bool Modified = false;
time_t SegmentStart = 0;
time_t SegmentEnd = 0;
SI::EIT::Event SiEitEvent; SI::EIT::Event SiEitEvent;
for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) { for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) {
@ -50,6 +52,9 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
if (SiEitEvent.getStartTime() == 0 || SiEitEvent.getStartTime() > 0 && SiEitEvent.getDuration() == 0) if (SiEitEvent.getStartTime() == 0 || SiEitEvent.getStartTime() > 0 && SiEitEvent.getDuration() == 0)
continue; continue;
Empty = false; Empty = false;
if (!SegmentStart)
SegmentStart = SiEitEvent.getStartTime();
SegmentEnd = SiEitEvent.getStartTime() + SiEitEvent.getDuration();
cEvent *newEvent = NULL; cEvent *newEvent = NULL;
cEvent *rEvent = NULL; cEvent *rEvent = NULL;
cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime()); cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime());
@ -242,6 +247,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
pSchedule->SetPresentSeen(); pSchedule->SetPresentSeen();
if (Modified) { if (Modified) {
pSchedule->Sort(); pSchedule->Sort();
pSchedule->DropOutdated(SegmentStart, SegmentEnd, Tid, getVersionNumber());
Schedules->SetModified(pSchedule); Schedules->SetModified(pSchedule);
} }
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: eitscan.c 1.29 2005/11/05 15:24:36 kls Exp $ * $Id: eitscan.c 1.30 2006/01/07 14:10:17 kls Exp $
*/ */
#include "eitscan.h" #include "eitscan.h"
@ -147,7 +147,7 @@ void cEITScanner::Process(void)
for (cScanData *ScanData = scanList->First(); ScanData; ScanData = scanList->Next(ScanData)) { for (cScanData *ScanData = scanList->First(); ScanData; ScanData = scanList->Next(ScanData)) {
const cChannel *Channel = ScanData->GetChannel(); const cChannel *Channel = ScanData->GetChannel();
if (Channel) { if (Channel) {
if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= 0x0100) { if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
if (Device->ProvidesTransponder(Channel)) { if (Device->ProvidesTransponder(Channel)) {
if (!Device->Receiving()) { if (!Device->Receiving()) {
bool MaySwitchTransponder = Device->MaySwitchTransponder(); bool MaySwitchTransponder = Device->MaySwitchTransponder();

58
epg.c
View File

@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by * Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* *
* $Id: epg.c 1.40 2005/11/11 13:37:43 kls Exp $ * $Id: epg.c 1.47 2005/12/30 15:41:59 kls Exp $
*/ */
#include "epg.h" #include "epg.h"
@ -234,7 +234,7 @@ void cEvent::Dump(FILE *f, const char *Prefix, bool InfoOnly) const
{ {
if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) { if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) {
if (!InfoOnly) if (!InfoOnly)
fprintf(f, "%sE %u %ld %d %X\n", Prefix, eventID, startTime, duration, tableID); fprintf(f, "%sE %u %ld %d %X %X\n", Prefix, eventID, startTime, duration, tableID, version);
if (!isempty(title)) if (!isempty(title))
fprintf(f, "%sT %s\n", Prefix, title); fprintf(f, "%sT %s\n", Prefix, title);
if (!isempty(shortText)) if (!isempty(shortText))
@ -296,8 +296,9 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
time_t StartTime; time_t StartTime;
int Duration; int Duration;
unsigned int TableID = 0; unsigned int TableID = 0;
int n = sscanf(t, "%u %ld %d %X", &EventID, &StartTime, &Duration, &TableID); unsigned int Version = 0xFF;
if (n == 3 || n == 4) { int n = sscanf(t, "%u %ld %d %X %X", &EventID, &StartTime, &Duration, &TableID, &Version);
if (n >= 3 && n <= 5) {
Event = (cEvent *)Schedule->GetEvent(EventID, StartTime); Event = (cEvent *)Schedule->GetEvent(EventID, StartTime);
cEvent *newEvent = NULL; cEvent *newEvent = NULL;
if (Event) if (Event)
@ -306,6 +307,7 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
Event = newEvent = new cEvent(EventID); Event = newEvent = new cEvent(EventID);
if (Event) { if (Event) {
Event->SetTableID(TableID); Event->SetTableID(TableID);
Event->SetVersion(Version);
Event->SetStartTime(StartTime); Event->SetStartTime(StartTime);
Event->SetDuration(Duration); Event->SetDuration(Duration);
if (newEvent) if (newEvent)
@ -635,7 +637,6 @@ void cSchedule::DelEvent(cEvent *Event)
if (Event->schedule == this) { if (Event->schedule == this) {
UnhashEvent(Event); UnhashEvent(Event);
events.Del(Event); events.Del(Event);
Event->schedule = NULL;
} }
} }
@ -737,6 +738,31 @@ void cSchedule::Sort(void)
events.Sort(); events.Sort();
} }
void cSchedule::DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version)
{
if (SegmentStart > 0 && SegmentEnd > 0) {
for (cEvent *p = events.First(); p; p = events.Next(p)) {
if (p->EndTime() > SegmentStart) {
if (p->StartTime() < SegmentEnd) {
// The event overlaps with the given time segment.
if (p->TableID() > TableID || p->TableID() == TableID && p->Version() != Version) {
// The segment overwrites all events from tables with higher ids, and
// within the same table id all events must have the same version.
// We can't delete the event right here because a timer might have
// a pointer to it, so let's set its id and start time to 0 to have it
// "phased out":
UnhashEvent(p);
p->eventID = 0;
p->startTime = 0;
}
}
else
break;
}
}
}
}
void cSchedule::Cleanup(void) void cSchedule::Cleanup(void)
{ {
Cleanup(time(NULL)); Cleanup(time(NULL));
@ -745,15 +771,12 @@ void cSchedule::Cleanup(void)
void cSchedule::Cleanup(time_t Time) void cSchedule::Cleanup(time_t Time)
{ {
cEvent *Event; cEvent *Event;
for (int a = 0; true ; a++) { while ((Event = events.First()) != NULL) {
Event = events.Get(a); if (!Event->HasTimer() && Event->EndTime() + Setup.EPGLinger * 60 + 3600 < Time) // adding one hour for safety
if (!Event) DelEvent(Event);
break; else
if (!Event->HasTimer() && Event->EndTime() + Setup.EPGLinger * 60 + 3600 < Time) { // adding one hour for safety break;
DelEvent(Event); }
a--;
}
}
} }
void cSchedule::Dump(FILE *f, const char *Prefix, eDumpMode DumpMode, time_t AtTime) const void cSchedule::Dump(FILE *f, const char *Prefix, eDumpMode DumpMode, time_t AtTime) const
@ -811,7 +834,7 @@ bool cSchedule::Read(FILE *f, cSchedules *Schedules)
} }
} }
else { else {
esyslog("ERROR: illegal channel ID: %s", s); esyslog("ERROR: invalid channel ID: %s", s);
return false; return false;
} }
} }
@ -871,7 +894,7 @@ void cSchedules::Cleanup(bool Force)
time_t now = time(NULL); time_t now = time(NULL);
struct tm tm_r; struct tm tm_r;
struct tm *ptm = localtime_r(&now, &tm_r); struct tm *ptm = localtime_r(&now, &tm_r);
if (now - lastCleanup > 3600 && ptm->tm_hour == 5) { if (now - lastCleanup > 3600) {
isyslog("cleaning up schedules data"); isyslog("cleaning up schedules data");
cSchedulesLock SchedulesLock(true, 1000); cSchedulesLock SchedulesLock(true, 1000);
cSchedules *s = (cSchedules *)Schedules(SchedulesLock); cSchedules *s = (cSchedules *)Schedules(SchedulesLock);
@ -880,7 +903,8 @@ void cSchedules::Cleanup(bool Force)
p->Cleanup(now); p->Cleanup(now);
} }
lastCleanup = now; lastCleanup = now;
ReportEpgBugFixStats(true); if (ptm->tm_hour == 5)
ReportEpgBugFixStats(true);
} }
if (epgDataFileName && now - lastDump > 600) { if (epgDataFileName && now - lastDump > 600) {
cSafeFile f(epgDataFileName); cSafeFile f(epgDataFileName);

4
epg.h
View File

@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by * Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* *
* $Id: epg.h 1.26 2005/09/11 12:54:30 kls Exp $ * $Id: epg.h 1.28 2005/12/27 14:31:24 kls Exp $
*/ */
#ifndef __EPG_H #ifndef __EPG_H
@ -67,6 +67,7 @@ public:
~cEvent(); ~cEvent();
virtual int Compare(const cListObject &ListObject) const; virtual int Compare(const cListObject &ListObject) const;
tChannelID ChannelID(void) const; tChannelID ChannelID(void) const;
const cSchedule *Schedule(void) const { return schedule; }
u_int16_t EventID(void) const { return eventID; } u_int16_t EventID(void) const { return eventID; }
uchar TableID(void) const { return tableID; } uchar TableID(void) const { return tableID; }
uchar Version(void) const { return version; } uchar Version(void) const { return version; }
@ -128,6 +129,7 @@ public:
void ClrRunningStatus(cChannel *Channel = NULL); void ClrRunningStatus(cChannel *Channel = NULL);
void ResetVersions(void); void ResetVersions(void);
void Sort(void); void Sort(void);
void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version);
void Cleanup(time_t Time); void Cleanup(time_t Time);
void Cleanup(void); void Cleanup(void);
cEvent *AddEvent(cEvent *Event); cEvent *AddEvent(cEvent *Event);

View File

@ -154,9 +154,9 @@ SuckGlyphsFromServer(Display * dpy, Font font)
character.byte2 = (i + fontinfo->min_char_or_byte2) & 255; character.byte2 = (i + fontinfo->min_char_or_byte2) & 255;
character.byte1 = (i + fontinfo->min_char_or_byte2) >> 8; character.byte1 = (i + fontinfo->min_char_or_byte2) >> 8;
/* XXX we could use XDrawImageString16 which would also paint the backing /* XXX we could use XDrawImageString16 which would also paint the backing
rectangle but X server bugs in some scalable font rasterizers makes it rectangle but X server bugs in some scalable font rasterizers makes it
more effective to do XFillRectangles to clear the pixmap and more effective to do XFillRectangles to clear the pixmap and
XDrawImage16 for the text. */ XDrawImage16 for the text. */

564
i18n.c

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: interface.c 1.70 2005/11/27 15:31:06 kls Exp $ * $Id: interface.c 1.71 2006/01/04 15:44:19 kls Exp $
*/ */
#include "interface.h" #include "interface.h"
@ -84,7 +84,9 @@ bool cInterface::QueryKeys(cRemote *Remote, cSkinDisplayMenu *DisplayMenu)
eKeys NewKey = kUp; eKeys NewKey = kUp;
while (NewKey != kNone) { while (NewKey != kNone) {
char *Prompt; char *Prompt;
asprintf(&Prompt, tr("Press key for '%s'"), tr(cKey::ToString(NewKey))); char buf[32];
snprintf(buf, sizeof(buf), "Key$%s", cKey::ToString(NewKey));
asprintf(&Prompt, tr("Press key for '%s'"), tr(buf));
DisplayMenu->SetItem(Prompt, 4, false, false); DisplayMenu->SetItem(Prompt, 4, false, false);
free(Prompt); free(Prompt);
cRemote::Clear(); cRemote::Clear();

View File

@ -9,4 +9,5 @@
Red Recordings Red Recordings
Green Schedule Green Schedule
Yellow Info
Blue Timers Blue Timers

3
keys.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: keys.c 1.9 2005/09/17 11:27:40 kls Exp $ * $Id: keys.c 1.10 2006/01/05 15:39:26 kls Exp $
*/ */
#include "keys.h" #include "keys.h"
@ -32,6 +32,7 @@ static tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ k7, "7" }, { k7, "7" },
{ k8, "8" }, { k8, "8" },
{ k9, "9" }, { k9, "9" },
{ kInfo, "Info" },
{ kPlay, "Play" }, { kPlay, "Play" },
{ kPause, "Pause" }, { kPause, "Pause" },
{ kStop, "Stop" }, { kStop, "Stop" },

3
keys.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: keys.h 1.6 2004/12/27 11:10:59 kls Exp $ * $Id: keys.h 1.7 2006/01/05 15:39:06 kls Exp $
*/ */
#ifndef __KEYS_H #ifndef __KEYS_H
@ -26,6 +26,7 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kYellow, kYellow,
kBlue, kBlue,
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kInfo,
kPlay, kPlay,
kPause, kPause,
kStop, kStop,

458
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.376 2005/11/05 17:29:22 kls Exp $ * $Id: menu.c 1.390 2006/01/08 11:39:57 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -31,6 +31,7 @@
#define MAXWAIT4EPGINFO 3 // seconds #define MAXWAIT4EPGINFO 3 // seconds
#define MODETIMEOUT 3 // seconds #define MODETIMEOUT 3 // seconds
#define DISKSPACECHEK 5 // seconds between disk space checks in the main menu
#define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS) #define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS)
#define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours #define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
@ -41,28 +42,25 @@
// --- cMenuEditCaItem ------------------------------------------------------- // --- cMenuEditCaItem -------------------------------------------------------
class cMenuEditCaItem : public cMenuEditIntItem { class cMenuEditCaItem : public cMenuEditIntItem {
private:
const cCaDefinition *ca;
bool allowCardNr;
protected: protected:
virtual void Set(void); virtual void Set(void);
public: public:
cMenuEditCaItem(const char *Name, int *Value, bool AllowCardNr = false); cMenuEditCaItem(const char *Name, int *Value);
eOSState ProcessKey(eKeys Key); eOSState ProcessKey(eKeys Key);
}; };
cMenuEditCaItem::cMenuEditCaItem(const char *Name, int *Value, bool AllowCardNr) cMenuEditCaItem::cMenuEditCaItem(const char *Name, int *Value)
:cMenuEditIntItem(Name, Value, 0) :cMenuEditIntItem(Name, Value, 0)
{ {
ca = CaDefinitions.Get(*Value);
allowCardNr = AllowCardNr;
Set(); Set();
} }
void cMenuEditCaItem::Set(void) void cMenuEditCaItem::Set(void)
{ {
if (ca) if (*value == CA_FTA)
SetValue(ca->Description()); SetValue(tr("Free To Air"));
else if (*value >= CA_ENCRYPTED_MIN)
SetValue(tr("encrypted"));
else else
cMenuEditIntItem::Set(); cMenuEditIntItem::Set();
} }
@ -72,18 +70,8 @@ eOSState cMenuEditCaItem::ProcessKey(eKeys Key)
eOSState state = cMenuEditItem::ProcessKey(Key); eOSState state = cMenuEditItem::ProcessKey(Key);
if (state == osUnknown) { if (state == osUnknown) {
if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? if (NORMALKEY(Key) == kLeft && *value >= CA_ENCRYPTED_MIN)
if (ca && ca->Prev()) { *value = CA_FTA;
ca = (cCaDefinition *)ca->Prev();
*value = ca->Number();
}
}
else if (NORMALKEY(Key) == kRight) {
if (ca && ca->Next() && (allowCardNr || ((cCaDefinition *)ca->Next())->Number() > MAXDEVICES)) {
ca = (cCaDefinition *)ca->Next();
*value = ca->Number();
}
}
else else
return cMenuEditIntItem::ProcessKey(Key); return cMenuEditIntItem::ProcessKey(Key);
Set(); Set();
@ -265,7 +253,7 @@ void cMenuEditChannel::Setup(void)
Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpids[0], 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpids[0], 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpids[1], 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpids[1], 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF));
Add(new cMenuEditCaItem( tr("CA"), &data.caids[0], true));//XXX Add(new cMenuEditCaItem( tr("CA"), &data.caids[0]));
Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF)); Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF));
/* XXX not yet used /* XXX not yet used
Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0)); Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0));
@ -380,12 +368,17 @@ void cMenuChannelItem::Set(void)
// --- cMenuChannels --------------------------------------------------------- // --- cMenuChannels ---------------------------------------------------------
#define CHANNELNUMBERTIMEOUT 1000 //ms
class cMenuChannels : public cOsdMenu { class cMenuChannels : public cOsdMenu {
private: private:
int number;
cTimeMs numberTimer;
void Setup(void); void Setup(void);
cChannel *GetChannel(int Index); cChannel *GetChannel(int Index);
void Propagate(void); void Propagate(void);
protected: protected:
eOSState Number(eKeys Key);
eOSState Switch(void); eOSState Switch(void);
eOSState Edit(void); eOSState Edit(void);
eOSState New(void); eOSState New(void);
@ -400,6 +393,7 @@ public:
cMenuChannels::cMenuChannels(void) cMenuChannels::cMenuChannels(void)
:cOsdMenu(tr("Channels"), CHNUMWIDTH) :cOsdMenu(tr("Channels"), CHNUMWIDTH)
{ {
number = 0;
Setup(); Setup();
Channels.IncBeingEdited(); Channels.IncBeingEdited();
} }
@ -427,7 +421,7 @@ void cMenuChannels::Setup(void)
if (cMenuChannelItem::SortMode() != cMenuChannelItem::csmNumber) if (cMenuChannelItem::SortMode() != cMenuChannelItem::csmNumber)
Sort(); Sort();
SetCurrent(currentItem); SetCurrent(currentItem);
SetHelp(tr("Edit"), tr("New"), tr("Delete"), cMenuChannelItem::SortMode() == cMenuChannelItem::csmNumber ? tr("Mark") : NULL); SetHelp(tr("Button$Edit"), tr("Button$New"), tr("Button$Delete"), tr("Button$Mark"));
Display(); Display();
} }
@ -446,6 +440,30 @@ void cMenuChannels::Propagate(void)
Channels.SetModified(true); Channels.SetModified(true);
} }
eOSState cMenuChannels::Number(eKeys Key)
{
if (HasSubMenu())
return osContinue;
if (numberTimer.TimedOut())
number = 0;
if (!number && Key == k0) {
cMenuChannelItem::IncSortMode();
Setup();
}
else {
number = number * 10 + Key - k0;
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) {
if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == number) {
SetCurrent(ci);
Display();
break;
}
}
numberTimer.Set(CHANNELNUMBERTIMEOUT);
}
return osContinue;
}
eOSState cMenuChannels::Switch(void) eOSState cMenuChannels::Switch(void)
{ {
if (HasSubMenu()) if (HasSubMenu())
@ -530,14 +548,13 @@ eOSState cMenuChannels::ProcessKey(eKeys Key)
default: default:
if (state == osUnknown) { if (state == osUnknown) {
switch (Key) { switch (Key) {
case k0: cMenuChannelItem::IncSortMode(); case k0 ... k9:
Setup(); return Number(Key);
break;
case kOk: return Switch(); case kOk: return Switch();
case kRed: return Edit(); case kRed: return Edit();
case kGreen: return New(); case kGreen: return New();
case kYellow: return Delete(); case kYellow: return Delete();
case kBlue: if (!HasSubMenu() && cMenuChannelItem::SortMode() == cMenuChannelItem::csmNumber) case kBlue: if (!HasSubMenu())
Mark(); Mark();
break; break;
default: break; default: break;
@ -771,7 +788,7 @@ cMenuTimers::cMenuTimers(void)
Add(new cMenuTimerItem(timer)); Add(new cMenuTimerItem(timer));
if (Setup.SortTimers) if (Setup.SortTimers)
Sort(); Sort();
SetHelp(tr("Edit"), tr("New"), tr("Delete"), Setup.SortTimers ? tr("On/Off") : tr("Mark")); SetHelp(tr("Button$Edit"), tr("Button$New"), tr("Button$Delete"), Setup.SortTimers ? tr("Button$On/Off") : tr("Button$Mark"));
Timers.IncBeingEdited(); Timers.IncBeingEdited();
} }
@ -897,7 +914,9 @@ cMenuEvent::cMenuEvent(const cEvent *Event, bool CanSwitch)
cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true); cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
if (channel) { if (channel) {
SetTitle(channel->Name()); SetTitle(channel->Name());
SetHelp(tr("Record"), NULL, NULL, CanSwitch ? tr("Switch") : NULL); int TimerMatch = tmNone;
Timers.GetMatch(event, &TimerMatch);
SetHelp(TimerMatch == tmFull ? tr("Timer") : tr("Button$Record"), NULL, NULL, CanSwitch ? tr("Button$Switch") : NULL);
} }
} }
} }
@ -939,36 +958,59 @@ eOSState cMenuEvent::ProcessKey(eKeys Key)
return state; return state;
} }
// --- cMenuWhatsOnItem ------------------------------------------------------ // --- cMenuScheduleItem -----------------------------------------------------
class cMenuWhatsOnItem : public cOsdItem { class cMenuScheduleItem : public cOsdItem {
public: public:
const cEvent *event; const cEvent *event;
const cChannel *channel; const cChannel *channel;
cMenuWhatsOnItem(const cEvent *Event, cChannel *Channel); int timerMatch;
cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL);
bool Update(bool Force = false);
}; };
cMenuWhatsOnItem::cMenuWhatsOnItem(const cEvent *Event, cChannel *Channel) cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel)
{ {
event = Event; event = Event;
channel = Channel; channel = Channel;
char *buffer = NULL; timerMatch = tmNone;
int TimerMatch; Update(true);
char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' '; }
char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
char r = event->IsRunning() ? '*' : ' '; static char *TimerMatchChars = " tT";
asprintf(&buffer, "%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), 6, channel->ShortName(true), *event->GetTimeString(), t, v, r, event->Title());
SetText(buffer, false); bool cMenuScheduleItem::Update(bool Force)
{
bool result = false;
int OldTimerMatch = timerMatch;
Timers.GetMatch(event, &timerMatch);
if (Force || timerMatch != OldTimerMatch) {
char *buffer = NULL;
char t = TimerMatchChars[timerMatch];
char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
char r = event->IsRunning() ? '*' : ' ';
if (channel)
asprintf(&buffer, "%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), 6, channel->ShortName(true), *event->GetTimeString(), t, v, r, event->Title());
else
asprintf(&buffer, "%.*s\t%s\t%c%c%c\t%s", 6, *event->GetDateString(), *event->GetTimeString(), t, v, r, event->Title());
SetText(buffer, false);
result = true;
}
return result;
} }
// --- cMenuWhatsOn ---------------------------------------------------------- // --- cMenuWhatsOn ----------------------------------------------------------
class cMenuWhatsOn : public cOsdMenu { class cMenuWhatsOn : public cOsdMenu {
private: private:
bool now;
int helpKeys;
eOSState Record(void); eOSState Record(void);
eOSState Switch(void); eOSState Switch(void);
static int currentChannel; static int currentChannel;
static const cEvent *scheduleEvent; static const cEvent *scheduleEvent;
bool Update(void);
void SetHelpKeys(void);
public: public:
cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr); cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr);
static int CurrentChannel(void) { return currentChannel; } static int CurrentChannel(void) { return currentChannel; }
@ -983,18 +1025,47 @@ const cEvent *cMenuWhatsOn::scheduleEvent = NULL;
cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4) :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4)
{ {
now = Now;
helpKeys = -1;
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
if (!Channel->GroupSep()) { if (!Channel->GroupSep()) {
const cSchedule *Schedule = Schedules->GetSchedule(Channel->GetChannelID()); const cSchedule *Schedule = Schedules->GetSchedule(Channel->GetChannelID());
if (Schedule) { if (Schedule) {
const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent();
if (Event) if (Event)
Add(new cMenuWhatsOnItem(Event, Channel), Channel->Number() == CurrentChannelNr); Add(new cMenuScheduleItem(Event, Channel), Channel->Number() == CurrentChannelNr);
} }
} }
} }
currentChannel = CurrentChannelNr; currentChannel = CurrentChannelNr;
SetHelp(Count() ? tr("Record") : NULL, Now ? tr("Next") : tr("Now"), tr("Button$Schedule"), tr("Switch")); SetHelpKeys();
}
bool cMenuWhatsOn::Update(void)
{
bool result = false;
for (cOsdItem *item = First(); item; item = Next(item)) {
if (((cMenuScheduleItem *)item)->Update())
result = true;
}
return result;
}
void cMenuWhatsOn::SetHelpKeys(void)
{
cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
int NewHelpKeys = 0;
if (item) {
if (item->timerMatch == tmFull)
NewHelpKeys = 2;
else
NewHelpKeys = 1;
}
if (NewHelpKeys != helpKeys) {
const char *Red[] = { NULL, tr("Button$Record"), tr("Timer") };
SetHelp(Red[NewHelpKeys], now ? tr("Button$Next") : tr("Button$Now"), tr("Button$Schedule"), tr("Button$Switch"));
helpKeys = NewHelpKeys;
}
} }
const cEvent *cMenuWhatsOn::ScheduleEvent(void) const cEvent *cMenuWhatsOn::ScheduleEvent(void)
@ -1006,7 +1077,7 @@ const cEvent *cMenuWhatsOn::ScheduleEvent(void)
eOSState cMenuWhatsOn::Switch(void) eOSState cMenuWhatsOn::Switch(void)
{ {
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current()); cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
if (item) { if (item) {
cChannel *channel = Channels.GetByChannelID(item->event->ChannelID(), true); cChannel *channel = Channels.GetByChannelID(item->event->ChannelID(), true);
if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true)) if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
@ -1018,21 +1089,39 @@ eOSState cMenuWhatsOn::Switch(void)
eOSState cMenuWhatsOn::Record(void) eOSState cMenuWhatsOn::Record(void)
{ {
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current()); cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
if (item) { if (item) {
if (item->timerMatch == tmFull) {
int tm = tmNone;
cTimer *timer = Timers.GetMatch(item->event, &tm);
if (timer)
return AddSubMenu(new cMenuEditTimer(timer));
}
cTimer *timer = new cTimer(item->event); cTimer *timer = new cTimer(item->event);
cTimer *t = Timers.GetTimer(timer); cTimer *t = Timers.GetTimer(timer);
if (t) { if (t) {
delete timer; delete timer;
timer = t; timer = t;
return AddSubMenu(new cMenuEditTimer(timer));
}
else {
Timers.Add(timer);
timer->Matches();
Timers.SetModified();
isyslog("timer %s added (active)", *timer->ToDescr());
if (HasSubMenu())
CloseSubMenu();
if (Update())
Display();
SetHelpKeys();
} }
return AddSubMenu(new cMenuEditTimer(timer, !t));
} }
return osContinue; return osContinue;
} }
eOSState cMenuWhatsOn::ProcessKey(eKeys Key) eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
{ {
bool HadSubMenu = HasSubMenu();
eOSState state = cOsdMenu::ProcessKey(Key); eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) { if (state == osUnknown) {
@ -1042,7 +1131,7 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
case kYellow: state = osBack; case kYellow: state = osBack;
// continue with kGreen // continue with kGreen
case kGreen: { case kGreen: {
cMenuWhatsOnItem *mi = (cMenuWhatsOnItem *)Get(Current()); cMenuScheduleItem *mi = (cMenuScheduleItem *)Get(Current());
if (mi) { if (mi) {
scheduleEvent = mi->event; scheduleEvent = mi->event;
currentChannel = mi->channel->Number(); currentChannel = mi->channel->Number();
@ -1051,34 +1140,20 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
break; break;
case kBlue: return Switch(); case kBlue: return Switch();
case kOk: if (Count()) case kOk: if (Count())
return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->event, true)); return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->event, true));
break; break;
default: break; default: break;
} }
} }
else if (!HasSubMenu()) {
if (HadSubMenu && Update())
Display();
if (Key != kNone)
SetHelpKeys();
}
return state; return state;
} }
// --- cMenuScheduleItem -----------------------------------------------------
class cMenuScheduleItem : public cOsdItem {
public:
const cEvent *event;
cMenuScheduleItem(const cEvent *Event);
};
cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event)
{
event = Event;
char *buffer = NULL;
int TimerMatch;
char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' ';
char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
char r = event->IsRunning() ? '*' : ' ';
asprintf(&buffer, "%.*s\t%s\t%c%c%c\t%s", 6, *event->GetDateString(), *event->GetTimeString(), t, v, r, event->Title());
SetText(buffer, false);
}
// --- cMenuSchedule --------------------------------------------------------- // --- cMenuSchedule ---------------------------------------------------------
class cMenuSchedule : public cOsdMenu { class cMenuSchedule : public cOsdMenu {
@ -1087,9 +1162,12 @@ private:
const cSchedules *schedules; const cSchedules *schedules;
bool now, next; bool now, next;
int otherChannel; int otherChannel;
int helpKeys;
eOSState Record(void); eOSState Record(void);
eOSState Switch(void); eOSState Switch(void);
void PrepareSchedule(cChannel *Channel); void PrepareSchedule(cChannel *Channel);
bool Update(void);
void SetHelpKeys(void);
public: public:
cMenuSchedule(void); cMenuSchedule(void);
virtual ~cMenuSchedule(); virtual ~cMenuSchedule();
@ -1101,12 +1179,13 @@ cMenuSchedule::cMenuSchedule(void)
{ {
now = next = false; now = next = false;
otherChannel = 0; otherChannel = 0;
helpKeys = -1;
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel()); cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
if (channel) { if (channel) {
cMenuWhatsOn::SetCurrentChannel(channel->Number()); cMenuWhatsOn::SetCurrentChannel(channel->Number());
schedules = cSchedules::Schedules(schedulesLock); schedules = cSchedules::Schedules(schedulesLock);
PrepareSchedule(channel); PrepareSchedule(channel);
SetHelp(Count() ? tr("Record") : NULL, tr("Now"), tr("Next")); SetHelpKeys();
} }
} }
@ -1135,17 +1214,61 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel)
} }
} }
bool cMenuSchedule::Update(void)
{
bool result = false;
for (cOsdItem *item = First(); item; item = Next(item)) {
if (((cMenuScheduleItem *)item)->Update())
result = true;
}
return result;
}
void cMenuSchedule::SetHelpKeys(void)
{
cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
int NewHelpKeys = 0;
if (item) {
if (item->timerMatch == tmFull)
NewHelpKeys = 2;
else
NewHelpKeys = 1;
}
if (NewHelpKeys != helpKeys) {
const char *Red[] = { NULL, tr("Button$Record"), tr("Timer") };
SetHelp(Red[NewHelpKeys], tr("Button$Now"), tr("Button$Next"));
helpKeys = NewHelpKeys;
}
}
eOSState cMenuSchedule::Record(void) eOSState cMenuSchedule::Record(void)
{ {
cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current()); cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
if (item) { if (item) {
if (item->timerMatch == tmFull) {
int tm = tmNone;
cTimer *timer = Timers.GetMatch(item->event, &tm);
if (timer)
return AddSubMenu(new cMenuEditTimer(timer));
}
cTimer *timer = new cTimer(item->event); cTimer *timer = new cTimer(item->event);
cTimer *t = Timers.GetTimer(timer); cTimer *t = Timers.GetTimer(timer);
if (t) { if (t) {
delete timer; delete timer;
timer = t; timer = t;
return AddSubMenu(new cMenuEditTimer(timer));
}
else {
Timers.Add(timer);
timer->Matches();
Timers.SetModified();
isyslog("timer %s added (active)", *timer->ToDescr());
if (HasSubMenu())
CloseSubMenu();
if (Update())
Display();
SetHelpKeys();
} }
return AddSubMenu(new cMenuEditTimer(timer, !t));
} }
return osContinue; return osContinue;
} }
@ -1162,6 +1285,7 @@ eOSState cMenuSchedule::Switch(void)
eOSState cMenuSchedule::ProcessKey(eKeys Key) eOSState cMenuSchedule::ProcessKey(eKeys Key)
{ {
bool HadSubMenu = HasSubMenu();
eOSState state = cOsdMenu::ProcessKey(Key); eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) { if (state == osUnknown) {
@ -1204,11 +1328,15 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
PrepareSchedule(channel); PrepareSchedule(channel);
if (channel->Number() != cDevice::CurrentChannel()) { if (channel->Number() != cDevice::CurrentChannel()) {
otherChannel = channel->Number(); otherChannel = channel->Number();
SetHelp(Count() ? tr("Record") : NULL, tr("Now"), tr("Next"), tr("Switch")); SetHelp(Count() ? tr("Button$Record") : NULL, tr("Button$Now"), tr("Button$Next"), tr("Button$Switch"));
} }
Display(); Display();
} }
} }
else if (HadSubMenu && Update())
Display();
if (Key != kNone)
SetHelpKeys();
} }
return state; return state;
} }
@ -1461,7 +1589,7 @@ cMenuRecording::cMenuRecording(const cRecording *Recording)
{ {
recording = Recording; recording = Recording;
if (recording) if (recording)
SetHelp(tr("Play"), tr("Rewind")); SetHelp(tr("Button$Play"), tr("Button$Rewind"));
} }
void cMenuRecording::Display(void) void cMenuRecording::Display(void)
@ -1586,9 +1714,9 @@ void cMenuRecordings::SetHelpKeys(void)
if (NewHelpKeys != helpKeys) { if (NewHelpKeys != helpKeys) {
switch (NewHelpKeys) { switch (NewHelpKeys) {
case 0: SetHelp(NULL); break; case 0: SetHelp(NULL); break;
case 1: SetHelp(tr("Open")); break; case 1: SetHelp(tr("Button$Open")); break;
case 2: case 2:
case 3: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Info") : NULL); case 3: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Button$Play"), tr("Button$Rewind"), tr("Button$Delete"), NewHelpKeys == 3 ? tr("Info") : NULL);
} }
helpKeys = NewHelpKeys; helpKeys = NewHelpKeys;
} }
@ -1876,6 +2004,7 @@ void cMenuSetupOSD::Set(void)
Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"), &data.ChannelInfoTime, 1, 60)); Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"), &data.ChannelInfoTime, 1, 60));
Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch));
Add(new cMenuEditBoolItem(tr("Setup.OSD$Timeout requested channel info"), &data.TimeoutRequChInfo));
Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage));
Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap));
Add(new cMenuEditBoolItem(tr("Setup.OSD$Sort timers"), &data.SortTimers)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Sort timers"), &data.SortTimers));
@ -1918,7 +2047,7 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys Key)
themeIndex = d ? themes.GetThemeIndex(d) : 0; themeIndex = d ? themes.GetThemeIndex(d) : 0;
free(d); free(d);
} }
Set(); Set();
Setup.OSDLanguage = OriginalOSDLanguage; Setup.OSDLanguage = OriginalOSDLanguage;
} }
@ -1943,7 +2072,7 @@ cMenuSetupEPG::cMenuSetupEPG(void)
; ;
originalNumLanguages = numLanguages; originalNumLanguages = numLanguages;
SetSection(tr("EPG")); SetSection(tr("EPG"));
SetHelp(tr("Scan")); SetHelp(tr("Button$Scan"));
Setup(); Setup();
} }
@ -2196,7 +2325,7 @@ cMenuSetupCICAM::cMenuSetupCICAM(void)
} }
} }
} }
SetHelp(tr("Menu"), tr("Reset")); SetHelp(tr("Button$Menu"), tr("Button$Reset"));
} }
eOSState cMenuSetupCICAM::Menu(void) eOSState cMenuSetupCICAM::Menu(void)
@ -2469,14 +2598,19 @@ cMenuPluginItem::cMenuPluginItem(const char *Name, int Index)
// --- cMenuMain ------------------------------------------------------------- // --- cMenuMain -------------------------------------------------------------
#define STOP_RECORDING tr(" Stop recording ") #define STOP_RECORDING tr(" Stop recording ")
#define ON_PRIMARY_INTERFACE tr("on primary interface")
cOsdObject *cMenuMain::pluginOsdObject = NULL; cOsdObject *cMenuMain::pluginOsdObject = NULL;
cMenuMain::cMenuMain(bool Replaying, eOSState State) cMenuMain::cMenuMain(eOSState State)
:cOsdMenu("") :cOsdMenu("")
{ {
replaying = Replaying; lastDiskSpaceCheck = 0;
lastFreeMB = 0;
replaying = false;
stopReplayItem = NULL;
cancelEditingItem = NULL;
stopRecordingItem = NULL;
recordControlsState = 0;
Set(); Set();
// Initial submenus: // Initial submenus:
@ -2502,23 +2636,9 @@ cOsdObject *cMenuMain::PluginOsdObject(void)
void cMenuMain::Set(void) void cMenuMain::Set(void)
{ {
Clear(); Clear();
//XXX //SetTitle("VDR"); // this is done below, including disk usage SetTitle("VDR");
SetHasHotkeys(); SetHasHotkeys();
// Title with disk usage:
#define MB_PER_MINUTE 25.75 // this is just an estimate!
char buffer[40];
int FreeMB;
int Percent = VideoDiskSpace(&FreeMB);
int Minutes = int(double(FreeMB) / MB_PER_MINUTE);
int Hours = Minutes / 60;
Minutes %= 60;
snprintf(buffer, sizeof(buffer), "%s - %s %d%% - %2d:%02d %s", tr("VDR"), tr("Disk"), Percent, Hours, Minutes, tr("free"));
//XXX -> skin function!!!
SetTitle(buffer);
// Basic menu items: // Basic menu items:
Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); Add(new cOsdItem(hk(tr("Schedule")), osSchedule));
@ -2545,37 +2665,82 @@ void cMenuMain::Set(void)
if (Commands.Count()) if (Commands.Count())
Add(new cOsdItem(hk(tr("Commands")), osCommands)); Add(new cOsdItem(hk(tr("Commands")), osCommands));
// Replay control: Update(true);
if (replaying) Display();
Add(new cOsdItem(tr(" Stop replaying"), osStopReplay)); }
// Record control: #define MB_PER_MINUTE 25.75 // this is just an estimate!
if (cRecordControls::StopPrimary()) { bool cMenuMain::Update(bool Force)
char *buffer = NULL; {
asprintf(&buffer, "%s%s", STOP_RECORDING, ON_PRIMARY_INTERFACE); bool result = false;
Add(new cOsdItem(buffer, osStopRecord));
free(buffer); // Title with disk usage:
if (Force || time(NULL) - lastDiskSpaceCheck > DISKSPACECHEK) {
int FreeMB;
int Percent = VideoDiskSpace(&FreeMB);
if (Force || FreeMB != lastFreeMB) {
int Minutes = int(double(FreeMB) / MB_PER_MINUTE);
int Hours = Minutes / 60;
Minutes %= 60;
char buffer[40];
snprintf(buffer, sizeof(buffer), "%s - %s %d%% - %2d:%02d %s", tr("VDR"), tr("Disk"), Percent, Hours, Minutes, tr("free"));
//XXX -> skin function!!!
SetTitle(buffer);
result = true;
}
lastDiskSpaceCheck = time(NULL);
} }
const char *s = NULL; bool NewReplaying = cControl::Control() != NULL;
while ((s = cRecordControls::GetInstantId(s)) != NULL) { if (Force || NewReplaying != replaying) {
char *buffer = NULL; replaying = NewReplaying;
asprintf(&buffer, "%s%s", STOP_RECORDING, s); // Replay control:
Add(new cOsdItem(buffer, osStopRecord)); if (replaying && !stopReplayItem)
free(buffer); Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay));
else if (stopReplayItem && !replaying) {
Del(stopReplayItem->Index());
stopReplayItem = NULL;
} }
// Color buttons:
SetHelp(!replaying ? tr("Button$Record") : NULL, tr("Button$Audio"), replaying ? NULL : tr("Button$Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Button$Resume") : NULL);
result = true;
}
// Editing control: // Editing control:
bool CutterActive = cCutter::Active();
if (CutterActive && !cancelEditingItem) {
Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit));
result = true;
}
else if (cancelEditingItem && !CutterActive) {
Del(cancelEditingItem->Index());
cancelEditingItem = NULL;
result = true;
}
if (cCutter::Active()) // Record control:
Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); if (cRecordControls::StateChanged(recordControlsState)) {
while (stopRecordingItem) {
cOsdItem *it = Next(stopRecordingItem);
Del(stopRecordingItem->Index());
stopRecordingItem = it;
}
const char *s = NULL;
while ((s = cRecordControls::GetInstantId(s)) != NULL) {
char *buffer = NULL;
asprintf(&buffer, "%s%s", STOP_RECORDING, s);
cOsdItem *item = new cOsdItem(osStopRecord);
item->SetText(buffer, false);
Add(item);
if (!stopRecordingItem)
stopRecordingItem = item;
}
result = true;
}
// Color buttons: return result;
SetHelp(!replaying ? tr("Record") : NULL, tr("Audio"), replaying ? NULL : tr("Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
Display();
} }
eOSState cMenuMain::ProcessKey(eKeys Key) eOSState cMenuMain::ProcessKey(eKeys Key)
@ -2595,11 +2760,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
cOsdItem *item = Get(Current()); cOsdItem *item = Get(Current());
if (item) { if (item) {
const char *s = item->Text() + strlen(STOP_RECORDING); cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING));
if (strcmp(s, ON_PRIMARY_INTERFACE) == 0)
cRecordControls::StopPrimary(true);
else
cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING));
return osEnd; return osEnd;
} }
} }
@ -2647,6 +2808,8 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
default: break; default: break;
} }
} }
if (!HasSubMenu() && Update(HadSubMenu))
Display();
if (Key != kNone) { if (Key != kNone) {
if (Setup.OSDLanguage != osdLanguage) { if (Setup.OSDLanguage != osdLanguage) {
Set(); Set();
@ -2710,6 +2873,7 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched)
withInfo = !Switched || Setup.ShowInfoOnChSwitch; withInfo = !Switched || Setup.ShowInfoOnChSwitch;
displayChannel = Skins.Current()->DisplayChannel(withInfo); displayChannel = Skins.Current()->DisplayChannel(withInfo);
number = 0; number = 0;
timeout = Switched || Setup.TimeoutRequChInfo;
channel = Channels.GetByNumber(Number); channel = Channels.GetByNumber(Number);
lastPresent = lastFollowing = NULL; lastPresent = lastFollowing = NULL;
if (channel) { if (channel) {
@ -2893,7 +3057,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
return osEnd; return osEnd;
} }
}; };
if (lastTime.Elapsed() < (uint64)(Setup.ChannelInfoTime * 1000)) { if (!timeout || lastTime.Elapsed() < (uint64)(Setup.ChannelInfoTime * 1000)) {
if (!number && group < 0 && channel && channel->Number() != cDevice::CurrentChannel()) if (!number && group < 0 && channel && channel->Number() != cDevice::CurrentChannel())
Refresh(); // makes sure a channel switch through the SVDRP CHAN command is displayed Refresh(); // makes sure a channel switch through the SVDRP CHAN command is displayed
DisplayInfo(); DisplayInfo();
@ -2996,7 +3160,7 @@ cDisplayTracks::cDisplayTracks(void)
} }
} }
timeout.Set(TRACKTIMEOUT); timeout.Set(TRACKTIMEOUT);
displayTracks = Skins.Current()->DisplayTracks(tr("Audio"), numTracks, descriptions); displayTracks = Skins.Current()->DisplayTracks(tr("Button$Audio"), numTracks, descriptions);
Show(); Show();
} }
@ -3147,7 +3311,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids()); recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids());
if (device->AttachReceiver(recorder)) { if (device->AttachReceiver(recorder)) {
Recording.WriteInfo(); Recording.WriteInfo();
cStatus::MsgRecording(device, Recording.Name()); cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo() if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
cReplayControl::SetRecording(fileName, Recording.Name()); cReplayControl::SetRecording(fileName, Recording.Name());
Recordings.AddByName(fileName); Recordings.AddByName(fileName);
@ -3206,7 +3370,7 @@ void cRecordControl::Stop(void)
DELETENULL(recorder); DELETENULL(recorder);
timer->SetRecording(false); timer->SetRecording(false);
timer = NULL; timer = NULL;
cStatus::MsgRecording(device, NULL); cStatus::MsgRecording(device, NULL, fileName, false);
cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName);
} }
} }
@ -3222,9 +3386,11 @@ bool cRecordControl::Process(time_t t)
// --- cRecordControls ------------------------------------------------------- // --- cRecordControls -------------------------------------------------------
cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL }; cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL };
int cRecordControls::state = 0;
bool cRecordControls::Start(cTimer *Timer, bool Pause) bool cRecordControls::Start(cTimer *Timer, bool Pause)
{ {
ChangeState();
int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel(); int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
cChannel *channel = Channels.GetByNumber(ch); cChannel *channel = Channels.GetByNumber(ch);
@ -3262,6 +3428,7 @@ bool cRecordControls::Start(cTimer *Timer, bool Pause)
void cRecordControls::Stop(const char *InstantId) void cRecordControls::Stop(const char *InstantId)
{ {
ChangeState();
for (int i = 0; i < MAXRECORDCONTROLS; i++) { for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) { if (RecordControls[i]) {
const char *id = RecordControls[i]->InstantId(); const char *id = RecordControls[i]->InstantId();
@ -3281,6 +3448,7 @@ void cRecordControls::Stop(const char *InstantId)
void cRecordControls::Stop(cDevice *Device) void cRecordControls::Stop(cDevice *Device)
{ {
ChangeState();
for (int i = 0; i < MAXRECORDCONTROLS; i++) { for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) { if (RecordControls[i]) {
if (RecordControls[i]->Device() == Device) { if (RecordControls[i]->Device() == Device) {
@ -3291,20 +3459,6 @@ void cRecordControls::Stop(cDevice *Device)
} }
} }
bool cRecordControls::StopPrimary(bool DoIt)
{
if (cDevice::PrimaryDevice()->Receiving()) {
//XXX+ disabled for the moment - might become obsolete with DVB_DRIVER_VERSION >= 2002090101
cDevice *device = NULL;//XXX cDevice::GetDevice(cDevice::PrimaryDevice()->Ca(), 0);
if (device) {
if (DoIt)
Stop(cDevice::PrimaryDevice());
return true;
}
}
return false;
}
bool cRecordControls::PauseLiveVideo(void) bool cRecordControls::PauseLiveVideo(void)
{ {
Skins.Message(mtStatus, tr("Pausing live video...")); Skins.Message(mtStatus, tr("Pausing live video..."));
@ -3349,8 +3503,10 @@ void cRecordControls::Process(time_t t)
{ {
for (int i = 0; i < MAXRECORDCONTROLS; i++) { for (int i = 0; i < MAXRECORDCONTROLS; i++) {
if (RecordControls[i]) { if (RecordControls[i]) {
if (!RecordControls[i]->Process(t)) if (!RecordControls[i]->Process(t)) {
DELETENULL(RecordControls[i]); DELETENULL(RecordControls[i]);
ChangeState();
}
} }
} }
} }
@ -3365,6 +3521,7 @@ void cRecordControls::ChannelDataModified(cChannel *Channel)
RecordControls[i]->Stop(); RecordControls[i]->Stop();
// This will restart the recording, maybe even from a different // This will restart the recording, maybe even from a different
// device in case conditional access has changed. // device in case conditional access has changed.
ChangeState();
} }
} }
} }
@ -3384,6 +3541,15 @@ void cRecordControls::Shutdown(void)
{ {
for (int i = 0; i < MAXRECORDCONTROLS; i++) for (int i = 0; i < MAXRECORDCONTROLS; i++)
DELETENULL(RecordControls[i]); DELETENULL(RecordControls[i]);
ChangeState();
}
bool cRecordControls::StateChanged(int &State)
{
int NewState = state;
bool Result = State != NewState;
State = state;
return Result;
} }
// --- cReplayControl -------------------------------------------------------- // --- cReplayControl --------------------------------------------------------
@ -3403,13 +3569,13 @@ cReplayControl::cReplayControl(void)
timeSearchActive = false; timeSearchActive = false;
marks.Load(fileName); marks.Load(fileName);
cRecording Recording(fileName); cRecording Recording(fileName);
cStatus::MsgReplaying(this, Recording.Name()); cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
} }
cReplayControl::~cReplayControl() cReplayControl::~cReplayControl()
{ {
Hide(); Hide();
cStatus::MsgReplaying(this, NULL); cStatus::MsgReplaying(this, NULL, fileName, false);
Stop(); Stop();
} }
@ -3698,6 +3864,14 @@ void cReplayControl::EditTest(void)
} }
} }
cOsdObject *cReplayControl::GetInfo(void)
{
cRecording *Recording = Recordings.GetByName(cReplayControl::LastReplayed());
if (Recording)
return new cMenuRecording(Recording);
return NULL;
}
eOSState cReplayControl::ProcessKey(eKeys Key) eOSState cReplayControl::ProcessKey(eKeys Key)
{ {
if (!Active()) if (!Active())

17
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.h 1.77 2005/11/05 17:26:09 kls Exp $ * $Id: menu.h 1.81 2006/01/06 11:30:38 kls Exp $
*/ */
#ifndef __MENU_H #ifndef __MENU_H
@ -55,11 +55,18 @@ public:
class cMenuMain : public cOsdMenu { class cMenuMain : public cOsdMenu {
private: private:
time_t lastDiskSpaceCheck;
int lastFreeMB;
bool replaying; bool replaying;
cOsdItem *stopReplayItem;
cOsdItem *cancelEditingItem;
cOsdItem *stopRecordingItem;
int recordControlsState;
static cOsdObject *pluginOsdObject; static cOsdObject *pluginOsdObject;
void Set(void); void Set(void);
bool Update(bool Force = false);
public: public:
cMenuMain(bool Replaying, eOSState State = osUnknown); cMenuMain(eOSState State = osUnknown);
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
static cOsdObject *PluginOsdObject(void); static cOsdObject *PluginOsdObject(void);
}; };
@ -71,6 +78,7 @@ private:
bool withInfo; bool withInfo;
cTimeMs lastTime; cTimeMs lastTime;
int number; int number;
bool timeout;
cChannel *channel; cChannel *channel;
const cEvent *lastPresent; const cEvent *lastPresent;
const cEvent *lastFollowing; const cEvent *lastFollowing;
@ -189,11 +197,11 @@ public:
class cRecordControls { class cRecordControls {
private: private:
static cRecordControl *RecordControls[]; static cRecordControl *RecordControls[];
static int state;
public: public:
static bool Start(cTimer *Timer = NULL, bool Pause = false); static bool Start(cTimer *Timer = NULL, bool Pause = false);
static void Stop(const char *InstantId); static void Stop(const char *InstantId);
static void Stop(cDevice *Device); static void Stop(cDevice *Device);
static bool StopPrimary(bool DoIt = false);
static bool PauseLiveVideo(void); static bool PauseLiveVideo(void);
static const char *GetInstantId(const char *LastInstantId); static const char *GetInstantId(const char *LastInstantId);
static cRecordControl *GetRecordControl(const char *FileName); static cRecordControl *GetRecordControl(const char *FileName);
@ -201,6 +209,8 @@ public:
static void ChannelDataModified(cChannel *Channel); static void ChannelDataModified(cChannel *Channel);
static bool Active(void); static bool Active(void);
static void Shutdown(void); static void Shutdown(void);
static void ChangeState(void) { state++; }
static bool StateChanged(int &State);
}; };
class cReplayControl : public cDvbPlayerControl { class cReplayControl : public cDvbPlayerControl {
@ -230,6 +240,7 @@ private:
public: public:
cReplayControl(void); cReplayControl(void);
virtual ~cReplayControl(); virtual ~cReplayControl();
virtual cOsdObject *GetInfo(void);
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
virtual void Show(void); virtual void Show(void);
virtual void Hide(void); virtual void Hide(void);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menuitems.c 1.24 2005/11/12 12:22:10 kls Exp $ * $Id: menuitems.c 1.29 2006/01/07 15:37:03 kls Exp $
*/ */
#include "menuitems.h" #include "menuitems.h"
@ -15,7 +15,7 @@
#include "skins.h" #include "skins.h"
#include "status.h" #include "status.h"
const char *FileNameChars = " abcdefghijklmnopqrstuvwxyz0123456789-.#~"; const char *FileNameChars = " abcdefghijklmnopqrstuvwxyz0123456789-.#~,/_@";
// --- cMenuEditItem --------------------------------------------------------- // --- cMenuEditItem ---------------------------------------------------------
@ -116,7 +116,7 @@ void cMenuEditBoolItem::Set(void)
// --- cMenuEditBitItem ------------------------------------------------------ // --- cMenuEditBitItem ------------------------------------------------------
cMenuEditBitItem::cMenuEditBitItem(const char *Name, int *Value, int Mask, const char *FalseString, const char *TrueString) cMenuEditBitItem::cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString, const char *TrueString)
:cMenuEditBoolItem(Name, &bit, FalseString, TrueString) :cMenuEditBoolItem(Name, &bit, FalseString, TrueString)
{ {
value = Value; value = Value;
@ -243,6 +243,9 @@ cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, co
pos = -1; pos = -1;
insert = uppercase = false; insert = uppercase = false;
newchar = true; newchar = true;
charMap = tr(" 0\t-.#~,/_@1\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
currentChar = NULL;
lastKey = kNone;
Set(); Set();
} }
@ -253,8 +256,8 @@ cMenuEditStrItem::~cMenuEditStrItem()
void cMenuEditStrItem::SetHelpKeys(void) void cMenuEditStrItem::SetHelpKeys(void)
{ {
if (pos >= 0) if (InEditMode())
cSkinDisplay::Current()->SetButtons(tr("ABC/abc"), tr(insert ? "Overwrite" : "Insert"), tr("Delete")); cSkinDisplay::Current()->SetButtons(tr("Button$ABC/abc"), tr(insert ? "Button$Overwrite" : "Button$Insert"), tr("Button$Delete"));
else else
cSkinDisplay::Current()->SetButtons(NULL); cSkinDisplay::Current()->SetButtons(NULL);
} }
@ -264,7 +267,7 @@ void cMenuEditStrItem::Set(void)
char buf[1000]; char buf[1000];
const char *fmt = insert && newchar ? "[]%c%s" : "[%c]%s"; const char *fmt = insert && newchar ? "[]%c%s" : "[%c]%s";
if (pos >= 0) { if (InEditMode()) {
const cFont *font = cFont::GetFont(fontOsd); const cFont *font = cFont::GetFont(fontOsd);
strncpy(buf, value, pos); strncpy(buf, value, pos);
snprintf(buf + pos, sizeof(buf) - pos - 2, fmt, *(value + pos), value + pos + 1); snprintf(buf + pos, sizeof(buf) - pos - 2, fmt, *(value + pos), value + pos + 1);
@ -320,9 +323,12 @@ char cMenuEditStrItem::Inc(char c, bool Up)
eOSState cMenuEditStrItem::ProcessKey(eKeys Key) eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
{ {
bool SameKey = Key == lastKey;
if (Key != kNone)
lastKey = Key;
switch (Key) { switch (Key) {
case kRed: // Switch between upper- and lowercase characters case kRed: // Switch between upper- and lowercase characters
if (pos >= 0) { if (InEditMode()) {
if (!insert || !newchar) { if (!insert || !newchar) {
uppercase = !uppercase; uppercase = !uppercase;
value[pos] = uppercase ? toupper(value[pos]) : tolower(value[pos]); value[pos] = uppercase ? toupper(value[pos]) : tolower(value[pos]);
@ -332,7 +338,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
return osUnknown; return osUnknown;
break; break;
case kGreen: // Toggle insert/overwrite modes case kGreen: // Toggle insert/overwrite modes
if (pos >= 0) { if (InEditMode()) {
insert = !insert; insert = !insert;
newchar = true; newchar = true;
SetHelpKeys(); SetHelpKeys();
@ -342,7 +348,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
break; break;
case kYellow|k_Repeat: case kYellow|k_Repeat:
case kYellow: // Remove the character at current position; in insert mode it is the character to the right of cursor case kYellow: // Remove the character at current position; in insert mode it is the character to the right of cursor
if (pos >= 0) { if (InEditMode()) {
if (strlen(value) > 1) { if (strlen(value) > 1) {
if (!insert || pos < int(strlen(value)) - 1) if (!insert || pos < int(strlen(value)) - 1)
memmove(value + pos, value + pos + 1, strlen(value) - pos); memmove(value + pos, value + pos + 1, strlen(value) - pos);
@ -361,7 +367,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
break; break;
case kBlue|k_Repeat: case kBlue|k_Repeat:
case kBlue: // consume the key only if in edit-mode case kBlue: // consume the key only if in edit-mode
if (pos >= 0) if (InEditMode())
; ;
else else
return osUnknown; return osUnknown;
@ -395,7 +401,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
case kUp|k_Repeat: case kUp|k_Repeat:
case kUp: case kUp:
case kDown|k_Repeat: case kDown|k_Repeat:
case kDown: if (pos >= 0) { case kDown: if (InEditMode()) {
if (insert && newchar) { if (insert && newchar) {
// create a new character in insert mode // create a new character in insert mode
if (int(strlen(value)) < length - 1) { if (int(strlen(value)) < length - 1) {
@ -412,7 +418,39 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
else else
return cMenuEditItem::ProcessKey(Key); return cMenuEditItem::ProcessKey(Key);
break; break;
case kOk: if (pos >= 0) { case k0 ... k9: {
if (!SameKey)
currentChar = NULL;
if (InEditMode()) {
if (insert && newchar) {
// create a new character in insert mode
if (int(strlen(value)) < length - 1) {
memmove(value + pos + 1, value + pos, strlen(value) - pos + 1);
value[pos] = ' ';
}
}
if (!currentChar || !*currentChar || *currentChar == '\t') {
// find the beginning of the character map entry for Key
int n = Key - k0;
currentChar = charMap;
while (n > 0 && *currentChar) {
if (*currentChar++ == '\t')
n--;
}
}
if (*currentChar && *currentChar != '\t') {
value[pos] = *currentChar;
if (uppercase)
value[pos] = toupper(value[pos]);
currentChar++;
}
newchar = false;
}
else
return cMenuEditItem::ProcessKey(Key);
}
break;
case kOk: if (InEditMode()) {
pos = -1; pos = -1;
newchar = true; newchar = true;
stripspace(value); stripspace(value);
@ -420,7 +458,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
break; break;
} }
// run into default // run into default
default: if (pos >= 0 && BASICKEY(Key) == kKbd) { default: if (InEditMode() && BASICKEY(Key) == kKbd) {
int c = KEYKBD(Key); int c = KEYKBD(Key);
if (c <= 0xFF) { if (c <= 0xFF) {
const char *p = strchr(allowed, tolower(c)); const char *p = strchr(allowed, tolower(c));
@ -667,6 +705,7 @@ eOSState cMenuEditDateItem::ProcessKey(eKeys Key)
} }
else { else {
*weekdays = days[cTimer::GetWDay(*value)]; *weekdays = days[cTimer::GetWDay(*value)];
dayindex = FindDayIndex(*weekdays);
oldvalue = *value; oldvalue = *value;
*value = 0; *value = 0;
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menuitems.h 1.12 2005/11/11 13:26:51 kls Exp $ * $Id: menuitems.h 1.15 2006/01/06 15:16:25 kls Exp $
*/ */
#ifndef __MENUITEMS_H #ifndef __MENUITEMS_H
@ -44,12 +44,12 @@ public:
class cMenuEditBitItem : public cMenuEditBoolItem { class cMenuEditBitItem : public cMenuEditBoolItem {
protected: protected:
int *value; uint *value;
uint mask;
int bit; int bit;
int mask;
virtual void Set(void); virtual void Set(void);
public: public:
cMenuEditBitItem(const char *Name, int *Value, int Mask, const char *FalseString = NULL, const char *TrueString = NULL); cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString = NULL, const char *TrueString = NULL);
}; };
class cMenuEditNumItem : public cMenuEditItem { class cMenuEditNumItem : public cMenuEditItem {
@ -82,9 +82,14 @@ private:
char *allowed; char *allowed;
int pos; int pos;
bool insert, newchar, uppercase; bool insert, newchar, uppercase;
const char *charMap;
const char *currentChar;
eKeys lastKey;
void SetHelpKeys(void); void SetHelpKeys(void);
virtual void Set(void); virtual void Set(void);
char Inc(char c, bool Up); char Inc(char c, bool Up);
protected:
bool InEditMode(void) { return pos >= 0; }
public: public:
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed); cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed);
~cMenuEditStrItem(); ~cMenuEditStrItem();

4
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.c 1.64 2005/11/04 14:19:31 kls Exp $ * $Id: osd.c 1.65 2005/12/30 15:42:04 kls Exp $
*/ */
#include "osd.h" #include "osd.h"
@ -145,7 +145,7 @@ void cBitmap::SetSize(int Width, int Height)
esyslog("ERROR: can't allocate bitmap!"); esyslog("ERROR: can't allocate bitmap!");
} }
else else
esyslog("ERROR: illegal bitmap parameters (%d, %d)!", width, height); esyslog("ERROR: invalid bitmap parameters (%d, %d)!", width, height);
} }
bool cBitmap::Contains(int x, int y) const bool cBitmap::Contains(int x, int y) const

3
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.h 1.49 2005/06/19 10:35:25 kls Exp $ * $Id: osd.h 1.50 2005/12/18 12:56:21 kls Exp $
*/ */
#ifndef __OSD_H #ifndef __OSD_H
@ -37,6 +37,7 @@ enum eOsdError { oeOk,
oeAreasOverlap, oeAreasOverlap,
oeWrongAlignment, oeWrongAlignment,
oeOutOfMemory, oeOutOfMemory,
oeWrongAreaSize,
oeUnknown, oeUnknown,
}; };

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osdbase.c 1.24 2005/10/09 10:56:26 kls Exp $ * $Id: osdbase.c 1.28 2006/01/08 11:40:02 kls Exp $
*/ */
#include "osdbase.h" #include "osdbase.h"
@ -19,7 +19,6 @@
cOsdItem::cOsdItem(eOSState State) cOsdItem::cOsdItem(eOSState State)
{ {
text = NULL; text = NULL;
offset = -1;
state = State; state = State;
selectable = true; selectable = true;
fresh = true; fresh = true;
@ -28,7 +27,6 @@ cOsdItem::cOsdItem(eOSState State)
cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable) cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable)
{ {
text = NULL; text = NULL;
offset = -1;
state = State; state = State;
selectable = Selectable; selectable = Selectable;
fresh = true; fresh = true;
@ -61,6 +59,14 @@ eOSState cOsdItem::ProcessKey(eKeys Key)
return Key == kOk ? state : osUnknown; return Key == kOk ? state : osUnknown;
} }
// --- cOsdObject ------------------------------------------------------------
void cOsdObject::Show(void)
{
if (isMenu)
((cOsdMenu *)this)->Display();
}
// --- cOsdMenu -------------------------------------------------------------- // --- cOsdMenu --------------------------------------------------------------
cSkinDisplayMenu *cOsdMenu::displayMenu = NULL; cSkinDisplayMenu *cOsdMenu::displayMenu = NULL;
@ -155,10 +161,10 @@ void cOsdMenu::Del(int Index)
{ {
cList<cOsdItem>::Del(Get(Index)); cList<cOsdItem>::Del(Get(Index));
int count = Count(); int count = Count();
while (current < count && !SelectableItem(current)) while (current < count && !SelectableItem(current))
current++; current++;
if (current == count) { if (current == count) {
while (current > 0 && !SelectableItem(current)) while (current > 0 && !SelectableItem(current))
current--; current--;
} }
if (Index == first && first > 0) if (Index == first && first > 0)
@ -252,6 +258,8 @@ void cOsdMenu::DisplayCurrent(bool Current)
void cOsdMenu::Clear(void) void cOsdMenu::Clear(void)
{ {
if (marked >= 0)
SetStatus(NULL);
first = 0; first = 0;
current = marked = -1; current = marked = -1;
cList<cOsdItem>::Clear(); cList<cOsdItem>::Clear();
@ -363,7 +371,7 @@ void cOsdMenu::PageUp(void)
CursorUp(); CursorUp();
} }
void cOsdMenu::PageDown(void) void cOsdMenu::PageDown(void)
{ {
int oldCurrent = current; int oldCurrent = current;
int oldFirst = first; int oldFirst = first;
@ -455,6 +463,7 @@ eOSState cOsdMenu::ProcessKey(eKeys Key)
} }
} }
switch (Key) { switch (Key) {
case k0: return osUnknown;
case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown; case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
case kUp|k_Repeat: case kUp|k_Repeat:
case kUp: CursorUp(); break; case kUp: CursorUp(); break;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osdbase.h 1.12 2005/10/02 09:18:20 kls Exp $ * $Id: osdbase.h 1.14 2006/01/06 11:55:30 kls Exp $
*/ */
#ifndef __OSDBASE_H #ifndef __OSDBASE_H
@ -49,7 +49,6 @@ enum eOSState { osUnknown,
class cOsdItem : public cListObject { class cOsdItem : public cListObject {
private: private:
char *text; char *text;
int offset;
eOSState state; eOSState state;
bool selectable; bool selectable;
protected: protected:
@ -78,7 +77,7 @@ public:
virtual ~cOsdObject() {} virtual ~cOsdObject() {}
bool NeedsFastResponse(void) { return needsFastResponse; } bool NeedsFastResponse(void) { return needsFastResponse; }
bool IsMenu(void) { return isMenu; } bool IsMenu(void) { return isMenu; }
virtual void Show(void) {} virtual void Show(void);
virtual eOSState ProcessKey(eKeys Key) { return osUnknown; } virtual eOSState ProcessKey(eKeys Key) { return osUnknown; }
}; };

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: player.c 1.9 2004/12/12 11:21:07 kls Exp $ * $Id: player.c 1.11 2006/01/06 11:30:07 kls Exp $
*/ */
#include "player.h" #include "player.h"
@ -40,6 +40,7 @@ void cPlayer::Detach(void)
// --- cControl -------------------------------------------------------------- // --- cControl --------------------------------------------------------------
cControl *cControl::control = NULL; cControl *cControl::control = NULL;
cMutex cControl::mutex;
cControl::cControl(cPlayer *Player, bool Hidden) cControl::cControl(cPlayer *Player, bool Hidden)
{ {
@ -54,19 +55,27 @@ cControl::~cControl()
control = NULL; control = NULL;
} }
cOsdObject *cControl::GetInfo(void)
{
return NULL;
}
cControl *cControl::Control(void) cControl *cControl::Control(void)
{ {
cMutexLock MutexLock(&mutex);
return (control && !control->hidden) ? control : NULL; return (control && !control->hidden) ? control : NULL;
} }
void cControl::Launch(cControl *Control) void cControl::Launch(cControl *Control)
{ {
cMutexLock MutexLock(&mutex);
delete control; delete control;
control = Control; control = Control;
} }
void cControl::Attach(void) void cControl::Attach(void)
{ {
cMutexLock MutexLock(&mutex);
if (control && !control->attached && control->player && !control->player->IsAttached()) { if (control && !control->attached && control->player && !control->player->IsAttached()) {
if (cDevice::PrimaryDevice()->AttachPlayer(control->player)) if (cDevice::PrimaryDevice()->AttachPlayer(control->player))
control->attached = true; control->attached = true;
@ -79,6 +88,7 @@ void cControl::Attach(void)
void cControl::Shutdown(void) void cControl::Shutdown(void)
{ {
cMutexLock MutexLock(&mutex);
cControl *c = control; // avoids recursions cControl *c = control; // avoids recursions
control = NULL; control = NULL;
delete c; delete c;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: player.h 1.17 2005/05/22 11:07:42 kls Exp $ * $Id: player.h 1.19 2006/01/06 11:29:27 kls Exp $
*/ */
#ifndef __PLAYER_H #ifndef __PLAYER_H
@ -62,6 +62,7 @@ public:
class cControl : public cOsdObject { class cControl : public cOsdObject {
private: private:
static cControl *control; static cControl *control;
static cMutex mutex;
bool attached; bool attached;
bool hidden; bool hidden;
protected: protected:
@ -70,6 +71,7 @@ public:
cControl(cPlayer *Player, bool Hidden = false); cControl(cPlayer *Player, bool Hidden = false);
virtual ~cControl(); virtual ~cControl();
virtual void Hide(void) = 0; virtual void Hide(void) = 0;
virtual cOsdObject *GetInfo(void);
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { return player->GetIndex(Current, Total, SnapToIFrame); } bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { return player->GetIndex(Current, Total, SnapToIFrame); }
bool GetReplayMode(bool &Play, bool &Forward, int &Speed) { return player->GetReplayMode(Play, Forward, Speed); } bool GetReplayMode(bool &Play, bool &Forward, int &Speed) { return player->GetReplayMode(Play, Forward, Speed); }
static void Launch(cControl *Control); static void Launch(cControl *Control);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: plugin.c 1.15 2005/08/27 16:13:24 kls Exp $ * $Id: plugin.c 1.16 2006/01/08 11:40:05 kls Exp $
*/ */
#include "plugin.h" #include "plugin.h"
@ -25,7 +25,7 @@
char *cPlugin::configDirectory = NULL; char *cPlugin::configDirectory = NULL;
cPlugin::cPlugin(void) cPlugin::cPlugin(void)
{ {
name = NULL; name = NULL;
started = false; started = false;

100
rcu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: rcu.c 1.10 2005/08/15 12:30:21 kls Exp $ * $Id: rcu.c 1.13 2006/01/08 11:40:09 kls Exp $
*/ */
#include "rcu.h" #include "rcu.h"
@ -23,8 +23,8 @@ cRcuRemote::cRcuRemote(const char *DeviceName)
dp = 0; dp = 0;
mode = modeB; mode = modeB;
code = 0; code = 0;
numberToSend = -1; number = 0;
lastNumber = 0; data = 0;
receivedCommand = false; receivedCommand = false;
if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) {
struct termios t; struct termios t;
@ -32,7 +32,7 @@ cRcuRemote::cRcuRemote(const char *DeviceName)
cfsetspeed(&t, B9600); cfsetspeed(&t, B9600);
cfmakeraw(&t); cfmakeraw(&t);
if (tcsetattr(f, TCSAFLUSH, &t) == 0) { if (tcsetattr(f, TCSAFLUSH, &t) == 0) {
Number(0);//XXX 8888??? SetNumber(8888);
const char *Setup = GetSetup(); const char *Setup = GetSetup();
if (Setup) { if (Setup) {
code = *Setup; code = *Setup;
@ -95,13 +95,12 @@ void cRcuRemote::Action(void)
time_t LastCodeRefresh = 0; time_t LastCodeRefresh = 0;
cTimeMs FirstTime; cTimeMs FirstTime;
unsigned char LastCode = 0, LastMode = 0;
uint64 LastCommand = 0; uint64 LastCommand = 0;
unsigned int LastData = 0;
bool repeat = false; bool repeat = false;
while (Running() && f >= 0) { while (Running() && f >= 0) {
LOCK_THREAD;
if (ReceiveByte(REPEATLIMIT) == 'X') { if (ReceiveByte(REPEATLIMIT) == 'X') {
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
int b = ReceiveByte(); int b = ReceiveByte();
@ -140,11 +139,22 @@ void cRcuRemote::Action(void)
LastCommand = 0; LastCommand = 0;
} }
else { else {
LastCommand = 0; unsigned int d = data;
if (numberToSend >= 0) { if (d != LastData) {
Number(numberToSend); SendData(d);
numberToSend = -1; LastData = d;
} }
unsigned char c = code;
if (c != LastCode) {
SendCommand(c);
LastCode = c;
}
unsigned char m = mode;
if (m != LastMode) {
SendCommand(m);
LastMode = m;
}
LastCommand = 0;
} }
if (code && time(NULL) - LastCodeRefresh > 60) { if (code && time(NULL) - LastCodeRefresh > 60) {
SendCommand(code); // in case the PIC listens to the wrong code SendCommand(code); // in case the PIC listens to the wrong code
@ -192,8 +202,6 @@ bool cRcuRemote::SendByteHandshake(unsigned char c)
bool cRcuRemote::SendByte(unsigned char c) bool cRcuRemote::SendByte(unsigned char c)
{ {
LOCK_THREAD;
for (int retry = 5; retry--;) { for (int retry = 5; retry--;) {
if (SendByteHandshake(c)) if (SendByteHandshake(c))
return true; return true;
@ -201,32 +209,34 @@ bool cRcuRemote::SendByte(unsigned char c)
return false; return false;
} }
bool cRcuRemote::SetCode(unsigned char Code) bool cRcuRemote::SendData(unsigned int n)
{ {
code = Code; for (int i = 0; i < 4; i++) {
return SendCommand(code); if (!SendByte(n & 0x7F))
} return false;
n >>= 8;
bool cRcuRemote::SetMode(unsigned char Mode) }
{
mode = Mode;
return SendCommand(mode); return SendCommand(mode);
} }
void cRcuRemote::SetCode(unsigned char Code)
{
code = Code;
}
void cRcuRemote::SetMode(unsigned char Mode)
{
mode = Mode;
}
bool cRcuRemote::SendCommand(unsigned char Cmd) bool cRcuRemote::SendCommand(unsigned char Cmd)
{ {
return SendByte(Cmd | 0x80); return SendByte(Cmd | 0x80);
} }
bool cRcuRemote::Digit(int n, int v) void cRcuRemote::SetNumber(int n, bool Hex)
{
return SendByte(((n & 0x03) << 5) | (v & 0x0F) | (((dp >> n) & 0x01) << 4));
}
bool cRcuRemote::Number(int n, bool Hex)
{ {
LOCK_THREAD; number = n;
if (!Hex) { if (!Hex) {
char buf[8]; char buf[8];
sprintf(buf, "%4d", n & 0xFFFF); sprintf(buf, "%4d", n & 0xFFFF);
@ -237,19 +247,17 @@ bool cRcuRemote::Number(int n, bool Hex)
n = (n << 4) | ((*d - '0') & 0x0F); n = (n << 4) | ((*d - '0') & 0x0F);
} }
} }
lastNumber = n; unsigned int m = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (!Digit(i, n)) m <<= 8;
return false; m |= ((i & 0x03) << 5) | (n & 0x0F) | (((dp >> i) & 0x01) << 4);
n >>= 4; n >>= 4;
} }
return SendCommand(mode); data = m;
} }
bool cRcuRemote::String(char *s) void cRcuRemote::SetString(char *s)
{ {
LOCK_THREAD;
const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP ";
int n = 0; int n = 0;
@ -262,16 +270,16 @@ bool cRcuRemote::String(char *s)
} }
} }
} }
return Number(n, true); SetNumber(n, true);
} }
void cRcuRemote::SetPoints(unsigned char Dp, bool On) void cRcuRemote::SetPoints(unsigned char Dp, bool On)
{ {
if (On) if (On)
dp |= Dp; dp |= Dp;
else else
dp &= ~Dp; dp &= ~Dp;
Number(lastNumber, true); SetNumber(number);
} }
bool cRcuRemote::DetectCode(unsigned char *Code) bool cRcuRemote::DetectCode(unsigned char *Code)
@ -291,12 +299,12 @@ bool cRcuRemote::DetectCode(unsigned char *Code)
SetMode(modeH); SetMode(modeH);
char buf[5]; char buf[5];
sprintf(buf, "C0D%c", *Code); sprintf(buf, "C0D%c", *Code);
String(buf); SetString(buf);
SetCode(*Code); SetCode(*Code);
cCondWait::SleepMs(2 * REPEATDELAY); cCondWait::SleepMs(2 * REPEATDELAY);
if (receivedCommand) { if (receivedCommand) {
SetMode(modeB); SetMode(modeB);
String("----"); SetString("----");
return true; return true;
} }
if (*Code < 'D') { if (*Code < 'D') {
@ -310,13 +318,11 @@ bool cRcuRemote::DetectCode(unsigned char *Code)
void cRcuRemote::ChannelSwitch(const cDevice *Device, int ChannelNumber) void cRcuRemote::ChannelSwitch(const cDevice *Device, int ChannelNumber)
{ {
if (ChannelNumber && Device->IsPrimaryDevice()) { if (ChannelNumber && Device->IsPrimaryDevice())
LOCK_THREAD; SetNumber(cDevice::CurrentChannel());
numberToSend = cDevice::CurrentChannel();
}
} }
void cRcuRemote::Recording(const cDevice *Device, const char *Name) void cRcuRemote::Recording(const cDevice *Device, const char *Name, const char *FileName, bool On)
{ {
SetPoints(1 << Device->DeviceNumber(), Device->Receiving()); SetPoints(1 << Device->DeviceNumber(), Device->Receiving());
} }

18
rcu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: rcu.h 1.4 2005/07/31 10:18:00 kls Exp $ * $Id: rcu.h 1.6 2005/12/31 15:09:25 kls Exp $
*/ */
#ifndef __RCU_H #ifndef __RCU_H
@ -19,23 +19,23 @@ private:
enum { modeH = 'h', modeB = 'b', modeS = 's' }; enum { modeH = 'h', modeB = 'b', modeS = 's' };
int f; int f;
unsigned char dp, code, mode; unsigned char dp, code, mode;
int numberToSend; int number;
int lastNumber; unsigned int data;
bool receivedCommand; bool receivedCommand;
bool SendCommand(unsigned char Cmd); bool SendCommand(unsigned char Cmd);
int ReceiveByte(int TimeoutMs = 0); int ReceiveByte(int TimeoutMs = 0);
bool SendByteHandshake(unsigned char c); bool SendByteHandshake(unsigned char c);
bool SendByte(unsigned char c); bool SendByte(unsigned char c);
bool Digit(int n, int v); bool SendData(unsigned int n);
bool SetCode(unsigned char Code); void SetCode(unsigned char Code);
bool SetMode(unsigned char Mode); void SetMode(unsigned char Mode);
bool Number(int n, bool Hex = false); void SetNumber(int n, bool Hex = false);
void SetPoints(unsigned char Dp, bool On); void SetPoints(unsigned char Dp, bool On);
bool String(char *s); void SetString(char *s);
bool DetectCode(unsigned char *Code); bool DetectCode(unsigned char *Code);
virtual void Action(void); virtual void Action(void);
virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
virtual void Recording(const cDevice *Device, const char *Name); virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On);
public: public:
cRcuRemote(const char *DeviceName); cRcuRemote(const char *DeviceName);
virtual ~cRcuRemote(); virtual ~cRcuRemote();

View File

@ -4,13 +4,13 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recorder.c 1.16 2005/10/31 12:35:29 kls Exp $ * $Id: recorder.c 1.17 2006/01/08 11:01:25 kls Exp $
*/ */
#include "recorder.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "recorder.h"
#define RECORDERBUFSIZE MEGABYTE(5) #define RECORDERBUFSIZE MEGABYTE(5)
@ -171,6 +171,8 @@ void cRecorder::Action(void)
int Count = remux->Put(b, r); int Count = remux->Put(b, r);
if (Count) if (Count)
ringBuffer->Del(Count); ringBuffer->Del(Count);
else
cCondWait::SleepMs(100); // avoid busy loop when resultBuffer is full in cRemux::Put()
} }
} }
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.c 1.124 2005/11/04 14:19:44 kls Exp $ * $Id: recording.c 1.132 2006/01/08 11:40:13 kls Exp $
*/ */
#include "recording.h" #include "recording.h"
@ -48,8 +48,8 @@
#define MINDISKSPACE 1024 // MB #define MINDISKSPACE 1024 // MB
#define DELETEDLIFETIME 1 // hours after which a deleted recording will be actually removed #define REMOVECHECKDELTA 60 // seconds between checks for removing deleted files
#define REMOVECHECKDELTA 3600 // seconds between checks for removing deleted files #define DELETEDLIFETIME 300 // seconds after which a deleted recording will be actually removed
#define DISKCHECKDELTA 100 // seconds between checks for free disk space #define DISKCHECKDELTA 100 // seconds between checks for free disk space
#define REMOVELATENCY 10 // seconds to wait until next check after removing a file #define REMOVELATENCY 10 // seconds to wait until next check after removing a file
@ -60,46 +60,67 @@
bool VfatFileSystem = false; bool VfatFileSystem = false;
static cRecordings DeletedRecordings(true); cRecordings DeletedRecordings(true);
// --- cRemoveDeletedRecordingsThread ----------------------------------------
class cRemoveDeletedRecordingsThread : public cThread {
protected:
virtual void Action(void);
public:
cRemoveDeletedRecordingsThread(void);
};
cRemoveDeletedRecordingsThread::cRemoveDeletedRecordingsThread(void)
:cThread("remove deleted recordings")
{
}
void cRemoveDeletedRecordingsThread::Action(void)
{
// Make sure only one instance of VDR does this:
cLockFile LockFile(VideoDirectory);
if (LockFile.Lock()) {
cThreadLock DeletedRecordingsLock(&DeletedRecordings);
for (cRecording *r = DeletedRecordings.First(); r; ) {
if (r->deleted && time(NULL) - r->deleted > DELETEDLIFETIME) {
cRecording *next = DeletedRecordings.Next(r);
r->Remove();
DeletedRecordings.Del(r);
r = next;
RemoveEmptyVideoDirectories();
continue;
}
r = DeletedRecordings.Next(r);
}
}
}
static cRemoveDeletedRecordingsThread RemoveDeletedRecordingsThread;
// ---
void RemoveDeletedRecordings(void) void RemoveDeletedRecordings(void)
{ {
static time_t LastRemoveCheck = 0; static time_t LastRemoveCheck = 0;
if (LastRemoveCheck == 0) { if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) {
DeletedRecordings.Update(); if (!RemoveDeletedRecordingsThread.Active()) {
LastRemoveCheck = time(NULL) - REMOVECHECKDELTA * 9 / 10; cThreadLock DeletedRecordingsLock(&DeletedRecordings);
} for (cRecording *r = DeletedRecordings.First(); r; r = DeletedRecordings.Next(r)) {
else if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) { if (r->deleted && time(NULL) - r->deleted > DELETEDLIFETIME) {
// Make sure only one instance of VDR does this: RemoveDeletedRecordingsThread.Start();
cLockFile LockFile(VideoDirectory); break;
if (!LockFile.Lock()) }
return; }
// Remove the oldest file that has been "deleted":
cThreadLock DeletedRecordingsLock(&DeletedRecordings);
if (DeletedRecordings.Count()) {
cRecording *r = DeletedRecordings.First();
cRecording *r0 = r;
while (r) {
if (r->start < r0->start)
r0 = r;
r = DeletedRecordings.Next(r);
}
if (r0 && time(NULL) - r0->start > DELETEDLIFETIME * 3600) {
r0->Remove();
DeletedRecordings.Del(r0);
RemoveEmptyVideoDirectories();
LastRemoveCheck += REMOVELATENCY;
return;
}
} }
else
DeletedRecordings.Update();
LastRemoveCheck = time(NULL); LastRemoveCheck = time(NULL);
} }
} }
void AssertFreeDiskSpace(int Priority) void AssertFreeDiskSpace(int Priority)
{ {
static cMutex Mutex;
cMutexLock MutexLock(&Mutex);
// With every call to this function we try to actually remove // With every call to this function we try to actually remove
// a file, or mark a file for removal ("delete" it), so that // a file, or mark a file for removal ("delete" it), so that
// it will get removed during the next call. // it will get removed during the next call.
@ -160,7 +181,7 @@ void AssertFreeDiskSpace(int Priority)
} }
// Unable to free disk space, but there's nothing we can do about that... // Unable to free disk space, but there's nothing we can do about that...
isyslog("...no old recording found, giving up"); isyslog("...no old recording found, giving up");
Interface->Confirm(tr("Low disk space!"), 30); Skins.QueueMessage(mtWarning, tr("Low disk space!"), 5, -1);
} }
LastFreeDiskCheck = time(NULL); LastFreeDiskCheck = time(NULL);
} }
@ -400,6 +421,8 @@ cRecording::cRecording(cTimer *Timer, const cEvent *Event)
sortBuffer = NULL; sortBuffer = NULL;
fileName = NULL; fileName = NULL;
name = NULL; name = NULL;
fileSizeMB = -1; // unknown
deleted = 0;
// set up the actual name: // set up the actual name:
const char *Title = Event ? Event->Title() : NULL; const char *Title = Event ? Event->Title() : NULL;
const char *Subtitle = Event ? Event->ShortText() : NULL; const char *Subtitle = Event ? Event->ShortText() : NULL;
@ -453,6 +476,8 @@ cRecording::cRecording(cTimer *Timer, const cEvent *Event)
cRecording::cRecording(const char *FileName) cRecording::cRecording(const char *FileName)
{ {
resume = RESUME_NOT_INITIALIZED; resume = RESUME_NOT_INITIALIZED;
fileSizeMB = -1; // unknown
deleted = 0;
titleBuffer = NULL; titleBuffer = NULL;
sortBuffer = NULL; sortBuffer = NULL;
fileName = strdup(FileName); fileName = strdup(FileName);
@ -525,7 +550,7 @@ cRecording::cRecording(const char *FileName)
// so assume the short text is missing and concatenate // so assume the short text is missing and concatenate
// line 1 and line 2 to be the long text: // line 1 and line 2 to be the long text:
int len = strlen(data[1]); int len = strlen(data[1]);
if (len > 80) { if (len > 80) {
data[1] = (char *)realloc(data[1], len + 1 + strlen(data[2]) + 1); data[1] = (char *)realloc(data[1], len + 1 + strlen(data[2]) + 1);
strcat(data[1], "\n"); strcat(data[1], "\n");
strcat(data[1], data[2]); strcat(data[1], data[2]);
@ -714,7 +739,7 @@ bool cRecording::Delete(void)
bool result = true; bool result = true;
char *NewName = strdup(FileName()); char *NewName = strdup(FileName());
char *ext = strrchr(NewName, '.'); char *ext = strrchr(NewName, '.');
if (strcmp(ext, RECEXT) == 0) { if (ext && strcmp(ext, RECEXT) == 0) {
strncpy(ext, DELEXT, strlen(ext)); strncpy(ext, DELEXT, strlen(ext));
if (access(NewName, F_OK) == 0) { if (access(NewName, F_OK) == 0) {
// the new name already exists, so let's remove that one first: // the new name already exists, so let's remove that one first:
@ -814,6 +839,10 @@ void cRecordings::ScanVideoDir(const char *DirName, bool Foreground)
Add(r); Add(r);
ChangeState(); ChangeState();
Unlock(); Unlock();
if (deleted) {
r->fileSizeMB = DirSizeMB(buffer);
r->deleted = time(NULL);
}
} }
else else
delete r; delete r;
@ -883,12 +912,33 @@ void cRecordings::DelByName(const char *FileName)
LOCK_THREAD; LOCK_THREAD;
cRecording *recording = GetByName(FileName); cRecording *recording = GetByName(FileName);
if (recording) { if (recording) {
Del(recording); cThreadLock DeletedRecordingsLock(&DeletedRecordings);
Del(recording, false);
char *ext = strrchr(recording->FileName(), '.');
if (ext) {
strncpy(ext, DELEXT, strlen(ext));
recording->fileSizeMB = DirSizeMB(recording->FileName());
recording->deleted = time(NULL);
DeletedRecordings.Add(recording);
}
else
delete recording;
ChangeState(); ChangeState();
TouchUpdate(); TouchUpdate();
} }
} }
int cRecordings::TotalFileSizeMB(void)
{
int size = 0;
LOCK_THREAD;
for (cRecording *recording = First(); recording; recording = Next(recording)) {
if (recording->fileSizeMB > 0)
size += recording->fileSizeMB;
}
return size;
}
void cRecordings::ResetResume(const char *ResumeFileName) void cRecordings::ResetResume(const char *ResumeFileName)
{ {
LOCK_THREAD; LOCK_THREAD;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.h 1.46 2005/10/31 12:27:12 kls Exp $ * $Id: recording.h 1.48 2005/12/18 11:26:51 kls Exp $
*/ */
#ifndef __RECORDING_H #ifndef __RECORDING_H
@ -55,12 +55,14 @@ public:
}; };
class cRecording : public cListObject { class cRecording : public cListObject {
friend class cRecordings;
private: private:
mutable int resume; mutable int resume;
mutable char *titleBuffer; mutable char *titleBuffer;
mutable char *sortBuffer; mutable char *sortBuffer;
mutable char *fileName; mutable char *fileName;
mutable char *name; mutable char *name;
mutable int fileSizeMB;
cRecordingInfo *info; cRecordingInfo *info;
static char *StripEpisodeName(char *s); static char *StripEpisodeName(char *s);
char *SortName(void) const; char *SortName(void) const;
@ -69,6 +71,7 @@ public:
time_t start; time_t start;
int priority; int priority;
int lifetime; int lifetime;
time_t deleted;
cRecording(cTimer *Timer, const cEvent *Event); cRecording(cTimer *Timer, const cEvent *Event);
cRecording(const char *FileName); cRecording(const char *FileName);
virtual ~cRecording(); virtual ~cRecording();
@ -126,9 +129,11 @@ public:
cRecording *GetByName(const char *FileName); cRecording *GetByName(const char *FileName);
void AddByName(const char *FileName); void AddByName(const char *FileName);
void DelByName(const char *FileName); void DelByName(const char *FileName);
int TotalFileSizeMB(void); ///< Only for deleted recordings!
}; };
extern cRecordings Recordings; extern cRecordings Recordings;
extern cRecordings DeletedRecordings;
class cMark : public cListObject { class cMark : public cListObject {
public: public:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: remote.c 1.45 2005/09/03 12:29:48 kls Exp $ * $Id: remote.c 1.46 2006/01/01 14:21:07 kls Exp $
*/ */
#include "remote.h" #include "remote.h"
@ -262,43 +262,72 @@ int cKbdRemote::MapCodeToFunc(uint64 Code)
return (Code <= 0xFF) ? Code : kfNone; return (Code <= 0xFF) ? Code : kfNone;
} }
void cKbdRemote::Action(void) int cKbdRemote::ReadKey(void)
{ {
cPoller Poller(STDIN_FILENO); cPoller Poller(STDIN_FILENO);
if (Poller.Poll(50)) {
uchar ch = 0;
int r = safe_read(STDIN_FILENO, &ch, 1);
if (r == 1)
return ch;
if (r < 0)
LOG_ERROR_STR("cKbdRemote");
}
return -1;
}
uint64 cKbdRemote::ReadKeySequence(void)
{
uint64 k = 0;
int key1;
if ((key1 = ReadKey()) >= 0) {
k = key1;
if (key1 == 0x1B) {
// Start of escape sequence
if ((key1 = ReadKey()) >= 0) {
k <<= 8;
k |= key1 & 0xFF;
switch (key1) {
case 0x4F: // 3-byte sequence
if ((key1 = ReadKey()) >= 0) {
k <<= 8;
k |= key1 & 0xFF;
}
break;
case 0x5B: // 3- or more-byte sequence
if ((key1 = ReadKey()) >= 0) {
k <<= 8;
k |= key1 & 0xFF;
switch (key1) {
case 0x31 ... 0x3F: // more-byte sequence
while (key1 != 0x7E) {
k <<= 8;
k |= key1 & 0xFF;
if ((key1 = ReadKey()) < 0)
break; // Sequence ends here
}
break;
}
}
break;
}
}
}
}
return k;
}
void cKbdRemote::Action(void)
{
while (Running()) { while (Running()) {
if (Poller.Poll(100)) { uint64 Command = ReadKeySequence();
uint64 Command = 0; if (Command) {
uint i = 0; if (rawMode || !Put(Command)) {
while (Running() && i < sizeof(Command)) { int func = MapCodeToFunc(Command);
uchar ch; if (func)
int r = read(STDIN_FILENO, &ch, 1); Put(KBDKEY(func));
if (r == 1) { }
Command <<= 8;
Command |= ch;
i++;
}
else if (r == 0) {
// don't know why, but sometimes special keys that start with
// 0x1B ('ESC') cause a short gap between the 0x1B and the rest
// of their codes, so we'll need to wait some 100ms to see if
// there is more coming up - or whether this really is the 'ESC'
// key (if somebody knows how to clean this up, please let me know):
if (Command == 0x1B && Poller.Poll(100))
continue;
if (Command) {
if (rawMode || !Put(Command)) {
int func = MapCodeToFunc(Command);
if (func)
Put(KBDKEY(func));
}
}
break;
}
else {
LOG_ERROR;
break;
}
}
} }
} }
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: remote.h 1.31 2005/09/03 12:28:42 kls Exp $ * $Id: remote.h 1.32 2006/01/01 14:00:50 kls Exp $
*/ */
#ifndef __REMOTE_H #ifndef __REMOTE_H
@ -89,6 +89,8 @@ private:
static bool rawMode; static bool rawMode;
struct termios savedTm; struct termios savedTm;
virtual void Action(void); virtual void Action(void);
int ReadKey(void);
uint64 ReadKeySequence(void);
int MapCodeToFunc(uint64 Code); int MapCodeToFunc(uint64 Code);
public: public:
cKbdRemote(void); cKbdRemote(void);

105
remux.c
View File

@ -11,7 +11,7 @@
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>, * The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de. * and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
* *
* $Id: remux.c 1.47 2005/09/11 13:26:50 kls Exp $ * $Id: remux.c 1.53 2006/01/08 11:40:16 kls Exp $
*/ */
#include "remux.h" #include "remux.h"
@ -88,15 +88,21 @@ ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset,
// --- cRepacker ------------------------------------------------------------- // --- cRepacker -------------------------------------------------------------
#define MIN_LOG_INTERVAL 10 // min. # of seconds between two consecutive log messages of a cRepacker
#define LOG(a...) (LogAllowed() && (esyslog(a), true))
class cRepacker { class cRepacker {
protected: protected:
bool initiallySyncing; bool initiallySyncing;
int maxPacketSize; int maxPacketSize;
uint8_t subStreamId; uint8_t subStreamId;
static void DroppedData(const char *Reason, int Count) { esyslog("%s (dropped %d bytes)", Reason, Count); } time_t lastLog;
int suppressedLogMessages;
bool LogAllowed(void);
void DroppedData(const char *Reason, int Count) { LOG("%s (dropped %d bytes)", Reason, Count); }
public: public:
static int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded); static int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded);
cRepacker(void) { initiallySyncing = true; maxPacketSize = 6 + 65535; subStreamId = 0; } cRepacker(void);
virtual ~cRepacker() {} virtual ~cRepacker() {}
virtual void Reset(void) { initiallySyncing = true; } virtual void Reset(void) { initiallySyncing = true; }
virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) = 0; virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) = 0;
@ -106,6 +112,30 @@ public:
void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; } void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; }
}; };
cRepacker::cRepacker(void)
{
initiallySyncing = true;
maxPacketSize = 6 + 65535;
subStreamId = 0;
suppressedLogMessages = 0;;
lastLog = 0;
}
bool cRepacker::LogAllowed(void)
{
bool Allowed = time(NULL) - lastLog >= MIN_LOG_INTERVAL;
lastLog = time(NULL);
if (Allowed) {
if (suppressedLogMessages) {
esyslog("%d cRepacker messages suppressed", suppressedLogMessages);
suppressedLogMessages = 0;
}
}
else
suppressedLogMessages++;
return Allowed;
}
int cRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded) int cRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded)
{ {
if (CapacityNeeded >= Count && ResultBuffer->Free() < CapacityNeeded) { if (CapacityNeeded >= Count && ResultBuffer->Free() < CapacityNeeded) {
@ -160,7 +190,7 @@ bool cCommonRepacker::PushOutPacket(cRingBufferLinear *ResultBuffer, const uchar
// just skip packets with no payload // just skip packets with no payload
int PesPayloadOffset = 0; int PesPayloadOffset = 0;
if (AnalyzePesHeader(fragmentData, fragmentLen, PesPayloadOffset) <= phInvalid) if (AnalyzePesHeader(fragmentData, fragmentLen, PesPayloadOffset) <= phInvalid)
esyslog("cCommonRepacker: invalid PES packet encountered in fragment buffer!"); LOG("cCommonRepacker: invalid PES packet encountered in fragment buffer!");
else if (6 + PacketLen <= PesPayloadOffset) { else if (6 + PacketLen <= PesPayloadOffset) {
fragmentLen = 0; fragmentLen = 0;
return true; // skip empty packet return true; // skip empty packet
@ -181,7 +211,7 @@ bool cCommonRepacker::PushOutPacket(cRingBufferLinear *ResultBuffer, const uchar
// just skip packets with no payload // just skip packets with no payload
int PesPayloadOffset = 0; int PesPayloadOffset = 0;
if (AnalyzePesHeader(pesHeader, pesHeaderLen, PesPayloadOffset) <= phInvalid) if (AnalyzePesHeader(pesHeader, pesHeaderLen, PesPayloadOffset) <= phInvalid)
esyslog("cCommonRepacker: invalid PES packet encountered in header buffer!"); LOG("cCommonRepacker: invalid PES packet encountered in header buffer!");
else if (6 + PacketLen <= PesPayloadOffset) { else if (6 + PacketLen <= PesPayloadOffset) {
pesHeaderLen = 0; pesHeaderLen = 0;
return true; // skip empty packet return true; // skip empty packet
@ -216,7 +246,8 @@ private:
syncing, syncing,
findPicture, findPicture,
scanPicture scanPicture
} state; };
int state;
public: public:
cVideoRepacker(void); cVideoRepacker(void);
virtual void Reset(void); virtual void Reset(void);
@ -278,14 +309,14 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
// which kind of start code have we got? // which kind of start code have we got?
switch (*data) { switch (*data) {
case 0xB9 ... 0xFF: // system start codes case 0xB9 ... 0xFF: // system start codes
esyslog("cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed"); LOG("cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed");
break; break;
case 0xB0 ... 0xB1: // reserved start codes case 0xB0 ... 0xB1: // reserved start codes
case 0xB6: case 0xB6:
esyslog("cVideoRepacker: found reserved start code: stream seems to be scrambled"); LOG("cVideoRepacker: found reserved start code: stream seems to be scrambled");
break; break;
case 0xB4: // sequence error code case 0xB4: // sequence error code
isyslog("cVideoRepacker: found sequence error code: stream seems to be damaged"); LOG("cVideoRepacker: found sequence error code: stream seems to be damaged");
case 0xB2: // user data start code case 0xB2: // user data start code
case 0xB5: // extension start code case 0xB5: // extension start code
break; break;
@ -307,7 +338,7 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
if (initiallySyncing) // omit report for the typical initial case if (initiallySyncing) // omit report for the typical initial case
initiallySyncing = false; initiallySyncing = false;
else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes
esyslog("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit); LOG("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit);
skippedBytes = 0; skippedBytes = 0;
// if there is a PES header available, then use it ... // if there is a PES header available, then use it ...
if (pesHeaderBackupLen > 0) { if (pesHeaderBackupLen > 0) {
@ -350,13 +381,13 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
// maximum we can hold in one PES packet // maximum we can hold in one PES packet
packetTodo = maxPacketSize - pesHeaderLen; packetTodo = maxPacketSize - pesHeaderLen;
// go on with finding the picture data // go on with finding the picture data
((int &)state)++; state++;
} }
break; break;
case 0x01 ... 0xAF: // slice start codes case 0x01 ... 0xAF: // slice start codes
if (state == findPicture) { if (state == findPicture) {
// go on with scanning the picture data // go on with scanning the picture data
((int &)state)++; state++;
} }
break; break;
} }
@ -465,7 +496,7 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
// report that syncing dropped some bytes // report that syncing dropped some bytes
if (skippedBytes > SkippedBytesLimit) { if (skippedBytes > SkippedBytesLimit) {
if (!initiallySyncing) // omit report for the typical initial case if (!initiallySyncing) // omit report for the typical initial case
esyslog("cVideoRepacker: skipped %d bytes while syncing on next picture", skippedBytes - SkippedBytesLimit); LOG("cVideoRepacker: skipped %d bytes while syncing on next picture", skippedBytes - SkippedBytesLimit);
skippedBytes = SkippedBytesLimit; skippedBytes = SkippedBytesLimit;
} }
} }
@ -517,7 +548,8 @@ private:
enum eState { enum eState {
syncing, syncing,
scanFrame scanFrame
} state; };
int state;
int frameTodo; int frameTodo;
int frameSize; int frameSize;
int cid; int cid;
@ -674,7 +706,7 @@ void cAudioRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
if (initiallySyncing) // omit report for the typical initial case if (initiallySyncing) // omit report for the typical initial case
initiallySyncing = false; initiallySyncing = false;
else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes
esyslog("cAudioRepacker(0x%02X): skipped %d bytes to sync on next audio frame", cid, skippedBytes - SkippedBytesLimit); LOG("cAudioRepacker(0x%02X): skipped %d bytes to sync on next audio frame", cid, skippedBytes - SkippedBytesLimit);
skippedBytes = 0; skippedBytes = 0;
// if there is a PES header available, then use it ... // if there is a PES header available, then use it ...
if (pesHeaderBackupLen > 0) { if (pesHeaderBackupLen > 0) {
@ -714,10 +746,10 @@ void cAudioRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
payload = data; payload = data;
// maximum we can hold in one PES packet // maximum we can hold in one PES packet
packetTodo = maxPacketSize - pesHeaderLen; packetTodo = maxPacketSize - pesHeaderLen;
// expected remainder of audio frame: so far we have read 3 bytes from the frame header // expected remainder of audio frame: so far we have read 3 bytes from the frame header
frameTodo = frameSize - 3; frameTodo = frameSize - 3;
// go on with collecting the frame's data // go on with collecting the frame's data
((int &)state)++; state++;
} }
} }
} }
@ -832,7 +864,7 @@ void cAudioRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
// report that syncing dropped some bytes // report that syncing dropped some bytes
if (skippedBytes > SkippedBytesLimit) { if (skippedBytes > SkippedBytesLimit) {
if (!initiallySyncing) // omit report for the typical initial case if (!initiallySyncing) // omit report for the typical initial case
esyslog("cAudioRepacker(0x%02X): skipped %d bytes while syncing on next audio frame", cid, skippedBytes - SkippedBytesLimit); LOG("cAudioRepacker(0x%02X): skipped %d bytes while syncing on next audio frame", cid, skippedBytes - SkippedBytesLimit);
skippedBytes = SkippedBytesLimit; skippedBytes = SkippedBytesLimit;
} }
} }
@ -898,14 +930,15 @@ private:
uchar chk1; uchar chk1;
uchar chk2; uchar chk2;
int ac3todo; int ac3todo;
enum { enum eState {
find_0b, find_0b,
find_77, find_77,
store_chk1, store_chk1,
store_chk2, store_chk2,
get_length, get_length,
output_packet output_packet
} state; };
int state;
int skippedBytes; int skippedBytes;
void ResetPesHeader(bool ContinuationFrame = false); void ResetPesHeader(bool ContinuationFrame = false);
void AppendSubStreamID(bool ContinuationFrame = false); void AppendSubStreamID(bool ContinuationFrame = false);
@ -1090,7 +1123,7 @@ void cDolbyRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
switch (state) { switch (state) {
case find_0b: case find_0b:
if (*data == 0x0B) { if (*data == 0x0B) {
++(int &)state; state++;
// copy header information once for later use // copy header information once for later use
if (pesHeaderBackupLen > 0) { if (pesHeaderBackupLen > 0) {
pesHeaderLen = pesHeaderBackupLen; pesHeaderLen = pesHeaderBackupLen;
@ -1113,21 +1146,21 @@ void cDolbyRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
done++; done++;
todo--; todo--;
skippedBytes++; // collect number of skipped bytes while syncing skippedBytes++; // collect number of skipped bytes while syncing
++(int &)state; state++;
continue; continue;
case store_chk1: case store_chk1:
chk1 = *data++; chk1 = *data++;
done++; done++;
todo--; todo--;
skippedBytes++; // collect number of skipped bytes while syncing skippedBytes++; // collect number of skipped bytes while syncing
++(int &)state; state++;
continue; continue;
case store_chk2: case store_chk2:
chk2 = *data++; chk2 = *data++;
done++; done++;
todo--; todo--;
skippedBytes++; // collect number of skipped bytes while syncing skippedBytes++; // collect number of skipped bytes while syncing
++(int &)state; state++;
continue; continue;
case get_length: case get_length:
ac3todo = 2 * frameSizes[*data]; ac3todo = 2 * frameSizes[*data];
@ -1157,7 +1190,7 @@ void cDolbyRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
if (initiallySyncing) // omit report for the typical initial case if (initiallySyncing) // omit report for the typical initial case
initiallySyncing = false; initiallySyncing = false;
else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes
esyslog("cDolbyRepacker: skipped %d bytes to sync on next AC3 frame", skippedBytes - SkippedBytesLimit); LOG("cDolbyRepacker: skipped %d bytes to sync on next AC3 frame", skippedBytes - SkippedBytesLimit);
skippedBytes = 0; skippedBytes = 0;
// append read data to header for common output processing // append read data to header for common output processing
pesHeader[pesHeaderLen++] = 0x0B; pesHeader[pesHeaderLen++] = 0x0B;
@ -1165,7 +1198,7 @@ void cDolbyRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
pesHeader[pesHeaderLen++] = chk1; pesHeader[pesHeaderLen++] = chk1;
pesHeader[pesHeaderLen++] = chk2; pesHeader[pesHeaderLen++] = chk2;
ac3todo -= 4; ac3todo -= 4;
++(int &)state; state++;
// fall through to output // fall through to output
case output_packet: { case output_packet: {
int bite = 0; int bite = 0;
@ -1188,7 +1221,7 @@ void cDolbyRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
// report that syncing dropped some bytes // report that syncing dropped some bytes
if (skippedBytes > SkippedBytesLimit) { if (skippedBytes > SkippedBytesLimit) {
if (!initiallySyncing) // omit report for the typical initial case if (!initiallySyncing) // omit report for the typical initial case
esyslog("cDolbyRepacker: skipped %d bytes while syncing on next AC3 frame", skippedBytes - 4); LOG("cDolbyRepacker: skipped %d bytes while syncing on next AC3 frame", skippedBytes - 4);
skippedBytes = SkippedBytesLimit; skippedBytes = SkippedBytesLimit;
} }
} }
@ -1248,9 +1281,10 @@ int cDolbyRepacker::BreakAt(const uchar *Data, int Count)
#define CONT_CNT_MASK 0x0F #define CONT_CNT_MASK 0x0F
// Flags: // Flags:
#define PAY_LOAD 0x10
#define ADAPT_FIELD 0x20
#define PAY_START 0x40 #define PAY_START 0x40
#define TS_ERROR 0x80 #define TS_ERROR 0x80
#define ADAPT_FIELD 0x20
#define MAX_PLENGTH 0xFFFF // the maximum PES packet length (theoretically) #define MAX_PLENGTH 0xFFFF // the maximum PES packet length (theoretically)
#define MMAX_PLENGTH (64*MAX_PLENGTH) // some stations send PES packets that are extremely large, e.g. DVB-T in Finland or HDTV 1920x1080 #define MMAX_PLENGTH (64*MAX_PLENGTH) // some stations send PES packets that are extremely large, e.g. DVB-T in Finland or HDTV 1920x1080
@ -1635,7 +1669,11 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
if (Buf[1] & TS_ERROR) if (Buf[1] & TS_ERROR)
tsErrors++; tsErrors++;
if ((Buf[3] ^ ccCounter) & CONT_CNT_MASK) {
if (!(Buf[3] & (ADAPT_FIELD | PAY_LOAD)))
return; // discard TS packet with adaption_field_control set to '00'.
if ((Buf[3] & PAY_LOAD) && ((Buf[3] ^ ccCounter) & CONT_CNT_MASK)) {
// This should check duplicates and packets which do not increase the counter. // This should check duplicates and packets which do not increase the counter.
// But as the errors usually come in bursts this should be enough to // But as the errors usually come in bursts this should be enough to
// show you there is something wrong with signal quality. // show you there is something wrong with signal quality.
@ -1650,12 +1688,14 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
} }
if (Buf[1] & PAY_START) { if (Buf[1] & PAY_START) {
if (plength == MMAX_PLENGTH - 6 && found > 6) { if (found > 6) {
if (plength != MMAX_PLENGTH - 6 && plength != found - 6)
dsyslog("PES packet shortened to %d bytes (expected: %d bytes)", found, plength + 6);
plength = found - 6; plength = found - 6;
found = 0;
send_ipack(); send_ipack();
reset_ipack(); reset_ipack();
} }
found = 0;
} }
uint8_t off = 0; uint8_t off = 0;
@ -1666,7 +1706,8 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
return; return;
} }
instant_repack(Buf + 4 + off, TS_SIZE - 4 - off); if (Buf[3] & PAY_LOAD)
instant_repack(Buf + 4 + off, TS_SIZE - 4 - off);
} }
// --- cRemux ---------------------------------------------------------------- // --- cRemux ----------------------------------------------------------------

View File

@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the * Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org). * LinuxDVB driver (see linuxtv.org).
* *
* $Id: ringbuffer.c 1.21 2004/10/15 13:49:25 kls Exp $ * $Id: ringbuffer.c 1.23 2005/12/30 15:42:08 kls Exp $
*/ */
#include "ringbuffer.h" #include "ringbuffer.h"
@ -46,7 +46,7 @@ void cRingBuffer::UpdatePercentage(int Fill)
int percent = Fill * 100 / (Size() - 1) / PERCENTAGEDELTA * PERCENTAGEDELTA; int percent = Fill * 100 / (Size() - 1) / PERCENTAGEDELTA * PERCENTAGEDELTA;
if (percent != lastPercent) { if (percent != lastPercent) {
if (percent >= PERCENTAGETHRESHOLD && percent > lastPercent || percent < PERCENTAGETHRESHOLD && lastPercent >= PERCENTAGETHRESHOLD) { if (percent >= PERCENTAGETHRESHOLD && percent > lastPercent || percent < PERCENTAGETHRESHOLD && lastPercent >= PERCENTAGETHRESHOLD) {
dsyslog("buffer usage: %d%% (tid=%ld)", percent, getThreadTid); dsyslog("buffer usage: %d%% (tid=%d)", percent, getThreadTid);
lastPercent = percent; lastPercent = percent;
} }
} }
@ -165,10 +165,10 @@ cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics, cons
Clear(); Clear();
} }
else else
esyslog("ERROR: illegal margin for ring buffer (%d > %d)", Margin, Size / 2); esyslog("ERROR: invalid margin for ring buffer (%d > %d)", Margin, Size / 2);
} }
else else
esyslog("ERROR: illegal size for ring buffer (%d)", Size); esyslog("ERROR: invalid size for ring buffer (%d)", Size);
#ifdef DEBUGRINGBUFFERS #ifdef DEBUGRINGBUFFERS
lastHead = head; lastHead = head;
lastTail = tail; lastTail = tail;
@ -286,7 +286,7 @@ uchar *cRingBufferLinear::Get(int &Count)
uchar *p = NULL; uchar *p = NULL;
int Head = head; int Head = head;
if (getThreadTid <= 0) if (getThreadTid <= 0)
getThreadTid = pthread_self(); getThreadTid = cThread::ThreadId();
int rest = Size() - tail; int rest = Size() - tail;
if (rest < margin && Head < tail) { if (rest < margin && Head < tail) {
int t = margin - rest; int t = margin - rest;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: ringbuffer.h 1.16 2004/10/15 13:50:46 kls Exp $ * $Id: ringbuffer.h 1.17 2005/12/10 10:54:51 kls Exp $
*/ */
#ifndef __RINGBUFFER_H #ifndef __RINGBUFFER_H
@ -23,7 +23,7 @@ private:
int overflowCount; int overflowCount;
int overflowBytes; int overflowBytes;
protected: protected:
pthread_t getThreadTid; tThreadId getThreadTid;
int maxFill;//XXX int maxFill;//XXX
int lastPercent; int lastPercent;
bool statistics;//XXX bool statistics;//XXX

8
runvdr
View File

@ -7,7 +7,7 @@
# #
# Set the environment variable VDRUSR to the user id you # Set the environment variable VDRUSR to the user id you
# want VDR to run with. If VDRUSR is not set, VDR will run # want VDR to run with. If VDRUSR is not set, VDR will run
# as 'root', which is not necessarily advisable. # as user 'vdr'.
# #
# Since this script loads the DVB driver, it must be started # Since this script loads the DVB driver, it must be started
# as user 'root'. # as user 'root'.
@ -18,11 +18,11 @@
# See the main source file 'vdr.c' for copyright information and # See the main source file 'vdr.c' for copyright information and
# how to reach the author. # how to reach the author.
# #
# $Id: runvdr 1.14 2004/11/21 11:30:00 kls Exp $ # $Id: runvdr 1.15 2005/12/31 16:04:53 kls Exp $
DVBDIR="../DVB/driver" DVBDIR="../DVB/driver"
VDRPRG="./vdr" VDRPRG="./vdr"
VDRCMD="$VDRPRG -w 60 $*" VDRCMD="$VDRPRG -u $VDRUSR -w 60 $*"
LSMOD="`/sbin/lsmod | grep -w '^dvb' | wc -l`" LSMOD="`/sbin/lsmod | grep -w '^dvb' | wc -l`"
KILL="/usr/bin/killall -q -TERM" KILL="/usr/bin/killall -q -TERM"
@ -33,7 +33,7 @@ if [ $LSMOD -eq 0 ] ; then
fi fi
while (true) do while (true) do
su $VDRUSR -c "$VDRCMD" $VDRCMD
if test $? -eq 0 -o $? -eq 2; then exit; fi if test $? -eq 0 -o $? -eq 2; then exit; fi
date date
echo "restarting VDR" echo "restarting VDR"

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: skinclassic.c 1.12 2005/05/16 10:45:07 kls Exp $ * $Id: skinclassic.c 1.13 2006/01/01 14:37:58 kls Exp $
*/ */
#include "skinclassic.h" #include "skinclassic.h"
@ -378,7 +378,6 @@ private:
int x0, x1; int x0, x1;
int y0, y1, y2, y3; int y0, y1, y2, y3;
int lastCurrentWidth; int lastCurrentWidth;
bool message;
public: public:
cSkinClassicDisplayReplay(bool ModeOnly); cSkinClassicDisplayReplay(bool ModeOnly);
virtual ~cSkinClassicDisplayReplay(); virtual ~cSkinClassicDisplayReplay();
@ -397,7 +396,6 @@ cSkinClassicDisplayReplay::cSkinClassicDisplayReplay(bool ModeOnly)
const cFont *font = cFont::GetFont(fontOsd); const cFont *font = cFont::GetFont(fontOsd);
int lineHeight = font->Height(); int lineHeight = font->Height();
lastCurrentWidth = 0; lastCurrentWidth = 0;
message = false;
x0 = 0; x0 = 0;
x1 = Setup.OSDWidth; x1 = Setup.OSDWidth;
y0 = 0; y0 = 0;
@ -467,12 +465,9 @@ void cSkinClassicDisplayReplay::SetMessage(eMessageType Type, const char *Text)
if (Text) { if (Text) {
osd->SaveRegion(x0, y2, x1 - 1, y3 - 1); osd->SaveRegion(x0, y2, x1 - 1, y3 - 1);
osd->DrawText(x0, y2, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), font, x1 - x0, y3 - y2, taCenter); osd->DrawText(x0, y2, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), font, x1 - x0, y3 - y2, taCenter);
message = true;
} }
else { else
osd->RestoreRegion(); osd->RestoreRegion();
message = false;
}
} }
void cSkinClassicDisplayReplay::Flush(void) void cSkinClassicDisplayReplay::Flush(void)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: skins.c 1.6 2005/11/27 15:52:25 kls Exp $ * $Id: skins.c 1.7 2006/01/08 11:40:18 kls Exp $
*/ */
#include "skins.h" #include "skins.h"
@ -323,7 +323,7 @@ void cSkins::ProcessQueuedMessages(void)
} }
else else
break; break;
} }
queueMessageMutex.Unlock(); queueMessageMutex.Unlock();
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: skins.h 1.9 2005/11/27 15:41:44 kls Exp $ * $Id: skins.h 1.10 2006/01/08 11:40:21 kls Exp $
*/ */
#ifndef __SKINS_H #ifndef __SKINS_H
@ -197,7 +197,7 @@ public:
///< take care that it is erased from the display when a Current string ///< take care that it is erased from the display when a Current string
///< _with_ ".ff" is followed by one without it. ///< _with_ ".ff" is followed by one without it.
virtual void SetTotal(const char *Total) = 0; virtual void SetTotal(const char *Total) = 0;
///< Sets the total length of the recording, as a user readable ///< Sets the total length of the recording, as a user readable
///< string if the form "h:mm:ss". ///< string if the form "h:mm:ss".
virtual void SetJump(const char *Jump) = 0; virtual void SetJump(const char *Jump) = 0;
///< Sets the prompt that allows the user to enter a jump point. ///< Sets the prompt that allows the user to enter a jump point.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: skinsttng.c 1.15 2005/08/15 11:14:59 kls Exp $ * $Id: skinsttng.c 1.16 2006/01/01 14:38:14 kls Exp $
*/ */
// Star Trek: The Next Generation® is a registered trademark of Paramount Pictures // Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
@ -643,7 +643,6 @@ private:
int y0, y1, y2, y3, y4, y5, y6, y7; int y0, y1, y2, y3, y4, y5, y6, y7;
tColor frameColor; tColor frameColor;
int lastCurrentWidth; int lastCurrentWidth;
bool message;
public: public:
cSkinSTTNGDisplayReplay(bool ModeOnly); cSkinSTTNGDisplayReplay(bool ModeOnly);
virtual ~cSkinSTTNGDisplayReplay(); virtual ~cSkinSTTNGDisplayReplay();
@ -666,7 +665,6 @@ cSkinSTTNGDisplayReplay::cSkinSTTNGDisplayReplay(bool ModeOnly)
int lineHeight = font->Height(); int lineHeight = font->Height();
frameColor = Theme.Color(clrReplayFrame); frameColor = Theme.Color(clrReplayFrame);
lastCurrentWidth = 0; lastCurrentWidth = 0;
message = false;
cBitmap bm(play_xpm); cBitmap bm(play_xpm);
x0 = 0; x0 = 0;
x1 = max(SymbolWidth, bm.Width()); x1 = max(SymbolWidth, bm.Width());
@ -772,12 +770,9 @@ void cSkinSTTNGDisplayReplay::SetMessage(eMessageType Type, const char *Text)
osd->SaveRegion(x2, y6, x4 - 1, y7 - 1); osd->SaveRegion(x2, y6, x4 - 1, y7 - 1);
osd->DrawRectangle(x2, y6, x3 - 1, y7 - 1, Theme.Color(clrBackground)); osd->DrawRectangle(x2, y6, x3 - 1, y7 - 1, Theme.Color(clrBackground));
osd->DrawText(x3, y6, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), font, x4 - x3, 0, taCenter); osd->DrawText(x3, y6, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), font, x4 - x3, 0, taCenter);
message = true;
} }
else { else
osd->RestoreRegion(); osd->RestoreRegion();
message = false;
}
} }
void cSkinSTTNGDisplayReplay::Flush(void) void cSkinSTTNGDisplayReplay::Flush(void)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: status.c 1.7 2005/01/09 11:51:04 kls Exp $ * $Id: status.c 1.8 2005/12/31 15:10:10 kls Exp $
*/ */
#include "status.h" #include "status.h"
@ -29,16 +29,16 @@ void cStatus::MsgChannelSwitch(const cDevice *Device, int ChannelNumber)
sm->ChannelSwitch(Device, ChannelNumber); sm->ChannelSwitch(Device, ChannelNumber);
} }
void cStatus::MsgRecording(const cDevice *Device, const char *Name) void cStatus::MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On)
{ {
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->Recording(Device, Name); sm->Recording(Device, Name, FileName, On);
} }
void cStatus::MsgReplaying(const cControl *Control, const char *Name) void cStatus::MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On)
{ {
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
sm->Replaying(Control, Name); sm->Replaying(Control, Name, FileName, On);
} }
void cStatus::MsgSetVolume(int Volume, bool Absolute) void cStatus::MsgSetVolume(int Volume, bool Absolute)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: status.h 1.8 2005/01/09 11:50:21 kls Exp $ * $Id: status.h 1.9 2005/12/31 15:15:25 kls Exp $
*/ */
#ifndef __STATUS_H #ifndef __STATUS_H
@ -24,15 +24,17 @@ protected:
// Indicates a channel switch on the given DVB device. // Indicates a channel switch on the given DVB device.
// If ChannelNumber is 0, this is before the channel is being switched, // 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. // otherwise ChannelNumber is the number of the channel that has been switched to.
virtual void Recording(const cDevice *Device, const char *Name) {} virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On) {}
// The given DVB device has started recording Name. Name is the name of the // The given DVB device has started (On = true) or stopped (On = false) recording Name.
// recording, without any directory path. // Name is the name of the recording, without any directory path. The full file name
// If Name is NULL, the recording has ended. // of the recording is given in FileName, which may be NULL in case there is no
virtual void Replaying(const cControl *Control, const char *Name) {} // actual file involved. If On is false, Name may be NULL.
// The given player control has started replaying Name. Name is the name of the virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On) {}
// recording, without any directory path. In case of a player that can't provide // The given player control has started (On = true) or stopped (On = false) replaying Name.
// Name is the name of the recording, without any directory path. In case of a player that can't provide
// a name, Name can be a string that identifies the player type (like, e.g., "DVD"). // a name, Name can be a string that identifies the player type (like, e.g., "DVD").
// If Name is NULL, the replay has ended. // The full file name of the recording is given in FileName, which may be NULL in case there is no
// actual file involved. If On is false, Name may be NULL.
virtual void SetVolume(int Volume, bool Absolute) {} virtual void SetVolume(int Volume, bool Absolute) {}
// The volume has been set to the given value, either // The volume has been set to the given value, either
// absolutely or relative to the current volume. // absolutely or relative to the current volume.
@ -70,8 +72,8 @@ public:
virtual ~cStatus(); virtual ~cStatus();
// These functions are called whenever the related status information changes: // These functions are called whenever the related status information changes:
static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber); static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber);
static void MsgRecording(const cDevice *Device, const char *Name); static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On);
static void MsgReplaying(const cControl *Control, const char *Name); static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On);
static void MsgSetVolume(int Volume, bool Absolute); static void MsgSetVolume(int Volume, bool Absolute);
static void MsgSetAudioTrack(int Index, const char * const *Tracks); static void MsgSetAudioTrack(int Index, const char * const *Tracks);
static void MsgSetAudioChannel(int AudioChannel); static void MsgSetAudioChannel(int AudioChannel);

126
svdrp.c
View File

@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured * and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection. * graphical interface that sits on top of an SVDRP connection.
* *
* $Id: svdrp.c 1.84 2005/11/27 15:29:28 kls Exp $ * $Id: svdrp.c 1.89 2005/12/30 15:42:29 kls Exp $
*/ */
#include "svdrp.h" #include "svdrp.h"
@ -201,10 +201,16 @@ const char *HelpPages[] = {
" Edit the recording with the given number. Before a recording can be\n" " Edit the recording with the given number. Before a recording can be\n"
" edited, an LSTR command must have been executed in order to retrieve\n" " edited, an LSTR command must have been executed in order to retrieve\n"
" the recording numbers.", " the recording numbers.",
"GRAB <filename> [ jpeg | pnm [ <quality> [ <sizex> <sizey> ] ] ]\n" "GRAB <filename> [ <quality> [ <sizex> <sizey> ] ]\n"
" Grab the current frame and save it to the given file. Images can\n" " Grab the current frame and save it to the given file. Images can\n"
" be stored as JPEG (default) or PNM, at the given quality (default\n" " be stored as JPEG or PNM, depending on the given file name extension.\n"
" is 'maximum', only applies to JPEG) and size (default is full screen).", " The quality of the grabbed image can be in the range 0..100, where 100\n"
" (the default) means \"best\" (only applies to JPEG). The size parameters\n"
" define the size of the resulting image (default is full screen).\n"
" If the file name is just an extension (.jpg, .jpeg or .pnm) the image\n"
" data will be sent to the SVDRP connection encoded in base64. The same\n"
" happens if '-' (a minus sign) is given as file name, in which case the\n"
" image format defaults to JPEG.",
"HELP [ <topic> ]\n" "HELP [ <topic> ]\n"
" The HELP command gives help info.", " The HELP command gives help info.",
"HITK [ <key> ]\n" "HITK [ <key> ]\n"
@ -307,6 +313,7 @@ const char *HelpPages[] = {
214 Help message 214 Help message
215 EPG or recording data record 215 EPG or recording data record
216 Image grab data (base 64)
220 VDR service ready 220 VDR service ready
221 VDR service closing transmission channel 221 VDR service closing transmission channel
250 Requested VDR action okay, completed 250 Requested VDR action okay, completed
@ -354,6 +361,8 @@ const char *GetHelpPage(const char *Cmd, const char **p)
return NULL; return NULL;
} }
char *cSVDRP::grabImageDir = NULL;
cSVDRP::cSVDRP(int Port) cSVDRP::cSVDRP(int Port)
:socket(Port) :socket(Port)
{ {
@ -656,36 +665,54 @@ void cSVDRP::CmdGRAB(const char *Option)
const char *delim = " \t"; const char *delim = " \t";
char *strtok_next; char *strtok_next;
FileName = strtok_r(p, delim, &strtok_next); FileName = strtok_r(p, delim, &strtok_next);
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) { // image type:
if (strcasecmp(p, "JPEG") == 0) char *Extension = strrchr(FileName, '.');
if (Extension) {
if (strcasecmp(Extension, ".jpg") == 0 || strcasecmp(Extension, ".jpeg") == 0)
Jpeg = true; Jpeg = true;
else if (strcasecmp(p, "PNM") == 0) else if (strcasecmp(Extension, ".pnm") == 0)
Jpeg = false; Jpeg = false;
else { else {
Reply(501, "Unknown image type \"%s\"", p); Reply(501, "Unknown image type \"%s\"", Extension + 1);
return; return;
} }
if (Extension == FileName)
FileName = NULL;
} }
else if (strcmp(FileName, "-") == 0)
FileName = NULL;
else {
Reply(501, "Missing filename extension in \"%s\"", FileName);
return;
}
// image quality (and obsolete type):
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) { if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (isnumber(p)) if (strcasecmp(p, "JPEG") == 0 || strcasecmp(p, "PNM") == 0) {
Quality = atoi(p); // tolerate for backward compatibility
else { p = strtok_r(NULL, delim, &strtok_next);
Reply(501, "Illegal quality \"%s\"", p); }
return; if (p) {
if (isnumber(p))
Quality = atoi(p);
else {
Reply(501, "Invalid quality \"%s\"", p);
return;
}
} }
} }
// image size:
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) { if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (isnumber(p)) if (isnumber(p))
SizeX = atoi(p); SizeX = atoi(p);
else { else {
Reply(501, "Illegal sizex \"%s\"", p); Reply(501, "Invalid sizex \"%s\"", p);
return; return;
} }
if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) { if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
if (isnumber(p)) if (isnumber(p))
SizeY = atoi(p); SizeY = atoi(p);
else { else {
Reply(501, "Illegal sizey \"%s\"", p); Reply(501, "Invalid sizey \"%s\"", p);
return; return;
} }
} }
@ -698,8 +725,67 @@ void cSVDRP::CmdGRAB(const char *Option)
Reply(501, "Unexpected parameter \"%s\"", p); Reply(501, "Unexpected parameter \"%s\"", p);
return; return;
} }
if (cDevice::PrimaryDevice()->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY)) // canonicalize the file name:
Reply(250, "Grabbed image %s", Option); char RealFileName[PATH_MAX];
if (FileName) {
if (grabImageDir) {
char *s;
asprintf(&s, "%s/%s", grabImageDir, FileName);
FileName = s;
char *slash = strrchr(FileName, '/'); // there definitely is one
*slash = 0;
char *r = realpath(FileName, RealFileName);
*slash = '/';
if (!r) {
LOG_ERROR_STR(FileName);
Reply(501, "Invalid file name \"%s\"", FileName);
free(s);
return;
}
strcat(RealFileName, slash);
FileName = RealFileName;
free(s);
if (strncmp(FileName, grabImageDir, strlen(grabImageDir)) != 0) {
Reply(501, "Invalid file name \"%s\"", FileName);
return;
}
}
else {
Reply(550, "Grabbing to file not allowed (use \"GRAB -\" instead)");
return;
}
}
// actual grabbing:
int ImageSize;
uchar *Image = cDevice::PrimaryDevice()->GrabImage(ImageSize, Jpeg, Quality, SizeX, SizeY);
if (Image) {
if (FileName) {
int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE);
if (fd >= 0) {
if (safe_write(fd, Image, ImageSize) == ImageSize) {
isyslog("grabbed image to %s", FileName);
Reply(250, "Grabbed image %s", Option);
}
else {
LOG_ERROR_STR(FileName);
Reply(451, "Can't write to '%s'", FileName);
}
close(fd);
}
else {
LOG_ERROR_STR(FileName);
Reply(451, "Can't open '%s'", FileName);
}
}
else {
cBase64Encoder Base64(Image, ImageSize);
const char *s;
while ((s = Base64.NextLine()) != NULL)
Reply(-216, s);
Reply(216, "Grabbed image %s", Option);
}
free(Image);
}
else else
Reply(451, "Grab image failed"); Reply(451, "Grab image failed");
} }
@ -1482,4 +1568,10 @@ bool cSVDRP::Process(void)
return false; return false;
} }
void cSVDRP::SetGrabImageDir(const char *GrabImageDir)
{
free(grabImageDir);
grabImageDir = GrabImageDir ? strdup(GrabImageDir) : NULL;
}
//TODO more than one connection??? //TODO more than one connection???

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: svdrp.h 1.26 2005/11/27 15:26:42 kls Exp $ * $Id: svdrp.h 1.27 2005/12/30 14:46:38 kls Exp $
*/ */
#ifndef __SVDRP_H #ifndef __SVDRP_H
@ -49,6 +49,7 @@ private:
int length; int length;
char *cmdLine; char *cmdLine;
time_t lastActivity; time_t lastActivity;
static char *grabImageDir;
void Close(bool Timeout = false); void Close(bool Timeout = false);
bool Send(const char *s, int length = -1); bool Send(const char *s, int length = -1);
void Reply(int Code, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); void Reply(int Code, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
@ -87,6 +88,7 @@ public:
~cSVDRP(); ~cSVDRP();
bool HasConnection(void) { return file.IsOpen(); } bool HasConnection(void) { return file.IsOpen(); }
bool Process(void); bool Process(void);
static void SetGrabImageDir(const char *GrabImageDir);
}; };
#endif //__SVDRP_H #endif //__SVDRP_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: thread.c 1.46 2005/11/27 15:15:53 kls Exp $ * $Id: thread.c 1.50 2006/01/04 15:01:22 kls Exp $
*/ */
#include "thread.h" #include "thread.h"
@ -12,6 +12,7 @@
#include <malloc.h> #include <malloc.h>
#include <stdarg.h> #include <stdarg.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
@ -136,7 +137,9 @@ void cCondVar::Broadcast(void)
cRwLock::cRwLock(bool PreferWriter) cRwLock::cRwLock(bool PreferWriter)
{ {
pthread_rwlockattr_t attr = { PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP }; pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
pthread_rwlockattr_setkind_np(&attr, PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP);
pthread_rwlock_init(&rwlock, &attr); pthread_rwlock_init(&rwlock, &attr);
} }
@ -170,7 +173,9 @@ void cRwLock::Unlock(void)
cMutex::cMutex(void) cMutex::cMutex(void)
{ {
locked = 0; locked = 0;
pthread_mutexattr_t attr = { PTHREAD_MUTEX_ERRORCHECK_NP }; pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init(&mutex, &attr); pthread_mutex_init(&mutex, &attr);
} }
@ -193,13 +198,14 @@ void cMutex::Unlock(void)
// --- cThread --------------------------------------------------------------- // --- cThread ---------------------------------------------------------------
tThreadId cThread::mainThreadId = cThread::ThreadId(); tThreadId cThread::mainThreadId = 0;
bool cThread::emergencyExitRequested = false; bool cThread::emergencyExitRequested = false;
cThread::cThread(const char *Description) cThread::cThread(const char *Description)
{ {
active = running = false; active = running = false;
childTid = 0; childTid = 0;
childThreadId = 0;
description = NULL; description = NULL;
SetDescription(Description); SetDescription(Description);
} }
@ -230,11 +236,12 @@ void cThread::SetDescription(const char *Description, ...)
void *cThread::StartThread(cThread *Thread) void *cThread::StartThread(cThread *Thread)
{ {
Thread->childThreadId = ThreadId();
if (Thread->description) if (Thread->description)
dsyslog("%s thread started (pid=%d, tid=%ld)", Thread->description, getpid(), pthread_self()); dsyslog("%s thread started (pid=%d, tid=%d)", Thread->description, getpid(), Thread->childThreadId);
Thread->Action(); Thread->Action();
if (Thread->description) if (Thread->description)
dsyslog("%s thread ended (pid=%d, tid=%ld)", Thread->description, getpid(), pthread_self()); dsyslog("%s thread ended (pid=%d, tid=%d)", Thread->description, getpid(), Thread->childThreadId);
Thread->running = false; Thread->running = false;
Thread->active = false; Thread->active = false;
return NULL; return NULL;
@ -292,7 +299,7 @@ void cThread::Cancel(int WaitSeconds)
return; return;
cCondWait::SleepMs(10); cCondWait::SleepMs(10);
} }
esyslog("ERROR: thread %ld won't end (waited %d seconds) - canceling it...", childTid, WaitSeconds); esyslog("ERROR: thread %d won't end (waited %d seconds) - canceling it...", childThreadId, WaitSeconds);
} }
pthread_cancel(childTid); pthread_cancel(childTid);
childTid = 0; childTid = 0;
@ -308,6 +315,21 @@ bool cThread::EmergencyExit(bool Request)
return emergencyExitRequested = true; // yes, it's an assignment, not a comparison! return emergencyExitRequested = true; // yes, it's an assignment, not a comparison!
} }
_syscall0(pid_t, gettid)
tThreadId cThread::ThreadId(void)
{
return gettid();
}
void cThread::SetMainThreadId(void)
{
if (mainThreadId == 0)
mainThreadId = ThreadId();
else
esyslog("ERROR: attempt to set main thread id to %d while it already is %d", ThreadId(), mainThreadId);
}
// --- cMutexLock ------------------------------------------------------------ // --- cMutexLock ------------------------------------------------------------
cMutexLock::cMutexLock(cMutex *Mutex) cMutexLock::cMutexLock(cMutex *Mutex)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: thread.h 1.32 2005/11/27 15:16:50 kls Exp $ * $Id: thread.h 1.36 2006/01/08 11:40:23 kls Exp $
*/ */
#ifndef __THREAD_H #ifndef __THREAD_H
@ -72,7 +72,7 @@ public:
void Unlock(void); void Unlock(void);
}; };
typedef pthread_t tThreadId; typedef pid_t tThreadId;
class cThread { class cThread {
friend class cThreadLock; friend class cThreadLock;
@ -80,6 +80,7 @@ private:
bool active; bool active;
bool running; bool running;
pthread_t childTid; pthread_t childTid;
tThreadId childThreadId;
cMutex mutex; cMutex mutex;
char *description; char *description;
static tThreadId mainThreadId; static tThreadId mainThreadId;
@ -106,7 +107,7 @@ public:
cThread(const char *Description = NULL); cThread(const char *Description = NULL);
///< Creates a new thread. ///< Creates a new thread.
///< If Description is present, a log file entry will be made when ///< If Description is present, a log file entry will be made when
///< the thread starts and stops. The Start() function must be called ///< the thread starts and stops. The Start() function must be called
///< to actually start the thread. ///< to actually start the thread.
virtual ~cThread(); virtual ~cThread();
void SetDescription(const char *Description, ...) __attribute__ ((format (printf, 2, 3))); void SetDescription(const char *Description, ...) __attribute__ ((format (printf, 2, 3)));
@ -115,8 +116,9 @@ public:
bool Active(void); bool Active(void);
///< Checks whether the thread is still alive. ///< Checks whether the thread is still alive.
static bool EmergencyExit(bool Request = false); static bool EmergencyExit(bool Request = false);
static tThreadId ThreadId(void) { return pthread_self(); } static tThreadId ThreadId(void);
static tThreadId IsMainThread(void) { return ThreadId() == mainThreadId; } static tThreadId IsMainThread(void) { return ThreadId() == mainThreadId; }
static void SetMainThreadId(void);
}; };
// cMutexLock can be used to easily set a lock on mutex and make absolutely // cMutexLock can be used to easily set a lock on mutex and make absolutely

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: timers.c 1.36 2005/09/09 15:22:33 kls Exp $ * $Id: timers.c 1.41 2006/01/08 11:40:29 kls Exp $
*/ */
#include "timers.h" #include "timers.h"
@ -20,14 +20,14 @@
// -- cTimer ----------------------------------------------------------------- // -- cTimer -----------------------------------------------------------------
cTimer::cTimer(bool Instant, bool Pause) cTimer::cTimer(bool Instant, bool Pause, cChannel *Channel)
{ {
startTime = stopTime = 0; startTime = stopTime = 0;
recording = pending = inVpsMargin = false; recording = pending = inVpsMargin = false;
flags = tfNone; flags = tfNone;
if (Instant) if (Instant)
SetFlags(tfActive | tfInstant); SetFlags(tfActive | tfInstant);
channel = Channels.GetByNumber(cDevice::CurrentChannel()); channel = Channel ? Channel : Channels.GetByNumber(cDevice::CurrentChannel());
time_t t = time(NULL); time_t t = time(NULL);
struct tm tm_r; struct tm tm_r;
struct tm *now = localtime_r(&t, &tm_r); struct tm *now = localtime_r(&t, &tm_r);
@ -110,7 +110,7 @@ cString cTimer::ToText(bool UseChannelID)
char *buffer; char *buffer;
strreplace(file, ':', '|'); strreplace(file, ':', '|');
strreplace(summary, '\n', '|'); strreplace(summary, '\n', '|');
asprintf(&buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? *Channel()->GetChannelID().ToString() : *itoa(Channel()->Number()), *PrintDay(day, weekdays), start, stop, priority, lifetime, file, summary ? summary : ""); asprintf(&buffer, "%u:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? *Channel()->GetChannelID().ToString() : *itoa(Channel()->Number()), *PrintDay(day, weekdays), start, stop, priority, lifetime, file, summary ? summary : "");
strreplace(summary, '|', '\n'); strreplace(summary, '|', '\n');
strreplace(file, '|', ':'); strreplace(file, '|', ':');
return cString(buffer, true); return cString(buffer, true);
@ -244,7 +244,7 @@ bool cTimer::Parse(const char *s)
s = s2; s = s2;
} }
bool result = false; bool result = false;
if (8 <= sscanf(s, "%d :%a[^:]:%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &flags, &channelbuffer, &daybuffer, &start, &stop, &priority, &lifetime, &filebuffer, &summary)) { if (8 <= sscanf(s, "%u :%a[^:]:%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &flags, &channelbuffer, &daybuffer, &start, &stop, &priority, &lifetime, &filebuffer, &summary)) {
if (summary && !*skipspace(summary)) { if (summary && !*skipspace(summary)) {
free(summary); free(summary);
summary = NULL; summary = NULL;
@ -363,7 +363,7 @@ bool cTimer::Matches(time_t t, bool Directly) const
} }
if (HasFlags(tfActive)) { if (HasFlags(tfActive)) {
if (HasFlags(tfVps) && !Directly && event && event->Vps() && schedule && schedule->PresentSeenWithin(30)) { if (HasFlags(tfVps) && !Directly && event && event->Vps() && event->Schedule() && event->Schedule()->PresentSeenWithin(30)) {
startTime = event->StartTime(); startTime = event->StartTime();
stopTime = event->EndTime(); stopTime = event->EndTime();
return event->IsRunning(true); return event->IsRunning(true);
@ -425,7 +425,7 @@ time_t cTimer::StopTime(void) const
return stopTime; return stopTime;
} }
void cTimer::SetEvent(const cSchedule *Schedule, const cEvent *Event) void cTimer::SetEvent(const cEvent *Event)
{ {
if (event != Event) { //XXX TODO check event data, too??? if (event != Event) { //XXX TODO check event data, too???
if (Event) { if (Event) {
@ -436,7 +436,6 @@ void cTimer::SetEvent(const cSchedule *Schedule, const cEvent *Event)
} }
else else
isyslog("timer %s set to no event", *ToDescr()); isyslog("timer %s set to no event", *ToDescr());
schedule = Event ? Schedule : NULL;
event = Event; event = Event;
} }
} }
@ -463,22 +462,27 @@ void cTimer::SetInVpsMargin(bool InVpsMargin)
inVpsMargin = InVpsMargin; inVpsMargin = InVpsMargin;
} }
void cTimer::SetFlags(int Flags) void cTimer::SetPriority(int Priority)
{
priority = Priority;
}
void cTimer::SetFlags(uint Flags)
{ {
flags |= Flags; flags |= Flags;
} }
void cTimer::ClrFlags(int Flags) void cTimer::ClrFlags(uint Flags)
{ {
flags &= ~Flags; flags &= ~Flags;
} }
void cTimer::InvFlags(int Flags) void cTimer::InvFlags(uint Flags)
{ {
flags ^= Flags; flags ^= Flags;
} }
bool cTimer::HasFlags(int Flags) const bool cTimer::HasFlags(uint Flags) const
{ {
return (flags & Flags) == Flags; return (flags & Flags) == Flags;
} }
@ -616,7 +620,7 @@ void cTimers::SetEvents(void)
distance = e->EndTime() - now; distance = e->EndTime() - now;
if (Event && overlap == Overlap) { if (Event && overlap == Overlap) {
if (Overlap > FULLMATCH) { // this means VPS if (Overlap > FULLMATCH) { // this means VPS
if (abs(Distance) < abs(distance)) if (abs(Distance) < abs(distance))
break; // we've already found the closest VPS event break; // we've already found the closest VPS event
} }
else if (e->Duration() <= Event->Duration()) else if (e->Duration() <= Event->Duration())
@ -629,7 +633,7 @@ void cTimers::SetEvents(void)
} }
if (Event && Event->EndTime() < now - EXPIRELATENCY && !Event->IsRunning()) if (Event && Event->EndTime() < now - EXPIRELATENCY && !Event->IsRunning())
Event = NULL; Event = NULL;
ti->SetEvent(Schedule, Event); ti->SetEvent(Event);
} }
} }
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: timers.h 1.19 2005/05/07 10:36:35 kls Exp $ * $Id: timers.h 1.23 2006/01/06 14:13:17 kls Exp $
*/ */
#ifndef __TIMERS_H #ifndef __TIMERS_H
@ -29,7 +29,7 @@ class cTimer : public cListObject {
private: private:
mutable time_t startTime, stopTime; mutable time_t startTime, stopTime;
bool recording, pending, inVpsMargin; bool recording, pending, inVpsMargin;
int flags; uint flags;
cChannel *channel; cChannel *channel;
mutable time_t day; ///< midnight of the day this timer shall hit, or of the first day it shall hit in case of a repeating timer mutable time_t day; ///< midnight of the day this timer shall hit, or of the first day it shall hit in case of a repeating timer
int weekdays; ///< bitmask, lowest bits: SSFTWTM (the 'M' is the LSB) int weekdays; ///< bitmask, lowest bits: SSFTWTM (the 'M' is the LSB)
@ -39,10 +39,9 @@ private:
int lifetime; int lifetime;
char file[MaxFileName]; char file[MaxFileName];
char *summary; char *summary;
const cSchedule *schedule;
const cEvent *event; const cEvent *event;
public: public:
cTimer(bool Instant = false, bool Pause = false); cTimer(bool Instant = false, bool Pause = false, cChannel *Channel = NULL);
cTimer(const cEvent *Event); cTimer(const cEvent *Event);
virtual ~cTimer(); virtual ~cTimer();
cTimer& operator= (const cTimer &Timer); cTimer& operator= (const cTimer &Timer);
@ -50,7 +49,7 @@ public:
bool Recording(void) const { return recording; } bool Recording(void) const { return recording; }
bool Pending(void) const { return pending; } bool Pending(void) const { return pending; }
bool InVpsMargin(void) const { return inVpsMargin; } bool InVpsMargin(void) const { return inVpsMargin; }
int Flags(void) const { return flags; } uint Flags(void) const { return flags; }
const cChannel *Channel(void) const { return channel; } const cChannel *Channel(void) const { return channel; }
time_t Day(void) const { return day; } time_t Day(void) const { return day; }
int WeekDays(void) const { return weekdays; } int WeekDays(void) const { return weekdays; }
@ -78,14 +77,15 @@ public:
bool Expired(void) const; bool Expired(void) const;
time_t StartTime(void) const; time_t StartTime(void) const;
time_t StopTime(void) const; time_t StopTime(void) const;
void SetEvent(const cSchedule *Schedule, const cEvent *Event); void SetEvent(const cEvent *Event);
void SetRecording(bool Recording); void SetRecording(bool Recording);
void SetPending(bool Pending); void SetPending(bool Pending);
void SetInVpsMargin(bool InVpsMargin); void SetInVpsMargin(bool InVpsMargin);
void SetFlags(int Flags); void SetPriority(int Priority);
void ClrFlags(int Flags); void SetFlags(uint Flags);
void InvFlags(int Flags); void ClrFlags(uint Flags);
bool HasFlags(int Flags) const; void InvFlags(uint Flags);
bool HasFlags(uint Flags) const;
void Skip(void); void Skip(void);
void OnOff(void); void OnOff(void);
cString PrintFirstDay(void) const; cString PrintFirstDay(void) const;

202
tools.c
View File

@ -4,13 +4,20 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.104 2005/11/26 14:12:31 kls Exp $ * $Id: tools.c 1.109 2006/01/08 11:40:35 kls Exp $
*/ */
#include "tools.h" #include "tools.h"
#include <ctype.h> #include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
extern "C" {
#ifdef boolean
#define HAVE_BOOLEAN
#endif
#include <jpeglib.h>
#undef boolean
}
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h> #include <sys/time.h>
@ -421,6 +428,42 @@ bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
return false; return false;
} }
int DirSizeMB(const char *DirName)
{
cReadDir d(DirName);
if (d.Ok()) {
int size = 0;
struct dirent *e;
while (size >= 0 && (e = d.Next()) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
char *buffer;
asprintf(&buffer, "%s/%s", DirName, e->d_name);
struct stat st;
if (stat(buffer, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
int n = DirSizeMB(buffer);
if (n >= 0)
size += n;
else
size = -1;
}
else
size += st.st_size / MEGABYTE(1);
}
else {
LOG_ERROR_STR(buffer);
size = -1;
}
free(buffer);
}
}
return size;
}
else
LOG_ERROR_STR(DirName);
return -1;
}
char *ReadLink(const char *FileName) char *ReadLink(const char *FileName)
{ {
char RealName[PATH_MAX]; char RealName[PATH_MAX];
@ -615,6 +658,145 @@ cString TimeString(time_t t)
return buf; return buf;
} }
// --- RgbToJpeg -------------------------------------------------------------
#define JPEGCOMPRESSMEM 500000
struct tJpegCompressData {
int size;
uchar *mem;
};
static void JpegCompressInitDestination(j_compress_ptr cinfo)
{
tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
if (jcd) {
cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM;
cinfo->dest->next_output_byte = jcd->mem = MALLOC(uchar, jcd->size);
}
}
static boolean JpegCompressEmptyOutputBuffer(j_compress_ptr cinfo)
{
tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
if (jcd) {
int Used = jcd->size;
jcd->size += JPEGCOMPRESSMEM;
jcd->mem = (uchar *)realloc(jcd->mem, jcd->size);
if (jcd->mem) {
cinfo->dest->next_output_byte = jcd->mem + Used;
cinfo->dest->free_in_buffer = jcd->size - Used;
return TRUE;
}
}
return FALSE;
}
static void JpegCompressTermDestination(j_compress_ptr cinfo)
{
tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
if (jcd) {
int Used = cinfo->dest->next_output_byte - jcd->mem;
if (Used < jcd->size) {
jcd->size = Used;
jcd->mem = (uchar *)realloc(jcd->mem, jcd->size);
}
}
}
uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality)
{
if (Quality < 0)
Quality = 0;
else if (Quality > 100)
Quality = 100;
jpeg_destination_mgr jdm;
jdm.init_destination = JpegCompressInitDestination;
jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer;
jdm.term_destination = JpegCompressTermDestination;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
cinfo.dest = &jdm;
tJpegCompressData jcd;
cinfo.client_data = &jcd;
cinfo.image_width = Width;
cinfo.image_height = Height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, Quality, true);
jpeg_start_compress(&cinfo, true);
int rs = Width * 3;
JSAMPROW rp[Height];
for (int k = 0; k < Height; k++)
rp[k] = &Mem[rs * k];
jpeg_write_scanlines(&cinfo, rp, Height);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
Size = jcd.size;
return jcd.mem;
}
// --- cBase64Encoder --------------------------------------------------------
const char *cBase64Encoder::b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
cBase64Encoder::cBase64Encoder(const uchar *Data, int Length, int MaxResult)
{
data = Data;
length = Length;
maxResult = MaxResult;
i = 0;
result = MALLOC(char, maxResult + 1);
}
cBase64Encoder::~cBase64Encoder()
{
free(result);
}
const char *cBase64Encoder::NextLine(void)
{
int r = 0;
while (i < length && r < maxResult - 3) {
result[r++] = b64[(data[i] >> 2) & 0x3F];
char c = (data[i] << 4) & 0x3F;
if (++i < length)
c |= (data[i] >> 4) & 0x0F;
result[r++] = b64[c];
if (i < length) {
c = (data[i] << 2) & 0x3F;
if (++i < length)
c |= (data[i] >> 6) & 0x03;
result[r++] = b64[c];
}
else {
i++;
result[r++] = '=';
}
if (i < length) {
c = data[i] & 0x3F;
result[r++] = b64[c];
}
else
result[r++] = '=';
i++;
}
if (r > 0) {
result[r] = 0;
return result;
}
return NULL;
}
// --- cReadLine ------------------------------------------------------------- // --- cReadLine -------------------------------------------------------------
cReadLine::cReadLine(void) cReadLine::cReadLine(void)
@ -858,6 +1040,8 @@ bool cSafeFile::Close(void)
// --- cUnbufferedFile ------------------------------------------------------- // --- cUnbufferedFile -------------------------------------------------------
//#define USE_FADVISE
#define READ_AHEAD MEGABYTE(2) #define READ_AHEAD MEGABYTE(2)
#define WRITE_BUFFER MEGABYTE(10) #define WRITE_BUFFER MEGABYTE(10)
@ -882,6 +1066,7 @@ int cUnbufferedFile::Open(const char *FileName, int Flags, mode_t Mode)
int cUnbufferedFile::Close(void) int cUnbufferedFile::Close(void)
{ {
#ifdef USE_FADVISE
if (fd >= 0) { if (fd >= 0) {
if (ahead > end) if (ahead > end)
end = ahead; end = ahead;
@ -894,6 +1079,7 @@ int cUnbufferedFile::Close(void)
begin = end = ahead = -1; begin = end = ahead = -1;
written = 0; written = 0;
} }
#endif
int OldFd = fd; int OldFd = fd;
fd = -1; fd = -1;
return close(OldFd); return close(OldFd);
@ -909,6 +1095,7 @@ off_t cUnbufferedFile::Seek(off_t Offset, int Whence)
ssize_t cUnbufferedFile::Read(void *Data, size_t Size) ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
{ {
if (fd >= 0) { if (fd >= 0) {
#ifdef USE_FADVISE
off_t pos = lseek(fd, 0, SEEK_CUR); off_t pos = lseek(fd, 0, SEEK_CUR);
// jump forward - adjust end position // jump forward - adjust end position
if (pos > end) if (pos > end)
@ -922,7 +1109,9 @@ ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
if (begin >= 0 && end > begin) if (begin >= 0 && end > begin)
posix_fadvise(fd, begin - KILOBYTE(200), end - begin + KILOBYTE(200), POSIX_FADV_DONTNEED);//XXX macros/parameters??? posix_fadvise(fd, begin - KILOBYTE(200), end - begin + KILOBYTE(200), POSIX_FADV_DONTNEED);//XXX macros/parameters???
begin = pos; begin = pos;
#endif
ssize_t bytesRead = safe_read(fd, Data, Size); ssize_t bytesRead = safe_read(fd, Data, Size);
#ifdef USE_FADVISE
if (bytesRead > 0) { if (bytesRead > 0) {
pos += bytesRead; pos += bytesRead;
end = pos; end = pos;
@ -935,6 +1124,7 @@ ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
} }
else else
end = pos; end = pos;
#endif
return bytesRead; return bytesRead;
} }
return -1; return -1;
@ -943,8 +1133,11 @@ ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
ssize_t cUnbufferedFile::Write(const void *Data, size_t Size) ssize_t cUnbufferedFile::Write(const void *Data, size_t Size)
{ {
if (fd >=0) { if (fd >=0) {
#ifdef USE_FADVISE
off_t pos = lseek(fd, 0, SEEK_CUR); off_t pos = lseek(fd, 0, SEEK_CUR);
#endif
ssize_t bytesWritten = safe_write(fd, Data, Size); ssize_t bytesWritten = safe_write(fd, Data, Size);
#ifdef USE_FADVISE
if (bytesWritten >= 0) { if (bytesWritten >= 0) {
written += bytesWritten; written += bytesWritten;
if (begin >= 0) { if (begin >= 0) {
@ -964,6 +1157,7 @@ ssize_t cUnbufferedFile::Write(const void *Data, size_t Size)
written = 0; written = 0;
} }
} }
#endif
return bytesWritten; return bytesWritten;
} }
return -1; return -1;
@ -1090,7 +1284,7 @@ int cListObject::Index(void) const
// --- cListBase ------------------------------------------------------------- // --- cListBase -------------------------------------------------------------
cListBase::cListBase(void) cListBase::cListBase(void)
{ {
objects = lastObject = NULL; objects = lastObject = NULL;
count = 0; count = 0;
} }
@ -1101,7 +1295,7 @@ cListBase::~cListBase()
} }
void cListBase::Add(cListObject *Object, cListObject *After) void cListBase::Add(cListObject *Object, cListObject *After)
{ {
if (After && After != lastObject) { if (After && After != lastObject) {
After->Next()->Insert(Object); After->Next()->Insert(Object);
After->Append(Object); After->Append(Object);
@ -1117,7 +1311,7 @@ void cListBase::Add(cListObject *Object, cListObject *After)
} }
void cListBase::Ins(cListObject *Object, cListObject *Before) void cListBase::Ins(cListObject *Object, cListObject *Before)
{ {
if (Before && Before != objects) { if (Before && Before != objects) {
Before->Prev()->Append(Object); Before->Prev()->Append(Object);
Before->Insert(Object); Before->Insert(Object);

38
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.h 1.84 2005/11/26 14:03:47 kls Exp $ * $Id: tools.h 1.89 2006/01/08 11:40:37 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
@ -110,6 +110,7 @@ bool DirectoryOk(const char *DirName, bool LogErrors = false);
bool MakeDirs(const char *FileName, bool IsDirectory = false); bool MakeDirs(const char *FileName, bool IsDirectory = false);
bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);
bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false); bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false);
int DirSizeMB(const char *DirName); ///< returns the total size of the files in the given directory, or -1 in case of an error
char *ReadLink(const char *FileName); ///< returns a new string allocated on the heap, which the caller must delete (or NULL in case of an error) char *ReadLink(const char *FileName); ///< returns a new string allocated on the heap, which the caller must delete (or NULL in case of an error)
bool SpinUpDisk(const char *FileName); bool SpinUpDisk(const char *FileName);
void TouchFile(const char *FileName); void TouchFile(const char *FileName);
@ -120,6 +121,39 @@ cString DayDateTime(time_t t = 0);
cString TimeToString(time_t t); cString TimeToString(time_t t);
cString DateString(time_t t); cString DateString(time_t t);
cString TimeString(time_t t); cString TimeString(time_t t);
uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality = 100);
///< Converts the given Memory to a JPEG image and returns a pointer
///< to the resulting image. Mem must point to a data block of exactly
///< (Width * Height) triplets of RGB image data bytes. Upon return, Size
///< will hold the number of bytes of the resulting JPEG data.
///< Quality can be in the range 0..100 and controls the quality of the
///< resulting image, where 100 is "best". The caller takes ownership of
///< the result and has to delete it once it is no longer needed.
///< The result may be NULL in case of an error.
class cBase64Encoder {
private:
const uchar *data;
int length;
int maxResult;
int i;
char *result;
static const char *b64;
public:
cBase64Encoder(const uchar *Data, int Length, int MaxResult = 64);
///< Sets up a new base 64 encoder for the given Data, with the given Length.
///< Data will not be copied and must be valid as long as NextLine() will be
///< called. MaxResult defines the maximum number of characters in any
///< result line. The resulting lines may be shorter than MaxResult in case
///< its value is not a multiple of 4.
~cBase64Encoder();
const char *NextLine(void);
///< Returns the next line of encoded data (terminated by '\0'), or NULL if
///< there is no more encoded data. The caller must call NextLine() and process
///< each returned line until NULL is returned, in order to get the entire
///< data encoded. The returned data is only valid until the next time NextLine()
///< is called, or until the object is destroyed.
};
class cTimeMs { class cTimeMs {
private: private:
@ -152,7 +186,7 @@ public:
bool Add(int FileHandle, bool Out); bool Add(int FileHandle, bool Out);
bool Poll(int TimeoutMs = 0); bool Poll(int TimeoutMs = 0);
}; };
class cReadDir { class cReadDir {
private: private:
DIR *directory; DIR *directory;

22
vdr.1
View File

@ -2,15 +2,15 @@
.\" ** The above line should force tbl to be a preprocessor ** .\" ** The above line should force tbl to be a preprocessor **
.\" Man page for vdr .\" Man page for vdr
.\" .\"
.\" Copyright (C) 2004 Klaus Schmidinger .\" Copyright (C) 2006 Klaus Schmidinger
.\" .\"
.\" You may distribute under the terms of the GNU General Public .\" You may distribute under the terms of the GNU General Public
.\" License as specified in the file COPYING that comes with the .\" License as specified in the file COPYING that comes with the
.\" vdr distribution. .\" vdr distribution.
.\" .\"
.\" $Id: vdr.1 1.15 2005/10/09 12:31:03 kls Exp $ .\" $Id: vdr.1 1.20 2006/01/08 11:51:36 kls Exp $
.\" .\"
.TH vdr 1 "19 Dec 2004" "1.3.18" "Video Disk Recorder" .TH vdr 1 "08 Jan 2006" "1.3.38" "Video Disk Recorder"
.SH NAME .SH NAME
vdr - the Video Disk Recorder vdr - the Video Disk Recorder
.SH SYNOPSIS .SH SYNOPSIS
@ -59,6 +59,13 @@ Use \fB\-E\-\fR to disable this.
If \fIfile\fR is a directory, the file \fIepg.data\fR If \fIfile\fR is a directory, the file \fIepg.data\fR
will be created in that directory. will be created in that directory.
.TP .TP
.BI \-g,\ \-\-grab= dir
Write images from the SVDRP command GRAB into the
given directory \fIdir\fR. \fIdir\fR must be the full path name of an
existing directory, without any "..", double '/'
or symlinks. By default, or if \fB\-g\-\fR is given,
grabbing images to disk is disabled.
.TP
.B \-h, \-\-help .B \-h, \-\-help
Print a help message and exit. Print a help message and exit.
.TP .TP
@ -121,6 +128,13 @@ Call \fIcmd\fR to shutdown the computer.
.BI \-t\ tty ,\ \-\-terminal= tty .BI \-t\ tty ,\ \-\-terminal= tty
Set the controlling terminal. Set the controlling terminal.
.TP .TP
.BI \-u\ user ,\ \-\-user= user
Run as user \fIuser\fR in case vdr was started as user 'root'.
Starting vdr as 'root' is necessary if the system time shall
be set from the transponder data, but for security reasons
during normal operation vdr switches to a lesser privileged
user id. By default the user 'vdr' is used.
.TP
.BI \-v\ dir ,\ \-\-video= dir .BI \-v\ dir ,\ \-\-video= dir
Use \fIdir\fR as video directory. Use \fIdir\fR as video directory.
The default is \fI/video\fR. The default is \fI/video\fR.
@ -199,7 +213,7 @@ See the file \fICONTRIBUTORS\fR in the \fBvdr\fR source distribution.
.SH REPORTING BUGS .SH REPORTING BUGS
Report bugs to <vdr\-bugs@cadsoft.de>. Report bugs to <vdr\-bugs@cadsoft.de>.
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2004 Klaus Schmidinger. Copyright \(co 2006 Klaus Schmidinger.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

37
vdr.5
View File

@ -2,15 +2,15 @@
.\" ** The above line should force tbl to be a preprocessor ** .\" ** The above line should force tbl to be a preprocessor **
.\" Man page for vdr file formats .\" Man page for vdr file formats
.\" .\"
.\" Copyright (C) 2004 Klaus Schmidinger .\" Copyright (C) 2006 Klaus Schmidinger
.\" .\"
.\" You may distribute under the terms of the GNU General Public .\" You may distribute under the terms of the GNU General Public
.\" License as specified in the file COPYING that comes with the .\" License as specified in the file COPYING that comes with the
.\" vdr distribution. .\" vdr distribution.
.\" .\"
.\" $Id: vdr.5 1.39 2005/09/26 21:38:44 kls Exp $ .\" $Id: vdr.5 1.45 2006/01/08 11:52:03 kls Exp $
.\" .\"
.TH vdr 5 "19 Mar 2005" "1.3.23" "Video Disk Recorder Files" .TH vdr 5 "08 Jan 2006" "1.3.38" "Video Disk Recorder Files"
.SH NAME .SH NAME
vdr file formats - the Video Disk Recorder Files vdr file formats - the Video Disk Recorder Files
.SH DESCRIPTION .SH DESCRIPTION
@ -152,7 +152,7 @@ tab (@);
l l. l l.
\fB0000\fR@Free To Air \fB0000\fR@Free To Air
\fB0001...000F\fR@explicitly requires the device with the given number \fB0001...000F\fR@explicitly requires the device with the given number
\fB0010...00FF\fR@reserved for user defined assignments defined in \fIca.conf\fR \fB0010...00FF\fR@reserved for user defined assignments
\fB0100...FFFF\fR@specific decryption methods as broadcast in the data stream\fR \fB0100...FFFF\fR@specific decryption methods as broadcast in the data stream\fR
.TE .TE
Values in the range 0001...00FF will not be overwritten, all other values Values in the range 0001...00FF will not be overwritten, all other values
@ -207,7 +207,7 @@ separated by ':' characters. Example:
The fields in a timer definition have the following meaning (from left The fields in a timer definition have the following meaning (from left
to right): to right):
.TP .TP
.B Status .B Flags
The individual bits in this field have the following meaning: The individual bits in this field have the following meaning:
.TS .TS
tab (@); tab (@);
@ -219,7 +219,7 @@ l l.
.TE .TE
Bits other than these can be used by external programs to mark active timers Bits other than these can be used by external programs to mark active timers
and recognize if the user has modified them. When a user modifies an active and recognize if the user has modified them. When a user modifies an active
timer, the upper 16 bits of this 32 bit parameter will be explicitly set to 0. timer, the upper 16 bits of this unsigned 32 bit parameter will be explicitly set to 0.
Note: in order to allow future extensibility, external programs using the Note: in order to allow future extensibility, external programs using the
\fBstatus\fR parameter should only use the upper 16 bit of this 32 bit parameter \fBstatus\fR parameter should only use the upper 16 bit of this 32 bit parameter
@ -227,7 +227,7 @@ and leave the lower 16 bit untouched.
.TP .TP
.B Channel .B Channel
The channel to record from. This is either the channel number as shown in the The channel to record from. This is either the channel number as shown in the
on-screen menus, or a complete channel ID. When reading \fItimers.conf\fR on-screen menus, or a complete channel ID. When reading \fItimers.conf\fR
any channel numbers will be mapped to the respective channel ids and when any channel numbers will be mapped to the respective channel ids and when
the file is written again, there will only be channel ids. Channel numbers the file is written again, there will only be channel ids. Channel numbers
are accepted as input in order to allow easier creation of timers when are accepted as input in order to allow easier creation of timers when
@ -389,24 +389,6 @@ l l.
There can be any number of actions in a line, including none at all - in which case There can be any number of actions in a line, including none at all - in which case
the entry would be used only to set the LOF to use for the given frequency range the entry would be used only to set the LOF to use for the given frequency range
and polarization. and polarization.
.SS CONDITIONAL ACCESS
The file \fIca.conf\fR defines the numbers to be used in the \fBConditional access\fR
field of channels in \fIchannels.conf\fR and assigns descriptive texts to them.
Example:
\fB101 Premiere World\fR
Anything after (and including) a '#' character is comment.
Value lines consist of an integer number, followed by a text describing
this decryption method (typically the name of the pay tv service using this
decryption method).
The special value \fB0\fR means \fBFree To Air\fR, which can be used for
channels that don't require additional decryption hardware.
The values \fB1...4\fR can be used for channels that for some reason explicitly
need a given DVB card (for backward compatibility).
.SS REMOTE CONTROL KEYS .SS REMOTE CONTROL KEYS
The file \fIremote.conf\fR contains the key assignments for all remote control The file \fIremote.conf\fR contains the key assignments for all remote control
units. Each line consists of one key assignment in the following format: units. Each line consists of one key assignment in the following format:
@ -627,7 +609,7 @@ The following tag characters are defined:
tab (@); tab (@);
l l. l l.
\fBC\fR@<channel id> <channel name> \fBC\fR@<channel id> <channel name>
\fBE\fR@<event id> <start time> <duration> <table id> \fBE\fR@<event id> <start time> <duration> <table id> <version>
\fBT\fR@<title> \fBT\fR@<title>
\fBS\fR@<short text> \fBS\fR@<short text>
\fBD\fR@<description> \fBD\fR@<description>
@ -654,6 +636,7 @@ l l.
<start time> @is the time (as a time_t integer) in UTC when this event starts <start time> @is the time (as a time_t integer) in UTC when this event starts
<duration> @is the time (in seconds) that this event will take <duration> @is the time (in seconds) that this event will take
<table id> @is a hex number that indicates the table this event is contained in (if this is left empty or 0 this event will not be overwritten or modified by data that comes from the DVB stream) <table id> @is a hex number that indicates the table this event is contained in (if this is left empty or 0 this event will not be overwritten or modified by data that comes from the DVB stream)
<version> @is a hex number that indicates the event's version number inside its table (optional)
<title> @is the title of the event <title> @is the title of the event
<short text> @is the short text of the event (typically the name of the episode etc.) <short text> @is the short text of the event (typically the name of the episode etc.)
<description> @is the description of the event (any '|' characters will be interpreted as newlines) <description> @is the description of the event (any '|' characters will be interpreted as newlines)
@ -673,7 +656,7 @@ Written by Klaus Schmidinger.
.SH REPORTING BUGS .SH REPORTING BUGS
Report bugs to <vdr\-bugs@cadsoft.de>. Report bugs to <vdr\-bugs@cadsoft.de>.
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2004 Klaus Schmidinger. Copyright \(co 2006 Klaus Schmidinger.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

214
vdr.c
View File

@ -1,7 +1,7 @@
/* /*
* vdr.c: Video Disk Recorder main program * vdr.c: Video Disk Recorder main program
* *
* Copyright (C) 2000, 2003 Klaus Schmidinger * Copyright (C) 2000, 2003, 2006 Klaus Schmidinger
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -22,13 +22,17 @@
* *
* The project's page is at http://www.cadsoft.de/vdr * The project's page is at http://www.cadsoft.de/vdr
* *
* $Id: vdr.c 1.220 2005/11/27 15:56:18 kls Exp $ * $Id: vdr.c 1.233 2006/01/08 11:49:03 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
#include <grp.h>
#include <locale.h> #include <locale.h>
#include <pwd.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include "audio.h" #include "audio.h"
@ -72,6 +76,57 @@
static int Interrupted = 0; static int Interrupted = 0;
static bool SetUser(const char *UserName)
{
if (UserName) {
struct passwd *user = getpwnam(UserName);
if (!user) {
fprintf(stderr, "vdr: unknown user: '%s'\n", UserName);
return false;
}
if (setgid(user->pw_gid) < 0) {
fprintf(stderr, "vdr: cannot set group id %u: %s\n", (unsigned int)user->pw_gid, strerror(errno));
return false;
}
if (initgroups(user->pw_name, user->pw_gid) < 0) {
fprintf(stderr, "vdr: cannot set supplemental group ids for user %s: %s\n", user->pw_name, strerror(errno));
return false;
}
if (setuid(user->pw_uid) < 0) {
fprintf(stderr, "vdr: cannot set user id %u: %s\n", (unsigned int)user->pw_uid, strerror(errno));
return false;
}
}
return true;
}
static bool SetCapSysTime(void)
{
// drop all capabilities except cap_sys_time
cap_t caps = cap_from_text("= cap_sys_time=ep");
if (!caps) {
fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
return false;
}
if (cap_set_proc(caps) == -1) {
fprintf(stderr, "vdr: cap_set_proc failed: %s\n", strerror(errno));
cap_free(caps);
return false;
}
cap_free(caps);
return true;
}
static bool SetKeepCaps(bool On)
{
// set keeping capabilities during setuid() on/off
if (prctl(PR_SET_KEEPCAPS, On ? 1 : 0, 0, 0, 0) != 0) {
fprintf(stderr, "vdr: prctl failed\n");
return false;
}
return true;
}
static void SignalHandler(int signum) static void SignalHandler(int signum)
{ {
if (signum != SIGPIPE) { if (signum != SIGPIPE) {
@ -102,11 +157,14 @@ int main(int argc, char *argv[])
// Command line options: // Command line options:
#define DEFAULTVDRUSER "vdr"
#define DEFAULTSVDRPPORT 2001 #define DEFAULTSVDRPPORT 2001
#define DEFAULTWATCHDOG 0 // seconds #define DEFAULTWATCHDOG 0 // seconds
#define DEFAULTPLUGINDIR PLUGINDIR #define DEFAULTPLUGINDIR PLUGINDIR
#define DEFAULTEPGDATAFILENAME "epg.data" #define DEFAULTEPGDATAFILENAME "epg.data"
bool StartedAsRoot = false;
const char *VdrUser = DEFAULTVDRUSER;
int SVDRPport = DEFAULTSVDRPPORT; int SVDRPport = DEFAULTSVDRPPORT;
const char *AudioCommand = NULL; const char *AudioCommand = NULL;
const char *ConfigDirectory = NULL; const char *ConfigDirectory = NULL;
@ -144,6 +202,7 @@ int main(int argc, char *argv[])
{ "daemon", no_argument, NULL, 'd' }, { "daemon", no_argument, NULL, 'd' },
{ "device", required_argument, NULL, 'D' }, { "device", required_argument, NULL, 'D' },
{ "epgfile", required_argument, NULL, 'E' }, { "epgfile", required_argument, NULL, 'E' },
{ "grab", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "lib", required_argument, NULL, 'L' }, { "lib", required_argument, NULL, 'L' },
{ "lirc", optional_argument, NULL, 'l' | 0x100 }, { "lirc", optional_argument, NULL, 'l' | 0x100 },
@ -156,6 +215,7 @@ int main(int argc, char *argv[])
{ "record", required_argument, NULL, 'r' }, { "record", required_argument, NULL, 'r' },
{ "shutdown", required_argument, NULL, 's' }, { "shutdown", required_argument, NULL, 's' },
{ "terminal", required_argument, NULL, 't' }, { "terminal", required_argument, NULL, 't' },
{ "user", required_argument, NULL, 'u' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "vfat", no_argument, NULL, 'v' | 0x100 }, { "vfat", no_argument, NULL, 'v' | 0x100 },
{ "video", required_argument, NULL, 'v' }, { "video", required_argument, NULL, 'v' },
@ -164,7 +224,7 @@ int main(int argc, char *argv[])
}; };
int c; 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) { while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'a': AudioCommand = optarg; case 'a': AudioCommand = optarg;
break; break;
@ -183,6 +243,8 @@ int main(int argc, char *argv[])
break; break;
case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL); case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL);
break; break;
case 'g': cSVDRP::SetGrabImageDir(*optarg != '-' ? optarg : NULL);
break;
case 'h': DisplayHelp = true; case 'h': DisplayHelp = true;
break; break;
case 'l': { case 'l': {
@ -248,6 +310,9 @@ int main(int argc, char *argv[])
return 2; return 2;
} }
break; break;
case 'u': if (*optarg)
VdrUser = optarg;
break;
case 'V': DisplayVersion = true; case 'V': DisplayVersion = true;
break; break;
case 'v' | 0x100: case 'v' | 0x100:
@ -270,6 +335,20 @@ int main(int argc, char *argv[])
} }
} }
// Set user id in case we were started as root:
if (getuid() == 0) {
StartedAsRoot = true;
if (!SetKeepCaps(true))
return 2;
if (!SetUser(VdrUser))
return 2;
if (!SetKeepCaps(false))
return 2;
if (!SetCapSysTime())
return 2;
}
// Help and version info: // Help and version info:
if (DisplayHelp || DisplayVersion) { if (DisplayHelp || DisplayVersion) {
@ -285,11 +364,15 @@ int main(int argc, char *argv[])
" -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
" there may be several -D options (default: all DVB\n" " there may be several -D options (default: all DVB\n"
" devices will be used)\n" " devices will be used)\n"
" -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n" " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n"
" '%s' in the video directory)\n" " '%s' in the video directory)\n"
" '-E-' disables this\n" " '-E-' disables this\n"
" if FILE is a directory, the default EPG file will be\n" " if FILE is a directory, the default EPG file will be\n"
" created in that directory\n" " created in that directory\n"
" -g DIR, --grab=DIR write images from the SVDRP command GRAB into the\n"
" given DIR; DIR must be the full path name of an\n"
" existing directory, without any \"..\", double '/'\n"
" or symlinks (default: none, same as -g-)\n"
" -h, --help print this help and exit\n" " -h, --help print this help and exit\n"
" -l LEVEL, --log=LEVEL set log level (default: 3)\n" " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
" 0 = no logging, 1 = errors only,\n" " 0 = no logging, 1 = errors only,\n"
@ -309,6 +392,8 @@ int main(int argc, char *argv[])
" -r CMD, --record=CMD call CMD before and after a recording\n" " -r CMD, --record=CMD call CMD before and after a recording\n"
" -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
" -t TTY, --terminal=TTY controlling tty\n" " -t TTY, --terminal=TTY controlling tty\n"
" -u USER, --user=USER run as user USER (default: %s); only applicable\n"
" if started as root\n"
" -v DIR, --video=DIR use DIR as video directory (default: %s)\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
" -V, --version print version information and exit\n" " -V, --version print version information and exit\n"
" --vfat encode special characters in recording names to\n" " --vfat encode special characters in recording names to\n"
@ -321,6 +406,7 @@ int main(int argc, char *argv[])
LIRC_DEVICE, LIRC_DEVICE,
DEFAULTSVDRPPORT, DEFAULTSVDRPPORT,
RCU_DEVICE, RCU_DEVICE,
DEFAULTVDRUSER,
VideoDirectory, VideoDirectory,
DEFAULTWATCHDOG DEFAULTWATCHDOG
); );
@ -371,7 +457,7 @@ int main(int argc, char *argv[])
if (DaemonMode) { if (DaemonMode) {
if (daemon(1, 0) == -1) { if (daemon(1, 0) == -1) {
fprintf(stderr, "%m\n"); fprintf(stderr, "vdr: %m\n");
esyslog("ERROR: %m"); esyslog("ERROR: %m");
return 2; return 2;
} }
@ -385,12 +471,16 @@ int main(int argc, char *argv[])
} }
isyslog("VDR version %s started", VDRVERSION); isyslog("VDR version %s started", VDRVERSION);
if (StartedAsRoot)
isyslog("switched to user '%s'", VdrUser);
if (DaemonMode)
dsyslog("running as daemon (tid=%d)", cThread::ThreadId());
cThread::SetMainThreadId();
// Main program loop variables - need to be here to have them initialized before any EXIT(): // Main program loop variables - need to be here to have them initialized before any EXIT():
cOsdObject *Menu = NULL; cOsdObject *Menu = NULL;
cOsdObject *Temp = NULL; int LastChannel = 0;
int LastChannel = -1;
int LastTimerChannel = -1; int LastTimerChannel = -1;
int PreviousChannel[2] = { 1, 1 }; int PreviousChannel[2] = { 1, 1 };
int PreviousChannelIndex = 0; int PreviousChannelIndex = 0;
@ -401,6 +491,7 @@ int main(int argc, char *argv[])
bool ForceShutdown = false; bool ForceShutdown = false;
bool UserShutdown = false; bool UserShutdown = false;
bool TimerInVpsMargin = false; bool TimerInVpsMargin = false;
bool IsInfoMenu = false;
// Load plugins: // Load plugins:
@ -423,7 +514,6 @@ int main(int argc, char *argv[])
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true) && Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true) &&
RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) && RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) &&
SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) && SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) &&
CaDefinitions.Load(AddDirectory(ConfigDirectory, "ca.conf"), true) &&
Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) && Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) &&
KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true) KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true)
)) ))
@ -434,6 +524,7 @@ int main(int argc, char *argv[])
// Recordings: // Recordings:
Recordings.Update(); Recordings.Update();
DeletedRecordings.Update();
// EPG data: // EPG data:
@ -555,6 +646,8 @@ int main(int argc, char *argv[])
// Main program loop: // Main program loop:
#define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
while (!Interrupted) { while (!Interrupted) {
// Handle emergency exits: // Handle emergency exits:
if (cThread::EmergencyExit()) { if (cThread::EmergencyExit()) {
@ -576,8 +669,8 @@ int main(int argc, char *argv[])
&& !(LastTimerChannel > 0 && Channels.SwitchTo(LastTimerChannel)) // ...or the one used by the last timer... && !(LastTimerChannel > 0 && Channels.SwitchTo(LastTimerChannel)) // ...or the one used by the last timer...
&& !cDevice::SwitchChannel(1) // ...or the next higher available one... && !cDevice::SwitchChannel(1) // ...or the next higher available one...
&& !cDevice::SwitchChannel(-1)) // ...or the next lower available one && !cDevice::SwitchChannel(-1)) // ...or the next lower available one
; ;
} }
lastTime = time(NULL); // don't do this too often lastTime = time(NULL); // don't do this too often
LastTimerChannel = -1; LastTimerChannel = -1;
} }
@ -626,7 +719,7 @@ int main(int argc, char *argv[])
// Channel display: // Channel display:
if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) { if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
if (!Menu) if (!Menu)
Menu = Temp = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel > 0); Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0);
LastChannel = cDevice::CurrentChannel(); LastChannel = cDevice::CurrentChannel();
LastChannelChanged = time(NULL); LastChannelChanged = time(NULL);
} }
@ -667,8 +760,10 @@ int main(int argc, char *argv[])
TimerInVpsMargin = true; TimerInVpsMargin = true;
} }
} }
if (!Menu && Recordings.NeedsUpdate()) if (!Menu && Recordings.NeedsUpdate()) {
Recordings.Update(); Recordings.Update();
DeletedRecordings.Update();
}
// CAM control: // CAM control:
if (!Menu && !cOsd::IsOpen()) { if (!Menu && !cOsd::IsOpen()) {
Menu = CamControl(); Menu = CamControl();
@ -692,22 +787,39 @@ int main(int argc, char *argv[])
// Menu control: // Menu control:
case kMenu: case kMenu:
key = kNone; // nobody else needs to see this key key = kNone; // nobody else needs to see this key
if (Menu) { if (Menu)
DELETENULL(Menu); DELETE_MENU;
if (!Temp) else if (cControl::Control() && cOsd::IsOpen())
break;
}
if (cControl::Control())
cControl::Control()->Hide(); cControl::Control()->Hide();
Menu = new cMenuMain(cControl::Control()); else
Temp = NULL; Menu = new cMenuMain;
break;
// Info:
case kInfo: {
bool WasInfoMenu = IsInfoMenu;
DELETE_MENU;
if (!WasInfoMenu) {
IsInfoMenu = true;
if (cControl::Control()) {
cControl::Control()->Hide();
Menu = cControl::Control()->GetInfo();
if (Menu)
Menu->Show();
else
IsInfoMenu = false;
}
else {
cRemote::Put(kOk, true);
cRemote::Put(kSchedule, true);
}
}
}
break; break;
#define DirectMainFunction(function)\ #define DirectMainFunction(function)\
DELETENULL(Menu);\ DELETE_MENU;\
if (cControl::Control())\ if (cControl::Control())\
cControl::Control()->Hide();\ cControl::Control()->Hide();\
Menu = new cMenuMain(cControl::Control(), function);\ Menu = new cMenuMain(function);\
Temp = NULL;\
key = kNone; // nobody else needs to see this key key = kNone; // nobody else needs to see this key
case kSchedule: DirectMainFunction(osSchedule); break; case kSchedule: DirectMainFunction(osSchedule); break;
case kChannels: DirectMainFunction(osChannels); break; case kChannels: DirectMainFunction(osChannels); break;
@ -717,18 +829,14 @@ int main(int argc, char *argv[])
case kCommands: DirectMainFunction(osCommands); break; case kCommands: DirectMainFunction(osCommands); break;
case kUser1 ... kUser9: cRemote::PutMacro(key); key = kNone; break; case kUser1 ... kUser9: cRemote::PutMacro(key); key = kNone; break;
case k_Plugin: { case k_Plugin: {
DELETENULL(Menu); DELETE_MENU;
Temp = NULL;
if (cControl::Control()) if (cControl::Control())
cControl::Control()->Hide(); cControl::Control()->Hide();
cPlugin *plugin = cPluginManager::GetPlugin(cRemote::GetPlugin()); cPlugin *plugin = cPluginManager::GetPlugin(cRemote::GetPlugin());
if (plugin) { if (plugin) {
Menu = Temp = plugin->MainMenuAction(); Menu = plugin->MainMenuAction();
if (Menu) { if (Menu)
Menu->Show(); Menu->Show();
if (Menu->IsMenu())
((cOsdMenu*)Menu)->Display();
}
} }
else else
esyslog("ERROR: unknown plugin '%s'", cRemote::GetPlugin()); esyslog("ERROR: unknown plugin '%s'", cRemote::GetPlugin());
@ -757,7 +865,7 @@ int main(int argc, char *argv[])
else else
cDevice::PrimaryDevice()->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); cDevice::PrimaryDevice()->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
if (!Menu && !cOsd::IsOpen()) if (!Menu && !cOsd::IsOpen())
Menu = Temp = cDisplayVolume::Create(); Menu = cDisplayVolume::Create();
cDisplayVolume::Process(key); cDisplayVolume::Process(key);
key = kNone; // nobody else needs to see these keys key = kNone; // nobody else needs to see these keys
break; break;
@ -765,12 +873,10 @@ int main(int argc, char *argv[])
case kAudio: case kAudio:
if (cControl::Control()) if (cControl::Control())
cControl::Control()->Hide(); cControl::Control()->Hide();
if (Temp && !cDisplayTracks::IsOpen()) { if (!cDisplayTracks::IsOpen()) {
DELETENULL(Menu); DELETE_MENU;
Temp = NULL; Menu = cDisplayTracks::Create();
} }
if (!Menu && !cOsd::IsOpen())
Menu = Temp = cDisplayTracks::Create();
else else
cDisplayTracks::Process(key); cDisplayTracks::Process(key);
key = kNone; key = kNone;
@ -778,8 +884,7 @@ int main(int argc, char *argv[])
// Pausing live video: // Pausing live video:
case kPause: case kPause:
if (!cControl::Control()) { if (!cControl::Control()) {
DELETENULL(Menu); DELETE_MENU;
Temp = NULL;
if (!cRecordControls::PauseLiveVideo()) if (!cRecordControls::PauseLiveVideo())
Skins.Message(mtError, tr("No free DVB device to record!")); Skins.Message(mtError, tr("No free DVB device to record!"));
key = kNone; // nobody else needs to see this key key = kNone; // nobody else needs to see this key
@ -797,8 +902,7 @@ int main(int argc, char *argv[])
break; break;
// Power off: // Power off:
case kPower: isyslog("Power button pressed"); case kPower: isyslog("Power button pressed");
DELETENULL(Menu); DELETE_MENU;
Temp = NULL;
if (!Shutdown) { if (!Shutdown) {
Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!")); Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
break; break;
@ -828,53 +932,46 @@ int main(int argc, char *argv[])
state = osEnd; state = osEnd;
} }
switch (state) { switch (state) {
case osPause: DELETENULL(Menu); case osPause: DELETE_MENU;
cControl::Shutdown(); // just in case cControl::Shutdown(); // just in case
Temp = NULL;
if (!cRecordControls::PauseLiveVideo()) if (!cRecordControls::PauseLiveVideo())
Skins.Message(mtError, tr("No free DVB device to record!")); Skins.Message(mtError, tr("No free DVB device to record!"));
break; break;
case osRecord: DELETENULL(Menu); case osRecord: DELETE_MENU;
Temp = NULL;
if (cRecordControls::Start()) if (cRecordControls::Start())
;//XXX Skins.Message(mtInfo, tr("Recording")); Skins.Message(mtInfo, tr("Recording started"));
else else
Skins.Message(mtError, tr("No free DVB device to record!")); Skins.Message(mtError, tr("No free DVB device to record!"));
break; break;
case osRecordings: case osRecordings:
DELETENULL(Menu); DELETE_MENU;
cControl::Shutdown(); cControl::Shutdown();
Temp = NULL; Menu = new cMenuMain(osRecordings);
Menu = new cMenuMain(false, osRecordings);
break; break;
case osReplay: DELETENULL(Menu); case osReplay: DELETE_MENU;
cControl::Shutdown(); cControl::Shutdown();
Temp = NULL;
cControl::Launch(new cReplayControl); cControl::Launch(new cReplayControl);
break; break;
case osStopReplay: case osStopReplay:
DELETENULL(Menu); DELETE_MENU;
cControl::Shutdown(); cControl::Shutdown();
Temp = NULL;
break; break;
case osSwitchDvb: case osSwitchDvb:
DELETENULL(Menu); DELETE_MENU;
cControl::Shutdown(); cControl::Shutdown();
Temp = NULL;
Skins.Message(mtInfo, tr("Switching primary DVB...")); Skins.Message(mtInfo, tr("Switching primary DVB..."));
cDevice::SetPrimaryDevice(Setup.PrimaryDVB); cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
break; break;
case osPlugin: DELETENULL(Menu); case osPlugin: DELETE_MENU;
Menu = Temp = cMenuMain::PluginOsdObject(); Menu = cMenuMain::PluginOsdObject();
if (Menu) if (Menu)
Menu->Show(); Menu->Show();
break; break;
case osBack: case osBack:
case osEnd: if (Interact == Menu) case osEnd: if (Interact == Menu)
DELETENULL(Menu); DELETE_MENU;
else else
cControl::Shutdown(); cControl::Shutdown();
Temp = NULL;
break; break;
default: ; default: ;
} }
@ -913,7 +1010,6 @@ int main(int argc, char *argv[])
case kPlay: case kPlay:
if (cReplayControl::LastReplayed()) { if (cReplayControl::LastReplayed()) {
cControl::Shutdown(); cControl::Shutdown();
Temp = NULL;
cControl::Launch(new cReplayControl); cControl::Launch(new cReplayControl);
} }
break; break;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: videodir.c 1.13 2005/10/31 12:07:41 kls Exp $ * $Id: videodir.c 1.14 2005/12/18 10:33:20 kls Exp $
*/ */
#include "videodir.h" #include "videodir.h"
@ -16,6 +16,7 @@
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include "recording.h"
#include "tools.h" #include "tools.h"
const char *VideoDirectory = VIDEODIR; const char *VideoDirectory = VIDEODIR;
@ -185,12 +186,17 @@ bool VideoFileSpaceAvailable(int SizeMB)
int VideoDiskSpace(int *FreeMB, int *UsedMB) int VideoDiskSpace(int *FreeMB, int *UsedMB)
{ {
int free = 0, used = 0; int free = 0, used = 0;
int deleted = DeletedRecordings.TotalFileSizeMB();
cVideoDirectory Dir; cVideoDirectory Dir;
do { do {
int u; int u;
free += Dir.FreeMB(&u); free += Dir.FreeMB(&u);
used += u; used += u;
} while (Dir.Next()); } while (Dir.Next());
if (deleted > used)
deleted = used; // let's not get beyond 100%
free += deleted;
used -= deleted;
if (FreeMB) if (FreeMB)
*FreeMB = free; *FreeMB = free;
if (UsedMB) if (UsedMB)