Version 1.3.23

- The setup option "DVB/Video display format" is now only available if "Video format"
  is set to "4:3" (suggested by Mikko Salo).
- Updated the Russian OSD texts (thanks to Vyacheslav Dikonov).
- Dropped CA support for the old '-icam' firmware.
- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
- Updated the Swedish OSD texts (thanks to Tomas Prybil).
- Fixed a few French OSD texts that were in the wrong place.
- Improved matching timers to EPG events, especially in case there are several events
  with the same VPS time.
- Fixed cDolbyRepacker to allow recording ProSieben HD broadcasts (thanks to Reinhard
  Nissl).
- Fixed cDvbDevice::SetVideoDisplayFormat() in case of 16:9 (thanks to Marco Schlüßler).
- The running status of a VPS event is now only taken seriously if that event has been
  seen within the last 30 seconds - otherwise recording is done as if no VPS was
  available.
- The day of a timer is now stored as a full date in ISO notation ("YYYY-MM-DD") in
  'timers.conf' and for the result of the SVDRP command LSTT (based in parts on a
  patch by Roman Krenický).
- Some fixes to avoid compiler warnings in gcc 4.0 (thanks to Ville Skyttä for reporting
  these).
- Single shot timers are now reliably deleted when they have expired.
- Fixed setting the colored button help after deleting a recording in case the next
  menu entry is a directory (thanks to Steffen Beyer).
- Improved falling back to normal recording if the VPS data hasn't been seen for more
  than 30 seconds.
- Added a missing cMutexLock to cRemote::HasKeys() (thanks to Wolfgang Rohdewald).
- All log entries regarding timers now contain a short description of the timer.
This commit is contained in:
Klaus Schmidinger 2005-03-20 18:00:00 +01:00
parent 05402c7407
commit 782b517c51
25 changed files with 557 additions and 416 deletions

View File

@ -1281,6 +1281,7 @@ Wolfgang Rohdewald <wolfgang@rohdewald.de>
in cDevice::Shutdown() in cDevice::Shutdown()
for removing some unneeded code and fixing access to unallocated memory in for removing some unneeded code and fixing access to unallocated memory in
cEvent::FixEpgBugs() cEvent::FixEpgBugs()
for adding a missing cMutexLock to cRemote::HasKeys()
Chad Flynt <hoochster@sofnet.com> Chad Flynt <hoochster@sofnet.com>
for suggestions and experiments regarding the buffer reserve in cTransfer for suggestions and experiments regarding the buffer reserve in cTransfer
@ -1292,3 +1293,17 @@ 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
Mikko Salo <mikko.salo@ppe.inet.fi>
for suggesting to make the setup option "DVB/Video display format" available only
if "Video format" is set to "4:3"
Roman Krenický <free-rtk@gmx.de>
for a patch that was used a a basis for changing a timer's day handling to full date
Ville Skyttä <ville.skytta@iki.fi>
for reporting several compiler warnings in gcc 4.0
Steffen Beyer <cpunk@reactor.de>
for fixing setting the colored button help after deleting a recording in case the next
menu entry is a directory

30
HISTORY
View File

@ -3443,3 +3443,33 @@ Video Disk Recorder Revision History
Luca Olivetti). Luca Olivetti).
- Fixed handling repeated kAudio keys. - Fixed handling repeated kAudio keys.
- Improved displaying the the current audio track in the ST:TNG channel display. - Improved displaying the the current audio track in the ST:TNG channel display.
2005-03-20: Version 1.3.23
- The setup option "DVB/Video display format" is now only available if "Video format"
is set to "4:3" (suggested by Mikko Salo).
- Updated the Russian OSD texts (thanks to Vyacheslav Dikonov).
- Dropped CA support for the old '-icam' firmware.
- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
- Updated the Swedish OSD texts (thanks to Tomas Prybil).
- Fixed a few French OSD texts that were in the wrong place.
- Improved matching timers to EPG events, especially in case there are several events
with the same VPS time.
- Fixed cDolbyRepacker to allow recording ProSieben HD broadcasts (thanks to Reinhard
Nissl).
- Fixed cDvbDevice::SetVideoDisplayFormat() in case of 16:9 (thanks to Marco Schlüßler).
- The running status of a VPS event is now only taken seriously if that event has been
seen within the last 30 seconds - otherwise recording is done as if no VPS was
available.
- The day of a timer is now stored as a full date in ISO notation ("YYYY-MM-DD") in
'timers.conf' and for the result of the SVDRP command LSTT (based in parts on a
patch by Roman Krenický).
- Some fixes to avoid compiler warnings in gcc 4.0 (thanks to Ville Skyttä for reporting
these).
- Single shot timers are now reliably deleted when they have expired.
- Fixed setting the colored button help after deleting a recording in case the next
menu entry is a directory (thanks to Steffen Beyer).
- Improved falling back to normal recording if the VPS data hasn't been seen for more
than 30 seconds.
- Added a missing cMutexLock to cRemote::HasKeys() (thanks to Wolfgang Rohdewald).
- All log entries regarding timers now contain a short description of the timer.

18
MANUAL
View File

@ -381,10 +381,9 @@ Version 1.2
Any changes made in the "Channels" list (like renaming or Any changes made in the "Channels" list (like renaming or
reordering channels) will be automatically reflected in the reordering channels) will be automatically reflected in the
timers settings. timers settings.
Day: The day on which this timer shall start. This can be either a Day: The day on which this timer shall start. This can be a
"day of month" (1..31), which allows programming a "single shot" date (like 2005-03-19), which allows programming a "single shot"
timer that hits once and is deleted after it ends. Single shot timer that hits once and is deleted after it ends.
timers can be programmed up to one month into the future.
Another option here are "repeating timers" which are defined Another option here are "repeating timers" which are defined
by listing the days of the week on which they shall record. by listing the days of the week on which they shall record.
For example, a timer that shall record every monday and wednesday For example, a timer that shall record every monday and wednesday
@ -392,6 +391,9 @@ Version 1.2
The '0' key toggles between a single shot and a repeating timer. The '0' key toggles between a single shot and a repeating timer.
If "Day" indicates a repeating timer, the keys '1'...'7' can be If "Day" indicates a repeating timer, the keys '1'...'7' can be
used to toggle the individual days ('1' is monday). used to toggle the individual days ('1' is monday).
You can also switch to a set of predefined repeating timer settings
by pressing the "Left" key when the day is the present day. To return
to the single shot mode just press "Right" until a date is displayed.
Start: The start time of the timer in hh:mm as 24 hour ("military") time. Start: The start time of the timer in hh:mm as 24 hour ("military") time.
Stop: The stop time of the timer. Stop: The stop time of the timer.
VPS: Defines whether the timer shall use VPS (if available). If this VPS: Defines whether the timer shall use VPS (if available). If this
@ -588,12 +590,14 @@ Version 1.2
from the primary DVB interface, so that the viewer will from the primary DVB interface, so that the viewer will
be disturbed as little as possible. be disturbed as little as possible.
Video format = 4:3 The video format (or aspect ratio) of the tv set in use
(4:3 or 16:9).
Video display format = letterbox Video display format = letterbox
The display format to use for playing wide screen video on The display format to use for playing wide screen video on
a 4:3 tv set ("pan & scan", "letterbox" or "center cut out"). a 4:3 tv set ("pan & scan", "letterbox" or "center cut out").
This option is only available if "Video format" is set to
Video format = 4:3 The video format (or aspect ratio) of the tv set in use 4:3.
(4:3 or 16:9).
Use Dolby Digital = yes Use Dolby Digital = yes
Turns recording of the Dolby Digital audio channels on Turns recording of the Dolby Digital audio channels on

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.35 2005/02/06 09:44:53 kls Exp $ * $Id: channels.c 1.36 2005/03/19 15:56:38 kls Exp $
*/ */
#include "channels.h" #include "channels.h"
@ -694,9 +694,12 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
char *p = strchr(vpidbuf, '+'); char *p = strchr(vpidbuf, '+');
if (p) if (p)
*p++ = 0; *p++ = 0;
sscanf(vpidbuf, "%d", &vpid); if (sscanf(vpidbuf, "%d", &vpid) != 1)
if (p) return false;
sscanf(p, "%d", &ppid); if (p) {
if (sscanf(p, "%d", &ppid) != 1)
return false;
}
else else
ppid = vpid; ppid = vpid;

View File

