diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2004-10-16 09:36:28 +0200 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2004-10-16 09:36:28 +0200 |
commit | 6415cc900de3361925d22f879077be687fce3858 (patch) | |
tree | 98ab10cda016e125e33966e371ccfe01e5fd9bd1 /recorder.c | |
parent | 15030f6acece1060f9736f875fe3abbcf9392263 (diff) | |
download | vdr-6415cc900de3361925d22f879077be687fce3858.tar.gz vdr-6415cc900de3361925d22f879077be687fce3858.tar.bz2 |
Improved buffer handling
Diffstat (limited to 'recorder.c')
-rw-r--r-- | recorder.c | 170 |
1 files changed, 106 insertions, 64 deletions
@@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recorder.c 1.10 2004/03/20 10:33:21 kls Exp $ + * $Id: recorder.c 1.11 2004/10/16 09:23:01 kls Exp $ */ #include <stdarg.h> @@ -12,9 +12,7 @@ #include <unistd.h> #include "recorder.h" -// The size of the array used to buffer video data: -// (must be larger than MINVIDEODATA - see remux.h) -#define VIDEOBUFSIZE MEGABYTE(5) +#define RECORDERBUFSIZE MEGABYTE(5) // The maximum time we wait before assuming that a recorded video data stream // is broken: @@ -23,25 +21,35 @@ #define MINFREEDISKSPACE (512) // MB #define DISKCHECKINTERVAL 100 // seconds -cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2) -:cReceiver(Ca, Priority, Setup.RecordDolbyDigital ? 5 : 3, VPid, APid1, APid2, DPid1, DPid2) -,cThread("recording") +class cFileWriter : public cThread { +private: + cRemux *remux; + cFileName *fileName; + cIndexFile *index; + uchar pictureType; + int fileSize; + int recordFile; + bool active; + time_t lastDiskSpaceCheck; + bool RunningLowOnDiskSpace(void); + bool NextFile(void); +protected: + virtual void Action(void); +public: + cFileWriter(const char *FileName, cRemux *Remux); + virtual ~cFileWriter(); + }; + +cFileWriter::cFileWriter(const char *FileName, cRemux *Remux) +:cThread("file writer") { - ringBuffer = NULL; - remux = NULL; + active = false; fileName = NULL; + remux = Remux; index = NULL; pictureType = NO_PICTURE; fileSize = 0; - active = false; lastDiskSpaceCheck = time(NULL); - - // Make sure the disk is up and running: - - SpinUpDisk(FileName); - - ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true); - remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true); fileName = new cFileName(FileName, true); recordFile = fileName->Open(); if (recordFile < 0) @@ -53,28 +61,15 @@ cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int A // let's continue without index, so we'll at least have the recording } -cRecorder::~cRecorder() +cFileWriter::~cFileWriter() { - Detach(); + active = false; + Cancel(3); delete index; delete fileName; - delete remux; - delete ringBuffer; } -void cRecorder::Activate(bool On) -{ - if (On) { - if (recordFile >= 0) - Start(); - } - else if (active) { - active = false; - Cancel(3); - } -} - -bool cRecorder::RunningLowOnDiskSpace(void) +bool cFileWriter::RunningLowOnDiskSpace(void) { if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { int Free = FreeDiskSpaceMB(fileName->Name()); @@ -87,7 +82,7 @@ bool cRecorder::RunningLowOnDiskSpace(void) return false; } -bool cRecorder::NextFile(void) +bool cFileWriter::NextFile(void) { if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { @@ -98,40 +93,29 @@ bool cRecorder::NextFile(void) return recordFile >= 0; } -void cRecorder::Receive(uchar *Data, int Length) -{ - int p = ringBuffer->Put(Data, Length); - if (p != Length && active) - ringBuffer->ReportOverflow(Length - p); -} - -void cRecorder::Action(void) +void cFileWriter::Action(void) { time_t t = time(NULL); active = true; while (active) { - int r; - const uchar *b = ringBuffer->Get(r); - if (b) { - int Count = r, Result; - uchar *p = remux->Process(b, Count, Result, &pictureType); - ringBuffer->Del(Count); - if (p) { - //XXX+ active??? see old version (Busy) - if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame + int Count; + uchar *p = remux->Get(Count, &pictureType); + if (p) { + //XXX+ active??? see old version (Busy) + if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame + break; + if (NextFile()) { + if (index && pictureType != NO_PICTURE) + index->Write(pictureType, fileName->Number(), fileSize); + if (safe_write(recordFile, p, Count) < 0) { + LOG_ERROR_STR(fileName->Name()); break; - if (NextFile()) { - if (index && pictureType != NO_PICTURE) - index->Write(pictureType, fileName->Number(), fileSize); - if (safe_write(recordFile, p, Result) < 0) { - LOG_ERROR_STR(fileName->Name()); - break; - } - fileSize += Result; } - else - break; + fileSize += Count; + remux->Del(Count); } + else + break; t = time(NULL); } else if (time(NULL) - t > MAXBROKENTIMEOUT) { @@ -139,7 +123,65 @@ void cRecorder::Action(void) cThread::EmergencyExit(true); t = time(NULL); } - else - usleep(1); // this keeps the CPU load low + } + active = false; +} + +cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2) +:cReceiver(Ca, Priority, Setup.RecordDolbyDigital ? 5 : 3, VPid, APid1, APid2, DPid1, DPid2) +,cThread("recording") +{ + active = false; + + // Make sure the disk is up and running: + + SpinUpDisk(FileName); + + ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); + ringBuffer->SetTimeouts(0, 100); + remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true); + writer = new cFileWriter(FileName, remux); +} + +cRecorder::~cRecorder() +{ + Detach(); + delete writer; + delete remux; + delete ringBuffer; +} + +void cRecorder::Activate(bool On) +{ + if (On) { + writer->Start(); + Start(); + } + else if (active) { + active = false; + Cancel(3); + } +} + +void cRecorder::Receive(uchar *Data, int Length) +{ + if (active) { + int p = ringBuffer->Put(Data, Length); + if (p != Length && active) + ringBuffer->ReportOverflow(Length - p); + } +} + +void cRecorder::Action(void) +{ + active = true; + while (active) { + int r; + uchar *b = ringBuffer->Get(r); + if (b) { + int Count = remux->Put(b, r); + if (Count) + ringBuffer->Del(Count); + } } } |