-
Notifications
You must be signed in to change notification settings - Fork 3
/
vdr_cl.h
471 lines (433 loc) · 13 KB
/
vdr_cl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
// vdr-classes
#ifndef VDR_CL_H
#define VDR_CL_H
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdint.h>
#include <unistd.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#include <signal.h>
#endif
#include "tools.h"
#include "channels.h"
typedef unsigned char uchar;
#define DIR_DELIM "/"
#define DIR_DELIMC '/'
#define INDEXFILESUFFIX DIR_DELIM"index"
#define INDEXFILESUFFIXEX DIR_DELIM"indexEx.vdr"
#define RECORDFILESUFFIX DIR_DELIM"%03d.vdr"
#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety...
//#define RESUMEFILESUFFIX DIR_DELIM ## "resume.vdr"
//#define MARKSFILESUFFIX DIR_DELIM ## "marks.vdr"
#ifdef VNOAD
#define NOADMARKSFILESUFFIX DIR_DELIM"noadmarks.vdr"
#endif
#define SUMMARYFALLBACK
#define RESUMEFILESUFFIX DIR_DELIM"resume%s%s"
#ifdef SUMMARYFALLBACK
#define SUMMARYFILESUFFIX DIR_DELIM"summary.vdr"
#endif
#define INFOFILESUFFIX DIR_DELIM"info"
#define MARKSFILESUFFIX DIR_DELIM"marks"
#define MAXFILESPERRECORDING 255
#define DEFAULTFRAMESPERSECOND 25.0
#define MAXPRIORITY 99
#define MINPRIORITY (-MAXPRIORITY)
#define LIVEPRIORITY 0 // priority used when selecting a device for live viewing
#define TRANSFERPRIORITY (LIVEPRIORITY - 1) // priority used for actual local Transfer Mode
#define IDLEPRIORITY (MINPRIORITY - 1) // priority of an idle device
#define MAXLIFETIME 99
#define DEFINSTRECTIME 180 // default instant recording time (minutes)
// The maximum time to wait before giving up while catching up on an index file:
#define MAXINDEXCATCHUP 8 // seconds
#define MINFREEDISKSPACE (512) // MB
#define DISKCHECKINTERVAL 100 // seconds
// Picture types:
#define NO_PICTURE 0
#define I_FRAME 1
#define P_FRAME 2
#define B_FRAME 3
#define KILOBYTE(n) ((n) * 1024)
#define TS_SIZE 188
// The maximum size of a single frame (up to HDTV 1920x1080):
#define MAXFRAMESIZE (KILOBYTE(1024) / TS_SIZE * TS_SIZE) // multiple of TS_SIZE to avoid breaking up TS packets
extern double framespersec;
#define FRAMESPERMIN (framespersec*60)
extern int SysLogLevel;
extern char MarksfileSuffix[];
bool setMarkfileSuffix(bool bIsPESFile);
bool setMarkfileName(const char *name, bool bIsPESFile = false);
void releaseMarkfileName();
class cReadLine
{
private:
size_t size;
//char *buffer;
public:
cReadLine(void);
~cReadLine();
char *Read(FILE *f);
};
// --- cFileName -------------------------------------------------------------
class cFileName
{
private:
cUnbufferedFile *file;
int fileNumber;
char *fileName, *pFileNumber;
char *dirname;
bool record;
bool blocking;
bool isPesRecording;
public:
cFileName(const char *FileName, bool Record, bool Blocking = false, bool IsPesRecording = false);
~cFileName();
const char *Name(void) { return fileName; }
const char *dirName(void) { return dirname; }
int Number(void) { return fileNumber; }
cUnbufferedFile *Open(void);
void Close(void);
cUnbufferedFile *SetOffset(int Number, off_t Offset = 0);
cUnbufferedFile *NextFile(void);
int File() { return file ? file->get_fd():-1; }
bool isPES() { return isPesRecording; }
};
// --- cResumeFile ------------------------------------------------------------
class cResumeFile
{
private:
char *fileName;
bool isPesRecording;
public:
cResumeFile(const char *FileName, bool IsPesRecording);
~cResumeFile();
int Read(void);
bool Save(int Index);
void Delete(void);
};
struct tIndexPes
{
uint32_t offset;
uchar type;
uchar number;
uint16_t reserved;
};
struct tIndexTs
{
// for MS all items must be same type
// else ms aligns each item on a boundary, giving a structure size >8!!!
uint64_t offset:40; // up to 1TB per file (not using off_t here - must definitely be exactly 64 bit!)
uint64_t reserved:7; // reserved for future use
uint64_t independent:1; // marks frames that can be displayed by themselves (for trick modes)
uint64_t number:16; // up to 64K files per recording
tIndexTs(off_t Offset, bool Independent, uint16_t Number)
{
offset = Offset;
reserved = 0;
independent = Independent;
number = Number;
}
tIndexTs(){}
};
// --- cIndexFile ------------------------------------------------------------
class cIndexFile
{
protected:
int f;
char *fileName;
int size, last;
tIndexTs *index;
bool isPesRecording;
cResumeFile resumeFile;
void ConvertFromPes(tIndexTs *IndexTs, int Count);
void ConvertToPes(tIndexTs *IndexTs, int Count);
bool CatchUp(int Index = -1);
public:
cIndexFile(const char *FileName, bool Record, bool IsPesRecording = false);
~cIndexFile();
bool Ok(void) { return index != NULL; }
bool Write(bool Independent, uint16_t FileNumber, off_t FileOffset);
bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent = NULL, int *Length = NULL);
int GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber = NULL, off_t *FileOffset = NULL, int *Length = NULL, bool StayOffEnd = false);
int Get(uint16_t FileNumber, off_t FileOffset);
int Last(void) { CatchUp(); return last; }
int GetResume(void) { return resumeFile.Read(); }
bool StoreResume(int Index) { return resumeFile.Save(Index); }
void check(int start=0);
#ifdef NOAD
int getLast() { return( last ); }
#endif
};
// --- cNoadIndexFile ------------------------------------------------------------
class cNoadIndexFile : public cIndexFile
{
struct tIndexEx{ int isLogo; int blackTop; int blackBottom; };
int fEx;
char *fileNameEx;
int sizeEx, lastEx;
tIndexEx *indexEx;
int interval;
int lastGetValue;
int64_t fileSize;
public:
cNoadIndexFile(const char *FileName, bool Record, bool IsPesRecording);
~cNoadIndexFile();
// ohne CatchUp !!!
bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent = NULL, int *Length = NULL);
// ohne CatchUp !!!
int GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber = NULL, off_t *FileOffset = NULL, int *Length = NULL, bool StayOffEnd = false);
bool setIndexEx( int index, int _isLogo, int _blackTop, int _blackBottom);
void logIndexEx();
bool CatchUp(int Index = -1);
void setInterval(int newInterval) { interval = newInterval; }
int Last(void) { return getLast(); }
int getLast();
int64_t getVideoFileSize();
int getIndexForFilepos(int64_t pos);
};
// --- cMark ------------------------------------------------------------
class cMark : public cListObject
{
private:
double framesPerSecond;
static char *buffer;
bool checked;
public:
int position;
char *comment;
cMark(int Position = 0, const char *Comment = NULL, double FramesPerSecond = DEFAULTFRAMESPERSECOND);
virtual ~cMark();
cString ToText(bool bWithNewline = true, bool bWithFrame = false);
bool Parse(const char *s);
bool Save(FILE *f);
//noad:
bool isChecked() { return checked; }
void setChecked(bool b) { checked = b; }
};
template<class T> class cConfig : public cList<T>
{
private:
char *fileName;
bool allowComments;
public:
void Clear(void)
{
free(fileName);
fileName = NULL;
cList<T>::Clear();
}
public:
cConfig(void) { fileName = NULL; }
virtual ~cConfig() { free(fileName); }
const char *FileName(void) { return fileName; }
bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false)
{
cConfig<T>::Clear();
if (FileName) {
free(fileName);
fileName = strdup(FileName);
allowComments = AllowComments;
}
bool result = !MustExist;
if (fileName && access(fileName, F_OK) == 0) {
isyslog("loading %s", fileName);
FILE *f = fopen(fileName, "r");
if (f)
{
char *s;
int line = 0;
cReadLine ReadLine;
result = true;
while ((s = ReadLine.Read(f)) != NULL)
{
line++;
if (allowComments)
{
char *p = strchr(s, '#');
if (p)
*p = 0;
}
stripspace(s);
if (!isempty(s))
{
T *l = new T;
if (l->Parse(s))
this->Add(l);
else
{
esyslog("ERROR: error in %s, line %d", fileName, line);
delete l;
result = false;
}
}
}
fclose(f);
}
else
{
LOG_ERROR_STR(fileName);
result = false;
}
}
return result;
}
bool Save(void)
{
bool result = true;
T *l = (T *)this->First();
cSafeFile f(fileName);
if (f.Open())
{
while (l)
{
if (!l->Save(f))
{
result = false;
break;
}
l = (T *)l->Next();
}
if (!f.Close())
result = false;
}
else
{
LOG_ERROR_STR(fileName);
result = false;
}
return result;
}
//#ifdef NOAD
public:
void ClearList(void)
{
cList<T>::Clear();
}
const char *getFilename() { return fileName; }
//#endif
};
// --- cMarks -------------------------------------------------------------
class cMarks : public cConfig<cMark>
{
private:
double framesPerSecond;
public:
bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false);
bool ReLoad();
void Sort(void);
cMark *Add(int Position);
cMark *Get(int Position);
cMark *GetPrev(int Position);
cMark *GetNext(int Position);
//noad:
bool Backup(const char *RecordingFileName);
int getActiveFrames(int totalFrames);
bool hasUncheckedMarks();
cMark *GetLast() { return Last(); }
int posOff(cMark *m);
};
class cRecordingInfo {
friend class cRecording;
private:
tChannelID channelID;
char *channelName;
//const cEvent *event;
//cEvent *ownEvent;
char *aux;
double framesPerSecond;
int priority;
int lifetime;
char *fileName;
//cRecordingInfo(const cChannel *Channel = NULL, const cEvent *Event = NULL);
bool Read(FILE *f);
void SetData(const char *Title, const char *ShortText, const char *Description);
void SetAux(const char *Aux);
public:
cRecordingInfo(const char *FileName, bool bFullFilename = false);
~cRecordingInfo();
tChannelID ChannelID(void) const { return channelID; }
const char *ChannelName(void) const { return channelName; }
//const cEvent *GetEvent(void) const { return event; }
//const char *Title(void) const { return event->Title(); }
//const char *ShortText(void) const { return event->ShortText(); }
//const char *Description(void) const { return event->Description(); }
//const cComponents *Components(void) const { return event->Components(); }
const char *Aux(void) const { return aux; }
double FramesPerSecond(void) const { return framesPerSecond; }
void SetFramesPerSecond(double FramesPerSecond);
bool Write(FILE *f, const char *Prefix = "") const;
bool Read(void);
bool Write(void) const;
};
class cRecording : public cListObject {
protected:
mutable int resume;
mutable char *titleBuffer;
char *sortBuffer;
mutable char *fileName;
mutable char *name;
mutable int fileSizeMB;
int channel;
int instanceId;
bool isPesRecording;
double framesPerSecond;
// cRecordingInfo *info;
cRecording(const cRecording&); // can't copy cRecording
cRecording &operator=(const cRecording &); // can't assign cRecording
static char *StripEpisodeName(char *s);
char *SortName(void) /*const*/;
int GetResume(void) const;
char *summary; // old
// char *StripEpisodeName(char *s);
public:
time_t start;
int priority;
int lifetime;
// cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary);
cRecording(const char *FileName);
~cRecording();
virtual bool operator< (const cListObject &ListObject);
const char *Name(void) const { return name; }
const char *FileName(void) const;
const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const;
const char *Summary(void) const { return summary; }
const char *PrefixFileName(char Prefix);
int HierarchyLevels(void) const;
bool IsNew(void) const { return GetResume() <= 0; }
bool IsEdited(void) const;
bool WriteSummary(void);
// bool WriteRecInfo(cTimer *timer);
bool Delete(void);
// Changes the file name so that it will no longer be visible in the "Recordings" menu
// Returns false in case of error
bool Remove(void);
// Actually removes the file from the disk
// Returns false in case of error
bool IsPesRecording(void) const { return isPesRecording; }
};
class cRecordings : public cList<cRecording> {
public:
bool Load(bool Deleted = false);
cRecording *GetByName(const char *FileName);
};
bool isPESRecording(const char *filename);
bool isRecording(const char *FileName);
cString IndexToHMSF(int Index, bool WithFrame = false, double FramesPerSecond = DEFAULTFRAMESPERSECOND);
int HMSFToIndex(const char *HMSF, double FramesPerSecond = DEFAULTFRAMESPERSECOND);
cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags);
int CloseVideoFile(cUnbufferedFile *File);
#endif