From 66bab90b60048a46e401ea506d3aa65c43779700 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 23 Sep 2001 18:00:00 +0200 Subject: Version 0.96 - Made VDR compile with libdvdread-0.9.1 (thanks to Andreas Schultz). Note that you now _need_ version 0.9.1 of libdvdread to compile VDR with DVD support! - Several fixes to the replay mode display (thanks to Stefan Huelswitt): no more replay mode display when pressing the "Green" or "Yellow" button (Skip +/-60s); fixed timeout when pressing '0' to set an editing mark while the progress display is not shown; mode display is shown after progress display is closed; pressing "Ok" while the mode display is on brings up the progress display; no more unnecessary display of "normal play mode". - Supplying the new frontend parameter 'Inversion' (currently it is always set to INVERSION_AUTO, which should work with all channels on Astra). - Removing unnecessary double quotes from EPG Subtitle in EPGBugfixLevel >=1. - EPG info is now updated if the contents changes but the ID remains the same. - Fixed handling SVDRP commands whith more than one blank between the command word and the options. - The current volume setting is now saved to setup.conf and restored at the next program start. - New command line option '-r' to define a command that gets called before and after each recording (see INSTALL for details). - Implemented a check to see whether the system time is running linearly. - Writing the current time (as seen by VDR) into the log file when starting a timer recording (this may help debugging cases where timers don't start at the expected time). - Made the volume, mute and power keys work when a menu is active, too (thanks to Matthias Weingart). --- CONTRIBUTORS | 3 + FORMATS | 2 +- HISTORY | 28 ++++++++ INSTALL | 57 ++++++++++++++-- config.c | 5 +- config.h | 5 +- dvbapi.c | 23 ++++--- dvbapi.h | 5 +- eit.c | 105 +++++++++++----------------- eit.h | 8 +-- menu.c | 36 +++++++--- menu.h | 3 +- recording.c | 16 ++++- recording.h | 14 +++- svdrp.c | 3 +- thread.c | 11 +-- tools.c | 15 +++- tools.h | 3 +- vdr.c | 220 ++++++++++++++++++++++++++++++++--------------------------- 19 files changed, 358 insertions(+), 204 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9090ca9..f1157b1 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -139,3 +139,6 @@ Rolf Hakenes Andreas Vitting for providing code that closes all unused file descriptors in the child process of a pipe (used in cPipe) + +Matthias Weingart + for fixing handling of the volume, mute and power keys when menus are active diff --git a/FORMATS b/FORMATS index 3c5d36d..9142fd7 100644 --- a/FORMATS +++ b/FORMATS @@ -102,7 +102,7 @@ Video Disk Recorder File Formats Examples: 1 Check for new mail: /usr/local/bin/checkmail 2>&1 - 2 CPU status : /usr/loval/bin/cpustatus 2>&1 + 2 CPU status : /usr/local/bin/cpustatus 2>&1 3 Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' If the first non-blank character of the 'title' is a digit in the range diff --git a/HISTORY b/HISTORY index 4b68aeb..143c2f4 100644 --- a/HISTORY +++ b/HISTORY @@ -758,3 +758,31 @@ Video Disk Recorder Revision History - Three new keys ("Volume+", Volume-" and "Mute") to control the DVB card's audio output volume. - New version of the 'epg2timers' tool (thanks to Carsten Koch). + +2001-09-23: Version 0.96 + +- Made VDR compile with libdvdread-0.9.1 (thanks to Andreas Schultz). + Note that you now _need_ version 0.9.1 of libdvdread to compile VDR with + DVD support! +- Several fixes to the replay mode display (thanks to Stefan Huelswitt): + no more replay mode display when pressing the "Green" or "Yellow" button + (Skip +/-60s); fixed timeout when pressing '0' to set an editing mark while + the progress display is not shown; mode display is shown after progress + display is closed; pressing "Ok" while the mode display is on brings up + the progress display; no more unnecessary display of "normal play mode". +- Supplying the new frontend parameter 'Inversion' (currently it is always + set to INVERSION_AUTO, which should work with all channels on Astra). +- Removing unnecessary double quotes from EPG Subtitle in EPGBugfixLevel >=1. +- EPG info is now updated if the contents changes but the ID remains the same. +- Fixed handling SVDRP commands whith more than one blank between the command + word and the options. +- The current volume setting is now saved to setup.conf and restored at the + next program start. +- New command line option '-r' to define a command that gets called before and + after each recording (see INSTALL for details). +- Implemented a check to see whether the system time is running linearly. +- Writing the current time (as seen by VDR) into the log file when starting + a timer recording (this may help debugging cases where timers don't start + at the expected time). +- Made the volume, mute and power keys work when a menu is active, too (thanks + to Matthias Weingart). diff --git a/INSTALL b/INSTALL index 56200e8..b942603 100644 --- a/INSTALL +++ b/INSTALL @@ -27,7 +27,12 @@ You can find 'libdvdread' at http://www.dtek.chalmers.se/groups/dvd/downloads.html -VDR requires the card driver version dated 2001-09-14 or higher +If you want to replay CSS encrypted DVDs you also need to get the 'libdvdcss' +library from + + http://www.videolan.org/libdvdcss/download.html + +VDR requires the Linux-DVB card driver version dated 2001-09-14 or higher to work properly. After extracting the package, change into the VDR directory @@ -112,10 +117,11 @@ for programming some sort of hardware device that makes sure the computer will be restarted in time before the next timer event. Your program must also initiate the actual shutdown procedure of the computer. After this your program should return to VDR. VDR will not automatically exit after -calling the shutdown program, but will rather continue normally untit it +calling the shutdown program, but will rather continue normally until it receives a SIGTERM when the computer is actually shut down. So in case the shutdown fails, or the shutdown program for some reason decides not to -perform a shutdown, VDR will stay up and running. +perform a shutdown, VDR will stay up and running and will call the shutdown +program again after another MinUserInactivity minutes. If there are currently no timers active, both parameters will be '0'. In that case the program shall not set the hardware for automatic restart @@ -152,6 +158,49 @@ particular hard- and software environment. If the '-s' option is present, the VDR machine can be turned off by pressing the "Power" key on the remote control. +Executing commands before and after a recording: +------------------------------------------------ + +You can use the '-r' option to define a program or script that gets called +before and after a recording is performed, and after an editing process +has finished. + +The program will be called with two string parameters. The first parameter +is one of + + before if this is *before* a recording starts + after if this is *after* a recording has finished + edited if this is after a recording has been *edited* + +and the second parameter contains the full name of the recording's +directory (which may not yet exists at that moment in the "before" case). +In the "edited" case it will be the name of the edited version. + +Within this program you can do anything you would like to do before and/or +after a recording or after an editing process. However, the program must return +as soon as possible, because otherwise it will block further execution of VDR. +Be especially careful to make sure the program returns before the watchdog +timeout you may have set up with the '-w' option! If the operation you want to +perform will take longer, you will have to run it as a background job. + +An example script for use with the '-r' option could look like this: + +#!/bin/sh +case "$1" in + before) + echo "Before recording $2" + ;; + after) + echo "After recording $2" + ;; + edited) + echo "Edited recording $2" + ;; + *) + echo "ERROR: unknown state: $1" + ;; + esac + Command line options: --------------------- @@ -177,7 +226,7 @@ You can use the '-V' option to overwrite this, as in Note that the user id under which VDR runs needs to have write access to the DVD device in order to replay CSS protected DVDs (which also requires -the presence of the 'libcss' library). +the presence of the 'libdvdcss' library). The video data directory: ------------------------- diff --git a/config.c b/config.c index 87e8332..4df7361 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.72 2001/09/16 14:54:32 kls Exp $ + * $Id: config.c 1.73 2001/09/22 13:36:59 kls Exp $ */ #include "config.h" @@ -808,6 +808,7 @@ cSetup::cSetup(void) MultiSpeedMode = 0; ShowReplayMode = 0; CurrentChannel = -1; + CurrentVolume = MAXVOLUME; } bool cSetup::Parse(char *s) @@ -847,6 +848,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); else return false; return true; @@ -921,6 +923,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode); fprintf(f, "ShowReplayMode = %d\n", ShowReplayMode); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); + fprintf(f, "CurrentVolume = %d\n", CurrentVolume); if (f.Close()) { isyslog(LOG_INFO, "saved setup to %s", FileName); return true; diff --git a/config.h b/config.h index 194d04e..8012cd2 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.79 2001/09/16 14:54:36 kls Exp $ + * $Id: config.h 1.81 2001/09/22 13:37:05 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.95" +#define VDRVERSION "0.96" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -302,6 +302,7 @@ public: int MultiSpeedMode; int ShowReplayMode; int CurrentChannel; + int CurrentVolume; cSetup(void); bool Load(const char *FileName); bool Save(const char *FileName = NULL); diff --git a/dvbapi.c b/dvbapi.c index 16b3e30..8a6e691 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz * based on dvdplayer-0.5 by Matjaz Thaler * - * $Id: dvbapi.c 1.125 2001/09/16 13:55:03 kls Exp $ + * $Id: dvbapi.c 1.129 2001/09/23 13:44:27 kls Exp $ */ //#define DVDDEBUG 1 @@ -1670,7 +1670,7 @@ void cDVDplayBuffer::Input(void) /** * Parse the contained dsi packet. */ - navRead_DSI(&dsi_pack, &(data[DSI_START_BYTE]), sizeof(dsi_t)); + navRead_DSI(&dsi_pack, &(data[DSI_START_BYTE])); if (cur_pack != dsi_pack.dsi_gi.nv_pck_lbn) { esyslog(LOG_ERR, "ERROR: cur_pack != dsi_pack.dsi_gi.nv_pck_lbn"); return; @@ -1748,7 +1748,7 @@ void cDVDplayBuffer::Input(void) dsyslog(LOG_INFO, "DVD: read pack: %d", cur_pack); #endif int len = DVDReadBlocks(title, cur_pack, cur_output_size, data); - if (len != (int)cur_output_size * DVD_VIDEO_LB_LEN) { + if (len != (int)cur_output_size) { esyslog(LOG_ERR, "ERROR: read failed for %d blocks at %d", cur_output_size, cur_pack); doplay = false; break; @@ -2406,16 +2406,18 @@ void cCuttingBuffer::Action(void) // --- cVideoCutter ---------------------------------------------------------- +char *cVideoCutter::editedVersionName = NULL; cCuttingBuffer *cVideoCutter::cuttingBuffer = NULL; bool cVideoCutter::Start(const char *FileName) { if (!cuttingBuffer) { cRecording Recording(FileName); - const char *EditedVersionName = Recording.PrefixFileName('%'); - if (EditedVersionName && RemoveVideoFile(EditedVersionName) && MakeDirs(EditedVersionName, true)) { + const char *evn = Recording.PrefixFileName('%'); + if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { + editedVersionName = strdup(evn); Recording.WriteSummary(); - cuttingBuffer = new cCuttingBuffer(FileName, EditedVersionName); + cuttingBuffer = new cCuttingBuffer(FileName, editedVersionName); return true; } } @@ -2434,6 +2436,9 @@ bool cVideoCutter::Active(void) if (cuttingBuffer->Active()) return true; Stop(); + cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName); + delete editedVersionName; + editedVersionName = NULL; } return false; } @@ -2540,7 +2545,7 @@ cDvbApi::cDvbApi(int n) #endif currentChannel = 1; mute = false; - volume = 255; + volume = MAXVOLUME; } cDvbApi::~cDvbApi() @@ -3252,6 +3257,7 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char FrontendParameters Frontend; Frontend.Frequency = freq * 1000UL; + Frontend.Inversion = INVERSION_AUTO; Frontend.u.qpsk.SymbolRate = Srate * 1000UL; Frontend.u.qpsk.FEC_inner = FEC_AUTO; @@ -3298,6 +3304,7 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char FrontendParameters Frontend; Frontend.Frequency = FrequencyMHz * 1000000UL; + Frontend.Inversion = INVERSION_AUTO; Frontend.u.qam.SymbolRate = Srate * 1000UL; Frontend.u.qam.FEC_inner = FEC_AUTO; Frontend.u.qam.QAM = QAM_64; @@ -3635,7 +3642,7 @@ void cDvbApi::ToggleMute(void) void cDvbApi::SetVolume(int Volume, bool Absolute) { if (fd_audio >= 0) { - volume = min(max(Absolute ? Volume : volume + Volume, 0), 255); + volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME); audioMixer_t am; am.volume_left = am.volume_right = volume; CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); diff --git a/dvbapi.h b/dvbapi.h index d0a68e7..8e67f9b 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.51 2001/09/16 13:54:23 kls Exp $ + * $Id: dvbapi.h 1.53 2001/09/23 11:01:46 kls Exp $ */ #ifndef __DVBAPI_H @@ -51,6 +51,8 @@ typedef struct CRect { #define MAXVIDEOFILESIZE 2000 // MB #define MINVIDEOFILESIZE 100 // MB +#define MAXVOLUME 255 + const char *IndexToHMSF(int Index, bool WithFrame = false); // Converts the given index to a string, optionally containing the frame number. int HMSFToIndex(const char *HMSF); @@ -71,6 +73,7 @@ class cCuttingBuffer; class cVideoCutter { private: + static char *editedVersionName; static cCuttingBuffer *cuttingBuffer; public: static bool Start(const char *FileName); diff --git a/eit.c b/eit.c index d2927cc..1fceeef 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.22 2001/08/19 14:44:32 kls Exp $ + * $Id: eit.c 1.24 2001/09/22 13:07:21 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -279,59 +279,19 @@ unsigned short cEventInfo::GetEventID() const return uEventID; } /** */ -bool cEventInfo::SetTitle(const char *string) +void cEventInfo::SetTitle(const char *string) { - if (string == NULL) - return false; - - pTitle = strdup(string); - if (pTitle == NULL) - return false; - - return true; + pTitle = strcpyrealloc(pTitle, string); } /** */ -bool cEventInfo::SetSubtitle(const char *string) +void cEventInfo::SetSubtitle(const char *string) { - if (string == NULL) - return false; - - pSubtitle = strdup(string); - if (pSubtitle == NULL) - return false; - - return true; + pSubtitle = strcpyrealloc(pSubtitle, string); } /** */ -bool cEventInfo::AddExtendedDescription(const char *string) +void cEventInfo::SetExtendedDescription(const char *string) { - int size = 0; - bool first = true; - char *p; - - if (string == NULL) - return false; - - if (pExtendedDescription) - { - first = false; - size += strlen(pExtendedDescription); - } - - size += (strlen(string) + 1); - - p = (char *)realloc(pExtendedDescription, size); - if (p == NULL) - return false; - - if (first) - *p = 0; - - strcat(p, string); - - pExtendedDescription = p; - - return true; + pExtendedDescription = strcpyrealloc(pExtendedDescription, string); } /** */ void cEventInfo::SetTime(time_t t) @@ -447,6 +407,22 @@ void cEventInfo::FixEpgBugs(void) pSubtitle = NULL; } + // ZDF.info puts the Subtitle between double quotes, which is nothing + // but annoying (some even put a '.' after the closing '"'): + // + // Title + // "Subtitle"[.] + // + if (pSubtitle && *pSubtitle == '"') { + int l = strlen(pSubtitle); + if (l > 2 && (pSubtitle[l - 1] == '"' || (pSubtitle[l - 1] == '.' && pSubtitle[l - 2] == '"'))) { + memmove(pSubtitle, pSubtitle + 1, l); + char *p = strrchr(pSubtitle, '"'); + if (p) + *p = 0; + } + } + if (Setup.EPGBugfixLevel <= 1) return; @@ -767,28 +743,29 @@ int cEIT::ProcessEIT(unsigned char *buffer) } pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); if (!pEvent) { + // If we don't have that event ID yet, we create a new one. + // Otherwise we copy the information into the existing event anyway, because the data might have changed. pSchedule->Events.Add(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID)); pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); if (!pEvent) break; - if (rEvent) { - pEvent->SetTitle(rEvent->GetTitle()); - pEvent->SetSubtitle(rEvent->GetSubtitle()); - pEvent->SetTime(VdrProgramInfo->StartTime); - pEvent->SetDuration(VdrProgramInfo->Duration); - pEvent->AddExtendedDescription(rEvent->GetExtendedDescription()); - pEvent->FixEpgBugs(); - } - else { - pEvent->SetTitle(VdrProgramInfo->ShortName); - pEvent->SetSubtitle(VdrProgramInfo->ShortText); - pEvent->SetTime(VdrProgramInfo->StartTime); - pEvent->SetDuration(VdrProgramInfo->Duration); - pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedName); - pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedText); - pEvent->FixEpgBugs(); - } } + if (rEvent) { + pEvent->SetTitle(rEvent->GetTitle()); + pEvent->SetSubtitle(rEvent->GetSubtitle()); + pEvent->SetExtendedDescription(rEvent->GetExtendedDescription()); + } + else { + pEvent->SetTitle(VdrProgramInfo->ShortName); + pEvent->SetSubtitle(VdrProgramInfo->ShortText); + pEvent->SetExtendedDescription(VdrProgramInfo->ExtendedName); + //XXX kls 2001-09-22: + //XXX apparently this never occurred, so I have simpified ExtendedDescription handling + //XXX pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedText); + } + pEvent->SetTime(VdrProgramInfo->StartTime); + pEvent->SetDuration(VdrProgramInfo->Duration); + pEvent->FixEpgBugs(); if (IsPresentFollowing()) { if ((GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_PAUSING) || (GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_RUNNING)) pSchedule->SetPresentEvent(pEvent); diff --git a/eit.h b/eit.h index 8ca5f1e..91d5b2b 100644 --- a/eit.h +++ b/eit.h @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.10 2001/08/15 15:47:31 kls Exp $ + * $Id: eit.h 1.11 2001/09/22 11:43:21 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -42,13 +42,13 @@ private: protected: void SetFollowing(bool foll); void SetPresent(bool pres); - bool SetTitle(const char *string); + void SetTitle(const char *string); void SetServiceID(unsigned short servid); void SetEventID(unsigned short evid); void SetDuration(long l); void SetTime(time_t t); - bool AddExtendedDescription(const char *string); - bool SetSubtitle(const char *string); + void SetExtendedDescription(const char *string); + void SetSubtitle(const char *string); cEventInfo(unsigned short serviceid, unsigned short eventid); public: ~cEventInfo(); diff --git a/menu.c b/menu.c index 98fd302..23b16e2 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.120 2001/09/15 10:36:31 kls Exp $ + * $Id: menu.c 1.127 2001/09/23 10:58:48 kls Exp $ */ #include "menu.h" @@ -2108,6 +2108,7 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) { eventInfo = NULL; instantId = NULL; + fileName = NULL; dvbApi = DvbApi; if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX timer = Timer; @@ -2128,7 +2129,9 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) Summary = eventInfo->GetExtendedDescription(); } cRecording Recording(timer, Subtitle, Summary); - if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) + fileName = strdup(Recording.FileName()); + cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); + if (dvbApi->StartRecord(fileName, Channels.GetByNumber(timer->channel)->ca, timer->priority)) Recording.WriteSummary(); Interface->DisplayRecording(dvbApi->CardIndex(), true); } @@ -2140,6 +2143,7 @@ cRecordControl::~cRecordControl() { Stop(true); delete instantId; + delete fileName; } bool cRecordControl::GetEventInfo(void) @@ -2184,6 +2188,7 @@ void cRecordControl::Stop(bool KeepInstant) } timer = NULL; Interface->DisplayRecording(dvbApi->CardIndex(), false); + cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); } } @@ -2386,10 +2391,11 @@ void cReplayControl::ClearLastReplayed(const char *FileName) void cReplayControl::Show(int Seconds) { + if (modeOnly) + Hide(); if (!visible) { shown = ShowProgress(true); - if (shown && Seconds > 0) - timeoutShow = time(NULL) + Seconds; + timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; } } @@ -2397,7 +2403,11 @@ void cReplayControl::Hide(void) { if (visible) { Interface->Close(); - needsFastResponse = visible = modeOnly = false; + needsFastResponse = visible = false; + if (!modeOnly) + ShowMode(); + else + modeOnly = false; } } @@ -2419,15 +2429,19 @@ void cReplayControl::ShowMode(void) bool Play, Forward; int Speed; if (dvbApi->GetReplayMode(Play, Forward, Speed)) { + bool NormalPlay = (Play && Speed == -1); if (!visible) { + if (NormalPlay) + return; // no need to do indicate ">" unless there was a different mode displayed before // open small display Interface->Open(9, -1); Interface->Clear(); visible = modeOnly = true; } - timeoutShow = (modeOnly && !timeoutShow && Speed == -1 && Play) ? time(NULL) + MODETIMEOUT : 0; + if (modeOnly && !timeoutShow && NormalPlay) + timeoutShow = time(NULL) + MODETIMEOUT; const char *Mode; if (Speed == -1) Mode = Play ? " > " : " || "; else if (Play) Mode = Forward ? " X>> " : " <Forward(); break; case kRed: TimeSearch(); break; case kGreen|k_Repeat: - case kGreen: dvbApi->SkipSeconds(-60); break; + case kGreen: dvbApi->SkipSeconds(-60); DoShowMode = false; break; case kYellow|k_Repeat: - case kYellow: dvbApi->SkipSeconds(60); break; + case kYellow: dvbApi->SkipSeconds( 60); DoShowMode = false; break; case kBlue: Hide(); dvbApi->StopReplay(); return osEnd; @@ -2721,7 +2735,11 @@ eOSState cReplayControl::ProcessKey(eKeys Key) switch (Key) { // Menu control: case kMenu: Hide(); return osMenu; // allow direct switching to menu - case kOk: visible ? Hide() : Show(); break; + case kOk: if (visible && !modeOnly) + Hide(); + else + Show(); + break; case kBack: return osRecordings; default: return osUnknown; } diff --git a/menu.h b/menu.h index bb31c72..f7411c6 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.28 2001/09/14 15:09:49 kls Exp $ + * $Id: menu.h 1.30 2001/09/23 10:57:33 kls Exp $ */ #ifndef _MENU_H @@ -75,6 +75,7 @@ private: cTimer *timer; const cEventInfo *eventInfo; char *instantId; + char *fileName; bool GetEventInfo(void); public: cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL); diff --git a/recording.c b/recording.c index f657378..df50407 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.36 2001/09/02 15:09:28 kls Exp $ + * $Id: recording.c 1.37 2001/09/23 13:43:29 kls Exp $ */ #define _GNU_SOURCE @@ -513,3 +513,17 @@ cMark *cMarks::GetNext(int Position) return NULL; } +// --- cRecordingUserCommand ------------------------------------------------- + +const char *cRecordingUserCommand::command = NULL; + +void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName) +{ + if (command) { + char *cmd; + asprintf(&cmd, "%s %s '%s'", command, State, RecordingFileName); + isyslog(LOG_INFO, "executing '%s'", cmd); + system(cmd); + delete cmd; + } +} diff --git a/recording.h b/recording.h index e1af3db..d2391a9 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.16 2001/09/02 11:35:56 kls Exp $ + * $Id: recording.h 1.17 2001/09/23 13:43:58 kls Exp $ */ #ifndef __RECORDING_H @@ -83,4 +83,16 @@ public: cMark *GetNext(int Position); }; +#define RUC_BEFORERECORDING "before" +#define RUC_AFTERRECORDING "after" +#define RUC_EDITEDRECORDING "edited" + +class cRecordingUserCommand { +private: + static const char *command; +public: + static void SetCommand(const char *Command) { command = Command; } + static void InvokeCommand(const char *State, const char *RecordingFileName); + }; + #endif //__RECORDING_H diff --git a/svdrp.c b/svdrp.c index d183361..3c90bb0 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.23 2001/09/14 14:31:22 kls Exp $ + * $Id: svdrp.c 1.24 2001/09/22 13:30:02 kls Exp $ */ #define _GNU_SOURCE @@ -909,6 +909,7 @@ void cSVDRP::Execute(char *Cmd) s++; if (*s) *s++ = 0; + s = skipspace(s); if (CMD("CHAN")) CmdCHAN(s); else if (CMD("DELC")) CmdDELC(s); else if (CMD("DELT")) CmdDELT(s); diff --git a/thread.c b/thread.c index ec66440..f4ba76a 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.12 2001/09/15 13:00:58 kls Exp $ + * $Id: thread.c 1.13 2001/09/23 14:04:35 kls Exp $ */ #include "thread.h" @@ -67,16 +67,19 @@ cMutex::~cMutex() void cMutex::Lock(void) { - if (getpid() != lockingPid || !locked) + if (getpid() != lockingPid || !locked) { pthread_mutex_lock(&mutex); - lockingPid = getpid(); + lockingPid = getpid(); + } locked++; } void cMutex::Unlock(void) { - if (!--locked) + if (!--locked) { + lockingPid = 0; pthread_mutex_unlock(&mutex); + } } // --- cThread --------------------------------------------------------------- diff --git a/tools.c b/tools.c index d6b65e5..7238137 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.45 2001/09/15 15:41:16 kls Exp $ + * $Id: tools.c 1.46 2001/09/22 12:13:40 kls Exp $ */ #define _GNU_SOURCE @@ -64,6 +64,19 @@ char *readline(FILE *f) return NULL; } +char *strcpyrealloc(char *dest, const char *src) +{ + if (src) { + int l = max(dest ? strlen(dest) : 0, strlen(src)) + 1; // don't let the block get smaller! + dest = (char *)realloc(dest, l); + if (dest) + strcpy(dest, src); + else + esyslog(LOG_ERR, "ERROR: out of memory"); + } + return dest; +} + char *strn0cpy(char *dest, const char *src, size_t n) { char *s = dest; diff --git a/tools.h b/tools.h index 188adb4..cc67a80 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.34 2001/09/15 15:22:57 kls Exp $ + * $Id: tools.h 1.35 2001/09/22 12:12:55 kls Exp $ */ #ifndef __TOOLS_H @@ -44,6 +44,7 @@ ssize_t safe_read(int filedes, void *buffer, size_t size); ssize_t safe_write(int filedes, const void *buffer, size_t size); void writechar(int filedes, char c); char *readline(FILE *f); +char *strcpyrealloc(char *dest, const char *src); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); char *skipspace(const char *s); diff --git a/vdr.c b/vdr.c index b288108..d7c3f06 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.73 2001/09/16 14:54:45 kls Exp $ + * $Id: vdr.c 1.79 2001/09/23 14:33:39 kls Exp $ */ #define _GNU_SOURCE @@ -96,6 +96,7 @@ int main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "log", required_argument, NULL, 'l' }, { "port", required_argument, NULL, 'p' }, + { "record", required_argument, NULL, 'r' }, { "shutdown", required_argument, NULL, 's' }, { "terminal", required_argument, NULL, 't' }, { "video", required_argument, NULL, 'v' }, @@ -106,7 +107,7 @@ int main(int argc, char *argv[]) int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:s:t:v:V:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:r:s:t:v:V:w:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -143,6 +144,7 @@ int main(int argc, char *argv[]) " 2 = errors and info, 3 = errors, info and debug\n" " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" " 0 turns off SVDRP\n" + " -r CMD, --record=CMD call CMD before and after a recording\n" " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" " -t TTY, --terminal=TTY controlling tty\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" @@ -180,6 +182,8 @@ int main(int argc, char *argv[]) return 2; } break; + case 'r': cRecordingUserCommand::SetCommand(optarg); + break; case 's': Shutdown = optarg; break; case 't': Terminal = optarg; @@ -278,6 +282,7 @@ int main(int argc, char *argv[]) cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); Channels.SwitchTo(Setup.CurrentChannel); + cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true); cEITScanner EITScanner; @@ -305,6 +310,7 @@ int main(int argc, char *argv[]) int LastChannel = -1; int PreviousChannel = cDvbApi::CurrentChannel(); time_t LastActivity = 0; + time_t LinearTime = time(NULL); int MaxLatencyTime = 0; bool ForceShutdown = false; @@ -314,6 +320,14 @@ int main(int argc, char *argv[]) } while (!Interrupted) { + // Test if we are running in the Einstein continuum: + time_t Now = time(NULL); + time_t LinearDelta = Now - LinearTime; + if (LinearDelta) { + if (LinearDelta < 0 || LinearDelta > 300) // assuming nothing will block for more than 5 minutes + esyslog(LOG_ERR, "ERROR: time warp detected (%d seconds)", LinearDelta); + LinearTime = Now; + } // Handle emergency exits: if (cThread::EmergencyExit()) { esyslog(LOG_ERR, "emergency exit requested - shutting down"); @@ -341,6 +355,7 @@ int main(int argc, char *argv[]) cRecordControls::Process(Now); cTimer *Timer = Timers.GetMatch(Now); if (Timer) { + dsyslog(LOG_INFO, "system time seen is %s", ctime(&Now)); if (!cRecordControls::Start(Timer)) Timer->SetPending(true); } @@ -352,106 +367,111 @@ int main(int argc, char *argv[]) EITScanner.Activity(); LastActivity = time(NULL); } - if (*Interact && key != kPower) { - switch ((*Interact)->ProcessKey(key)) { - case osMenu: DELETENULL(Menu); - Menu = new cMenuMain(ReplayControl); - break; - case osRecord: DELETENULL(Menu); - if (!cRecordControls::Start()) - Interface->Error(tr("No free DVB device to record!")); - break; - case osRecordings: - DELETENULL(Menu); - DELETENULL(ReplayControl); - Menu = new cMenuRecordings; - break; - case osReplay: DELETENULL(Menu); - DELETENULL(ReplayControl); - ReplayControl = new cReplayControl; - break; + // Keys that must work independent of any interactive mode: + switch (key) { + // Volume Control: + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: + case kVolDn: + cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); + break; + case kMute: + cDvbApi::PrimaryDvbApi->ToggleMute(); + break; + // Power off: + case kPower: isyslog(LOG_INFO, "Power button pressed"); + DELETENULL(*Interact); + if (!Shutdown) { + Interface->Error(tr("Can't shutdown - option '-s' not given!")); + break; + } + if (cRecordControls::Active()) { + if (Interface->Confirm(tr("Recording - shut down anyway?"))) + ForceShutdown = true; + } + LastActivity = 1; // not 0, see below! + break; + default: + if (*Interact) { + switch ((*Interact)->ProcessKey(key)) { + case osMenu: DELETENULL(Menu); + Menu = new cMenuMain(ReplayControl); + break; + case osRecord: DELETENULL(Menu); + if (!cRecordControls::Start()) + Interface->Error(tr("No free DVB device to record!")); + break; + case osRecordings: + DELETENULL(Menu); + DELETENULL(ReplayControl); + Menu = new cMenuRecordings; + break; + case osReplay: DELETENULL(Menu); + DELETENULL(ReplayControl); + ReplayControl = new cReplayControl; + break; #ifdef DVDSUPPORT - case osDVD: DELETENULL(Menu); - DELETENULL(ReplayControl); - Menu = new cMenuDVD; - break; + case osDVD: DELETENULL(Menu); + DELETENULL(ReplayControl); + Menu = new cMenuDVD; + break; #endif //DVDSUPPORT - case osStopReplay: - DELETENULL(*Interact); - DELETENULL(ReplayControl); - break; - case osSwitchDvb: - DELETENULL(*Interact); - Interface->Info(tr("Switching primary DVB...")); - cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); - break; - case osBack: - case osEnd: DELETENULL(*Interact); - break; - default: ; - } - } - else { - switch (key) { - // Toggle channels: - case k0: { - int CurrentChannel = cDvbApi::CurrentChannel(); - Channels.SwitchTo(PreviousChannel); - PreviousChannel = CurrentChannel; - break; - } - // Direct Channel Select: - case k1 ... k9: - Menu = new cDisplayChannel(key); - break; - // Left/Right rotates trough channel groups: - case kLeft|k_Repeat: - case kLeft: - case kRight|k_Repeat: - case kRight: - Menu = new cDisplayChannel(NORMALKEY(key)); - break; - // Up/Down Channel Select: - case kUp|k_Repeat: - case kUp: - case kDown|k_Repeat: - case kDown: { - int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); - cChannel *channel = Channels.GetByNumber(n); - if (channel) - channel->Switch(); - break; - } - // Menu Control: - case kMenu: Menu = new cMenuMain(ReplayControl); break; - // Viewing Control: - case kOk: LastChannel = -1; break; // forces channel display - // Volume Control: - case kVolUp|k_Repeat: - case kVolUp: - case kVolDn|k_Repeat: - case kVolDn: - cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); - break; - case kMute: - cDvbApi::PrimaryDvbApi->ToggleMute(); - break; - // Power off: - case kPower: isyslog(LOG_INFO, "Power button pressed"); - DELETENULL(*Interact); - if (!Shutdown) { - Interface->Error(tr("Can't shutdown - option '-s' not given!")); - break; - } - if (cRecordControls::Active()) { - if (Interface->Confirm(tr("Recording - shut down anyway?"))) - ForceShutdown = true; - } - LastActivity = 1; // not 0, see below! - break; - default: break; - } - } + case osStopReplay: + DELETENULL(*Interact); + DELETENULL(ReplayControl); + break; + case osSwitchDvb: + DELETENULL(*Interact); + Interface->Info(tr("Switching primary DVB...")); + cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); + break; + case osBack: + case osEnd: DELETENULL(*Interact); + break; + default: ; + } + } + else { + // Key functions in "normal" viewing mode: + switch (key) { + // Toggle channels: + case k0: { + int CurrentChannel = cDvbApi::CurrentChannel(); + Channels.SwitchTo(PreviousChannel); + PreviousChannel = CurrentChannel; + break; + } + // Direct Channel Select: + case k1 ... k9: + Menu = new cDisplayChannel(key); + break; + // Left/Right rotates trough channel groups: + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: + Menu = new cDisplayChannel(NORMALKEY(key)); + break; + // Up/Down Channel Select: + case kUp|k_Repeat: + case kUp: + case kDown|k_Repeat: + case kDown: { + int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); + cChannel *channel = Channels.GetByNumber(n); + if (channel) + channel->Switch(); + break; + } + // Menu Control: + case kMenu: Menu = new cMenuMain(ReplayControl); break; + // Viewing Control: + case kOk: LastChannel = -1; break; // forces channel display + default: break; + } + } + } if (!Menu) { EITScanner.Process(); cVideoCutter::Active(); -- cgit v1.2.3