vdr
1.7.27
|
00001 /* 00002 * recording.h: Recording file handling 00003 * 00004 * See the main source file 'vdr.c' for copyright information and 00005 * how to reach the author. 00006 * 00007 * $Id: recording.h 2.30 2012/03/13 12:41:05 kls Exp $ 00008 */ 00009 00010 #ifndef __RECORDING_H 00011 #define __RECORDING_H 00012 00013 #include <time.h> 00014 #include "channels.h" 00015 #include "config.h" 00016 #include "epg.h" 00017 #include "thread.h" 00018 #include "timers.h" 00019 #include "tools.h" 00020 00021 #define FOLDERDELIMCHAR '~' 00022 #define TIMERMACRO_TITLE "TITLE" 00023 #define TIMERMACRO_EPISODE "EPISODE" 00024 00025 //#define __RECORDING_H_DEPRECATED_DIRECT_MEMBER_ACCESS // Code enclosed with this macro is deprecated and may be removed in a future version 00026 00027 extern bool VfatFileSystem; 00028 extern int InstanceId; 00029 00030 void RemoveDeletedRecordings(void); 00031 void AssertFreeDiskSpace(int Priority = 0, bool Force = false); 00036 00037 class cResumeFile { 00038 private: 00039 char *fileName; 00040 bool isPesRecording; 00041 public: 00042 cResumeFile(const char *FileName, bool IsPesRecording); 00043 ~cResumeFile(); 00044 int Read(void); 00045 bool Save(int Index); 00046 void Delete(void); 00047 }; 00048 00049 class cRecordingInfo { 00050 friend class cRecording; 00051 private: 00052 tChannelID channelID; 00053 char *channelName; 00054 const cEvent *event; 00055 cEvent *ownEvent; 00056 char *aux; 00057 double framesPerSecond; 00058 int priority; 00059 int lifetime; 00060 char *fileName; 00061 cRecordingInfo(const cChannel *Channel = NULL, const cEvent *Event = NULL); 00062 bool Read(FILE *f); 00063 void SetData(const char *Title, const char *ShortText, const char *Description); 00064 void SetAux(const char *Aux); 00065 public: 00066 cRecordingInfo(const char *FileName); 00067 ~cRecordingInfo(); 00068 tChannelID ChannelID(void) const { return channelID; } 00069 const char *ChannelName(void) const { return channelName; } 00070 const cEvent *GetEvent(void) const { return event; } 00071 const char *Title(void) const { return event->Title(); } 00072 const char *ShortText(void) const { return event->ShortText(); } 00073 const char *Description(void) const { return event->Description(); } 00074 const cComponents *Components(void) const { return event->Components(); } 00075 const char *Aux(void) const { return aux; } 00076 double FramesPerSecond(void) const { return framesPerSecond; } 00077 void SetFramesPerSecond(double FramesPerSecond); 00078 bool Write(FILE *f, const char *Prefix = "") const; 00079 bool Read(void); 00080 bool Write(void) const; 00081 }; 00082 00083 class cRecording : public cListObject { 00084 friend class cRecordings; 00085 private: 00086 mutable int resume; 00087 mutable char *titleBuffer; 00088 mutable char *sortBuffer; 00089 mutable char *fileName; 00090 mutable char *name; 00091 mutable int fileSizeMB; 00092 mutable int numFrames; 00093 int channel; 00094 int instanceId; 00095 bool isPesRecording; 00096 double framesPerSecond; 00097 cRecordingInfo *info; 00098 cRecording(const cRecording&); // can't copy cRecording 00099 cRecording &operator=(const cRecording &); // can't assign cRecording 00100 static char *StripEpisodeName(char *s); 00101 char *SortName(void) const; 00102 int GetResume(void) const; 00103 #ifdef __RECORDING_H_DEPRECATED_DIRECT_MEMBER_ACCESS 00104 public: 00105 #endif 00106 time_t start; 00107 int priority; 00108 int lifetime; 00109 time_t deleted; 00110 public: 00111 cRecording(cTimer *Timer, const cEvent *Event); 00112 cRecording(const char *FileName); 00113 virtual ~cRecording(); 00114 time_t Start(void) const { return start; } 00115 int Priority(void) const { return priority; } 00116 int Lifetime(void) const { return lifetime; } 00117 time_t Deleted(void) const { return deleted; } 00118 virtual int Compare(const cListObject &ListObject) const; 00119 const char *Name(void) const { return name; } 00120 const char *FileName(void) const; 00121 const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const; 00122 const cRecordingInfo *Info(void) const { return info; } 00123 const char *PrefixFileName(char Prefix); 00124 const char *UpdateFileName(const char *FileName); 00125 int HierarchyLevels(void) const; 00126 void ResetResume(void) const; 00127 double FramesPerSecond(void) const { return framesPerSecond; } 00128 int NumFrames(void) const; 00131 int LengthInSeconds(void) const; 00133 int FileSizeMB(void) const; 00136 bool IsNew(void) const { return GetResume() <= 0; } 00137 bool IsEdited(void) const; 00138 bool IsPesRecording(void) const { return isPesRecording; } 00139 void ReadInfo(void); 00140 bool WriteInfo(void); 00141 void SetStartTime(time_t Start); 00149 bool Delete(void); 00152 bool Remove(void); 00155 bool Undelete(void); 00159 }; 00160 00161 class cRecordings : public cList<cRecording>, public cThread { 00162 private: 00163 static char *updateFileName; 00164 bool deleted; 00165 time_t lastUpdate; 00166 int state; 00167 const char *UpdateFileName(void); 00168 void Refresh(bool Foreground = false); 00169 void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0); 00170 protected: 00171 void Action(void); 00172 public: 00173 cRecordings(bool Deleted = false); 00174 virtual ~cRecordings(); 00175 bool Load(void) { return Update(true); } 00179 bool Update(bool Wait = false); 00185 void TouchUpdate(void); 00189 bool NeedsUpdate(void); 00190 void ChangeState(void) { state++; } 00191 bool StateChanged(int &State); 00192 void ResetResume(const char *ResumeFileName = NULL); 00193 cRecording *GetByName(const char *FileName); 00194 void AddByName(const char *FileName, bool TriggerUpdate = true); 00195 void DelByName(const char *FileName, bool RemoveRecording = true); 00196 void UpdateByName(const char *FileName); 00197 int TotalFileSizeMB(void); 00198 double MBperMinute(void); 00201 }; 00202 00203 extern cRecordings Recordings; 00204 extern cRecordings DeletedRecordings; 00205 00206 #define DEFAULTFRAMESPERSECOND 25.0 00207 00208 class cMark : public cListObject { 00209 friend class cMarks; // for sorting 00210 private: 00211 double framesPerSecond; 00212 #ifdef __RECORDING_H_DEPRECATED_DIRECT_MEMBER_ACCESS 00213 public: 00214 #endif 00215 int position; 00216 cString comment; 00217 public: 00218 cMark(int Position = 0, const char *Comment = NULL, double FramesPerSecond = DEFAULTFRAMESPERSECOND); 00219 virtual ~cMark(); 00220 int Position(void) const { return position; } 00221 const char *Comment(void) const { return comment; } 00222 void SetPosition(int Position) { position = Position; } 00223 void SetComment(const char *Comment) { comment = Comment; } 00224 cString ToText(void); 00225 bool Parse(const char *s); 00226 bool Save(FILE *f); 00227 }; 00228 00229 class cMarks : public cConfig<cMark> { 00230 private: 00231 cString fileName; 00232 double framesPerSecond; 00233 time_t nextUpdate; 00234 time_t lastFileTime; 00235 time_t lastChange; 00236 public: 00237 bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false); 00238 bool Update(void); 00239 void Sort(void); 00240 cMark *Add(int Position); 00241 cMark *Get(int Position); 00242 cMark *GetPrev(int Position); 00243 cMark *GetNext(int Position); 00244 }; 00245 00246 #define RUC_BEFORERECORDING "before" 00247 #define RUC_AFTERRECORDING "after" 00248 #define RUC_EDITEDRECORDING "edited" 00249 00250 class cRecordingUserCommand { 00251 private: 00252 static const char *command; 00253 public: 00254 static void SetCommand(const char *Command) { command = Command; } 00255 static void InvokeCommand(const char *State, const char *RecordingFileName); 00256 }; 00257 00258 // The maximum size of a single frame (up to HDTV 1920x1080): 00259 #define MAXFRAMESIZE (KILOBYTE(1024) / TS_SIZE * TS_SIZE) // multiple of TS_SIZE to avoid breaking up TS packets 00260 00261 // The maximum file size is limited by the range that can be covered 00262 // with a 40 bit 'unsigned int', which is 1TB. The actual maximum value 00263 // used is 6MB below the theoretical maximum, to have some safety (the 00264 // actual file size may be slightly higher because we stop recording only 00265 // before the next independent frame, to have a complete Group Of Pictures): 00266 #define MAXVIDEOFILESIZETS 1048570 // MB 00267 #define MAXVIDEOFILESIZEPES 2000 // MB 00268 #define MINVIDEOFILESIZE 1 // MB 00269 #define MAXVIDEOFILESIZEDEFAULT MAXVIDEOFILESIZEPES 00270 00271 #define MINRECORDINGSIZE 25 // GB 00272 #define MAXRECORDINGSIZE 500 // GB 00273 #define DEFAULTRECORDINGSIZE 100 // GB 00274 // Dynamic recording size: 00275 // Keep recording file size at Setup.MaxVideoFileSize for as long as possible, 00276 // but switch to MAXVIDEOFILESIZE early enough, so that Setup.MaxRecordingSize 00277 // will be reached, before recording to file 65535.vdr 00278 00279 struct tIndexTs; 00280 class cIndexFileGenerator; 00281 00282 class cIndexFile { 00283 private: 00284 int f; 00285 cString fileName; 00286 int size, last; 00287 tIndexTs *index; 00288 bool isPesRecording; 00289 cResumeFile resumeFile; 00290 cIndexFileGenerator *indexFileGenerator; 00291 cMutex mutex; 00292 static cString IndexFileName(const char *FileName, bool IsPesRecording); 00293 void ConvertFromPes(tIndexTs *IndexTs, int Count); 00294 void ConvertToPes(tIndexTs *IndexTs, int Count); 00295 bool CatchUp(int Index = -1); 00296 public: 00297 cIndexFile(const char *FileName, bool Record, bool IsPesRecording = false, bool PauseLive = false); 00298 ~cIndexFile(); 00299 bool Ok(void) { return index != NULL; } 00300 bool Write(bool Independent, uint16_t FileNumber, off_t FileOffset); 00301 bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent = NULL, int *Length = NULL); 00302 int GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber = NULL, off_t *FileOffset = NULL, int *Length = NULL); 00303 int Get(uint16_t FileNumber, off_t FileOffset); 00304 int Last(void) { CatchUp(); return last; } 00305 int GetResume(void) { return resumeFile.Read(); } 00306 bool StoreResume(int Index) { return resumeFile.Save(Index); } 00307 bool IsStillRecording(void); 00308 void Delete(void); 00309 static int GetLength(const char *FileName, bool IsPesRecording = false); 00312 }; 00313 00314 class cFileName { 00315 private: 00316 cUnbufferedFile *file; 00317 uint16_t fileNumber; 00318 char *fileName, *pFileNumber; 00319 bool record; 00320 bool blocking; 00321 bool isPesRecording; 00322 public: 00323 cFileName(const char *FileName, bool Record, bool Blocking = false, bool IsPesRecording = false); 00324 ~cFileName(); 00325 const char *Name(void) { return fileName; } 00326 uint16_t Number(void) { return fileNumber; } 00327 bool GetLastPatPmtVersions(int &PatVersion, int &PmtVersion); 00328 cUnbufferedFile *Open(void); 00329 void Close(void); 00330 cUnbufferedFile *SetOffset(int Number, off_t Offset = 0); // yes, Number is int for easier internal calculating 00331 off_t MaxFileSize(); 00332 // Dynamic file size for this file 00333 cUnbufferedFile *NextFile(void); 00334 }; 00335 00336 cString IndexToHMSF(int Index, bool WithFrame = false, double FramesPerSecond = DEFAULTFRAMESPERSECOND); 00337 // Converts the given index to a string, optionally containing the frame number. 00338 int HMSFToIndex(const char *HMSF, double FramesPerSecond = DEFAULTFRAMESPERSECOND); 00339 // Converts the given string (format: "hh:mm:ss.ff") to an index. 00340 int SecondsToFrames(int Seconds, double FramesPerSecond = DEFAULTFRAMESPERSECOND); 00341 // Returns the number of frames corresponding to the given number of seconds. 00342 00343 int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max); 00344 00345 char *ExchangeChars(char *s, bool ToFileSystem); 00346 // Exchanges the characters in the given string to or from a file system 00347 // specific representation (depending on ToFileSystem). The given string will 00348 // be modified and may be reallocated if more space is needed. The return 00349 // value points to the resulting string, which may be different from s. 00350 00351 bool GenerateIndex(const char *FileName); 00352 00353 #endif //__RECORDING_H