@ -48,7 +48,7 @@ PREMIERE 1,PREM 1;PREMIERE:11797:hC34:S19.2E:27500:511:512=deu,513=deu;515=deu:3
PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:32:1722,1801,1702:11:133:2:0 PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:32:1722,1801,1702:11:133:2:0
PREMIERE 3,PREM 3;PREMIERE:11797:hC34:S19.2E:27500:2303:2304=deu,2305=deu:32:1722,1801,1702:43:133:2:0 PREMIERE 3,PREM 3;PREMIERE:11797:hC34:S19.2E:27500:2303:2304=deu,2305=deu:32:1722,1801,1702:43: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 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:32:1801,1722,1702:29:133:2:0 PREMIERE 5,PREM 5;PREMIERE:11797:hC34:S19.2E:27500:1279:1280=deu,1281=deu:32:1801,1722,1702: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:1722,1702,1801:20:133:2:0 PREMIERE 7,PREM 7;PREMIERE:11797:hC34:S19.2E:27500:1023:1024=deu:32:1722,1702,1801:20:133:2:0
DISNEY CHANNEL,DISNEY;PREMIERE:11758:hC34:S19.2E:27500:2559:2560=deu:0:1722,1801,1702:34:133:17:0 DISNEY CHANNEL,DISNEY;PREMIERE:11758:hC34:S19.2E:27500:2559:2560=deu:0:1722,1801,1702:34:133:17:0
@ -90,9 +90,9 @@ TELE 5;BetaDigital:12480:vC34:S19.2E:27500:1535:1536=deu:38:0:51:133:33:0
:@201 Sky :@201 Sky
Sky One;BSkyB:12226:hC23:S28.2E:27500:2305+2304:2306=eng:2307:960,961:4705:2:2027:0 Sky One;BSkyB:12226:hC23:S28.2E:27500:2305+2304:2306=eng:2307:960,961:4705:2:2027:0
Sky Mix;BSkyB:12226:hC23:S28.2E:27500:2314+2304:2315=eng,2316=NAR:2317:960,961:5104:2:2027:0 Sky Mix;BSkyB:12226:hC23:S28.2E:27500:2314+2304:2315=eng,2316=NAR:2317:960,961:5104:2:2027:0
ITV2;BSkyB:10906:vC56:S28.2E:22000:2350:2351=eng,2352=eng:2353:960,961:10240:2:2054:0 ITV2;BSkyB:10906:vC56:S28.2E:22000:2350:2351=eng:2353:960,961:10240:2:2054:0
Sci-Fi;BSkyB:12148:hC23:S28.2E:27500:2314+2304:2315=eng:2316:960,961:4905:2:2023:0 Sci-Fi;BSkyB:12148:hC23:S28.2E:27500:2320+2304:2321=eng:2322:960,961:4905:2:2023:0
Paramount;BSkyB:12187:hC23:S28.2E:27500:2313+2304:2314=eng:2315:960,961:5904:2:2025:0 Paramount;BSkyB:12187:hC23:S28.2E:27500:2313+2304:2317=eng,2318=NAR:2315:960,961:5904:2:2025:0
Discovery;BSkyB:11875:hC23:S28.2E:27500:2304:2306=eng,2307=NAR:2305:960,961:6201:2:2009:0 Discovery;BSkyB:11875:hC23:S28.2E:27500:2304:2306=eng,2307=NAR:2305: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

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.215 2005/02/20 12:50:37 kls Exp $ * $Id: config.h 1.216 2005/03/05 15:44:35 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -20,8 +20,8 @@
#include "i18n.h" #include "i18n.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "1.3.22" #define VDRVERSION "1.3.23"
#define VDRVERSNUM 10322 // Version * 10000 + Major * 100 + Minor #define VDRVERSNUM 10323 // Version * 10000 + Major * 100 + Minor
#define MAXPRIORITY 99 #define MAXPRIORITY 99
#define MAXLIFETIME 99 #define MAXLIFETIME 99

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.c 1.124 2005/02/20 13:35:28 kls Exp $ * $Id: dvbdevice.c 1.127 2005/03/20 10:10:38 kls Exp $
*/ */
#include "dvbdevice.h" #include "dvbdevice.h"
@ -577,7 +577,7 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz
else { else {
// write PNM file: // write PNM file:
if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 || if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) { fwrite(mem, vm.width * vm.height * 3, 1, f) != 1) {
LOG_ERROR_STR(FileName); LOG_ERROR_STR(FileName);
result |= 1; result |= 1;
} }
@ -604,7 +604,7 @@ void cDvbDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
cDevice::SetVideoDisplayFormat(VideoDisplayFormat); cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
if (HasDecoder()) { if (HasDecoder()) {
if (Setup.VideoFormat) { if (Setup.VideoFormat) {
CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_CENTER_CUT_OUT)); CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX));
} }
else { else {
switch (VideoDisplayFormat) { switch (VideoDisplayFormat) {
@ -757,8 +757,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
if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE) if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE)
needsDetachReceivers = !ciHandler // only LL-firmware can do non-live CA channels needsDetachReceivers = Ca() != Channel->Ca();
|| Ca() != Channel->Ca();
else if (!IsPrimaryDevice()) else if (!IsPrimaryDevice())
result = true; result = true;
#ifdef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE #ifdef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
@ -781,27 +780,21 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{ {
bool IsEncrypted = Channel->Ca() > CACONFBASE && !ciHandler; // only LL-firmware can do non-live CA channels
bool DoTune = !dvbTuner->IsTunedTo(Channel); bool DoTune = !dvbTuner->IsTunedTo(Channel);
bool TurnOffLivePIDs = HasDecoder() bool TurnOffLivePIDs = HasDecoder()
&& (DoTune && (DoTune
|| IsEncrypted && pidHandles[ptVideo].pid != Channel->Vpid() // CA channels can only be decrypted in "live" mode
|| !IsPrimaryDevice() || !IsPrimaryDevice()
|| LiveView // for a new live view the old PIDs need to be turned off || LiveView // for a new live view the old PIDs need to be turned off
|| pidHandles[ptVideo].pid == Channel->Vpid() // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER || pidHandles[ptVideo].pid == Channel->Vpid() // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
); );
bool StartTransferMode = IsPrimaryDevice() && !IsEncrypted && !DoTune bool StartTransferMode = IsPrimaryDevice() && !DoTune
&& (LiveView && HasPid(Channel->Vpid() ? Channel->Vpid() : Channel->Apid(0)) && (pidHandles[ptVideo].pid != Channel->Vpid() || pidHandles[ptAudio].pid != Channel->Apid(0))// the PID is already set as DMX_PES_OTHER && (LiveView && HasPid(Channel->Vpid() ? Channel->Vpid() : Channel->Apid(0)) && (pidHandles[ptVideo].pid != Channel->Vpid() || pidHandles[ptAudio].pid != Channel->Apid(0))// the PID is already set as DMX_PES_OTHER
|| !LiveView && (pidHandles[ptVideo].pid == Channel->Vpid() || pidHandles[ptAudio].pid == Channel->Apid(0)) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER || !LiveView && (pidHandles[ptVideo].pid == Channel->Vpid() || pidHandles[ptAudio].pid == Channel->Apid(0)) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
); );
bool TurnOnLivePIDs = HasDecoder() && !StartTransferMode bool TurnOnLivePIDs = HasDecoder() && !StartTransferMode && LiveView;
&& (IsEncrypted // CA channels can only be decrypted in "live" mode
|| LiveView
);
#ifndef DO_MULTIPLE_RECORDINGS #ifndef DO_MULTIPLE_RECORDINGS
TurnOffLivePIDs = TurnOnLivePIDs = true; TurnOffLivePIDs = TurnOnLivePIDs = true;
@ -919,7 +912,7 @@ bool cDvbDevice::CanReplay(void) const
if (Receiving()) if (Receiving())
return false; return false;
#endif #endif
return cDevice::CanReplay() && (Ca() <= MAXDEVICES || ciHandler); // with non-LL-firmware we can only replay if there is no CA recording going on return cDevice::CanReplay();
} }
bool cDvbDevice::SetPlayMode(ePlayMode PlayMode) bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)

4
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.102 2005/01/02 11:52:12 kls Exp $ * $Id: eit.c 1.103 2005/03/20 12:33:51 kls Exp $
*/ */
#include "eit.h" #include "eit.h"
@ -246,6 +246,8 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
if (Empty && Tid == 0x4E && getSectionNumber() == 0) if (Empty && Tid == 0x4E && getSectionNumber() == 0)
// ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
pSchedule->ClrRunningStatus(channel); pSchedule->ClrRunningStatus(channel);
if (Tid == 0x4E)
pSchedule->SetPresentSeen();
if (Modified) { if (Modified) {
pSchedule->Sort(); pSchedule->Sort();
Schedules->SetModified(pSchedule); Schedules->SetModified(pSchedule);

5
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.25 2005/02/19 11:35:00 kls Exp $ * $Id: epg.c 1.27 2005/03/20 12:34:19 kls Exp $
*/ */
#include "epg.h" #include "epg.h"
@ -645,6 +645,7 @@ cSchedule::cSchedule(tChannelID ChannelID)
channelID = ChannelID; channelID = ChannelID;
hasRunning = false;; hasRunning = false;;
modified = 0; modified = 0;
presentSeen = 0;
} }
cEvent *cSchedule::AddEvent(cEvent *Event) cEvent *cSchedule::AddEvent(cEvent *Event)
@ -663,7 +664,7 @@ const cEvent *cSchedule::GetPresentEvent(bool CheckRunningStatus) const
if (!CheckRunningStatus) if (!CheckRunningStatus)
break; break;
} }
if (CheckRunningStatus && time(NULL) - p->Seen() < 30 && p->RunningStatus() >= SI::RunningStatusPausing) if (CheckRunningStatus && p->SeenWithin(30) && p->RunningStatus() >= SI::RunningStatusPausing)
return p; return p;
} }
return pe; return pe;

7
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.19 2005/01/02 10:44:41 kls Exp $ * $Id: epg.h 1.21 2005/03/20 12:32:36 kls Exp $
*/ */
#ifndef __EPG_H #ifndef __EPG_H
@ -79,6 +79,7 @@ public:
int Duration(void) const { return duration; } int Duration(void) const { return duration; }
time_t Vps(void) const { return vps; } time_t Vps(void) const { return vps; }
time_t Seen(void) const { return seen; } time_t Seen(void) const { return seen; }
bool SeenWithin(int Seconds) const { return time(NULL) - seen < Seconds; }
bool HasTimer(void) const; bool HasTimer(void) const;
bool IsRunning(bool OrAboutToStart = false) const; bool IsRunning(bool OrAboutToStart = false) const;
cString GetDateString(void) const; cString GetDateString(void) const;
@ -110,11 +111,15 @@ private:
cList<cEvent> events; cList<cEvent> events;
bool hasRunning; bool hasRunning;
time_t modified; time_t modified;
time_t presentSeen;
public: public:
cSchedule(tChannelID ChannelID); cSchedule(tChannelID ChannelID);
tChannelID ChannelID(void) const { return channelID; } tChannelID ChannelID(void) const { return channelID; }
time_t Modified(void) const { return modified; } time_t Modified(void) const { return modified; }
time_t PresentSeen(void) const { return presentSeen; }
bool PresentSeenWithin(int Seconds) const { return time(NULL) - presentSeen < Seconds; }
void SetModified(void) { modified = time(NULL); } void SetModified(void) { modified = time(NULL); }
void SetPresentSeen(void) { presentSeen = time(NULL); }
void SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel = NULL); void SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel = NULL);
void ClrRunningStatus(cChannel *Channel = NULL); void ClrRunningStatus(cChannel *Channel = NULL);
void ResetVersions(void); void ResetVersions(void);

3
font.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: font.h 1.10 2005/01/14 13:25:35 kls Exp $ * $Id: font.h 1.11 2005/03/19 15:51:19 kls Exp $
*/ */
#ifndef __FONT_H #ifndef __FONT_H
@ -44,6 +44,7 @@ private:
int height; int height;
public: public:
cFont(void *Data); cFont(void *Data);
virtual ~cFont() {}
void SetData(void *Data); void SetData(void *Data);
virtual int Width(unsigned char c) const { return data[c]->width; } virtual int Width(unsigned char c) const { return data[c]->width; }
///< Returns the width of the given character. ///< Returns the width of the given character.

