diff options
Diffstat (limited to 'recorder.c')
-rw-r--r-- | recorder.c | 172 |
1 files changed, 77 insertions, 95 deletions
@@ -4,13 +4,10 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recorder.c 1.19 2007/02/24 16:36:24 kls Exp $ + * $Id: recorder.c 2.1 2009/01/06 12:38:01 kls Exp $ */ #include "recorder.h" -#include <stdarg.h> -#include <stdio.h> -#include <unistd.h> #include "shutdown.h" #define RECORDERBUFSIZE MEGABYTE(5) @@ -22,33 +19,34 @@ #define MINFREEDISKSPACE (512) // MB #define DISKCHECKINTERVAL 100 // seconds -// --- cFileWriter ----------------------------------------------------------- - -class cFileWriter : public cThread { -private: - cRemux *remux; - cFileName *fileName; - cIndexFile *index; - uchar pictureType; - int fileSize; - cUnbufferedFile *recordFile; - time_t lastDiskSpaceCheck; - bool RunningLowOnDiskSpace(void); - bool NextFile(void); -protected: - virtual void Action(void); -public: - cFileWriter(const char *FileName, cRemux *Remux); - virtual ~cFileWriter(); - }; +// --- cRecorder ------------------------------------------------------------- -cFileWriter::cFileWriter(const char *FileName, cRemux *Remux) -:cThread("file writer") +cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids) +:cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids) +,cThread("recording") +,recordingInfo(FileName) { + // Make sure the disk is up and running: + + SpinUpDisk(FileName); + + ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); + ringBuffer->SetTimeouts(0, 100); + cChannel *Channel = Channels.GetByChannelID(ChannelID); + int Pid = VPid; + int Type = Channel ? Channel->Vtype() : 0; + if (!Pid && APids) { + Pid = APids[0]; + Type = 0x04; + } + if (!Pid && DPids) { + Pid = DPids[0]; + Type = 0x06; + } + frameDetector = new cFrameDetector(Pid, Type); + patPmtGenerator.GeneratePmt(ChannelID); fileName = NULL; - remux = Remux; index = NULL; - pictureType = NO_PICTURE; fileSize = 0; lastDiskSpaceCheck = time(NULL); fileName = new cFileName(FileName, true); @@ -62,14 +60,16 @@ cFileWriter::cFileWriter(const char *FileName, cRemux *Remux) // let's continue without index, so we'll at least have the recording } -cFileWriter::~cFileWriter() +cRecorder::~cRecorder() { - Cancel(3); + Detach(); delete index; delete fileName; + delete frameDetector; + delete ringBuffer; } -bool cFileWriter::RunningLowOnDiskSpace(void) +bool cRecorder::RunningLowOnDiskSpace(void) { if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { int Free = FreeDiskSpaceMB(fileName->Name()); @@ -82,10 +82,10 @@ bool cFileWriter::RunningLowOnDiskSpace(void) return false; } -bool cFileWriter::NextFile(void) +bool cRecorder::NextFile(void) { - if (recordFile && pictureType == I_FRAME) { // every file shall start with an I_FRAME - if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { + if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame + if (fileSize > MEGABYTE(off_t(Setup.MaxVideoFileSize)) || RunningLowOnDiskSpace()) { recordFile = fileName->NextFile(); fileSize = 0; } @@ -93,67 +93,10 @@ bool cFileWriter::NextFile(void) return recordFile != NULL; } -void cFileWriter::Action(void) -{ - time_t t = time(NULL); - while (Running()) { - int Count; - uchar *p = remux->Get(Count, &pictureType); - if (p) { - if (!Running() && 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 (recordFile->Write(p, Count) < 0) { - LOG_ERROR_STR(fileName->Name()); - break; - } - fileSize += Count; - remux->Del(Count); - } - else - break; - t = time(NULL); - } - else if (time(NULL) - t > MAXBROKENTIMEOUT) { - esyslog("ERROR: video data stream broken"); - ShutdownHandler.RequestEmergencyExit(); - t = time(NULL); - } - } -} - -// --- cRecorder ------------------------------------------------------------- - -cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids) -:cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids) -,cThread("recording") -{ - // 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, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, true); - writer = new cFileWriter(FileName, remux); -} - -cRecorder::~cRecorder() -{ - Detach(); - delete writer; - delete remux; - delete ringBuffer; -} - void cRecorder::Activate(bool On) { - if (On) { - writer->Start(); + if (On) Start(); - } else Cancel(3); } @@ -169,15 +112,54 @@ void cRecorder::Receive(uchar *Data, int Length) void cRecorder::Action(void) { + time_t t = time(NULL); + bool Synced = false; + bool InfoWritten = false; while (Running()) { int r; uchar *b = ringBuffer->Get(r); if (b) { - int Count = remux->Put(b, r); - if (Count) + int Count = frameDetector->Analyze(b, r); + if (Count) { + if (!Running() && frameDetector->IndependentFrame()) // finish the recording before the next independent frame + break; + if (Synced |= frameDetector->IndependentFrame()) { // start with first independent frame + if (!InfoWritten) { + if (recordingInfo.Read()) { + if (frameDetector->FramesPerSecond() > 0 && recordingInfo.FramesPerSecond() != frameDetector->FramesPerSecond()) { + recordingInfo.SetFramesPerSecond(frameDetector->FramesPerSecond()); + recordingInfo.Write(); + } + } + InfoWritten = true; + } + if (!NextFile()) + break; + if (index && frameDetector->NewFrame()) + index->Write(frameDetector->IndependentFrame(), fileName->Number(), fileSize); + if (frameDetector->IndependentFrame()) { + recordFile->Write(patPmtGenerator.GetPat(), TS_SIZE); + fileSize += TS_SIZE; + int Index = 0; + while (uchar *pmt = patPmtGenerator.GetPmt(Index)) { + recordFile->Write(pmt, TS_SIZE); + fileSize += TS_SIZE; + } + } + if (recordFile->Write(b, Count) < 0) { + LOG_ERROR_STR(fileName->Name()); + break; + } + fileSize += Count; + t = time(NULL); + } ringBuffer->Del(Count); - else - cCondWait::SleepMs(100); // avoid busy loop when resultBuffer is full in cRemux::Put() + } + } + if (time(NULL) - t > MAXBROKENTIMEOUT) { + esyslog("ERROR: video data stream broken"); + ShutdownHandler.RequestEmergencyExit(); + t = time(NULL); } } } |