summaryrefslogtreecommitdiff
path: root/recorder.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2009-01-06 14:41:11 +0100
committerKlaus Schmidinger <vdr@tvdr.de>2009-01-06 14:41:11 +0100
commit7de7ede26fcabc232d5647b728080fe3c5d9fca2 (patch)
tree930f06d43802fefd93c83ac0e78e31aa25d7bf52 /recorder.c
parent7470253c60f98e654e01de5bd7cc3da893524462 (diff)
downloadvdr-7de7ede26fcabc232d5647b728080fe3c5d9fca2.tar.gz
vdr-7de7ede26fcabc232d5647b728080fe3c5d9fca2.tar.bz2
The recording format is now Transport Stream
Diffstat (limited to 'recorder.c')
-rw-r--r--recorder.c172
1 files changed, 77 insertions, 95 deletions
diff --git a/recorder.c b/recorder.c
index 7bcd0cc7..83024ac1 100644
--- a/recorder.c
+++ b/recorder.c
@@ -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);
}
}
}