90
i18n.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: i18n.c 1.181 2005/02/27 09:45:57 kls Exp $ * $Id: i18n.c 1.185 2005/03/12 10:43:16 kls Exp $
* *
* Translations provided by: * Translations provided by:
* *
@ -958,7 +958,7 @@ const tI18nPhrase Phrases[] = {
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "Skanna",
"Cãutare canale", "Cãutare canale",
"",//TODO "",//TODO
"",//TODO "",//TODO
@ -1801,7 +1801,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "VPS",
"VPS", "VPS",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2301,16 +2301,16 @@ const tI18nPhrase Phrases[] = {
"Geen audio beschikbaar!", "Geen audio beschikbaar!",
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "Pas d'audio disponible!",
"Äänen kieli ei ole valittavissa!", "Äänen kieli ei ole valittavissa!",
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Pas d'audio disponible!", "Ljud saknas!"
"",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"¾âáãâáâÒãÕâ ×ÒãÚ!",
"",//TODO "",//TODO
"Audio kättesaamatu!", "Audio kättesaamatu!",
"Ingen lyd tilgængelig!", "Ingen lyd tilgængelig!",
@ -2581,7 +2581,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Skin",
"Skin", "Skin",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2602,7 +2602,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Tema",
"Temã", "Temã",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2623,7 +2623,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Vänster",
"Stânga", "Stânga",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2644,7 +2644,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Övre",
"Sus", "Sus",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2728,7 +2728,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Använd liten font",
"Utilizare fonturi mici", "Utilizare fonturi mici",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2749,7 +2749,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "aldrig",
"niciodatã", "niciodatã",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2770,7 +2770,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "skin beroende",
"dep. de skin", "dep. de skin",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2791,7 +2791,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "alltid",
"întotdeauna", "întotdeauna",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2833,11 +2833,11 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"Kanal information (s)",
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "¿ÞÚÐ× ØÝäÞàÜÐæØØ Þ ÚÐÝÐÛÕ (áÕÚ)",
"",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"Tid kanalinfo skal vises (s)", "Tid kanalinfo skal vises (s)",
@ -3043,11 +3043,11 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Önskade språk",
"Limbi preferate", "Limbi preferate",
"",// TODO "",// TODO
"",// TODO "",// TODO
"¿àÕÔßÞçØâÐÕÜëÕ ï×ëÚØ", "¿àÕÔßÞçØâÐÕÜëÕ ï×ëÚØ (âÕÛÕÓØÔ)",
"Preferirani jezici", "Preferirani jezici",
"Eelistatuid keeli", "Eelistatuid keeli",
"Foretrukne sprog", "Foretrukne sprog",
@ -3064,7 +3064,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Önskat språk",
"Limba preferatã", "Limba preferatã",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3102,15 +3102,15 @@ const tI18nPhrase Phrases[] = {
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Näyttömuoto",
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Format för Video display",
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "ÈØàÞÚÞíÚàÐÝÝÞÕ Ø×ÞÑàÐÖÕÝØÕ",
"",//TODO
"",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
@ -3131,7 +3131,7 @@ const tI18nPhrase Phrases[] = {
"pan&scan", "pan&scan",
"pan&scan", "pan&scan",
"pan&scan", "pan&scan",
"pan&scan", "ßÐÝÞàÐÜØàÞÒÐâì",
"pan&scan", "pan&scan",
"pan&scan", "pan&scan",
"pan&scan", "pan&scan",
@ -3152,7 +3152,7 @@ const tI18nPhrase Phrases[] = {
"letterbox", "letterbox",
"letterbox", "letterbox",
"letterbox", "letterbox",
"letterbox", "ãÜÕÝìèÐâì",
"letterbox", "letterbox",
"letterbox", "letterbox",
"letterbox", "letterbox",
@ -3173,7 +3173,7 @@ const tI18nPhrase Phrases[] = {
"center cut out", "center cut out",
"center cut out", "center cut out",
"center cut out", "center cut out",
"center cut out", "ÞÑàÕ×Ðâì áÑÞÚã",
"center cut out", "center cut out",
"center cut out", "center cut out",
"center cut out", "center cut out",
@ -3205,17 +3205,17 @@ const tI18nPhrase Phrases[] = {
"",//TODO "",//TODO
"Dolby Digital gebruiken", "Dolby Digital gebruiken",
"",//TODO "",//TODO
"",//TODO "Utiliser le Dolby Digital",
"",//TODO "",//TODO
"Käytä Dolby Digital -ääntä", "Käytä Dolby Digital -ääntä",
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Utiliser le Dolby Digital", "Använd Dolby Digital",
"",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"²ÚÛîçØâì Dolby Digital",
"",//TODO "",//TODO
"Dolby Digital kasutamine", "Dolby Digital kasutamine",
"Anvend Dolby Digital", "Anvend Dolby Digital",
@ -3232,7 +3232,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Uppdatera kanaler",
"Actualizare canale", "Actualizare canale",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3253,7 +3253,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "bara namn",
"doar numele", "doar numele",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3274,7 +3274,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "namn och PIDdar",
"nume si PID-uri", "nume si PID-uri",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3295,7 +3295,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "lägg till nya kanaler",
"adãugare canale noi", "adãugare canale noi",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3316,7 +3316,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "lägg till nya transponders",
"adãugare transpondere noi", "adãugare transpondere noi",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3337,11 +3337,11 @@ const tI18nPhrase Phrases[] = {
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Antal ljudspråk",
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "¿àÕÔßÞçØâÐÕÜëÕ ï×ëÚØ (×ÒãÚ)",
"",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Audio sprog (ant.)", "Audio sprog (ant.)",
@ -3358,11 +3358,11 @@ const tI18nPhrase Phrases[] = {
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Ljudspråk",
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"",//TODO "²ëÑàÐÝ",
"",//TODO
"",//TODO "",//TODO
"",//TODO "",//TODO
"Audio sprog", "Audio sprog",
@ -3652,7 +3652,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Använd VPS",
"Utilizeazã VPS", "Utilizeazã VPS",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3673,7 +3673,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "VPS marginal (s)",
"Marjã de timp la utilizare VPS (s)", "Marjã de timp la utilizare VPS (s)",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -3925,7 +3925,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"ÆÜðéíãê äéáêïðÞ (ä)", "ÆÜðéíãê äéáêïðÞ (ä)",
"",// TODO "Zap timeout(s)",
"Interval zapping (s)", "Interval zapping (s)",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -4784,17 +4784,17 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"Audio", "Audio",
"",// TODO "",// TODO
"",// TODO "Audio",
"",// TODO "",// TODO
"Ääni", "Ääni",
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"Audio", "Ljud",
"",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"Ï×ëÚ",
"",// TODO "",// TODO
"Audio", "Audio",
"Audio", "Audio",
@ -5274,7 +5274,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "Klassisk VDR",
"VDR clasic", "VDR clasic",
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -5295,7 +5295,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "ST:TNG konsol",
"Cons. ST:TNG", "Cons. ST:TNG",
"",// TODO "",// TODO
"",// TODO "",// TODO

75
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.342 2005/02/27 14:09:00 kls Exp $ * $Id: menu.c 1.348 2005/03/20 15:14:51 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -632,7 +632,7 @@ cMenuEditTimer::cMenuEditTimer(cTimer *Timer, bool New)
channel = data.Channel()->Number(); channel = data.Channel()->Number();
Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive)); Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive));
Add(new cMenuEditChanItem(tr("Channel"), &channel)); Add(new cMenuEditChanItem(tr("Channel"), &channel));
Add(new cMenuEditDayItem( tr("Day"), &data.day)); Add(new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays));
Add(new cMenuEditTimeItem(tr("Start"), &data.start)); Add(new cMenuEditTimeItem(tr("Start"), &data.start));
Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); Add(new cMenuEditTimeItem(tr("Stop"), &data.stop));
Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps)); Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps));
@ -654,13 +654,12 @@ cMenuEditTimer::~cMenuEditTimer()
void cMenuEditTimer::SetFirstDayItem(void) void cMenuEditTimer::SetFirstDayItem(void)
{ {
if (!firstday && !data.IsSingleEvent()) { if (!firstday && !data.IsSingleEvent()) {
Add(firstday = new cMenuEditDateItem(tr("First day"), &data.firstday)); Add(firstday = new cMenuEditDateItem(tr("First day"), &data.day));
Display(); Display();
} }
else if (firstday && data.IsSingleEvent()) { else if (firstday && data.IsSingleEvent()) {
Del(firstday->Index()); Del(firstday->Index());
firstday = NULL; firstday = NULL;
data.firstday = 0;
Display(); Display();
} }
} }
@ -691,7 +690,7 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
Timers.Add(timer); Timers.Add(timer);
timer->Matches(); timer->Matches();
Timers.SetModified(); Timers.SetModified();
isyslog("timer %d %s (%s)", timer->Index() + 1, addIfConfirmed ? "added" : "modified", timer->HasFlags(tfActive) ? "active" : "inactive"); isyslog("timer %s %s (%s)", *timer->ToDescr(), addIfConfirmed ? "added" : "modified", timer->HasFlags(tfActive) ? "active" : "inactive");
addIfConfirmed = false; addIfConfirmed = false;
} }
} }
@ -733,13 +732,28 @@ int cMenuTimerItem::Compare(const cListObject &ListObject) const
void cMenuTimerItem::Set(void) void cMenuTimerItem::Set(void)
{ {
cString day, name("");
if (timer->WeekDays())
day = timer->PrintDay(0, timer->WeekDays());
else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
day = itoa(timer->GetMDay(timer->Day()));
name = WeekDayName(timer->Day());
}
else {
struct tm tm_r;
time_t Day = timer->Day();
localtime_r(&Day, &tm_r);
char buffer[16];
strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r);
day = buffer;
}
char *buffer = NULL; char *buffer = NULL;
asprintf(&buffer, "%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", asprintf(&buffer, "%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s",
!(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
timer->Channel()->Number(), timer->Channel()->Number(),
timer->IsSingleEvent() ? *WeekDayName(timer->StartTime()) : "", *name,
timer->IsSingleEvent() ? " " : "", *name && **name ? " " : "",
*timer->PrintDay(timer->Day()), *day,
timer->Start() / 100, timer->Start() / 100,
timer->Start() % 100, timer->Start() % 100,
timer->Stop() / 100, timer->Stop() / 100,
@ -795,9 +809,9 @@ eOSState cMenuTimers::OnOff(void)
RefreshCurrent(); RefreshCurrent();
DisplayCurrent(true); DisplayCurrent(true);
if (timer->FirstDay()) if (timer->FirstDay())
isyslog("timer %d first day set to %s", timer->Index() + 1, *timer->PrintFirstDay()); isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay());
else else
isyslog("timer %d %sactivated", timer->Index() + 1, timer->HasFlags(tfActive) ? "" : "de"); isyslog("timer %s %sactivated", *timer->ToDescr(), timer->HasFlags(tfActive) ? "" : "de");
Timers.SetModified(); Timers.SetModified();
} }
return osContinue; return osContinue;
@ -807,7 +821,7 @@ eOSState cMenuTimers::Edit(void)
{ {
if (HasSubMenu() || Count() == 0) if (HasSubMenu() || Count() == 0)
return osContinue; return osContinue;
isyslog("editing timer %d", CurrentTimer()->Index() + 1); isyslog("editing timer %s", *CurrentTimer()->ToDescr());
return AddSubMenu(new cMenuEditTimer(CurrentTimer())); return AddSubMenu(new cMenuEditTimer(CurrentTimer()));
} }
@ -832,12 +846,11 @@ eOSState cMenuTimers::Delete(void)
else else
return osContinue; return osContinue;
} }
int Index = ti->Index(); isyslog("deleting timer %s", *ti->ToDescr());
Timers.Del(ti); Timers.Del(ti);
cOsdMenu::Del(Current()); cOsdMenu::Del(Current());
Timers.SetModified(); Timers.SetModified();
Display(); Display();
isyslog("timer %d deleted", Index + 1);
} }
} }
return osContinue; return osContinue;
@ -1603,9 +1616,8 @@ eOSState cMenuRecordings::Delete(void)
timer->Skip(); timer->Skip();
cRecordControls::Process(time(NULL)); cRecordControls::Process(time(NULL));
if (timer->IsSingleEvent()) { if (timer->IsSingleEvent()) {
int Index = timer->Index(); isyslog("deleting timer %s", *timer->ToDescr());
Timers.Del(timer); Timers.Del(timer);
isyslog("timer %d deleted", Index + 1);
} }
Timers.SetModified(); Timers.SetModified();
} }
@ -1619,6 +1631,7 @@ eOSState cMenuRecordings::Delete(void)
cReplayControl::ClearLastReplayed(ri->FileName()); cReplayControl::ClearLastReplayed(ri->FileName());
cOsdMenu::Del(Current()); cOsdMenu::Del(Current());
Recordings.Del(recording); Recordings.Del(recording);
SetHelpKeys();
Display(); Display();
if (!Count()) if (!Count())
return osBack; return osBack;
@ -1947,8 +1960,9 @@ void cMenuSetupDVB::Setup(void)
Clear(); Clear();
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices())); Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9")); Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
if (data.VideoFormat == 0)
Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Dolby Digital"), &data.UseDolbyDigital)); Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Dolby Digital"), &data.UseDolbyDigital));
Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 5, updateChannelsTexts)); Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 5, updateChannelsTexts));
Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nNumLanguages)); Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nNumLanguages));
@ -1964,10 +1978,12 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
int oldPrimaryDVB = ::Setup.PrimaryDVB; int oldPrimaryDVB = ::Setup.PrimaryDVB;
int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat; int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
bool oldVideoFormat = ::Setup.VideoFormat; bool oldVideoFormat = ::Setup.VideoFormat;
bool newVideoFormat = data.VideoFormat;
int oldnumAudioLanguages = numAudioLanguages; int oldnumAudioLanguages = numAudioLanguages;
eOSState state = cMenuSetupBase::ProcessKey(Key); eOSState state = cMenuSetupBase::ProcessKey(Key);
if (Key != kNone) { if (Key != kNone) {
bool DoSetup = data.VideoFormat != newVideoFormat;
if (numAudioLanguages != oldnumAudioLanguages) { if (numAudioLanguages != oldnumAudioLanguages) {
for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) { for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
data.AudioLanguages[i] = 0; data.AudioLanguages[i] = 0;
@ -1984,8 +2000,10 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
} }
} }
data.AudioLanguages[numAudioLanguages] = -1; data.AudioLanguages[numAudioLanguages] = -1;
Setup(); DoSetup = true;
} }
if (DoSetup)
Setup();
} }
if (state == osBack && Key == kOk) { if (state == osBack && Key == kOk) {
if (::Setup.PrimaryDVB != oldPrimaryDVB) if (::Setup.PrimaryDVB != oldPrimaryDVB)
@ -3048,7 +3066,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
cRecordControl::~cRecordControl() cRecordControl::~cRecordControl()
{ {
Stop(true); Stop();
free(instantId); free(instantId);
free(fileName); free(fileName);
} }
@ -3083,16 +3101,11 @@ bool cRecordControl::GetEvent(void)
return false; return false;
} }
void cRecordControl::Stop(bool KeepInstant) void cRecordControl::Stop(void)
{ {
if (timer) { if (timer) {
DELETENULL(recorder); DELETENULL(recorder);
timer->SetRecording(false); timer->SetRecording(false);
if ((IsInstant() && !KeepInstant) || (timer->IsSingleEvent() && timer->StopTime() <= time(NULL))) {
isyslog("deleting timer %d", timer->Index() + 1);
Timers.Del(timer);
Timers.SetModified();
}
timer = NULL; timer = NULL;
cStatus::MsgRecording(device, NULL); cStatus::MsgRecording(device, NULL);
cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName);
@ -3153,8 +3166,16 @@ void cRecordControls::Stop(const char *InstantId)
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();
if (id && strcmp(id, InstantId) == 0) if (id && strcmp(id, InstantId) == 0) {
cTimer *timer = RecordControls[i]->Timer();
RecordControls[i]->Stop(); RecordControls[i]->Stop();
if (timer) {
isyslog("deleting timer %s", *timer->ToDescr());
Timers.Del(timer);
Timers.SetModified();
}
break;
}
} }
} }
} }
@ -3165,7 +3186,7 @@ void cRecordControls::Stop(cDevice *Device)
if (RecordControls[i]) { if (RecordControls[i]) {
if (RecordControls[i]->Device() == Device) { if (RecordControls[i]->Device() == Device) {
isyslog("stopping recording on DVB device %d due to higher priority", Device->CardIndex() + 1); isyslog("stopping recording on DVB device %d due to higher priority", Device->CardIndex() + 1);
RecordControls[i]->Stop(true); RecordControls[i]->Stop();
} }
} }
} }
@ -3242,7 +3263,7 @@ void cRecordControls::ChannelDataModified(cChannel *Channel)
if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) { if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
isyslog("stopping recording due to modification of channel %d", Channel->Number()); isyslog("stopping recording due to modification of channel %d", Channel->Number());
RecordControls[i]->Stop(true); 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.
} }

