Improved buffer handling

This commit is contained in:
Klaus Schmidinger
2004-10-16 09:36:28 +02:00
parent 15030f6ace
commit 6415cc900d
19 changed files with 724 additions and 544 deletions

View File

@@ -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);
}
}
}