summaryrefslogtreecommitdiff
path: root/recorder.c
diff options
context:
space:
mode:
Diffstat (limited to 'recorder.c')
-rw-r--r--recorder.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/recorder.c b/recorder.c
new file mode 100644
index 00000000..3a0941bb
--- /dev/null
+++ b/recorder.c
@@ -0,0 +1,149 @@
+/*
+ * recorder.h: The actual DVB recorder
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: recorder.c 1.1 2002/06/16 10:03:25 kls Exp $
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#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(1)
+
+#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, 5, VPid, APid1, APid2, DPid1, DPid2)
+{
+ ringBuffer = NULL;
+ remux = NULL;
+ fileName = NULL;
+ index = NULL;
+ pictureType = NO_PICTURE;
+ fileSize = 0;
+ active = false;
+ lastDiskSpaceCheck = time(NULL);
+ isyslog("record %s", FileName);
+
+ // Create directories if necessary:
+
+ if (!MakeDirs(FileName, true))
+ return;
+
+ // Make sure the disk is up and running:
+
+ SpinUpDisk(FileName);
+
+ ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
+ remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
+ fileName = new cFileName(FileName, true);
+ recordFile = fileName->Open();
+ if (recordFile < 0)
+ return;
+ // Create the index file:
+ index = new cIndexFile(FileName, true);
+ if (!index)
+ esyslog("ERROR: can't allocate index");
+ // let's continue without index, so we'll at least have the recording
+}
+
+cRecorder::~cRecorder()
+{
+ Detach();
+ 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)
+{
+ if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) {
+ int Free = FreeDiskSpaceMB(fileName->Name());
+ lastDiskSpaceCheck = time(NULL);
+ if (Free < MINFREEDISKSPACE) {
+ dsyslog("low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cRecorder::NextFile(void)
+{
+ if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME
+ if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) {
+ recordFile = fileName->NextFile();
+ fileSize = 0;
+ }
+ }
+ return recordFile >= 0;
+}
+
+void cRecorder::Receive(uchar *Data, int Length)
+{
+ int p = ringBuffer->Put(Data, Length);
+ if (p != Length && active)
+ esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
+}
+
+void cRecorder::Action(void)
+{
+ dsyslog("recording thread started (pid=%d)", getpid());
+
+ uchar b[MINVIDEODATA];
+ int r = 0;
+ active = true;
+ while (active) {
+ int g = ringBuffer->Get(b + r, sizeof(b) - r);
+ if (g > 0)
+ r += g;
+ if (r > 0) {
+ int Count = r, Result;
+ const uchar *p = remux->Process(b, Count, Result, &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, Result) < 0) {
+ LOG_ERROR_STR(fileName->Name());
+ break;
+ }
+ fileSize += Result;
+ }
+ else
+ break;
+ }
+ if (Count > 0) {
+ r -= Count;
+ memmove(b, b + Count, r);
+ }
+ }
+ else
+ usleep(1); // this keeps the CPU load low
+ }
+
+ dsyslog("recording thread ended (pid=%d)", getpid());
+}