5
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.68 2005/01/08 15:48:57 kls Exp $ * $Id: menu.h 1.69 2005/03/20 10:57:29 kls Exp $
*/ */
#ifndef __MENU_H #ifndef __MENU_H
@ -155,8 +155,7 @@ public:
virtual ~cRecordControl(); virtual ~cRecordControl();
bool Process(time_t t); bool Process(time_t t);
cDevice *Device(void) { return device; } cDevice *Device(void) { return device; }
void Stop(bool KeepInstant = false); void Stop(void);
bool IsInstant(void) { return instantId; }
const char *InstantId(void) { return instantId; } const char *InstantId(void) { return instantId; }
const char *FileName(void) { return fileName; } const char *FileName(void) { return fileName; }
cTimer *Timer(void) { return timer; } cTimer *Timer(void) { return timer; }

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.21 2004/11/21 13:24:10 kls Exp $ * $Id: menuitems.c 1.22 2005/03/19 15:33:34 kls Exp $
*/ */
#include "menuitems.h" #include "menuitems.h"
@ -535,117 +535,35 @@ eOSState cMenuEditTranItem::ProcessKey(eKeys Key)
return state; return state;
} }
// --- cMenuEditDayItem ------------------------------------------------------
int cMenuEditDayItem::days[] ={ cTimer::ParseDay("M------"),
cTimer::ParseDay("-T-----"),
cTimer::ParseDay("--W----"),
cTimer::ParseDay("---T---"),
cTimer::ParseDay("----F--"),
cTimer::ParseDay("-----S-"),
cTimer::ParseDay("------S"),
cTimer::ParseDay("MTWTF--"),
cTimer::ParseDay("MTWTFS-"),
cTimer::ParseDay("MTWTFSS"),
cTimer::ParseDay("-----SS"),
0 };
cMenuEditDayItem::cMenuEditDayItem(const char *Name, int *Value)
:cMenuEditIntItem(Name, Value, -INT_MAX, 31)
{
d = -1;
md = 0;
if (*value < 0) {
int n = 0;
while (days[n]) {
if (days[n] == *value) {
d = n;
break;
}
n++;
}
}
Set();
}
void cMenuEditDayItem::Set(void)
{
SetValue(cTimer::PrintDay(*value));
}
eOSState cMenuEditDayItem::ProcessKey(eKeys Key)
{
switch (Key) {
case kLeft|k_Repeat:
case kLeft: if (d > 0)
*value = days[--d];
else if (d == 0) {
*value = 31;
d = -1;
}
else if (*value == 1) {
d = sizeof(days) / sizeof(int) - 2;
*value = days[d];
}
else
return cMenuEditIntItem::ProcessKey(Key);
Set();
break;
case kRight|k_Repeat:
case kRight: if (d >= 0) {
*value = days[++d];
if (*value == 0) {
*value = 1;
d = -1;
}
}
else if (*value == 31) {
d = 0;
*value = days[d];
}
else
return cMenuEditIntItem::ProcessKey(Key);
Set();
break;
default: {
if (d >= 0) {
if (k1 <= Key && Key <= k7) {
int v = *value ^ (1 << (Key - k1));
if ((v & 0xFF) != 0) {
*value = v; // can't let this become all 0
Set();
}
break;
}
}
int v = *value;
eOSState result = cMenuEditIntItem::ProcessKey(Key);
if (result == osContinue && Key == k0) {
if (d >= 0) {
*value = md ? md : cTimer::GetMDay(time(NULL));
md = 0;
d = -1;
Set();
}
else if (*value == 0 || *value == v) {
md = v;
d = cTimer::GetWDayFromMDay(v);
*value = days[d];
Set();
}
}
return result;
}
}
return osContinue;
}
// --- cMenuEditDateItem ----------------------------------------------------- // --- cMenuEditDateItem -----------------------------------------------------
cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value) static int ParseWeekDays(const char *s)
{
time_t day;
int weekdays;
return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
}
int cMenuEditDateItem::days[] = { ParseWeekDays("M------"),
ParseWeekDays("-T-----"),
ParseWeekDays("--W----"),
ParseWeekDays("---T---"),
ParseWeekDays("----F--"),
ParseWeekDays("-----S-"),
ParseWeekDays("------S"),
ParseWeekDays("MTWTF--"),
ParseWeekDays("MTWTFS-"),
ParseWeekDays("MTWTFSS"),
ParseWeekDays("-----SS"),
0 };
cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays)
:cMenuEditItem(Name) :cMenuEditItem(Name)
{ {
value = Value; value = Value;
weekdays = WeekDays;
oldvalue = 0;
dayindex = 0;
Set(); Set();
} }
@ -653,7 +571,11 @@ void cMenuEditDateItem::Set(void)
{ {
#define DATEBUFFERSIZE 32 #define DATEBUFFERSIZE 32
char buf[DATEBUFFERSIZE]; char buf[DATEBUFFERSIZE];
if (*value) { if (weekdays && *weekdays) {
SetValue(cTimer::PrintDay(0, *weekdays));
return;
}
else if (*value) {
struct tm tm_r; struct tm tm_r;
localtime_r(value, &tm_r); localtime_r(value, &tm_r);
strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r); strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r);
@ -669,15 +591,73 @@ eOSState cMenuEditDateItem::ProcessKey(eKeys Key)
eOSState state = cMenuEditItem::ProcessKey(Key); eOSState state = cMenuEditItem::ProcessKey(Key);
if (state == osUnknown) { if (state == osUnknown) {
time_t now = time(NULL);
if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
*value -= SECSINDAY; if (!weekdays || !*weekdays) {
if (*value < time(NULL)) // Decrement single day:
*value = 0; time_t v = *value;
v -= SECSINDAY;
if (v < now) {
if (now <= v + SECSINDAY) { // switched from tomorrow to today
if (!weekdays)
v = 0;
}
else if (weekdays) { // switched from today to yesterday, so enter weekdays mode
v = 0;
dayindex = sizeof(days) / sizeof(int) - 2;
*weekdays = days[dayindex];
}
else // don't go before today
v = *value;
}
*value = v;
}
else {
// Decrement weekday index:
if (dayindex > 0)
*weekdays = days[--dayindex];
}
} }
else if (NORMALKEY(Key) == kRight) { else if (NORMALKEY(Key) == kRight) {
if (!*value) if (!weekdays || !*weekdays) {
*value = cTimer::SetTime(time(NULL), 0); // Increment single day:
*value += SECSINDAY; if (!*value)
*value = cTimer::SetTime(now, 0);
*value += SECSINDAY;
}
else {
// Increment weekday index:
*weekdays = days[++dayindex];
if (!*weekdays) { // was last weekday entry, so switch to today
*value = cTimer::SetTime(now, 0);
dayindex = 0;
}
}
}
else if (weekdays) {
if (Key == k0) {
// Toggle between weekdays and single day:
if (*weekdays) {
*value = cTimer::SetTime(oldvalue ? oldvalue : now, 0);
oldvalue = 0;
*weekdays = 0;
}
else {
*weekdays = days[cTimer::GetWDay(*value)];
oldvalue = *value;
*value = 0;
}
}
else if (k1 <= Key && Key <= k7) {
// Toggle individual weekdays:
if (*weekdays) {
int v = *weekdays ^ (1 << (Key - k1));
if (v != 0)
*weekdays = v; // can't let this become all 0
}
}
else
return state;
} }
else else
return state; return state;

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.10 2004/11/21 13:23:00 kls Exp $ * $Id: menuitems.h 1.11 2005/03/19 15:02:57 kls Exp $
*/ */
#ifndef __MENUITEMS_H #ifndef __MENUITEMS_H
@ -118,24 +118,16 @@ public:
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
class cMenuEditDayItem : public cMenuEditIntItem { class cMenuEditDateItem : public cMenuEditItem {
private: private:
static int days[]; static int days[];
int d;
int md;
protected:
virtual void Set(void);
public:
cMenuEditDayItem(const char *Name, int *Value);
virtual eOSState ProcessKey(eKeys Key);
};
class cMenuEditDateItem : public cMenuEditItem {
protected:
time_t *value; time_t *value;
int *weekdays;
time_t oldvalue;
int dayindex;
virtual void Set(void); virtual void Set(void);
public: public:
cMenuEditDateItem(const char *Name, time_t *Value); cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays = NULL);
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };

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.41 2004/10/31 14:05:12 kls Exp $ * $Id: remote.c 1.42 2005/03/20 13:25:31 kls Exp $
*/ */
#include "remote.h" #include "remote.h"
@ -145,6 +145,7 @@ bool cRemote::Put(const char *Code, bool Repeat, bool Release)
bool cRemote::HasKeys(void) bool cRemote::HasKeys(void)
{ {
cMutexLock MutexLock(&mutex);
return in != out && !(keys[out] & k_Repeat); return in != out && !(keys[out] & k_Repeat);
} }

44
remux.c
View File

@ -11,7 +11,7 @@
* The cDolbyRepacker code was originally written by Reinhard Nissl <rnissl@gmx.de>, * The cDolbyRepacker 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.31 2005/02/13 14:36:23 kls Exp $ * $Id: remux.c 1.33 2005/03/20 13:18:15 kls Exp $
*/ */
#include "remux.h" #include "remux.h"
@ -46,6 +46,8 @@ private:
int fragmentTodo; int fragmentTodo;
uchar pesHeader[6 + 3 + 255 + 4 + 4]; uchar pesHeader[6 + 3 + 255 + 4 + 4];
int pesHeaderLen; int pesHeaderLen;
uchar pesHeaderBackup[6 + 3 + 255];
int pesHeaderBackupLen;
uchar chk1; uchar chk1;
uchar chk2; uchar chk2;
int ac3todo; int ac3todo;
@ -57,8 +59,8 @@ private:
get_length, get_length,
output_packet output_packet
} state; } state;
void ResetPesHeader(void); void ResetPesHeader(bool ContinuationFrame = false);
void AppendSubStreamID(void); void AppendSubStreamID(bool ContinuationFrame = false);
bool FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite); bool FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite);
bool StartNewPacket(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite); bool StartNewPacket(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite);
public: public:
@ -103,23 +105,26 @@ cDolbyRepacker::cDolbyRepacker(void)
Reset(); Reset();
} }
void cDolbyRepacker::AppendSubStreamID(void) void cDolbyRepacker::AppendSubStreamID(bool ContinuationFrame)
{ {
if (subStreamId) { if (subStreamId) {
pesHeader[pesHeaderLen++] = subStreamId; pesHeader[pesHeaderLen++] = subStreamId;
// number of ac3 frames "starting" in this packet (1 by design).
pesHeader[pesHeaderLen++] = 0x01;
// offset to start of first ac3 frame (0 means "no ac3 frame starting"
// so 1 (by design) addresses the first byte after the next two bytes).
pesHeader[pesHeaderLen++] = 0x00; pesHeader[pesHeaderLen++] = 0x00;
pesHeader[pesHeaderLen++] = 0x00; pesHeader[pesHeaderLen++] = (ContinuationFrame ? 0x00 : 0x01);
pesHeader[pesHeaderLen++] = 0x00;
} }
} }
void cDolbyRepacker::ResetPesHeader(void) void cDolbyRepacker::ResetPesHeader(bool ContinuationFrame)
{ {
pesHeader[6] = 0x80; pesHeader[6] = 0x80;
pesHeader[7] = 0x00; pesHeader[7] = 0x00;
pesHeader[8] = 0x00; pesHeader[8] = 0x00;
pesHeaderLen = 9; pesHeaderLen = 9;
AppendSubStreamID(); AppendSubStreamID(ContinuationFrame);
} }
void cDolbyRepacker::Reset(void) void cDolbyRepacker::Reset(void)
@ -131,6 +136,7 @@ void cDolbyRepacker::Reset(void)
chk2 = 0; chk2 = 0;
fragmentLen = 0; fragmentLen = 0;
fragmentTodo = 0; fragmentTodo = 0;
pesHeaderBackupLen = 0;
} }
bool cDolbyRepacker::FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite) bool cDolbyRepacker::FinishRemainder(cRingBufferLinear *ResultBuffer, const uchar *const Data, const int Todo, int &Done, int &Bite)
@ -229,11 +235,16 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
if ((Data[6] & 0xC0) != 0x80) if ((Data[6] & 0xC0) != 0x80)
return 0; return 0;
// backup PES header
if (Data[6] != 0x80 || Data[7] != 0x00 || Data[8] != 0x00) {
pesHeaderBackupLen = 6 + 3 + Data[8];
memcpy(pesHeaderBackup, Data, pesHeaderBackupLen);
}
// skip PES header // skip PES header
int done = 6 + 3 + Data[8]; int done = 6 + 3 + Data[8];
int todo = Count - done; int todo = Count - done;
const uchar *data = Data + done; const uchar *data = Data + done;
bool headerCopied = false;
// look for 0x0B 0x77 <chk1> <chk2> <frameSize> // look for 0x0B 0x77 <chk1> <chk2> <frameSize>
while (todo > 0) { while (todo > 0) {
@ -242,10 +253,10 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
if (*data == 0x0B) { if (*data == 0x0B) {
++(int &)state; ++(int &)state;
// copy header information once for later use // copy header information once for later use
if (!headerCopied) { if (pesHeaderBackupLen > 0) {
headerCopied = true; pesHeaderLen = pesHeaderBackupLen;
pesHeaderLen = 6 + 3 + Data[8]; pesHeaderBackupLen = 0;
memcpy(pesHeader, Data, pesHeaderLen); memcpy(pesHeader, pesHeaderBackup, pesHeaderLen);
AppendSubStreamID(); AppendSubStreamID();
} }
} }
@ -279,9 +290,8 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
ac3todo = 2 * frameSizes[*data]; ac3todo = 2 * frameSizes[*data];
// frameSizeCode was invalid => restart searching // frameSizeCode was invalid => restart searching
if (ac3todo <= 0) { if (ac3todo <= 0) {
// reset PES header instead of using/copying a wrong one // reset PES header instead of using a wrong one
ResetPesHeader(); ResetPesHeader();
headerCopied = true;
if (chk1 == 0x0B) { if (chk1 == 0x0B) {
if (chk2 == 0x77) { if (chk2 == 0x77) {
state = store_chk1; state = store_chk1;
@ -320,8 +330,8 @@ int cDolbyRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int
// start a new packet // start a new packet
if (!StartNewPacket(ResultBuffer, data, todo, done, bite)) if (!StartNewPacket(ResultBuffer, data, todo, done, bite))
return done; return done;
// prepare for next packet // prepare for next (continuation) packet
ResetPesHeader(); ResetPesHeader(state == output_packet);
} }
data += bite; data += bite;
done += bite; done += bite;

15
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.67 2004/12/26 12:23:55 kls Exp $ * $Id: svdrp.c 1.69 2005/03/20 15:04:00 kls Exp $
*/ */
#include "svdrp.h" #include "svdrp.h"
@ -111,7 +111,8 @@ int cSocket::Accept(void)
bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr);
if (!accepted) { if (!accepted) {
const char *s = "Access denied!\n"; const char *s = "Access denied!\n";
write(newsock, s, strlen(s)); if (write(newsock, s, strlen(s)) < 0)
LOG_ERROR;
close(newsock); close(newsock);
newsock = -1; newsock = -1;
} }
@ -528,9 +529,9 @@ void cSVDRP::CmdDELT(const char *Option)
cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1); cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
if (timer) { if (timer) {
if (!timer->Recording()) { if (!timer->Recording()) {
isyslog("deleting timer %s", *timer->ToDescr());
Timers.Del(timer); Timers.Del(timer);
Timers.SetModified(); Timers.SetModified();
isyslog("timer %s deleted", Option);
Reply(250, "Timer \"%s\" deleted", Option); Reply(250, "Timer \"%s\" deleted", Option);
} }
else else
@ -918,7 +919,7 @@ void cSVDRP::CmdMODT(const char *Option)
} }
*timer = t; *timer = t;
Timers.SetModified(); Timers.SetModified();
isyslog("timer %d modified (%s)", timer->Index() + 1, timer->HasFlags(tfActive) ? "active" : "inactive"); isyslog("timer %s modified (%s)", *timer->ToDescr(), timer->HasFlags(tfActive) ? "active" : "inactive");
Reply(250, "%d %s", timer->Index() + 1, *timer->ToText()); Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
} }
else else
@ -976,7 +977,7 @@ void cSVDRP::CmdNEWT(const char *Option)
if (!t) { if (!t) {
Timers.Add(timer); Timers.Add(timer);
Timers.SetModified(); Timers.SetModified();
isyslog("timer %d added", timer->Index() + 1); isyslog("timer %s added", *timer->ToDescr());
Reply(250, "%d %s", timer->Index() + 1, *timer->ToText()); Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
return; return;
} }
@ -1050,11 +1051,11 @@ void cSVDRP::CmdUPDT(const char *Option)
t->Parse(Option); t->Parse(Option);
delete timer; delete timer;
timer = t; timer = t;
isyslog("timer %d updated", timer->Index() + 1); isyslog("timer %s updated", *timer->ToDescr());
} }
else { else {
Timers.Add(timer); Timers.Add(timer);
isyslog("timer %d added", timer->Index() + 1); isyslog("timer %s added", *timer->ToDescr());
} }
Timers.SetModified(); Timers.SetModified();
Reply(250, "%d %s", timer->Index() + 1, *timer->ToText()); Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());

