mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
Improved buffer handling
This commit is contained in:
170
recorder.c
170
recorder.c
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user