Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

recorder.c

Go to the documentation of this file.
00001 /*
00002  * recorder.h: The actual DVB recorder
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: recorder.c 1.3 2002/10/12 13:34:29 kls Exp $
00008  */
00009 
00010 #include <stdarg.h>
00011 #include <stdio.h>
00012 #include <unistd.h>
00013 #include "recorder.h"
00014 
00015 // The size of the array used to buffer video data:
00016 // (must be larger than MINVIDEODATA - see remux.h)
00017 #define VIDEOBUFSIZE  MEGABYTE(5)
00018 
00019 #define MINFREEDISKSPACE    (512) // MB
00020 #define DISKCHECKINTERVAL   100 // seconds
00021 
00022 cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2)
00023 :cReceiver(Ca, Priority, 5, VPid, APid1, APid2, DPid1, DPid2)
00024 {
00025   ringBuffer = NULL;
00026   remux = NULL;
00027   fileName = NULL;
00028   index = NULL;
00029   pictureType = NO_PICTURE;
00030   fileSize = 0;
00031   active = false;
00032   lastDiskSpaceCheck = time(NULL);
00033   isyslog("record %s", FileName);
00034 
00035   // Create directories if necessary:
00036 
00037   if (!MakeDirs(FileName, true))
00038      return;
00039 
00040   // Make sure the disk is up and running:
00041 
00042   SpinUpDisk(FileName);
00043 
00044   ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
00045   remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
00046   fileName = new cFileName(FileName, true);
00047   recordFile = fileName->Open();
00048   if (recordFile < 0)
00049      return;
00050   // Create the index file:
00051   index = new cIndexFile(FileName, true);
00052   if (!index)
00053      esyslog("ERROR: can't allocate index");
00054      // let's continue without index, so we'll at least have the recording
00055 }
00056 
00057 cRecorder::~cRecorder()
00058 {
00059   Detach();
00060   delete index;
00061   delete fileName;
00062   delete remux;
00063   delete ringBuffer;
00064 }
00065 
00066 void cRecorder::Activate(bool On)
00067 {
00068   if (On) {
00069      if (recordFile >= 0)
00070         Start();
00071      }
00072   else if (active) {
00073      active = false;
00074      Cancel(3);
00075      }
00076 }
00077 
00078 bool cRecorder::RunningLowOnDiskSpace(void)
00079 {
00080   if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) {
00081      int Free = FreeDiskSpaceMB(fileName->Name());
00082      lastDiskSpaceCheck = time(NULL);
00083      if (Free < MINFREEDISKSPACE) {
00084         dsyslog("low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE);
00085         return true;
00086         }
00087      }
00088   return false;
00089 }
00090 
00091 bool cRecorder::NextFile(void)
00092 {
00093   if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME
00094      if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) {
00095         recordFile = fileName->NextFile();
00096         fileSize = 0;
00097         }
00098      }
00099   return recordFile >= 0;
00100 }
00101 
00102 void cRecorder::Receive(uchar *Data, int Length)
00103 {
00104   int p = ringBuffer->Put(Data, Length);
00105   if (p != Length && active)
00106      esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
00107 }
00108 
00109 void cRecorder::Action(void)
00110 {
00111   dsyslog("recording thread started (pid=%d)", getpid());
00112 
00113   uchar b[MINVIDEODATA];
00114   int r = 0;
00115   active = true;
00116   while (active) {
00117         int g = ringBuffer->Get(b + r, sizeof(b) - r);
00118         if (g > 0)
00119            r += g;
00120         if (r > 0) {
00121            int Count = r, Result;
00122            uchar *p = remux->Process(b, Count, Result, &pictureType);
00123            if (p) {
00124               //XXX+ active??? see old version (Busy)
00125               if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame
00126                  break;
00127               if (NextFile()) {
00128                  if (index && pictureType != NO_PICTURE)
00129                     index->Write(pictureType, fileName->Number(), fileSize);
00130                  if (safe_write(recordFile, p, Result) < 0) {
00131                     LOG_ERROR_STR(fileName->Name());
00132                     break;
00133                     }
00134                  fileSize += Result;
00135                  }
00136               else
00137                  break;
00138               }
00139            if (Count > 0) {
00140               r -= Count;
00141               memmove(b, b + Count, r);
00142               }
00143            }
00144         else
00145            usleep(1); // this keeps the CPU load low
00146         }
00147 
00148   dsyslog("recording thread ended (pid=%d)", getpid());
00149 }

Generated on Wed Feb 5 23:30:11 2003 for VDR by doxygen1.3-rc2