307
timers.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: timers.c 1.22 2005/02/06 09:45:52 kls Exp $ * $Id: timers.c 1.30 2005/03/20 14:50:37 kls Exp $
*/ */
#include "timers.h" #include "timers.h"
@ -30,7 +30,8 @@ cTimer::cTimer(bool Instant, bool Pause)
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);
day = now->tm_mday; day = SetTime(t, 0);
weekdays = 0;
start = now->tm_hour * 100 + now->tm_min; start = now->tm_hour * 100 + now->tm_min;
stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime; stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime;
stop = (stop / 60) * 100 + (stop % 60); stop = (stop / 60) * 100 + (stop % 60);
@ -39,7 +40,6 @@ cTimer::cTimer(bool Instant, bool Pause)
priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; priority = Pause ? Setup.PausePriority : Setup.DefaultPriority;
lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime; lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime;
*file = 0; *file = 0;
firstday = 0;
summary = NULL; summary = NULL;
event = NULL; event = NULL;
if (Instant && channel) if (Instant && channel)
@ -62,7 +62,8 @@ cTimer::cTimer(const cEvent *Event)
} }
struct tm tm_r; struct tm tm_r;
struct tm *time = localtime_r(&tstart, &tm_r); struct tm *time = localtime_r(&tstart, &tm_r);
day = time->tm_mday; day = SetTime(tstart, 0);
weekdays = 0;
start = time->tm_hour * 100 + time->tm_min; start = time->tm_hour * 100 + time->tm_min;
time = localtime_r(&tstop, &tm_r); time = localtime_r(&tstop, &tm_r);
stop = time->tm_hour * 100 + time->tm_min; stop = time->tm_hour * 100 + time->tm_min;
@ -74,7 +75,6 @@ cTimer::cTimer(const cEvent *Event)
const char *Title = Event->Title(); const char *Title = Event->Title();
if (!isempty(Title)) if (!isempty(Title))
strn0cpy(file, Event->Title(), sizeof(file)); strn0cpy(file, Event->Title(), sizeof(file));
firstday = 0;
summary = NULL; summary = NULL;
event = Event; event = Event;
} }
@ -109,85 +109,111 @@ 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, firstday), start, stop, priority, lifetime, file, summary ? summary : ""); 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 : "");
strreplace(summary, '|', '\n'); strreplace(summary, '|', '\n');
strreplace(file, '|', ':'); strreplace(file, '|', ':');
return cString(buffer, true); return cString(buffer, true);
} }
cString cTimer::ToDescr(void) const
{
char *buffer;
asprintf(&buffer, "%d (%d %04d-%04d '%s')", Index() + 1, Channel()->Number(), start, stop, file);
return cString(buffer, true);
}
int cTimer::TimeToInt(int t) int cTimer::TimeToInt(int t)
{ {
return (t / 100 * 60 + t % 100) * 60; return (t / 100 * 60 + t % 100) * 60;
} }
int cTimer::ParseDay(const char *s, time_t *FirstDay) bool cTimer::ParseDay(const char *s, time_t &Day, int &WeekDays)
{ {
char *tail; // possible formats are:
int d = strtol(s, &tail, 10); // 19
if (FirstDay) // 2005-03-19
*FirstDay = 0; // MTWTFSS
if (tail && *tail) { // MTWTFSS@19
d = 0; // MTWTFSS@2005-03-19
if (tail == s) {
const char *first = strchr(s, '@'); Day = 0;
int l = first ? first - s : strlen(s); WeekDays = 0;
if (l == 7) { s = skipspace(s);
for (const char *p = s + 6; p >= s; p--) { if (!*s)
d <<= 1; return false;
d |= (*p != '-'); const char *a = strchr(s, '@');
const char *d = a ? a + 1 : isdigit(*s) ? s : NULL;
if (d) {
if (strlen(d) == 10) {
struct tm tm_r;
if (3 == sscanf(d, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
tm_r.tm_year -= 1900;
tm_r.tm_mon--;
tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
Day = mktime(&tm_r);
}
else
return false;
}
else {
// handle "day of month" for compatibility with older versions:
char *tail = NULL;
int day = strtol(s, &tail, 10);
if (tail && *tail || day < 1 || day > 31)
return false;
time_t t = time(NULL);
int DaysToCheck = 61; // 61 to handle months with 31/30/31
for (int i = -1; i <= DaysToCheck; i++) {
time_t t0 = IncDay(t, i);
if (GetMDay(t0) == day) {
Day = SetTime(t0, 0);
break;
} }
d |= 0x80000000; }
}
if (FirstDay && first) {
++first;
if (strlen(first) == 10) {
struct tm tm_r;
if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
tm_r.tm_year -= 1900;
tm_r.tm_mon--;
tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
*FirstDay = mktime(&tm_r);
}
}
else
d = 0;
}
} }
} }
else if (d < 1 || d > 31) if (a || !isdigit(*s)) {
d = 0; if ((a && a - s == 7) || strlen(s) == 7) {
return d; for (const char *p = s + 6; p >= s; p--) {
WeekDays <<= 1;
WeekDays |= (*p != '-');
}
}
else
return false;
}
return true;
} }
cString cTimer::PrintDay(int d, time_t FirstDay) cString cTimer::PrintDay(time_t Day, int WeekDays)
{ {
#define DAYBUFFERSIZE 32 #define DAYBUFFERSIZE 32
char buffer[DAYBUFFERSIZE]; char buffer[DAYBUFFERSIZE];
if ((d & 0x80000000) != 0) { char *b = buffer;
char *b = buffer; if (WeekDays) {
const char *w = tr("MTWTFSS"); const char *w = tr("MTWTFSS");
while (*w) { while (*w) {
*b++ = (d & 1) ? *w : '-'; *b++ = (WeekDays & 1) ? *w : '-';
d >>= 1; WeekDays >>= 1;
w++; w++;
} }
if (FirstDay) { if (Day)
struct tm tm_r; *b++ = '@';
localtime_r(&FirstDay, &tm_r);
b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r);
}
*b = 0;
} }
else if (Day) {
sprintf(buffer, "%d", d); struct tm tm_r;
localtime_r(&Day, &tm_r);
b += strftime(b, DAYBUFFERSIZE - (b - buffer), "%Y-%m-%d", &tm_r);
}
*b = 0;
return buffer; return buffer;
} }
cString cTimer::PrintFirstDay(void) cString cTimer::PrintFirstDay(void) const
{ {
if (firstday) { if (weekdays) {
cString s = PrintDay(day, firstday); cString s = PrintDay(day, weekdays);
if (strlen(s) == 18) if (strlen(s) == 18)
return *s + 8; return *s + 8;
} }
@ -223,8 +249,7 @@ bool cTimer::Parse(const char *s)
summary = NULL; summary = NULL;
} }
//TODO add more plausibility checks //TODO add more plausibility checks
day = ParseDay(daybuffer, &firstday); result = ParseDay(daybuffer, day, weekdays);
result = day != 0;
strn0cpy(file, filebuffer, MaxFileName); strn0cpy(file, filebuffer, MaxFileName);
strreplace(file, '|', ':'); strreplace(file, '|', ':');
strreplace(summary, '|', '\n'); strreplace(summary, '|', '\n');
@ -251,7 +276,7 @@ bool cTimer::Save(FILE *f)
bool cTimer::IsSingleEvent(void) const bool cTimer::IsSingleEvent(void) const
{ {
return (day & 0x80000000) == 0; return !weekdays;
} }
int cTimer::GetMDay(time_t t) int cTimer::GetMDay(time_t t)
@ -267,20 +292,9 @@ int cTimer::GetWDay(time_t t)
return weekday == 0 ? 6 : weekday - 1; // we start with monday==0! return weekday == 0 ? 6 : weekday - 1; // we start with monday==0!
} }
int cTimer::GetWDayFromMDay(int MDay)
{
time_t now = time(NULL);
for (int i = -1; i <= 28; i++) { // looking 4 weeks into the future should be enough
time_t t0 = IncDay(now, i);
if (GetMDay(t0) == MDay)
return GetWDay(t0);
}
return GetWDay(now); // just to return something
}
bool cTimer::DayMatches(time_t t) const bool cTimer::DayMatches(time_t t) const
{ {
return IsSingleEvent() ? GetMDay(t) == day : (day & (1 << GetWDay(t))) != 0; return IsSingleEvent() ? SetTime(t, 0) == day : (weekdays & (1 << GetWDay(t))) != 0;
} }
time_t cTimer::IncDay(time_t t, int Days) time_t cTimer::IncDay(time_t t, int Days)
@ -324,26 +338,31 @@ bool cTimer::Matches(time_t t, bool Directly) const
if (length < 0) if (length < 0)
length += SECSINDAY; length += SECSINDAY;
int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31 if (IsSingleEvent()) {
for (int i = -1; i <= DaysToCheck; i++) { startTime = SetTime(day, begin);
time_t t0 = IncDay(t, i); stopTime = startTime + length;
if (DayMatches(t0)) { }
time_t a = SetTime(t0, begin); else {
time_t b = a + length; for (int i = -1; i <= 7; i++) {
if ((!firstday || a >= firstday) && t <= b) { time_t t0 = IncDay(t, i);
startTime = a; if (DayMatches(t0)) {
stopTime = b; time_t a = SetTime(t0, begin);
break; time_t b = a + length;
if ((!day || a >= day) && t <= b) {
startTime = a;
stopTime = b;
break;
}
} }
} }
} if (!startTime)
if (!startTime) startTime = day; // just to have something that's more than a week in the future
startTime = firstday; // just to have something that's more than a week in the future else if (!Directly && (t > startTime || t > day + SECSINDAY + 3600)) // +3600 in case of DST change
else if (!Directly && (t > startTime || t > firstday + SECSINDAY + 3600)) // +3600 in case of DST change day = 0;
firstday = 0; }
if (HasFlags(tfActive)) { if (HasFlags(tfActive)) {
if (HasFlags(tfVps) && !Directly && event && event->Vps()) { if (HasFlags(tfVps) && !Directly && event && event->Vps() && schedule && schedule->PresentSeenWithin(30)) {
startTime = event->StartTime(); startTime = event->StartTime();
stopTime = event->EndTime(); stopTime = event->EndTime();
return event->IsRunning(true); return event->IsRunning(true);
@ -353,28 +372,42 @@ bool cTimer::Matches(time_t t, bool Directly) const
return false; return false;
} }
int cTimer::Matches(const cEvent *Event) #define FULLMATCH 1000
int cTimer::Matches(const cEvent *Event, int *Overlap) const
{ {
if (channel->GetChannelID() == Event->ChannelID()) { // Overlap is the percentage of the Event's duration that is covered by
// this timer (based on FULLMATCH for finer granularity than just 100).
// To make sure a VPS timer can be distinguished from a plain 100% overlap,
// it gets an additional 100 added, and a VPS event that is actually running
// gets 200 added to the FULLMATCH.
if (HasFlags(tfActive) && channel->GetChannelID() == Event->ChannelID()) {
bool UseVps = HasFlags(tfVps) && Event->Vps(); bool UseVps = HasFlags(tfVps) && Event->Vps();
time_t t1 = UseVps ? Event->Vps() : Event->StartTime(); Matches(UseVps ? Event->Vps() : Event->StartTime(), true);
time_t t2 = t1 + Event->Duration(); int overlap;
bool m1 = Matches(t1, true); if (UseVps)
bool m2 = UseVps ? m1 : Matches(t2, true); overlap = (startTime == Event->Vps()) ? FULLMATCH + (Event->IsRunning() ? 200 : 100) : 0;
else if (startTime <= Event->StartTime() && Event->EndTime() <= stopTime)
overlap = FULLMATCH;
else if (stopTime <= Event->StartTime() || Event->EndTime() <= startTime)
overlap = 0;
else
overlap = (min(stopTime, Event->EndTime()) - max(startTime, Event->StartTime())) * FULLMATCH / max(Event->Duration(), 1);
startTime = stopTime = 0; startTime = stopTime = 0;
if (m1 && m2) { if (Overlap)
if (UseVps && Event->IsRunning(true)) *Overlap = overlap;
return tmFull; return overlap >= 1000 ? tmFull : overlap > 0 ? tmPartial : tmNone;
if (time(NULL) > Event->EndTime())
return tmNone;
return tmFull;
}
if ((m1 || m2) && time(NULL) <= Event->EndTime())
return tmPartial;
} }
return tmNone; return tmNone;
} }
#define EXPIRELATENCY 60 // seconds (just in case there's a short glitch in the VPS signal)
bool cTimer::Expired(void) const
{
return IsSingleEvent() && !Recording() && StopTime() + EXPIRELATENCY <= time(NULL);
}
time_t cTimer::StartTime(void) const time_t cTimer::StartTime(void) const
{ {
if (!startTime) if (!startTime)
@ -389,17 +422,18 @@ time_t cTimer::StopTime(void) const
return stopTime; return stopTime;
} }
void cTimer::SetEvent(const cEvent *Event) void cTimer::SetEvent(const cSchedule *Schedule, 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) {
char vpsbuf[64] = ""; char vpsbuf[64] = "";
if (Event->Vps()) if (Event->Vps())
sprintf(vpsbuf, "(VPS: %s) ", *Event->GetVpsString()); sprintf(vpsbuf, "(VPS: %s) ", *Event->GetVpsString());
isyslog("timer %d (%d %04d-%04d '%s') set to event %s %s-%s %s'%s'", Index() + 1, Channel()->Number(), start, stop, file, *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString(), vpsbuf, Event->Title()); isyslog("timer %s set to event %s %s-%s %s'%s'", *ToDescr(), *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString(), vpsbuf, Event->Title());
} }
else else
isyslog("timer %d (%d %04d-%04d '%s') set to no event", Index() + 1, Channel()->Number(), start, stop, file); isyslog("timer %s set to no event", *ToDescr());
schedule = Event ? Schedule : NULL;
event = Event; event = Event;
} }
} }
@ -407,7 +441,7 @@ void cTimer::SetEvent(const cEvent *Event)
void cTimer::SetRecording(bool Recording) void cTimer::SetRecording(bool Recording)
{ {
recording = Recording; recording = Recording;
isyslog("timer %d (%d %04d-%04d '%s') %s", Index() + 1, Channel()->Number(), start, stop, file, recording ? "start" : "stop"); isyslog("timer %s %s", *ToDescr(), recording ? "start" : "stop");
} }
void cTimer::SetPending(bool Pending) void cTimer::SetPending(bool Pending)
@ -418,7 +452,7 @@ void cTimer::SetPending(bool Pending)
void cTimer::SetInVpsMargin(bool InVpsMargin) void cTimer::SetInVpsMargin(bool InVpsMargin)
{ {
if (InVpsMargin && !inVpsMargin) if (InVpsMargin && !inVpsMargin)
isyslog("timer %d (%d %04d-%04d '%s') entered VPS margin", Index() + 1, Channel()->Number(), start, stop, file); isyslog("timer %s entered VPS margin", *ToDescr());
inVpsMargin = InVpsMargin; inVpsMargin = InVpsMargin;
} }
@ -444,7 +478,7 @@ bool cTimer::HasFlags(int Flags) const
void cTimer::Skip(void) void cTimer::Skip(void)
{ {
firstday = IncDay(SetTime(StartTime(), 0), 1); day = IncDay(SetTime(StartTime(), 0), 1);
event = NULL; event = NULL;
} }
@ -452,8 +486,8 @@ void cTimer::OnOff(void)
{ {
if (IsSingleEvent()) if (IsSingleEvent())
InvFlags(tfActive); InvFlags(tfActive);
else if (firstday) { else if (day) {
firstday = 0; day = 0;
ClrFlags(tfActive); ClrFlags(tfActive);
} }
else if (HasFlags(tfActive)) else if (HasFlags(tfActive))
@ -536,6 +570,9 @@ bool cTimers::Modified(void)
return Result; return Result;
} }
#define EPGLIMITPAST (2 * 3600) // time in seconds around now, within which EPG events will be taken into consideration
#define EPGLIMITFUTURE (4 * 3600)
void cTimers::SetEvents(void) void cTimers::SetEvents(void)
{ {
if (time(NULL) - lastSetEvents < 5) if (time(NULL) - lastSetEvents < 5)
@ -549,20 +586,40 @@ void cTimers::SetEvents(void)
if (Schedule) { if (Schedule) {
if (!lastSetEvents || Schedule->Modified() >= lastSetEvents) { if (!lastSetEvents || Schedule->Modified() >= lastSetEvents) {
const cEvent *Event = NULL; const cEvent *Event = NULL;
int Match = tmNone; int Overlap = 0;
int Distance = INT_MIN;
time_t now = time(NULL);
for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) { for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) {
if (cRemote::HasKeys()) if (cRemote::HasKeys())
return; // react immediately on user input return; // react immediately on user input
int m = ti->Matches(e); if (e->EndTime() < now - EPGLIMITPAST)
if (m > Match) { continue; // skip old events
Match = m; if (e->StartTime() > now + EPGLIMITFUTURE)
break; // no need to process events too far in the future
int overlap = 0;
ti->Matches(e, &overlap);
if (overlap && overlap >= Overlap) {
int distance = 0;
if (now < e->StartTime())
distance = e->StartTime() - now;
else if (now > e->EndTime())
distance = e->EndTime() - now;
if (Event && overlap == Overlap) {
if (Overlap > FULLMATCH) { // this means VPS
if (abs(Distance) < abs(distance))
break; // we've already found the closest VPS event
}
else if (e->Duration() <= Event->Duration())
continue; // if overlap is the same, we take the longer event
}
Overlap = overlap;
Distance = distance;
Event = e; Event = e;
if (Match == tmFull)
break;
//XXX what if there's another event with the same VPS time???
} }
} }
ti->SetEvent(Event); if (Event && Event->EndTime() < now - EXPIRELATENCY && !Event->IsRunning())
Event = NULL;
ti->SetEvent(Schedule, Event);
} }
} }
} }
@ -570,3 +627,17 @@ void cTimers::SetEvents(void)
} }
lastSetEvents = time(NULL); lastSetEvents = time(NULL);
} }
void cTimers::DeleteExpired(void)
{
cTimer *ti = First();
while (ti) {
cTimer *next = Next(ti);
if (ti->Expired()) {
isyslog("deleting timer %s", *ti->ToDescr());
Del(ti);
SetModified();
}
ti = next;
}
}

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.13 2004/12/26 12:21:29 kls Exp $ * $Id: timers.h 1.18 2005/03/20 14:47:45 kls Exp $
*/ */
#ifndef __TIMERS_H #ifndef __TIMERS_H
@ -30,14 +30,15 @@ private:
bool recording, pending, inVpsMargin; bool recording, pending, inVpsMargin;
int flags; int flags;
cChannel *channel; cChannel *channel;
int day; 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 start; int start;
int stop; int stop;
int priority; int priority;
int lifetime; int lifetime;
char file[MaxFileName]; char file[MaxFileName];
mutable time_t firstday;
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);
@ -45,36 +46,38 @@ public:
virtual ~cTimer(); virtual ~cTimer();
cTimer& operator= (const cTimer &Timer); cTimer& operator= (const cTimer &Timer);
virtual int Compare(const cListObject &ListObject) const; virtual int Compare(const cListObject &ListObject) const;
bool Recording(void) { return recording; } bool Recording(void) const { return recording; }
bool Pending(void) { return pending; } bool Pending(void) const { return pending; }
bool InVpsMargin(void) { return inVpsMargin; } bool InVpsMargin(void) const { return inVpsMargin; }
int Flags(void) { return flags; } int Flags(void) const { return flags; }
const cChannel *Channel(void) { return channel; } const cChannel *Channel(void) const { return channel; }
int Day(void) { return day; } time_t Day(void) const { return day; }
int Start(void) { return start; } int WeekDays(void) const { return weekdays; }
int Stop(void) { return stop; } int Start(void) const { return start; }
int Priority(void) { return priority; } int Stop(void) const { return stop; }
int Lifetime(void) { return lifetime; } int Priority(void) const { return priority; }
const char *File(void) { return file; } int Lifetime(void) const { return lifetime; }
time_t FirstDay(void) { return firstday; } const char *File(void) const { return file; }
const char *Summary(void) { return summary; } time_t FirstDay(void) const { return weekdays ? day : 0; }
const char *Summary(void) const { return summary; }
cString ToText(bool UseChannelID = false); cString ToText(bool UseChannelID = false);
const cEvent *Event(void) { return event; } cString ToDescr(void) const;
const cEvent *Event(void) const { return event; }
bool Parse(const char *s); bool Parse(const char *s);
bool Save(FILE *f); bool Save(FILE *f);
bool IsSingleEvent(void) const; bool IsSingleEvent(void) const;
static int GetMDay(time_t t); static int GetMDay(time_t t);
static int GetWDay(time_t t); static int GetWDay(time_t t);
static int GetWDayFromMDay(int MDay);
bool DayMatches(time_t t) const; bool DayMatches(time_t t) const;
static time_t IncDay(time_t t, int Days); static time_t IncDay(time_t t, int Days);
static time_t SetTime(time_t t, int SecondsFromMidnight); static time_t SetTime(time_t t, int SecondsFromMidnight);
char *SetFile(const char *File); char *SetFile(const char *File);
bool Matches(time_t t = 0, bool Directly = false) const; bool Matches(time_t t = 0, bool Directly = false) const;
int Matches(const cEvent *Event); int Matches(const cEvent *Event, int *Overlap = NULL) 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 cEvent *Event); void SetEvent(const cSchedule *Schedule, 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);
@ -84,10 +87,10 @@ public:
bool HasFlags(int Flags) const; bool HasFlags(int Flags) const;
void Skip(void); void Skip(void);
void OnOff(void); void OnOff(void);
cString PrintFirstDay(void); cString PrintFirstDay(void) const;
static int TimeToInt(int t); static int TimeToInt(int t);
static int ParseDay(const char *s, time_t *FirstDay = NULL); static bool ParseDay(const char *s, time_t &Day, int &WeekDays);
static cString PrintDay(int d, time_t FirstDay = 0); static cString PrintDay(time_t Day, int WeekDays);
}; };
class cTimers : public cConfig<cTimer> { class cTimers : public cConfig<cTimer> {
@ -109,6 +112,7 @@ public:
///< Returns true if any of the timers have been modified. ///< Returns true if any of the timers have been modified.
///< Calling this function resets the 'modified' flag to false. ///< Calling this function resets the 'modified' flag to false.
void SetEvents(void); void SetEvents(void);
void DeleteExpired(void);
}; };
extern cTimers Timers; extern cTimers Timers;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.90 2005/02/19 13:43:03 kls Exp $ * $Id: tools.c 1.91 2005/03/20 14:44:33 kls Exp $
*/ */
#include "tools.h" #include "tools.h"
@ -896,7 +896,7 @@ void cListObject::Unlink(void)
next = prev = NULL; next = prev = NULL;
} }
int cListObject::Index(void) int cListObject::Index(void) const
{ {
cListObject *p = prev; cListObject *p = prev;
int i = 0; int i = 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: tools.h 1.67 2005/02/12 10:17:14 kls Exp $ * $Id: tools.h 1.68 2005/03/20 14:44:24 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
@ -202,7 +202,7 @@ public:
void Append(cListObject *Object); void Append(cListObject *Object);
void Insert(cListObject *Object); void Insert(cListObject *Object);
void Unlink(void); void Unlink(void);
int Index(void); int Index(void) const;
cListObject *Prev(void) const { return prev; } cListObject *Prev(void) const { return prev; }
cListObject *Next(void) const { return next; } cListObject *Next(void) const { return next; }
}; };

