vdr  1.7.31
recorder.c
Go to the documentation of this file.
1 /*
2  * recorder.c: The actual DVB recorder
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: recorder.c 2.17 2012/09/22 11:53:57 kls Exp $
8  */
9 
10 #include "recorder.h"
11 #include "shutdown.h"
12 
13 #define RECORDERBUFSIZE (MEGABYTE(20) / TS_SIZE * TS_SIZE) // multiple of TS_SIZE
14 
15 // The maximum time we wait before assuming that a recorded video data stream
16 // is broken:
17 #define MAXBROKENTIMEOUT 30 // seconds
18 
19 #define MINFREEDISKSPACE (512) // MB
20 #define DISKCHECKINTERVAL 100 // seconds
21 
22 // --- cRecorder -------------------------------------------------------------
23 
24 cRecorder::cRecorder(const char *FileName, const cChannel *Channel, int Priority)
25 :cReceiver(Channel, Priority)
26 ,cThread("recording")
27 {
28  recordingName = strdup(FileName);
29 
30  // Make sure the disk is up and running:
31 
32  SpinUpDisk(FileName);
33 
35  ringBuffer->SetTimeouts(0, 100);
37 
38  int Pid = Channel->Vpid();
39  int Type = Channel->Vtype();
40  if (!Pid && Channel->Apid(0)) {
41  Pid = Channel->Apid(0);
42  Type = 0x04;
43  }
44  if (!Pid && Channel->Dpid(0)) {
45  Pid = Channel->Dpid(0);
46  Type = 0x06;
47  }
48  frameDetector = new cFrameDetector(Pid, Type);
49  index = NULL;
50  fileSize = 0;
51  lastDiskSpaceCheck = time(NULL);
52  fileName = new cFileName(FileName, true);
53  int PatVersion, PmtVersion;
54  if (fileName->GetLastPatPmtVersions(PatVersion, PmtVersion))
55  patPmtGenerator.SetVersions(PatVersion + 1, PmtVersion + 1);
56  patPmtGenerator.SetChannel(Channel);
58  if (!recordFile)
59  return;
60  // Create the index file:
61  index = new cIndexFile(FileName, true);
62  if (!index)
63  esyslog("ERROR: can't allocate index");
64  // let's continue without index, so we'll at least have the recording
65 }
66 
68 {
69  Detach();
70  delete index;
71  delete fileName;
72  delete frameDetector;
73  delete ringBuffer;
74  free(recordingName);
75 }
76 
78 {
79  if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) {
80  int Free = FreeDiskSpaceMB(fileName->Name());
81  lastDiskSpaceCheck = time(NULL);
82  if (Free < MINFREEDISKSPACE) {
83  dsyslog("low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE);
84  return true;
85  }
86  }
87  return false;
88 }
89 
91 {
92  if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame
95  fileSize = 0;
96  }
97  }
98  return recordFile != NULL;
99 }
100 
101 void cRecorder::Activate(bool On)
102 {
103  if (On)
104  Start();
105  else
106  Cancel(3);
107 }
108 
109 void cRecorder::Receive(uchar *Data, int Length)
110 {
111  if (Running()) {
112  int p = ringBuffer->Put(Data, Length);
113  if (p != Length && Running())
114  ringBuffer->ReportOverflow(Length - p);
115  }
116 }
117 
119 {
120  time_t t = time(NULL);
121  bool InfoWritten = false;
122  bool FirstIframeSeen = false;
123  while (Running()) {
124  int r;
125  uchar *b = ringBuffer->Get(r);
126  if (b) {
127  int Count = frameDetector->Analyze(b, r);
128  if (Count) {
129  if (!Running() && frameDetector->IndependentFrame()) // finish the recording before the next independent frame
130  break;
131  if (frameDetector->Synced()) {
132  if (!InfoWritten) {
133  cRecordingInfo RecordingInfo(recordingName);
134  if (RecordingInfo.Read()) {
137  RecordingInfo.Write();
139  }
140  }
141  InfoWritten = true;
142  }
143  if (FirstIframeSeen || frameDetector->IndependentFrame()) {
144  FirstIframeSeen = true; // start recording with the first I-frame
145  if (!NextFile())
146  break;
147  if (index && frameDetector->NewFrame())
151  fileSize += TS_SIZE;
152  int Index = 0;
153  while (uchar *pmt = patPmtGenerator.GetPmt(Index)) {
154  recordFile->Write(pmt, TS_SIZE);
155  fileSize += TS_SIZE;
156  }
157  }
158  if (recordFile->Write(b, Count) < 0) {
160  break;
161  }
162  fileSize += Count;
163  t = time(NULL);
164  }
165  }
166  ringBuffer->Del(Count);
167  }
168  }
169  if (time(NULL) - t > MAXBROKENTIMEOUT) {
170  esyslog("ERROR: video data stream broken");
172  t = time(NULL);
173  }
174  }
175 }