From 6b0658a9775aba758b4f6e2e7ef854126ef1e597 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Fri, 8 Dec 2000 16:23:32 +0100 Subject: Switched to PES recording --- HISTORY | 9 +- INSTALL | 12 +- Makefile | 6 +- config.h | 4 +- dvbapi.c | 777 ++++++++++++++++++++++++++------------------------------------- dvbapi.h | 22 +- eit.c | 6 +- menu.c | 6 +- remote.c | 6 +- svdrp.c | 3 +- thread.c | 33 ++- thread.h | 7 +- tools.c | 65 +----- tools.h | 15 +- vdr.c | 6 +- 15 files changed, 404 insertions(+), 573 deletions(-) diff --git a/HISTORY b/HISTORY index b4310f0f..9f4f09e7 100644 --- a/HISTORY +++ b/HISTORY @@ -312,8 +312,15 @@ Video Disk Recorder Revision History an early state and may still cause some problems, but it appears to work nice already. -2000-12-01: Version 0.69 +2000-12-08: Version 0.70 +- VDR now requires driver version 0.80 or higher. +- Recordings are now saved in PES mode. Note that you now need to install the + driver *WITHOUT* 'outstream=0'! This is the default when you 'make insmod' in + the DVB/driver directory. + Old recordings (in AV_PES mode) can still be replayed (as long as the driver + still supports replaying AV_PES files). The only limitation with this is that + in fast forward/back mode the picture may be slightly distorted. - The EPG data is now dumped into the file /video/epg.data every ten minutes. Use the Perl script 'epg2html.pl' to convert the raw EPG data into a simple HTML programme listing. diff --git a/INSTALL b/INSTALL index 7def1687..590138b9 100644 --- a/INSTALL +++ b/INSTALL @@ -15,13 +15,11 @@ If you have the DVB driver source in a different location you will have to change the definition of DVBDIR in the Makefile. -This program requires the card driver version 0.71 or higher -to work properly. Currently you need to load the dvb.o module with -option outstream=0, so your insmod statement should read -'insmod dvb.o outstream=0'. This is necessary because 'vdr' works -with AV_PES data and will change once it has been modified to work -directly with MPEG2. You also need to apply the patch 'dvb.c.071.diff' -for the On Screen Display to work properly. +This program requires the card driver version 0.80 or higher +to work properly. You need to load the dvb.o module *without* option +'outstream=0' (previous versions of VDR required this option to have +the driver supply the data in AV_PES format; as of version 0.70 VDR +works with PES format). After extracting the package, change into the VDR directory and type 'make'. This should produce an executable file diff --git a/Makefile b/Makefile index 739d3942..fbe16ccb 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.16 2000/11/18 14:58:10 kls Exp $ +# $Id: Makefile 1.17 2000/12/03 15:24:20 kls Exp $ DVBDIR = ../DVB @@ -39,7 +39,7 @@ font: genfontfile fontfix.c fontosd.c config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h videodir.h dvbosd.o : dvbosd.c dvbosd.h font.h tools.h -eit.o : eit.c eit.h thread.h tools.h +eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h font.o : font.c font.h fontfix.c fontosd.c tools.h i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h @@ -48,7 +48,7 @@ osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h os recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h -thread.o : thread.c thread.h +thread.o : thread.c thread.h tools.h tools.o : tools.c tools.h vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h diff --git a/config.h b/config.h index db3f1edc..655b5a0b 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.34 2000/11/18 13:25:53 kls Exp $ + * $Id: config.h 1.35 2000/12/08 13:57:23 kls Exp $ */ #ifndef __CONFIG_H @@ -18,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.68" +#define VDRVERSION "0.70" #define MaxBuffer 10000 diff --git a/dvbapi.c b/dvbapi.c index 5e4f2e64..45d50766 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.40 2000/11/19 16:46:37 kls Exp $ + * $Id: dvbapi.c 1.41 2000/12/08 15:29:27 kls Exp $ */ #include "dvbapi.h" @@ -32,23 +32,22 @@ extern "C" { // The minimum amount of video data necessary to identify frames // (must be smaller than VIDEOBUFSIZE!): -#define MINVIDEODATA (20*1024) // just a safe guess (max. size of any AV_PES block, plus some safety) +#define MINVIDEODATA (256*1024) // just a safe guess (max. size of any frame block, plus some safety) // The maximum time the buffer is allowed to write data to disk when recording: #define MAXRECORDWRITETIME 50 // ms -#define AV_PES_HEADER_LEN 8 - -// AV_PES block types: -#define AV_PES_VIDEO 1 -#define AV_PES_AUDIO 2 - // Picture types: #define NO_PICTURE 0 #define I_FRAME 1 #define P_FRAME 2 #define B_FRAME 3 +// Start codes: +#define SC_PICTURE 0x00 +#define SC_BLOCK 0xBA +#define SC_AUDIO 0xC0 + #define FRAMESPERSEC 25 // The maximum file size is limited by the range that can be covered @@ -73,6 +72,15 @@ extern "C" { typedef unsigned char uchar; +static void SetPlayMode(int VideoDev, int Mode) +{ + if (VideoDev >= 0) { + struct video_play_mode pmode; + pmode.mode = Mode; + ioctl(VideoDev, VIDIOCSPLAYMODE, &pmode); + } +} + // --- cResumeFile ------------------------------------------------------------ cResumeFile::cResumeFile(const char *FileName) @@ -378,6 +386,7 @@ protected: int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap! int Writeable(void) { return (tail >= head) ? tail - head : size - head; } int Byte(int Offset); + void Set(int Offset, int Length, int Value); public: cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); virtual ~cRingBuffer(); @@ -422,19 +431,34 @@ int cRingBuffer::Byte(int Offset) return -1; } -void cRingBuffer::Skip(int n) +void cRingBuffer::Set(int Offset, int Length, int Value) { - if (head < tail) { - head += n; - if (head > tail) - head = tail; + if (buffer && Offset + Length <= Available() ) { + Offset += head; + while (Length--) { + if (Offset >= size) + Offset -= size; + buffer[Offset] = Value; + Offset++; + } } - else if (head > tail) { - head += n; - if (head >= size) - head -= size; - if (head > tail) - head = tail; +} + +void cRingBuffer::Skip(int n) +{ + if (n > 0) { + if (head < tail) { + head += n; + if (head > tail) + head = tail; + } + else if (head > tail) { + head += n; + if (head >= size) + head -= size; + if (head > tail) + head = tail; + } } } @@ -477,9 +501,11 @@ int cRingBuffer::Read(int Max) if (tail >= size) tail = 0; } - else if (r < 0 && errno != EAGAIN) { - LOG_ERROR; - return -1; + else if (r < 0) { + if (errno != EAGAIN) { + LOG_ERROR; + return -1; + } } else eof = true; @@ -540,22 +566,13 @@ protected: cIndexFile *index; uchar fileNumber; char *fileName, *pFileNumber; - bool stop; - int GetAvPesLength(void) - { - if (Byte(0) == 'A' && Byte(1) == 'V' && Byte(4) == 'U') - return (Byte(6) << 8) + Byte(7) + AV_PES_HEADER_LEN; - return 0; - } - int GetAvPesType(void) { return Byte(2); } - int GetAvPesTag(void) { return Byte(3); } - int FindAvPesBlock(void); + int GetStartCode(int Offset) { return (Byte(Offset) == 0x00 && Byte(Offset + 1) == 0x00 && Byte(Offset + 2) == 0x01) ? Byte(Offset + 3) : -1; } int GetPictureType(int Offset) { return (Byte(Offset + 5) >> 3) & 0x07; } - int FindPictureStartCode(int Length); + int FindStartCode(uchar Code, int Offset = 0); + int FindPacketLength(int Offset = 0); public: cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool Recording, int Size, int FreeLimit = 0, int AvailLimit = 0); virtual ~cFileBuffer(); - void Stop(void) { stop = true; } }; cFileBuffer::cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool Recording, int Size, int FreeLimit = 0, int AvailLimit = 0) @@ -563,7 +580,6 @@ cFileBuffer::cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool R { index = NULL; fileNumber = 0; - stop = false; // Prepare the file name: fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN]; if (!fileName) { @@ -585,46 +601,57 @@ cFileBuffer::~cFileBuffer() delete fileName; } -int cFileBuffer::FindAvPesBlock(void) +int cFileBuffer::FindStartCode(uchar Code, int Offset) { - int Skipped = 0; + // Searches for a start code (beginning at Offset) and returns the number + // of bytes from Offset to the start code. - while (Available() > MINVIDEODATA) { - if (GetAvPesLength()) - return Skipped; - Skip(1); - Skipped++; - } + int n = Available() - Offset; + + for (int i = 0; i < n; i++) { + int c = GetStartCode(Offset + i); + if (c == Code) + return i; + if (i > 0 && c == SC_BLOCK) + break; // found another block start while looking for a different code + } return -1; } -int cFileBuffer::FindPictureStartCode(int Length) +int cFileBuffer::FindPacketLength(int Offset) { - for (int i = AV_PES_HEADER_LEN; i < Length; i++) { - if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1 && Byte(i + 3) == 0) + // Determines the length of the packet starting at offset. + + int n = Available() - Offset; + + for (int i = 1; i < n; i++) { // starts at 1 to exclude the current packet start code! + int c = GetStartCode(Offset + i); + if (c >= 0) return i; } - return -1; + return n; } // --- cRecordBuffer --------------------------------------------------------- -class cRecordBuffer : public cFileBuffer { +class cRecordBuffer : public cFileBuffer, public cThread { private: uchar pictureType; int fileSize; + int videoDev; int recordFile; - uchar tagAudio, tagVideo; - bool ok, synced; + bool ok, synced, stop; time_t lastDiskSpaceCheck; bool RunningLowOnDiskSpace(void); int Synchronize(void); bool NextFile(void); virtual int Write(int Max = -1); + bool WriteWithTimeout(void); +protected: + virtual void Action(void); public: cRecordBuffer(int *InFile, const char *FileName); virtual ~cRecordBuffer(); - int WriteWithTimeout(bool EndIfEmpty = false); }; cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) @@ -632,9 +659,9 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) { pictureType = NO_PICTURE; fileSize = 0; + videoDev = *InFile; recordFile = -1; - tagAudio = tagVideo = 0; - ok = synced = false; + ok = synced = stop = false; lastDiskSpaceCheck = time(NULL); if (!fileName) return;//XXX find a better way??? @@ -649,17 +676,42 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) } } ok = true; - //XXX hack to make the video device go into 'recording' mode: - char dummy; - read(*InFile, &dummy, sizeof(dummy)); + Start(); } cRecordBuffer::~cRecordBuffer() { + stop = true; + Cancel(3); if (recordFile >= 0) CloseVideoFile(recordFile); } +void cRecordBuffer::Action(void) +{ + dsyslog(LOG_INFO, "recording thread started (pid=%d)", getpid()); + + time_t t = time(NULL); + for (;;) { + usleep(1); // this keeps the CPU load low + + LOCK_THREAD; + + int r = Read(); + if (r >= 0) { + if (r > 0) + t = time(NULL); + if (!WriteWithTimeout()) + break; + } + if (r < 0 || (r == 0 && time(NULL) - t > 3)) + esyslog(LOG_ERR, "ERROR: video data stream broken"); + } + SetPlayMode(videoDev, VID_PLAY_RESET); + + dsyslog(LOG_INFO, "end recording thread"); +} + bool cRecordBuffer::RunningLowOnDiskSpace(void) { if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { @@ -675,71 +727,41 @@ bool cRecordBuffer::RunningLowOnDiskSpace(void) int cRecordBuffer::Synchronize(void) { + // Positions to the start of a data block (skipping everything up to + // an I-frame if not synced) and returns the block length. + int Length = 0; int Skipped = 0; int s; - while ((s = FindAvPesBlock()) >= 0) { + while (Available() > MINVIDEODATA && (s = FindStartCode(SC_BLOCK)) >= 0) { pictureType = NO_PICTURE; Skipped += s; - Length = GetAvPesLength(); - if (Length <= MINVIDEODATA) { - switch (GetAvPesType()) { - case AV_PES_VIDEO: - { - int PictureOffset = FindPictureStartCode(Length); - if (PictureOffset >= 0) { - pictureType = GetPictureType(PictureOffset); - if (pictureType < I_FRAME || pictureType > B_FRAME) - esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pictureType); - } - } - if (!synced) { - tagVideo = GetAvPesTag(); - if (pictureType == I_FRAME) { - synced = true; - Skipped = 0; - } - else { - Skip(Length - 1); - Length = 0; - } - } - else { - if (++tagVideo != GetAvPesTag()) { - esyslog(LOG_ERR, "ERROR: missed video data block #%d (next block is #%d)", tagVideo, GetAvPesTag()); - tagVideo = GetAvPesTag(); - } - } - break; - case AV_PES_AUDIO: - if (!synced) { - tagAudio = GetAvPesTag(); - Skip(Length - 1); - Length = 0; - } - else { - //XXX might get fooled the first time!!! - if (++tagAudio != GetAvPesTag()) { - esyslog(LOG_ERR, "ERROR: missed audio data block #%d (next block is #%d)", tagAudio, GetAvPesTag()); - tagAudio = GetAvPesTag(); - } - } - break; - default: // unknown data - Length = 0; // don't skip entire block - maybe we're just not in sync with AV_PES yet - if (synced) - esyslog(LOG_ERR, "ERROR: unknown data type '%d'", GetAvPesType()); - } - if (Length > 0) - break; + Skip(s); + int PictureOffset = FindStartCode(SC_PICTURE); + if (PictureOffset >= 0) { + pictureType = GetPictureType(PictureOffset); + if (I_FRAME <= pictureType && pictureType <= B_FRAME) { + if (!synced && pictureType == I_FRAME) { + synced = true; + Skipped = 0; + } + if (synced && (Length = FindStartCode(SC_BLOCK, PictureOffset)) > 0) { + Length += PictureOffset; + break; + } + Length = 0; + } + else + esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pictureType); } - else if (synced) { - esyslog(LOG_ERR, "ERROR: block length too big (%d)", Length); - Length = 0; + else { + if (synced && (Length = FindStartCode(SC_BLOCK, 1)) > 0) { + Length++; + break; + } } Skip(1); - Skipped++; } if (synced && Skipped) esyslog(LOG_ERR, "ERROR: skipped %d bytes", Skipped); @@ -775,7 +797,7 @@ bool cRecordBuffer::NextFile(void) int cRecordBuffer::Write(int Max) { // This function ignores the incoming 'Max'! - // It tries to write out exactly *one* block of AV_PES data. + // It tries to write out exactly *one* frame block. if (!ok) return -1; int n = Synchronize(); @@ -806,30 +828,38 @@ int cRecordBuffer::Write(int Max) return 0; } -int cRecordBuffer::WriteWithTimeout(bool EndIfEmpty) +bool cRecordBuffer::WriteWithTimeout(void) { - int w, written = 0; int t0 = time_ms(); - while ((w = Write()) > 0 && time_ms() - t0 < MAXRECORDWRITETIME) - written += w; - return w < 0 ? w : (written == 0 && EndIfEmpty ? -1 : written); + do { + int w = Write(); + if (w < 0) + return false; + if (w == 0) + break; + } while (time_ms() - t0 < MAXRECORDWRITETIME); + return true; } // --- cReplayBuffer --------------------------------------------------------- -enum eReplayMode { rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; - -class cReplayBuffer : public cFileBuffer { +class cReplayBuffer : public cFileBuffer, public cThread { private: + enum eReplayCmd { rcNone, rcPause, rcPlay, rcForward, rcBackward }; + enum eReplayMode { rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; int fileOffset; + int videoDev; int replayFile; eReplayMode mode; - bool skipAudio; int lastIndex; int brakeCounter; - void SkipAudioBlocks(void); + eReplayCmd command; + bool active; bool NextFile(uchar FileNumber = 0, int FileOffset = -1); void Close(void); + void SetCmd(eReplayCmd Cmd) { LOCK_THREAD; command = Cmd; } +protected: + virtual void Action(void); public: cReplayBuffer(int *OutFile, const char *FileName); virtual ~cReplayBuffer(); @@ -838,6 +868,10 @@ public: void SetMode(eReplayMode Mode); int Resume(void); bool Save(void); + void Pause(void) { SetCmd(rcPause); } + void Play(void) { SetCmd(rcPlay); } + void Forward(void) { SetCmd(rcForward); } + void Backward(void) { SetCmd(rcBackward); } void SkipSeconds(int Seconds); void GetIndex(int &Current, int &Total); }; @@ -846,23 +880,100 @@ cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) :cFileBuffer(&replayFile, OutFile, FileName, false, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) { fileOffset = 0; + videoDev = *OutFile; replayFile = -1; mode = rmPlay; brakeCounter = 0; - skipAudio = false; + command = rcNone; lastIndex = -1; + active = false; if (!fileName) return;//XXX find a better way??? // All recordings start with '1': fileNumber = 1; //TODO what if it doesn't start with '1'??? - //XXX hack to make the video device go into 'replaying' mode: - char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode! - write(*OutFile, dummy, strlen(dummy)); + Start(); } cReplayBuffer::~cReplayBuffer() { + active = false; + Cancel(3); Close(); + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + SetPlayMode(videoDev, VID_PLAY_RESET); +} + +void cReplayBuffer::Action(void) +{ + dsyslog(LOG_INFO, "replay thread started (pid=%d)", getpid()); + + bool Paused = false; + bool FastForward = false; + bool FastRewind = false; + + int ResumeIndex = Resume(); + if (ResumeIndex >= 0) + isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, cIndexFile::Str(ResumeIndex, true)); + active = true; + for (; active;) { + usleep(1); // this keeps the CPU load low + + LOCK_THREAD; + + if (command != rcNone) { + switch (command) { + case rcPause: SetPlayMode(videoDev, Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); + Paused = !Paused; + if (FastForward || FastRewind) { + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + Clear(); + } + FastForward = FastRewind = false; + SetMode(rmPlay); + break; + case rcPlay: if (FastForward || FastRewind || Paused) { + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + SetPlayMode(videoDev, VID_PLAY_NORMAL); + FastForward = FastRewind = Paused = false; + SetMode(rmPlay); + } + break; + case rcForward: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + Clear(); + FastForward = !FastForward; + FastRewind = false; + if (Paused) { + SetMode(rmPlay); + SetPlayMode(videoDev, FastForward ? VID_PLAY_SLOW_MOTION : VID_PLAY_PAUSE); + } + else { + SetPlayMode(videoDev, VID_PLAY_NORMAL); + SetMode(FastForward ? rmFastForward : rmPlay); + } + break; + case rcBackward: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + Clear(); + FastRewind = !FastRewind; + FastForward = false; + if (Paused) { + SetMode(FastRewind ? rmSlowRewind : rmPlay); + SetPlayMode(videoDev, FastRewind ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); + } + else { + SetPlayMode(videoDev, VID_PLAY_NORMAL); + SetMode(FastRewind ? rmFastRewind : rmPlay); + } + break; + default: break; + } + command = rcNone; + } + if (Read() < 0 || Write() < 0) + break; + } + Save(); + + dsyslog(LOG_INFO, "end replaying thread"); } void cReplayBuffer::Close(void) @@ -878,7 +989,6 @@ void cReplayBuffer::Close(void) void cReplayBuffer::SetMode(eReplayMode Mode) { mode = Mode; - skipAudio = Mode != rmPlay; brakeCounter = 0; if (mode != rmPlay) Clear(); @@ -920,6 +1030,15 @@ bool cReplayBuffer::Save(void) void cReplayBuffer::SkipSeconds(int Seconds) { + LOCK_THREAD; + + SetPlayMode(videoDev, VID_PLAY_PAUSE); + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + SetPlayMode(videoDev, VID_PLAY_NORMAL); + command = rcPlay; + SetMode(rmPlay); + Clear(); + if (index && Seconds) { int Index = index->Get(fileNumber, fileOffset); if (Index >= 0) { @@ -943,6 +1062,9 @@ void cReplayBuffer::SkipSeconds(int Seconds) void cReplayBuffer::GetIndex(int &Current, int &Total) { if (index) { + + LOCK_THREAD; + Current = index->Get(fileNumber, fileOffset); Total = index->Last(); } @@ -950,18 +1072,6 @@ void cReplayBuffer::GetIndex(int &Current, int &Total) Current = Total = -1; } -void cReplayBuffer::SkipAudioBlocks(void) -{ - int Length; - - while ((Length = GetAvPesLength()) > 0) { - if (GetAvPesType() == AV_PES_AUDIO) - Skip(Length); - else - break; - } -} - bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) { if (FileNumber > 0) { @@ -1003,8 +1113,6 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) int cReplayBuffer::Read(int Max = -1) { - if (stop) - return -1; if (mode != rmPlay) { if (index) { if (Available()) @@ -1047,6 +1155,14 @@ int cReplayBuffer::Read(int Max = -1) else return -1; } while (readin < Max && Free() > 0); + if (mode != rmPlay) { + // delete the audio data in modes other than rmPlay: + int AudioOffset = FindStartCode(SC_AUDIO); + if (AudioOffset >= 0) { + int AudioLength = FindPacketLength(AudioOffset); + Set(AudioOffset, AudioLength, 0); + } + } return readin; } if (Available() > 0) @@ -1057,12 +1173,6 @@ int cReplayBuffer::Read(int Max = -1) int cReplayBuffer::Write(int Max) { int Written = 0; - int Av = Available(); - if (skipAudio) { - SkipAudioBlocks(); - Max = GetAvPesLength(); - fileOffset += Av - Available(); - } if (Max) { int w; do { @@ -1076,7 +1186,7 @@ int cReplayBuffer::Write(int Max) } else return w; - } while (Max > 0); // we MUST write this entire AV_PES block + } while (Max > 0); // we MUST write this entire frame block } return Written; } @@ -1098,44 +1208,34 @@ cTransferBuffer::cTransferBuffer(int FromDevice, int ToDevice) { fromDevice = FromDevice; toDevice = ToDevice; - active = true; + active = false; Start(); } cTransferBuffer::~cTransferBuffer() { - { - LOCK_THREAD; - active = false; - } - for (time_t t0 = time(NULL); time(NULL) - t0 < 3; ) { - LOCK_THREAD; - if (active) - break; - } + active = false; + Cancel(3); + SetPlayMode(fromDevice, VID_PLAY_RESET); + SetPlayMode(toDevice, VID_PLAY_RESET); } void cTransferBuffer::Action(void) { dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid()); - //XXX hack to make the video device go into 'replaying' mode: - char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode! - write(toDevice, dummy, strlen(dummy)); - { - cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); - while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start - Buffer.Read(); // initializes fromDevice for reading - usleep(1); // this keeps the CPU load low - } - for (; active;) { - if (Buffer.Read() < 0 || Buffer.Write() < 0) - break; + + cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); + active = true; + while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start + Buffer.Read(); // initializes fromDevice for reading usleep(1); // this keeps the CPU load low } - } + for (; active;) { + if (Buffer.Read() < 0 || Buffer.Write() < 0) + break; + usleep(1); // this keeps the CPU load low + } dsyslog(LOG_INFO, "data transfer thread stopped (pid=%d)", getpid()); - LOCK_THREAD; - active = true; } // --- cDvbApi --------------------------------------------------------------- @@ -1147,13 +1247,12 @@ cDvbApi *cDvbApi::PrimaryDvbApi = NULL; cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) { siProcessor = NULL; - pidRecord = pidReplay = 0; - fromRecord = toRecord = -1; - fromReplay = toReplay = -1; - ca = 0; - priority = -1; + recordBuffer = NULL; + replayBuffer = NULL; transferBuffer = NULL; transferringFromDvbApi = NULL; + ca = 0; + priority = -1; videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK); if (videoDev >= 0) { siProcessor = new cSIProcessor(VbiFileName); @@ -1201,7 +1300,7 @@ cDvbApi::~cDvbApi() if (videoDev >= 0) { delete siProcessor; Close(); - Stop(); + StopReplay(); StopRecord(); StopTransfer(); OvlO(false); //Overlay off! @@ -1728,7 +1827,7 @@ bool cDvbApi::ShowProgress(bool Initial) { int Current, Total; - if (GetIndex(&Current, &Total)) { + if (GetIndex(Current, Total)) { if (Initial) { Clear(); if (replayTitle) @@ -1784,7 +1883,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, transferringFromDvbApi->StopTransfer(); transferringFromDvbApi = NULL; } - SetReplayMode(VID_PLAY_RESET); + SetPlayMode(videoDev, VID_PLAY_RESET); struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); unsigned int freq = FrequencyMHz; @@ -1843,22 +1942,22 @@ void cDvbApi::StopTransfer(void) if (transferBuffer) { delete transferBuffer; transferBuffer = NULL; - SetReplayMode(VID_PLAY_RESET); + SetPlayMode(videoDev, VID_PLAY_RESET); } } bool cDvbApi::Recording(void) { - if (pidRecord && !CheckProcess(pidRecord)) - pidRecord = 0; - return pidRecord; + if (recordBuffer && !recordBuffer->Active()) + StopRecord(); + return recordBuffer != NULL; } bool cDvbApi::Replaying(void) { - if (pidReplay && !CheckProcess(pidReplay)) - pidReplay = 0; - return pidReplay; + if (replayBuffer && !replayBuffer->Active()) + StopReplay(); + return replayBuffer != NULL; } bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) @@ -1871,7 +1970,7 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) StopTransfer(); - Stop(); // TODO: remove this if the driver is able to do record and replay at the same time + StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time // Check FileName: @@ -1886,109 +1985,28 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) if (!MakeDirs(FileName, true)) return false; - // Open pipes for recording process: - - int fromRecordPipe[2], toRecordPipe[2]; - - if (pipe(fromRecordPipe) != 0) { - LOG_ERROR; - return false; - } - if (pipe(toRecordPipe) != 0) { - LOG_ERROR; - return false; - } + // Create recording buffer: - // Create recording process: + recordBuffer = new cRecordBuffer(&videoDev, FileName); - pidRecord = fork(); - if (pidRecord < 0) { - LOG_ERROR; - return false; - } - if (pidRecord == 0) { - - // This is the actual recording process - - dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); - bool DataStreamBroken = false; - int fromMain = toRecordPipe[0]; - int toMain = fromRecordPipe[1]; - cRecordBuffer *Buffer = new cRecordBuffer(&videoDev, FileName); - if (Buffer) { - for (;;) { - fd_set set; - FD_ZERO(&set); - FD_SET(videoDev, &set); - FD_SET(fromMain, &set); - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - bool ForceEnd = false; - if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) { - if (FD_ISSET(videoDev, &set)) { - if (Buffer->Read() < 0) - break; - DataStreamBroken = false; - } - if (FD_ISSET(fromMain, &set)) { - switch (readchar(fromMain)) { - case dvbStop: Buffer->Stop(); - ForceEnd = DataStreamBroken; - break; - } - } - } - else { - DataStreamBroken = true; - esyslog(LOG_ERR, "ERROR: video data stream broken"); - } - if (Buffer->WriteWithTimeout(ForceEnd) < 0) - break; - } - delete Buffer; - } - else - esyslog(LOG_ERR, "ERROR: can't allocate recording buffer"); - close(fromMain); - close(toMain); - dsyslog(LOG_INFO, "end recording process"); - exit(0); + if (recordBuffer) { + ca = Ca; + priority = Priority; + return true; } - - // Establish communication with the recording process: - - fromRecord = fromRecordPipe[0]; - toRecord = toRecordPipe[1]; - - ca = Ca; - priority = Priority; - return true; + else + esyslog(LOG_ERR, "ERROR: can't allocate recording buffer"); } return false; } void cDvbApi::StopRecord(void) { - if (pidRecord) { - writechar(toRecord, dvbStop); - close(toRecord); - close(fromRecord); - toRecord = fromRecord = -1; - KillProcess(pidRecord); - pidRecord = 0; + if (recordBuffer) { + delete recordBuffer; + recordBuffer = NULL; ca = 0; priority = -1; - SetReplayMode(VID_PLAY_RESET); //XXX - } -} - -void cDvbApi::SetReplayMode(int Mode) -{ - if (videoDev >= 0) { - struct video_play_mode pmode; - pmode.mode = Mode; - ioctl(videoDev, VIDIOCSPLAYMODE, &pmode); } } @@ -1999,7 +2017,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) return false; } StopTransfer(); - Stop(); + StopReplay(); if (videoDev >= 0) { lastProgress = lastTotal = -1; @@ -2017,205 +2035,60 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) } isyslog(LOG_INFO, "replay %s", FileName); - // Open pipes for replay process: - - int fromReplayPipe[2], toReplayPipe[2]; - - if (pipe(fromReplayPipe) != 0) { - LOG_ERROR; - return false; - } - if (pipe(toReplayPipe) != 0) { - LOG_ERROR; - return false; - } + // Create replay buffer: - // Create replay process: - - pidReplay = fork(); - if (pidReplay < 0) { - LOG_ERROR; - return false; - } - if (pidReplay == 0) { - - // This is the actual replaying process - - dsyslog(LOG_INFO, "start replaying process (pid=%d)", getpid()); - int fromMain = toReplayPipe[0]; - int toMain = fromReplayPipe[1]; - cReplayBuffer *Buffer = new cReplayBuffer(&videoDev, FileName); - if (Buffer) { - bool Paused = false; - bool FastForward = false; - bool FastRewind = false; - int ResumeIndex = Buffer->Resume(); - if (ResumeIndex >= 0) - isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, cIndexFile::Str(ResumeIndex, true)); - for (;;) { - if (Buffer->Read() < 0) - break; - fd_set setIn, setOut; - FD_ZERO(&setIn); - FD_ZERO(&setOut); - FD_SET(fromMain, &setIn); - FD_SET(videoDev, &setOut); - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - if (select(FD_SETSIZE, &setIn, &setOut, NULL, &timeout) > 0) { - if (FD_ISSET(videoDev, &setOut)) { - if (Buffer->Write() < 0) - break; - } - if (FD_ISSET(fromMain, &setIn)) { - switch (readchar(fromMain)) { - case dvbStop: SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Stop(); - break; - case dvbPause: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); - Paused = !Paused; - if (FastForward || FastRewind) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Clear(); - } - FastForward = FastRewind = false; - Buffer->SetMode(rmPlay); - break; - case dvbPlay: if (FastForward || FastRewind || Paused) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - SetReplayMode(VID_PLAY_NORMAL); - FastForward = FastRewind = Paused = false; - Buffer->SetMode(rmPlay); - } - break; - case dvbForward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Clear(); - FastForward = !FastForward; - FastRewind = false; - if (Paused) { - Buffer->SetMode(rmPlay); - SetReplayMode(FastForward ? VID_PLAY_SLOW_MOTION : VID_PLAY_PAUSE); - } - else { - SetReplayMode(VID_PLAY_NORMAL); - Buffer->SetMode(FastForward ? rmFastForward : rmPlay); - } - break; - case dvbBackward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Clear(); - FastRewind = !FastRewind; - FastForward = false; - if (Paused) { - Buffer->SetMode(FastRewind ? rmSlowRewind : rmPlay); - SetReplayMode(FastRewind ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); - } - else { - SetReplayMode(VID_PLAY_NORMAL); - Buffer->SetMode(FastRewind ? rmFastRewind : rmPlay); - } - break; - case dvbSkip: { - int Seconds; - if (readint(fromMain, Seconds)) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - SetReplayMode(VID_PLAY_NORMAL); - FastForward = FastRewind = Paused = false; - Buffer->SetMode(rmPlay); - Buffer->SkipSeconds(Seconds); - } - } - break; - case dvbGetIndex: { - int Current, Total; - Buffer->GetIndex(Current, Total); - writeint(toMain, Current); - writeint(toMain, Total); - } - break; - } - } - } - } - Buffer->Save(); - delete Buffer; - } - else - esyslog(LOG_ERR, "ERROR: can't allocate replaying buffer"); - close(fromMain); - close(toMain); - SetReplayMode(VID_PLAY_RESET); //XXX - dsyslog(LOG_INFO, "end replaying process"); - exit(0); - } - - // Establish communication with the replay process: - - fromReplay = fromReplayPipe[0]; - toReplay = toReplayPipe[1]; - return true; + replayBuffer = new cReplayBuffer(&videoDev, FileName); + if (replayBuffer) + return true; + else + esyslog(LOG_ERR, "ERROR: can't allocate replaying buffer"); } return false; } -void cDvbApi::Stop(void) +void cDvbApi::StopReplay(void) { - if (pidReplay) { - writechar(toReplay, dvbStop); - close(toReplay); - close(fromReplay); - toReplay = fromReplay = -1; - KillProcess(pidReplay); - pidReplay = 0; - SetReplayMode(VID_PLAY_RESET); //XXX + if (replayBuffer) { + delete replayBuffer; + replayBuffer = NULL; } } void cDvbApi::Pause(void) { - if (pidReplay) - writechar(toReplay, dvbPause); + if (replayBuffer) + replayBuffer->Pause(); } void cDvbApi::Play(void) { - if (pidReplay) - writechar(toReplay, dvbPlay); + if (replayBuffer) + replayBuffer->Play(); } void cDvbApi::Forward(void) { - if (pidReplay) - writechar(toReplay, dvbForward); + if (replayBuffer) + replayBuffer->Forward(); } void cDvbApi::Backward(void) { - if (pidReplay) - writechar(toReplay, dvbBackward); + if (replayBuffer) + replayBuffer->Backward(); } void cDvbApi::Skip(int Seconds) { - if (pidReplay) { - writechar(toReplay, dvbSkip); - writeint(toReplay, Seconds); - } + if (replayBuffer) + replayBuffer->SkipSeconds(Seconds); } -bool cDvbApi::GetIndex(int *Current, int *Total) +bool cDvbApi::GetIndex(int &Current, int &Total) { - if (pidReplay) { - int total; - purge(fromReplay); - writechar(toReplay, dvbGetIndex); - if (readint(fromReplay, *Current) && readint(fromReplay, total)) { - if (Total) - *Total = total; - } - else - *Current = -1; - return *Current >= 0; + if (replayBuffer) { + replayBuffer->GetIndex(Current, Total); + return true; } return false; } diff --git a/dvbapi.h b/dvbapi.h index f6640ff5..b9f045de 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.26 2000/11/19 14:09:41 kls Exp $ + * $Id: dvbapi.h 1.27 2000/12/03 13:44:28 kls Exp $ */ #ifndef __DVBAPI_H @@ -42,6 +42,8 @@ public: bool Save(int Index); }; +class cRecordBuffer; +class cReplayBuffer; class cTransferBuffer; class cDvbApi { @@ -171,20 +173,10 @@ private: // Record/Replay facilities private: - enum { dvbStop = 1, // let's not have 0 as a command - dvbPause, - dvbPlay, - dvbForward, - dvbBackward, - dvbSkip, - dvbGetIndex, - }; - pid_t pidRecord, pidReplay; - int fromRecord, toRecord; - int fromReplay, toReplay; + cRecordBuffer *recordBuffer; + cReplayBuffer *replayBuffer; int ca; int priority; - void SetReplayMode(int Mode); protected: int Ca(void) { return ca; } // Returns the ca of the current recording session (0..MAXDVBAPI). @@ -214,7 +206,7 @@ public: // If there is already a replay session active, it will be stopped // and the new file will be played back. // If provided Title will be used in the progress display. - void Stop(void); + void StopReplay(void); // Stops the current replay session (if any). void Pause(void); // Pauses the current replay session, or resumes a paused session. @@ -229,7 +221,7 @@ public: // The sign of 'Seconds' determines the direction in which to skip. // Use a very large negative value to go all the way back to the // beginning of the recording. - bool GetIndex(int *Current, int *Total = NULL); + bool GetIndex(int &Current, int &Total); }; class cEITScanner { diff --git a/eit.c b/eit.c index 52dc6618..e7c60c16 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.10 2000/11/25 12:51:06 kls Exp $ + * $Id: eit.c 1.11 2000/12/03 15:33:37 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -131,7 +131,7 @@ bool cMJD::SetSystemTime() isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim); isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime); if (stime(&mjdtime) < 0) - esyslog(LOG_ERR, "ERROR while setting system time: %s", strerror(errno)); + esyslog(LOG_ERR, "ERROR while setting system time: %m"); return true; } @@ -1117,7 +1117,7 @@ cSIProcessor::~cSIProcessor() { if (fsvbi >= 0) { - Stop(); + Cancel(); ShutDownFilters(); delete filters; if (!--numSIProcessors) // the last one deletes it diff --git a/menu.c b/menu.c index 273cb22f..fd230d95 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.53 2000/11/26 16:15:30 kls Exp $ + * $Id: menu.c 1.54 2000/12/03 11:43:35 kls Exp $ */ #include "menu.h" @@ -2009,7 +2009,7 @@ cReplayControl::cReplayControl(void) cReplayControl::~cReplayControl() { Hide(); - dvbApi->Stop(); + dvbApi->StopReplay(); } void cReplayControl::SetRecording(const char *FileName, const char *Title) @@ -2060,7 +2060,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) case kUp: dvbApi->Play(); break; case kDown: dvbApi->Pause(); break; case kBlue: Hide(); - dvbApi->Stop(); + dvbApi->StopReplay(); return osEnd; case kLeft: dvbApi->Backward(); break; case kRight: dvbApi->Forward(); break; diff --git a/remote.c b/remote.c index 349a4452..691b5e94 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.19 2000/11/11 11:22:22 kls Exp $ + * $Id: remote.c 1.20 2000/12/03 11:55:06 kls Exp $ */ #include "remote.h" @@ -115,7 +115,7 @@ cRcIoRCU::cRcIoRCU(char *DeviceName) cRcIoRCU::~cRcIoRCU() { - Stop(); + Cancel(); } void cRcIoRCU::Action(void) @@ -420,7 +420,7 @@ cRcIoLIRC::cRcIoLIRC(char *DeviceName) cRcIoLIRC::~cRcIoLIRC() { - Stop(); + Cancel(); } void cRcIoLIRC::Action(void) diff --git a/svdrp.c b/svdrp.c index 66ae8e9a..0ce30dba 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.12 2000/11/05 13:44:42 kls Exp $ + * $Id: svdrp.c 1.13 2000/12/03 15:34:35 kls Exp $ */ #define _GNU_SOURCE @@ -18,6 +18,7 @@ #include "svdrp.h" #include #include +#include #include #include #include diff --git a/thread.c b/thread.c index 8705fe2f..d56e8808 100644 --- a/thread.c +++ b/thread.c @@ -4,12 +4,15 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.5 2000/11/22 17:11:04 kls Exp $ + * $Id: thread.c 1.6 2000/12/03 15:35:02 kls Exp $ */ #include "thread.h" +#include #include +#include #include +#include "tools.h" // --- cThread --------------------------------------------------------------- @@ -25,7 +28,7 @@ cThread::cThread(void) signalHandlerInstalled = true; } running = false; - parentPid = lockingPid = 0; + parentPid = threadPid = lockingPid = 0; locked = 0; } @@ -40,6 +43,7 @@ void cThread::SignalHandler(int signum) void *cThread::StartThread(cThread *Thread) { + Thread->threadPid = getpid(); Thread->Action(); return NULL; } @@ -54,8 +58,31 @@ bool cThread::Start(void) return true; //XXX return value of pthread_create()??? } -void cThread::Stop(void) +bool cThread::Active(void) { + if (threadPid) { + if (kill(threadPid, SIGIO) < 0) { // couldn't find another way of checking whether the thread is still running - any ideas? + if (errno == ESRCH) + threadPid = 0; + else + LOG_ERROR; + } + else + return true; + } + return false; +} + +void cThread::Cancel(int WaitSeconds) +{ + if (WaitSeconds > 0) { + for (time_t t0 = time(NULL) + WaitSeconds; time(NULL) < t0; ) { + if (!Active()) + return; + usleep(10000); + } + esyslog(LOG_ERR, "ERROR: thread %d won't end (waited %d seconds) - cancelling it...", threadPid, WaitSeconds); + } pthread_cancel(thread); } diff --git a/thread.h b/thread.h index c85c51e2..6aaee0b9 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.3 2000/11/14 18:38:11 kls Exp $ + * $Id: thread.h 1.4 2000/12/03 11:18:37 kls Exp $ */ #ifndef __THREAD_H @@ -28,7 +28,7 @@ class cThread { private: pthread_t thread; cMutex Mutex; - pid_t parentPid, lockingPid; + pid_t parentPid, threadPid, lockingPid; int locked; bool running; static bool signalHandlerInstalled; @@ -39,11 +39,12 @@ private: protected: void WakeUp(void); virtual void Action(void) = 0; - void Stop(void); + void Cancel(int WaitSeconds = 0); public: cThread(void); virtual ~cThread(); bool Start(void); + bool Active(void); }; // cThreadLock can be used to easily set a lock in a thread and make absolutely diff --git a/tools.c b/tools.c index 6d86f162..2397b2a3 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.23 2000/11/11 15:17:12 kls Exp $ + * $Id: tools.c 1.24 2000/12/03 15:39:11 kls Exp $ */ #define _GNU_SOURCE @@ -15,10 +15,7 @@ #if defined(DEBUG_OSD) #include #endif -#include -#include #include -#include #include #define MaxBuffer 1000 @@ -30,29 +27,6 @@ void writechar(int filedes, char c) write(filedes, &c, sizeof(c)); } -void writeint(int filedes, int n) -{ - write(filedes, &n, sizeof(n)); -} - -char readchar(int filedes) -{ - char c; - read(filedes, &c, 1); - return c; -} - -bool readint(int filedes, int &n) -{ - return cFile::AnyFileReady(filedes, 0) && read(filedes, &n, sizeof(n)) == sizeof(n); -} - -void purge(int filedes) -{ - while (cFile::AnyFileReady(filedes, 0)) - readchar(filedes); -} - char *readline(FILE *f) { static char buffer[MaxBuffer]; @@ -205,7 +179,7 @@ bool MakeDirs(const char *FileName, bool IsDirectory) if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) { dsyslog(LOG_INFO, "creating directory %s", s); if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { - esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno)); + LOG_ERROR_STR(s); result = false; break; } @@ -271,41 +245,6 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks) return false; } -bool CheckProcess(pid_t pid) -{ - pid_t Pid2Check = pid; - int status; - pid = waitpid(Pid2Check, &status, WNOHANG); - if (pid < 0) { - if (errno != ECHILD) - LOG_ERROR; - return false; - } - return true; -} - -void KillProcess(pid_t pid, int Timeout) -{ - pid_t Pid2Wait4 = pid; - for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) { - int status; - pid_t pid = waitpid(Pid2Wait4, &status, WNOHANG); - if (pid < 0) { - if (errno != ECHILD) - LOG_ERROR; - return; - } - if (pid == Pid2Wait4) - return; - } - esyslog(LOG_ERR, "ERROR: process %d won't end (waited %d seconds) - terminating it...", Pid2Wait4, Timeout); - if (kill(Pid2Wait4, SIGTERM) < 0) { - esyslog(LOG_ERR, "ERROR: process %d won't terminate (%s) - killing it...", Pid2Wait4, strerror(errno)); - if (kill(Pid2Wait4, SIGKILL) < 0) - esyslog(LOG_ERR, "ERROR: process %d won't die (%s) - giving up", Pid2Wait4, strerror(errno)); - } -} - // --- cFile ----------------------------------------------------------------- bool cFile::files[FD_SETSIZE] = { false }; diff --git a/tools.h b/tools.h index f83e7da4..b76d7e95 100644 --- a/tools.h +++ b/tools.h @@ -4,13 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.20 2000/11/12 15:27:06 kls Exp $ + * $Id: tools.h 1.21 2000/12/03 15:32:54 kls Exp $ */ #ifndef __TOOLS_H #define __TOOLS_H -#include +//#include #include #include #include @@ -24,19 +24,14 @@ extern int SysLogLevel; #define isyslog if (SysLogLevel > 1) syslog #define dsyslog if (SysLogLevel > 2) syslog -#define LOG_ERROR esyslog(LOG_ERR, "ERROR (%s,%d): %s", __FILE__, __LINE__, strerror(errno)) -#define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno)); +#define LOG_ERROR esyslog(LOG_ERR, "ERROR (%s,%d): %m", __FILE__, __LINE__) +#define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %m", s) #define SECSINDAY 86400 -#define MAXPROCESSTIMEOUT 3 // seconds #define DELETENULL(p) (delete (p), p = NULL) void writechar(int filedes, char c); -void writeint(int filedes, int n); -char readchar(int filedes); -bool readint(int filedes, int &n); -void purge(int filedes); char *readline(FILE *f); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); @@ -51,8 +46,6 @@ uint FreeDiskSpaceMB(const char *Directory); bool DirectoryOk(const char *DirName, bool LogErrors = false); bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); -bool CheckProcess(pid_t pid); -void KillProcess(pid_t pid, int Timeout = MAXPROCESSTIMEOUT); class cFile { private: diff --git a/vdr.c b/vdr.c index 8a842003..fbef0eb0 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.46 2000/11/18 13:46:56 kls Exp $ + * $Id: vdr.c 1.47 2000/12/03 15:36:46 kls Exp $ */ #include @@ -141,8 +141,8 @@ int main(int argc, char *argv[]) #if !defined(DEBUG_OSD) && !defined(REMOTE_KBD) pid_t pid = fork(); if (pid < 0) { - fprintf(stderr, "%s\n", strerror(errno)); - esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); + fprintf(stderr, "%m\n"); + esyslog(LOG_ERR, "ERROR: %m"); abort(); } if (pid != 0) -- cgit v1.2.3