14
vdr.5
View File

@ -8,9 +8,9 @@
.\" 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.34 2005/01/23 14:16:12 kls Exp $ .\" $Id: vdr.5 1.35 2005/03/19 15:20:47 kls Exp $
.\" .\"
.TH vdr 5 "19 Dec 2004" "1.3.18" "Video Disk Recorder Files" .TH vdr 5 "19 Mar 2005" "1.3.23" "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
@ -231,8 +231,13 @@ commands, the channels are given as numbers.
.B Day .B Day
The day when this timer shall record. The day when this timer shall record.
If this is a `single-shot' timer, this is the day of month on which this If this is a `single-shot' timer, this is the date on which this
timer shall record. This must be in the range \fB1...31\fR. timer shall record, given in ISO notation (\fBYYYY-MM-DD\fR), as in:
.B 2005-03-19
For compatibility with earlier versions of VDR this may also be just the day of month
on which this timer shall record (must be in the range \fB1...31\fR).
In case of a `repeating' timer this is a string consisting of exactly seven In case of a `repeating' timer this is a string consisting of exactly seven
characters, where each character position corresponds to one day of the week characters, where each character position corresponds to one day of the week
@ -245,6 +250,7 @@ cause the timer to record on that day. Example:
will define a timer that records on Monday thru Friday and does not record will define a timer that records on Monday thru Friday and does not record
on weekends. The same result could be achieved with \fBABCDE\-\-\fR (this is on weekends. The same result could be achieved with \fBABCDE\-\-\fR (this is
used to allow setting the days with language specific characters). used to allow setting the days with language specific characters).
Note that only letters may be used here, no digits.
The day definition of a `repeating' timer may be followed by the date when that The day definition of a `repeating' timer may be followed by the date when that
timer shall hit for the first time. The format for this is \fB@YYYY\-MM\-DD\fR, timer shall hit for the first time. The format for this is \fB@YYYY\-MM\-DD\fR,

4
vdr.c
View File

@ -22,7 +22,7 @@
* *
* 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.202 2005/02/12 15:06:16 kls Exp $ * $Id: vdr.c 1.203 2005/03/20 10:58:59 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -606,6 +606,8 @@ int main(int argc, char *argv[])
PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel; PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
// Timers and Recordings: // Timers and Recordings:
if (!Timers.BeingEdited()) { if (!Timers.BeingEdited()) {
// Delete expired timers:
Timers.DeleteExpired();
// Assign events to timers: // Assign events to timers:
Timers.SetEvents(); Timers.SetEvents();
// Must do all following calls with the exact same time! // Must do all following calls with the exact same time!