vdr  2.2.0
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 3.3 2014/02/21 09:19:52 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 30000 // milliseconds
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 {
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;
143  }
144  if (FirstIframeSeen || frameDetector->IndependentFrame()) {
145  FirstIframeSeen = true; // start recording with the first I-frame
146  if (!NextFile())
147  break;
148  if (index && frameDetector->NewFrame())
152  fileSize += TS_SIZE;
153  int Index = 0;
154  while (uchar *pmt = patPmtGenerator.GetPmt(Index)) {
155  recordFile->Write(pmt, TS_SIZE);
156  fileSize += TS_SIZE;
157  }
159  }
160  if (recordFile->Write(b, Count) < 0) {
162  break;
163  }
164  fileSize += Count;
165  }
166  }
167  ringBuffer->Del(Count);
168  }
169  }
170  if (t.TimedOut()) {
171  esyslog("ERROR: video data stream broken");
174  }
175  }
176 }
unsigned char uchar
Definition: tools.h:30
void SetFramesPerSecond(double FramesPerSecond)
Definition: recording.c:440
int Vpid(void) const
Definition: channels.h:154
ssize_t Write(const void *Data, size_t Size)
Definition: tools.c:1832
void SetVersions(int PatVersion, int PmtVersion)
Sets the version numbers for the generated PAT and PMT, in case this generator is used to...
Definition: remux.c:566
#define dsyslog(a...)
Definition: tools.h:36
void Set(int Ms=0)
Definition: tools.c:738
#define DEFAULTFRAMESPERSECOND
Definition: recording.h:333
cFrameDetector * frameDetector
Definition: recorder.h:22
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
Definition: recording.c:2232
int Dpid(int i) const
Definition: channels.h:161
bool RunningLowOnDiskSpace(void)
Definition: recorder.c:77
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
Definition: remux.c:1472
#define esyslog(a...)
Definition: tools.h:34
cUnbufferedFile * NextFile(void)
Definition: recording.c:2965
#define LOG_ERROR_STR(s)
Definition: tools.h:39
time_t lastDiskSpaceCheck
Definition: recorder.h:29
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition: remux.c:572
double FramesPerSecond(void) const
Definition: recording.h:90
int Put(const uchar *Data, int Count)
Puts at most Count bytes of Data into the ring buffer.
Definition: ringbuffer.c:305
#define MINFREEDISKSPACE
Definition: recorder.c:19
bool GetLastPatPmtVersions(int &PatVersion, int &PmtVersion)
Definition: recording.c:2838
bool Synced(void)
Returns true if the frame detector has synced on the data stream.
Definition: remux.h:508
uint16_t Number(void)
Definition: recording.h:475
bool Read(FILE *f)
Definition: recording.c:452
bool Write(FILE *f, const char *Prefix="") const
Definition: recording.c:511
bool TimedOut(void) const
Definition: tools.c:743
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition: recorder.c:118
void UpdateByName(const char *FileName)
Definition: recording.c:1559
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition: thread.c:273
uchar * GetPmt(int &Index)
Returns a pointer to the Index&#39;th TS packet of the PMT section.
Definition: remux.c:587
cUnbufferedFile * Open(void)
Definition: recording.c:2889
cSetup Setup
Definition: config.c:372
int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
Definition: tools.c:410
cPatPmtGenerator patPmtGenerator
Definition: recorder.h:23
cShutdownHandler ShutdownHandler
Definition: shutdown.c:27
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition: thread.h:99
virtual void Receive(uchar *Data, int Length)
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
Definition: recorder.c:109
cRecorder(const char *FileName, const cChannel *Channel, int Priority)
Creates a new recorder for the given Channel and the given Priority that will record into the file Fi...
Definition: recorder.c:24
void Del(int Count)
Deletes at most Count bytes from the ring buffer.
Definition: ringbuffer.c:370
#define DISKCHECKINTERVAL
Definition: recorder.c:20
int MaxVideoFileSize
Definition: config.h:332
cIndexFile * index
Definition: recorder.h:25
const char * Name(void)
Definition: recording.h:474
int Priority(void) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY), or IDLEPRIORITY if no receiver is currently active.
Definition: device.c:1614
bool SpinUpDisk(const char *FileName)
Definition: tools.c:631
#define MEGABYTE(n)
Definition: tools.h:44
char * recordingName
Definition: recorder.h:27
void SetIoThrottle(void)
Definition: ringbuffer.c:95
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition: remux.h:473
virtual ~cRecorder()
Definition: recorder.c:67
bool NewFrame(void)
Returns true if the data given to the last call to Analyze() started a new frame. ...
Definition: remux.h:510
bool IndependentFrame(void)
Returns true if a new frame was detected and this is an independent frame (i.e.
Definition: remux.h:513
int Apid(int i) const
Definition: channels.h:160
cRecordings Recordings
Any access to Recordings that loops through the list of recordings needs to hold a thread lock on thi...
Definition: recording.c:1366
uchar * Get(int &Count)
Gets data from the ring buffer.
Definition: ringbuffer.c:345
cFileName * fileName
Definition: recorder.h:24
Definition: thread.h:77
double FramesPerSecond(void)
Returns the number of frames per second, or 0 if this information is not available.
Definition: remux.h:517
off_t fileSize
Definition: recorder.h:28
cRingBufferLinear * ringBuffer
Definition: recorder.h:21
Definition: tools.h:333
#define TS_SIZE
Definition: remux.h:34
bool DoubleEqual(double a, double b)
Definition: tools.h:87
#define RECORDERBUFSIZE
Definition: recorder.c:13
#define MAXBROKENTIMEOUT
Definition: recorder.c:17
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting &#39;running&#39; to false, so that the Action() loop can finish in an or...
Definition: thread.c:323
virtual void Activate(bool On)
If you override Activate() you need to call Detach() (which is a member of the cReceiver class) from ...
Definition: recorder.c:101
#define RUC_STARTRECORDING
Definition: recording.h:396
void Detach(void)
Definition: receiver.c:113
int Vtype(void) const
Definition: channels.h:156
void SetTimeouts(int PutTimeout, int GetTimeout)
Definition: ringbuffer.c:89
void RequestEmergencyExit(void)
Requests an emergency exit of the VDR main loop.
Definition: shutdown.c:96
bool Write(bool Independent, uint16_t FileNumber, off_t FileOffset)
Definition: recording.c:2629
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition: remux.c:581
bool NextFile(void)
Definition: recorder.c:90
cUnbufferedFile * recordFile
Definition: recorder.h:26
void ReportOverflow(int Bytes)
Definition: ringbuffer.c:101