2000-03-11 11:22:37 +01:00
/*
* recording . h : Recording file handling
*
2000-04-24 09:46:05 +02:00
* See the main source file ' vdr . c ' for copyright information and
2000-03-11 11:22:37 +01:00
* how to reach the author .
*
2021-05-23 15:03:17 +02:00
* $ Id : recording . h 5.5 2021 / 05 / 23 15 : 03 : 17 kls Exp $
2000-03-11 11:22:37 +01:00
*/
# ifndef __RECORDING_H
# define __RECORDING_H
# include <time.h>
2005-05-28 09:53:54 +02:00
# include "channels.h"
2000-03-11 11:22:37 +01:00
# include "config.h"
2005-05-16 14:45:11 +02:00
# include "epg.h"
2003-09-09 16:09:05 +02:00
# include "thread.h"
2002-10-20 12:28:55 +02:00
# include "timers.h"
2000-03-11 11:22:37 +01:00
# include "tools.h"
2010-01-17 12:08:03 +01:00
# define FOLDERDELIMCHAR '~'
2013-02-08 09:24:55 +01:00
extern int DirectoryPathMax ;
extern int DirectoryNameMax ;
extern bool DirectoryEncoding ;
2009-01-18 11:10:29 +01:00
extern int InstanceId ;
2005-09-03 13:35:55 +02:00
2013-10-10 13:13:30 +02:00
enum eRecordingUsage {
ruNone = 0x0000 , // the recording is currently unused
ruTimer = 0x0001 , // the recording is currently written to by a timer
ruReplay = 0x0002 , // the recording is being replayed
// mutually exclusive:
ruCut = 0x0004 , // the recording is being cut
ruMove = 0x0008 , // the recording is being moved
ruCopy = 0x0010 , // the recording is being copied
// mutually exclusive:
ruSrc = 0x0020 , // the recording is the source of a cut, move or copy process
ruDst = 0x0040 , // the recording is the destination of a cut, move or copy process
//
ruPending = 0x0080 , // the recording is pending a cut, move or copy process
2017-12-11 13:55:38 +01:00
ruCanceled = 0x8000 , // the operation has been canceled, waiting for cleanup
2013-10-10 13:13:30 +02:00
} ;
2001-02-04 12:36:32 +01:00
void RemoveDeletedRecordings ( void ) ;
2006-01-20 17:19:46 +01:00
void AssertFreeDiskSpace ( int Priority = 0 , bool Force = false ) ;
2003-08-17 09:18:40 +02:00
///< The special Priority value -1 means that we shall get rid of any
///< deleted recordings faster than normal (because we're cutting).
2006-01-20 17:19:46 +01:00
///< If Force is true, the check will be done even if the timeout
///< hasn't expired yet.
2000-03-11 11:22:37 +01:00
2001-02-11 11:04:41 +01:00
class cResumeFile {
private :
char * fileName ;
2009-01-06 14:41:11 +01:00
bool isPesRecording ;
2001-02-11 11:04:41 +01:00
public :
2009-01-06 14:41:11 +01:00
cResumeFile ( const char * FileName , bool IsPesRecording ) ;
2001-02-11 11:04:41 +01:00
~ cResumeFile ( ) ;
int Read ( void ) ;
bool Save ( int Index ) ;
void Delete ( void ) ;
} ;
2005-05-16 14:45:11 +02:00
class cRecordingInfo {
2005-05-22 09:13:26 +02:00
friend class cRecording ;
2005-05-16 14:45:11 +02:00
private :
2005-05-28 09:53:54 +02:00
tChannelID channelID ;
2007-06-17 13:13:47 +02:00
char * channelName ;
2005-05-16 14:45:11 +02:00
const cEvent * event ;
cEvent * ownEvent ;
2006-02-25 12:09:22 +01:00
char * aux ;
2009-01-06 14:41:11 +01:00
double framesPerSecond ;
int priority ;
int lifetime ;
char * fileName ;
2021-05-19 11:22:20 +02:00
int errors ;
2006-02-18 16:03:40 +01:00
cRecordingInfo ( const cChannel * Channel = NULL , const cEvent * Event = NULL ) ;
2011-04-03 11:22:16 +02:00
bool Read ( FILE * f ) ;
2005-05-22 09:13:26 +02:00
public :
2009-01-06 14:41:11 +01:00
cRecordingInfo ( const char * FileName ) ;
2005-05-16 14:45:11 +02:00
~ cRecordingInfo ( ) ;
2006-12-01 15:09:10 +01:00
tChannelID ChannelID ( void ) const { return channelID ; }
2007-06-17 13:13:47 +02:00
const char * ChannelName ( void ) const { return channelName ; }
2009-02-28 10:51:42 +01:00
const cEvent * GetEvent ( void ) const { return event ; }
2005-05-16 14:45:11 +02:00
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 ( ) ; }
2006-02-25 12:09:22 +01:00
const char * Aux ( void ) const { return aux ; }
2009-01-06 14:41:11 +01:00
double FramesPerSecond ( void ) const { return framesPerSecond ; }
void SetFramesPerSecond ( double FramesPerSecond ) ;
2013-10-10 13:13:30 +02:00
void SetFileName ( const char * FileName ) ;
2021-05-23 15:03:17 +02:00
int Errors ( void ) const { return errors ; } // returns -1 if undefined
2021-05-19 11:22:20 +02:00
void SetErrors ( int Errors ) ;
2005-05-16 14:45:11 +02:00
bool Write ( FILE * f , const char * Prefix = " " ) const ;
2009-01-06 14:41:11 +01:00
bool Read ( void ) ;
bool Write ( void ) const ;
2021-01-18 12:55:47 +01:00
void SetData ( const char * Title , const char * ShortText , const char * Description ) ;
void SetAux ( const char * Aux ) ;
2005-05-16 14:45:11 +02:00
} ;
2000-03-11 11:22:37 +01:00
class cRecording : public cListObject {
2005-12-18 10:41:26 +01:00
friend class cRecordings ;
2000-04-23 15:38:16 +02:00
private :
2017-04-03 14:11:41 +02:00
int id ;
2004-05-16 10:35:36 +02:00
mutable int resume ;
mutable char * titleBuffer ;
2012-06-09 14:32:29 +02:00
mutable char * sortBufferName ;
mutable char * sortBufferTime ;
2004-05-16 10:35:36 +02:00
mutable char * fileName ;
mutable char * name ;
2005-12-18 10:41:26 +01:00
mutable int fileSizeMB ;
2011-08-21 13:47:07 +02:00
mutable int numFrames ;
2009-01-06 14:41:11 +01:00
int channel ;
2009-01-18 11:10:29 +01:00
int instanceId ;
2009-01-06 14:41:11 +01:00
bool isPesRecording ;
2012-06-03 10:03:55 +02:00
mutable int isOnVideoDirectoryFileSystem ; // -1 = unknown, 0 = no, 1 = yes
2009-01-06 14:41:11 +01:00
double framesPerSecond ;
2005-05-16 14:45:11 +02:00
cRecordingInfo * info ;
2007-10-14 10:09:08 +02:00
cRecording ( const cRecording & ) ; // can't copy cRecording
cRecording & operator = ( const cRecording & ) ; // can't assign cRecording
2013-03-03 11:04:22 +01:00
static char * StripEpisodeName ( char * s , bool Strip ) ;
2004-11-01 10:40:38 +01:00
char * SortName ( void ) const ;
2013-03-04 14:11:47 +01:00
void ClearSortName ( void ) ;
2017-04-03 14:11:41 +02:00
void SetId ( int Id ) ; // should only be set by cRecordings
2000-03-11 11:22:37 +01:00
time_t start ;
int priority ;
int lifetime ;
2005-12-18 12:14:11 +01:00
time_t deleted ;
2011-08-21 11:34:30 +02:00
public :
2005-05-16 14:45:11 +02:00
cRecording ( cTimer * Timer , const cEvent * Event ) ;
2000-03-11 11:22:37 +01:00
cRecording ( const char * FileName ) ;
2005-09-25 11:00:57 +02:00
virtual ~ cRecording ( ) ;
2017-04-03 14:11:41 +02:00
int Id ( void ) const { return id ; }
2011-08-21 11:34:30 +02:00
time_t Start ( void ) const { return start ; }
int Priority ( void ) const { return priority ; }
int Lifetime ( void ) const { return lifetime ; }
time_t Deleted ( void ) const { return deleted ; }
2015-09-01 11:14:27 +02:00
void SetDeleted ( void ) { deleted = time ( NULL ) ; }
2004-11-01 10:40:38 +01:00
virtual int Compare ( const cListObject & ListObject ) const ;
2015-09-01 11:14:27 +02:00
bool IsInPath ( const char * Path ) const ;
2013-10-10 13:13:30 +02:00
///< Returns true if this recording is stored anywhere under the given Path.
///< If Path is NULL or an empty string, the entire video directory is checked.
cString Folder ( void ) const ;
///< Returns the name of the folder this recording is stored in (without the
///< video directory). For use in menus etc.
cString BaseName ( void ) const ;
///< Returns the base name of this recording (without the
///< video directory and folder). For use in menus etc.
2004-05-16 10:35:36 +02:00
const char * Name ( void ) const { return name ; }
2015-09-01 11:14:27 +02:00
///< Returns the full name of the recording (without the video directory).
2013-10-10 13:13:30 +02:00
///< For use in menus etc.
2004-05-16 10:35:36 +02:00
const char * FileName ( void ) const ;
2013-10-10 13:13:30 +02:00
///< Returns the full path name to the recording directory, including the
///< video directory and the actual '*.rec'. For disk file access use.
2004-05-16 10:35:36 +02:00
const char * Title ( char Delimiter = ' ' , bool NewIndicator = false , int Level = - 1 ) const ;
2021-01-18 12:55:47 +01:00
cRecordingInfo * Info ( void ) const { return info ; }
2001-09-01 13:38:09 +02:00
const char * PrefixFileName ( char Prefix ) ;
2004-05-16 10:35:36 +02:00
int HierarchyLevels ( void ) const ;
2005-09-25 11:35:56 +02:00
void ResetResume ( void ) const ;
2009-04-19 09:02:16 +02:00
double FramesPerSecond ( void ) const { return framesPerSecond ; }
2011-08-21 13:47:07 +02:00
int NumFrames ( void ) const ;
///< Returns the number of frames in this recording.
///< If the number of frames is unknown, -1 will be returned.
int LengthInSeconds ( void ) const ;
///< Returns the length (in seconds) of this recording, or -1 in case of error.
2012-03-13 13:22:06 +01:00
int FileSizeMB ( void ) const ;
///< Returns the total file size of this recording (in MB), or -1 if the file
///< size is unknown.
2015-01-31 13:37:02 +01:00
int GetResume ( void ) const ;
///< Returns the index of the frame where replay of this recording shall
///< be resumed, or -1 in case of an error.
2004-05-16 10:35:36 +02:00
bool IsNew ( void ) const { return GetResume ( ) < = 0 ; }
bool IsEdited ( void ) const ;
2009-01-06 14:41:11 +01:00
bool IsPesRecording ( void ) const { return isPesRecording ; }
2012-06-03 10:03:55 +02:00
bool IsOnVideoDirectoryFileSystem ( void ) const ;
2015-09-01 11:14:27 +02:00
bool HasMarks ( void ) const ;
2013-10-10 13:13:30 +02:00
///< Returns true if this recording has any editing marks.
bool DeleteMarks ( void ) ;
///< Deletes the editing marks from this recording (if any).
///< Returns true if the operation was successful. If there is no marks file
///< for this recording, it also returns true.
2010-12-27 12:25:19 +01:00
void ReadInfo ( void ) ;
2013-10-10 13:13:30 +02:00
bool WriteInfo ( const char * OtherFileName = NULL ) ;
///< Writes in info file of this recording. If OtherFileName is given, the info
///< file will be written under that recording file name instead of this
///< recording's file name.
2011-08-20 10:09:05 +02:00
void SetStartTime ( time_t Start ) ;
///< Sets the start time of this recording to the given value.
///< If a filename has already been set for this recording, it will be
///< deleted and a new one will be generated (using the new start time)
///< at the next call to FileName().
///< Use this function with care - it does not check whether a recording with
///< this new name already exists, and if there is one, results may be
///< unexpected!
2013-10-10 13:13:30 +02:00
bool ChangePriorityLifetime ( int NewPriority , int NewLifetime ) ;
///< Changes the priority and lifetime of this recording to the given values.
///< If the new values are the same as the old ones, nothing happens.
///< Returns false in case of error.
bool ChangeName ( const char * NewName ) ;
///< Changes the name of this recording to the given value. NewName is in the
///< same format as the one returned by Name(), i.e. without the video directory
///< and the actual '*.rec' part, and using FOLDERDELIMCHAR as the directory
///< delimiter.
///< If the new name is the same as the old one, nothing happens.
///< Returns false in case of error.
2000-03-11 11:22:37 +01:00
bool Delete ( void ) ;
2011-08-13 12:51:23 +02:00
///< Changes the file name so that it will no longer be visible in the "Recordings" menu
///< Returns false in case of error
2000-03-11 11:22:37 +01:00
bool Remove ( void ) ;
2011-08-13 12:51:23 +02:00
///< Actually removes the file from the disk
///< Returns false in case of error
2007-10-14 10:23:19 +02:00
bool Undelete ( void ) ;
2011-08-13 12:51:23 +02:00
///< Changes the file name so that it will be visible in the "Recordings" menu again and
///< not processed by cRemoveDeletedRecordingsThread.
///< Returns false in case of error
2013-10-10 13:13:30 +02:00
int IsInUse ( void ) const ;
///< Checks whether this recording is currently in use and therefore shall not
///< be tampered with. Returns 0 (ruNone) if the recording is not in use.
///< The return value may consist of several or'd eRecordingUsage flags. If the
///< caller is just interested in whether the recording is in use or not, the
///< return value can be used like a boolean value.
///< A recording may be in use for several reasons (like being recorded and replayed,
///< as in time-shift).
2000-03-11 11:22:37 +01:00
} ;
2015-09-01 11:14:27 +02:00
class cVideoDirectoryScannerThread ;
class cRecordings : public cList < cRecording > {
2004-06-13 20:26:51 +02:00
private :
2015-09-01 11:14:27 +02:00
static cRecordings recordings ;
static cRecordings deletedRecordings ;
2017-04-03 14:11:41 +02:00
static int lastRecordingId ;
2005-10-01 10:33:38 +02:00
static char * updateFileName ;
2015-09-01 11:14:27 +02:00
static time_t lastUpdate ;
static cVideoDirectoryScannerThread * videoDirectoryScannerThread ;
static const char * UpdateFileName ( void ) ;
2000-03-11 11:22:37 +01:00
public :
2004-06-13 20:26:51 +02:00
cRecordings ( bool Deleted = false ) ;
2005-09-25 11:00:57 +02:00
virtual ~ cRecordings ( ) ;
2015-09-01 11:14:27 +02:00
static const cRecordings * GetRecordingsRead ( cStateKey & StateKey , int TimeoutMs = 0 ) { return recordings . Lock ( StateKey , false , TimeoutMs ) ? & recordings : NULL ; }
///< Gets the list of recordings for read access.
///< See cTimers::GetTimersRead() for details.
static cRecordings * GetRecordingsWrite ( cStateKey & StateKey , int TimeoutMs = 0 ) { return recordings . Lock ( StateKey , true , TimeoutMs ) ? & recordings : NULL ; }
///< Gets the list of recordings for write access.
///< See cTimers::GetTimersWrite() for details.
static const cRecordings * GetDeletedRecordingsRead ( cStateKey & StateKey , int TimeoutMs = 0 ) { return deletedRecordings . Lock ( StateKey , false , TimeoutMs ) ? & deletedRecordings : NULL ; }
///< Gets the list of deleted recordings for read access.
///< See cTimers::GetTimersRead() for details.
static cRecordings * GetDeletedRecordingsWrite ( cStateKey & StateKey , int TimeoutMs = 0 ) { return deletedRecordings . Lock ( StateKey , true , TimeoutMs ) ? & deletedRecordings : NULL ; }
///< Gets the list of deleted recordings for write access.
///< See cTimers::GetTimersWrite() for details.
static void Update ( bool Wait = false ) ;
2005-09-25 11:00:57 +02:00
///< Triggers an update of the list of recordings, which will run
///< as a separate thread if Wait is false. If Wait is true, the
///< function returns only after the update has completed.
2015-09-01 11:14:27 +02:00
static void TouchUpdate ( void ) ;
2005-09-25 13:49:31 +02:00
///< Touches the '.update' file in the video directory, so that other
///< instances of VDR that access the same video directory can be triggered
///< to update their recordings list.
2015-09-01 11:14:27 +02:00
static bool NeedsUpdate ( void ) ;
2005-09-25 11:35:56 +02:00
void ResetResume ( const char * ResumeFileName = NULL ) ;
2013-03-04 14:11:47 +01:00
void ClearSortNames ( void ) ;
2017-04-03 14:11:41 +02:00
const cRecording * GetById ( int Id ) const ;
cRecording * GetById ( int Id ) { return const_cast < cRecording * > ( static_cast < const cRecordings * > ( this ) - > GetById ( Id ) ) ; } ;
2015-09-01 11:14:27 +02:00
const cRecording * GetByName ( const char * FileName ) const ;
cRecording * GetByName ( const char * FileName ) { return const_cast < cRecording * > ( static_cast < const cRecordings * > ( this ) - > GetByName ( FileName ) ) ; }
2017-04-03 14:11:41 +02:00
void Add ( cRecording * Recording ) ;
2006-07-30 10:29:24 +02:00
void AddByName ( const char * FileName , bool TriggerUpdate = true ) ;
2004-06-13 20:26:51 +02:00
void DelByName ( const char * FileName ) ;
2010-12-27 12:25:19 +01:00
void UpdateByName ( const char * FileName ) ;
2015-09-01 11:14:27 +02:00
int TotalFileSizeMB ( void ) const ;
double MBperMinute ( void ) const ;
2012-03-13 13:22:06 +01:00
///< Returns the average data rate (in MB/min) of all recordings, or -1 if
///< this value is unknown.
2015-09-01 11:14:27 +02:00
int PathIsInUse ( const char * Path ) const ;
2013-10-10 13:13:30 +02:00
///< Checks whether any recording in the given Path is currently in use and therefore
///< the whole Path shall not be tampered with. Returns 0 (ruNone) if no recording
///< is in use.
///< See cRecording::IsInUse() for details about the possible non-zero return values.
///< If several recordings in the Path are currently in use, the return value will
///< be the combination of all individual recordings' flags.
///< If Path is NULL or an empty string, the entire video directory is checked.
2015-09-01 11:14:27 +02:00
int GetNumRecordingsInPath ( const char * Path ) const ;
2013-10-10 13:13:30 +02:00
///< Returns the total number of recordings in the given Path, including all
///< sub-folders of Path.
///< If Path is NULL or an empty string, the entire video directory is checked.
bool MoveRecordings ( const char * OldPath , const char * NewPath ) ;
///< Moves all recordings in OldPath to NewPath.
///< Returns true if all recordings were successfully moved.
///< As soon as the operation fails for one recording, the whole
///< action is aborted and false will be returned. Any recordings that
///< have been successfully moved thus far will keep their new name.
///< If OldPath and NewPath are on different file systems, the recordings
///< will be moved in a background process and this function returns true
///< if all recordings have been successfully added to the RecordingsHandler.
2000-03-11 11:22:37 +01:00
} ;
2015-09-01 11:14:27 +02:00
// Provide lock controlled access to the list:
DEF_LIST_LOCK ( Recordings ) ;
DEF_LIST_LOCK2 ( Recordings , DeletedRecordings ) ;
// These macros provide a convenient way of locking the global recordings list
// and making sure the lock is released as soon as the current scope is left
// (note that these macros wait forever to obtain the lock!):
# define LOCK_RECORDINGS_READ USE_LIST_LOCK_READ(Recordings)
# define LOCK_RECORDINGS_WRITE USE_LIST_LOCK_WRITE(Recordings)
# define LOCK_DELETEDRECORDINGS_READ USE_LIST_LOCK_READ2(Recordings, DeletedRecordings)
# define LOCK_DELETEDRECORDINGS_WRITE USE_LIST_LOCK_WRITE2(Recordings, DeletedRecordings)
2004-06-13 20:26:51 +02:00
2013-10-10 13:13:30 +02:00
class cRecordingsHandlerEntry ;
2016-12-13 13:54:00 +01:00
class cRecordingsHandler : public cThread {
2013-10-10 13:13:30 +02:00
private :
cMutex mutex ;
cList < cRecordingsHandlerEntry > operations ;
bool finished ;
bool error ;
cRecordingsHandlerEntry * Get ( const char * FileName ) ;
2016-12-13 13:54:00 +01:00
protected :
virtual void Action ( void ) ;
2013-10-10 13:13:30 +02:00
public :
cRecordingsHandler ( void ) ;
2016-12-13 13:54:00 +01:00
virtual ~ cRecordingsHandler ( ) ;
2013-10-10 13:13:30 +02:00
bool Add ( int Usage , const char * FileNameSrc , const char * FileNameDst = NULL ) ;
///< Adds the given FileNameSrc to the recordings handler for (later)
///< processing. Usage can be either ruCut, ruMove or ruCopy. FileNameDst
///< is only applicable for ruMove and ruCopy.
///< At any given time there can be only one operation for any FileNameSrc
///< or FileNameDst in the list. An attempt to add a file name twice will
///< result in an error.
///< Returns true if the operation was successfully added to the list.
void Del ( const char * FileName ) ;
///< Deletes the given FileName from the list of operations.
///< If an action is already in progress, it will be terminated.
///< FileName can be either the FileNameSrc or FileNameDst (if applicable)
///< that was given when the operation was added with Add().
void DelAll ( void ) ;
///< Deletes/terminates all operations.
int GetUsage ( const char * FileName ) ;
///< Returns the usage type for the given FileName.
bool Finished ( bool & Error ) ;
///< Returns true if all operations in the list have been finished.
///< If there have been any errors, Errors will be set to true.
///< This function will only return true once if the list of operations
///< has actually become empty since the last call.
} ;
extern cRecordingsHandler RecordingsHandler ;
2009-01-06 14:41:11 +01:00
# define DEFAULTFRAMESPERSECOND 25.0
2000-12-28 12:57:16 +01:00
class cMark : public cListObject {
2011-08-21 11:34:30 +02:00
friend class cMarks ; // for sorting
2009-01-06 14:41:11 +01:00
private :
double framesPerSecond ;
2000-12-28 12:57:16 +01:00
int position ;
2011-08-21 11:34:30 +02:00
cString comment ;
public :
2009-01-06 14:41:11 +01:00
cMark ( int Position = 0 , const char * Comment = NULL , double FramesPerSecond = DEFAULTFRAMESPERSECOND ) ;
2005-09-25 11:00:57 +02:00
virtual ~ cMark ( ) ;
2011-08-21 11:34:30 +02:00
int Position ( void ) const { return position ; }
const char * Comment ( void ) const { return comment ; }
void SetPosition ( int Position ) { position = Position ; }
void SetComment ( const char * Comment ) { comment = Comment ; }
2004-12-26 12:45:22 +01:00
cString ToText ( void ) ;
2000-12-28 12:57:16 +01:00
bool Parse ( const char * s ) ;
bool Save ( FILE * f ) ;
} ;
2015-09-01 11:14:27 +02:00
class cMarks : public cConfig < cMark > {
2009-01-06 14:41:11 +01:00
private :
2012-10-15 11:23:59 +02:00
cString recordingFileName ;
2011-02-27 13:40:43 +01:00
cString fileName ;
2009-01-06 14:41:11 +01:00
double framesPerSecond ;
2012-10-15 11:23:59 +02:00
bool isPesRecording ;
2011-03-20 11:46:58 +01:00
time_t nextUpdate ;
2011-02-27 13:40:43 +01:00
time_t lastFileTime ;
2011-04-17 13:22:44 +02:00
time_t lastChange ;
2000-12-28 12:57:16 +01:00
public :
2015-09-01 11:14:27 +02:00
cMarks ( void ) : cConfig < cMark > ( " Marks " ) { } ;
2013-10-10 13:13:30 +02:00
static cString MarksFileName ( const cRecording * Recording ) ;
///< Returns the marks file name for the given Recording (regardless whether such
///< a file actually exists).
2015-09-01 11:14:27 +02:00
static bool DeleteMarksFile ( const cRecording * Recording ) ;
2009-01-06 14:41:11 +01:00
bool Load ( const char * RecordingFileName , double FramesPerSecond = DEFAULTFRAMESPERSECOND , bool IsPesRecording = false ) ;
2011-02-27 13:40:43 +01:00
bool Update ( void ) ;
2013-02-11 11:27:34 +01:00
bool Save ( void ) ;
2012-10-15 11:23:59 +02:00
void Align ( void ) ;
2000-12-28 12:57:16 +01:00
void Sort ( void ) ;
2012-11-12 14:51:18 +01:00
void Add ( int Position ) ;
2015-02-07 14:29:14 +01:00
///< If this cMarks object is used by multiple threads, the caller must Lock()
///< it before calling Add() and Unlock() it afterwards. The same applies to
///< calls to Del(), or any of the functions that return a "cMark *", in case
2020-09-16 13:48:33 +02:00
///< an other thread might modify the list while the returned pointer is
2015-02-07 14:29:14 +01:00
///< considered valid.
2015-09-01 11:14:27 +02:00
const cMark * Get ( int Position ) const ;
const cMark * GetPrev ( int Position ) const ;
const cMark * GetNext ( int Position ) const ;
const cMark * GetNextBegin ( const cMark * EndMark = NULL ) const ;
2012-11-18 12:19:51 +01:00
///< Returns the next "begin" mark after EndMark, skipping any marks at the
///< same position as EndMark. If EndMark is NULL, the first actual "begin"
///< will be returned (if any).
2015-09-01 11:14:27 +02:00
const cMark * GetNextEnd ( const cMark * BeginMark ) const ;
2012-11-18 12:19:51 +01:00
///< Returns the next "end" mark after BeginMark, skipping any marks at the
///< same position as BeginMark.
2015-09-01 11:14:27 +02:00
int GetNumSequences ( void ) const ;
2012-11-18 12:19:51 +01:00
///< Returns the actual number of sequences to be cut from the recording.
///< If there is only one actual "begin" mark, and it is positioned at index
///< 0 (the beginning of the recording), and there is no "end" mark, the
///< return value is 0, which means that the result is the same as the original
///< recording.
2015-09-01 11:14:27 +02:00
cMark * Get ( int Position ) { return const_cast < cMark * > ( static_cast < const cMarks * > ( this ) - > Get ( Position ) ) ; }
cMark * GetPrev ( int Position ) { return const_cast < cMark * > ( static_cast < const cMarks * > ( this ) - > GetPrev ( Position ) ) ; }
cMark * GetNext ( int Position ) { return const_cast < cMark * > ( static_cast < const cMarks * > ( this ) - > GetNext ( Position ) ) ; }
cMark * GetNextBegin ( const cMark * EndMark = NULL ) { return const_cast < cMark * > ( static_cast < const cMarks * > ( this ) - > GetNextBegin ( EndMark ) ) ; }
cMark * GetNextEnd ( const cMark * BeginMark ) { return const_cast < cMark * > ( static_cast < const cMarks * > ( this ) - > GetNextEnd ( BeginMark ) ) ; }
2000-12-28 12:57:16 +01:00
} ;
2015-04-11 12:12:43 +02:00
# define RUC_BEFORERECORDING "before"
# define RUC_STARTRECORDING "started"
# define RUC_AFTERRECORDING "after"
# define RUC_EDITINGRECORDING "editing"
# define RUC_EDITEDRECORDING "edited"
# define RUC_DELETERECORDING "deleted"
2021-01-19 20:38:28 +01:00
# define RUC_RENAMEDRECORDING "renamed" // same directory, only the base name is changed
# define RUC_MOVEDRECORDING "moved" // different directory (and maybe base name), or "copy" to other filesystem + delete original (triggers copying->copied->deleted)
# define RUC_COPYINGRECORDING "copying"
# define RUC_COPIEDRECORDING "copied"
2001-09-23 14:02:11 +02:00
class cRecordingUserCommand {
private :
static const char * command ;
public :
static void SetCommand ( const char * Command ) { command = Command ; }
2012-06-02 13:57:41 +02:00
static void InvokeCommand ( const char * State , const char * RecordingFileName , const char * SourceFileName = NULL ) ;
2001-09-23 14:02:11 +02:00
} ;
2005-01-16 15:30:43 +01:00
// The maximum size of a single frame (up to HDTV 1920x1080):
2009-08-16 10:45:58 +02:00
# define MAXFRAMESIZE (KILOBYTE(1024) / TS_SIZE * TS_SIZE) // multiple of TS_SIZE to avoid breaking up TS packets
2002-06-22 10:11:59 +02:00
2002-06-16 12:57:31 +02:00
// The maximum file size is limited by the range that can be covered
2009-01-24 15:24:19 +01:00
// with a 40 bit 'unsigned int', which is 1TB. The actual maximum value
// used is 6MB below the theoretical maximum, to have some safety (the
// actual file size may be slightly higher because we stop recording only
// before the next independent frame, to have a complete Group Of Pictures):
# define MAXVIDEOFILESIZETS 1048570 // MB
# define MAXVIDEOFILESIZEPES 2000 // MB
# define MINVIDEOFILESIZE 100 // MB
# define MAXVIDEOFILESIZEDEFAULT MAXVIDEOFILESIZEPES
2002-06-16 12:57:31 +02:00
2009-01-06 14:41:11 +01:00
struct tIndexTs ;
2009-11-22 11:30:27 +01:00
class cIndexFileGenerator ;
2009-01-06 14:41:11 +01:00
2002-06-16 12:57:31 +02:00
class cIndexFile {
private :
int f ;
2011-08-13 11:16:41 +02:00
cString fileName ;
2002-06-16 12:57:31 +02:00
int size , last ;
2009-01-06 14:41:11 +01:00
tIndexTs * index ;
bool isPesRecording ;
2002-06-16 12:57:31 +02:00
cResumeFile resumeFile ;
2009-11-22 11:30:27 +01:00
cIndexFileGenerator * indexFileGenerator ;
2003-09-09 16:09:05 +02:00
cMutex mutex ;
2009-01-06 14:41:11 +01:00
void ConvertFromPes ( tIndexTs * IndexTs , int Count ) ;
2009-01-24 13:16:43 +01:00
void ConvertToPes ( tIndexTs * IndexTs , int Count ) ;
2002-06-16 12:57:31 +02:00
bool CatchUp ( int Index = - 1 ) ;
public :
2015-01-17 15:03:01 +01:00
cIndexFile ( const char * FileName , bool Record , bool IsPesRecording = false , bool PauseLive = false , bool Update = false ) ;
2002-06-16 12:57:31 +02:00
~ cIndexFile ( ) ;
bool Ok ( void ) { return index ! = NULL ; }
2009-01-06 14:41:11 +01:00
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 ) ;
2012-03-12 14:53:59 +01:00
int GetNextIFrame ( int Index , bool Forward , uint16_t * FileNumber = NULL , off_t * FileOffset = NULL , int * Length = NULL ) ;
2012-10-15 11:23:59 +02:00
int GetClosestIFrame ( int Index ) ;
///< Returns the index of the I-frame that is closest to the given Index (or Index itself,
///< if it already points to an I-frame). Index may be any value, even outside the current
///< range of frame indexes.
///< If there is no actual index data available, 0 is returned.
2009-01-06 14:41:11 +01:00
int Get ( uint16_t FileNumber , off_t FileOffset ) ;
2002-06-16 12:57:31 +02:00
int Last ( void ) { CatchUp ( ) ; return last ; }
2012-11-12 14:51:18 +01:00
///< Returns the index of the last entry in this file, or -1 if the file is empty.
2002-06-16 12:57:31 +02:00
int GetResume ( void ) { return resumeFile . Read ( ) ; }
bool StoreResume ( int Index ) { return resumeFile . Save ( Index ) ; }
2006-04-09 13:57:39 +02:00
bool IsStillRecording ( void ) ;
2009-11-22 11:30:27 +01:00
void Delete ( void ) ;
2011-08-13 12:45:42 +02:00
static int GetLength ( const char * FileName , bool IsPesRecording = false ) ;
2011-12-04 13:40:52 +01:00
///< Calculates the recording length (number of frames) without actually reading the index file.
2011-08-13 12:45:42 +02:00
///< Returns -1 in case of error.
2012-09-06 10:07:25 +02:00
static cString IndexFileName ( const char * FileName , bool IsPesRecording ) ;
2002-06-16 12:57:31 +02:00
} ;
class cFileName {
private :
2005-10-31 13:14:26 +01:00
cUnbufferedFile * file ;
2009-12-06 12:57:45 +01:00
uint16_t fileNumber ;
2002-06-16 12:57:31 +02:00
char * fileName , * pFileNumber ;
bool record ;
bool blocking ;
2009-01-06 14:41:11 +01:00
bool isPesRecording ;
2002-06-16 12:57:31 +02:00
public :
2009-01-06 14:41:11 +01:00
cFileName ( const char * FileName , bool Record , bool Blocking = false , bool IsPesRecording = false ) ;
2002-06-16 12:57:31 +02:00
~ cFileName ( ) ;
const char * Name ( void ) { return fileName ; }
2009-12-06 12:57:45 +01:00
uint16_t Number ( void ) { return fileNumber ; }
2009-05-24 15:11:28 +02:00
bool GetLastPatPmtVersions ( int & PatVersion , int & PmtVersion ) ;
2005-10-31 13:14:26 +01:00
cUnbufferedFile * Open ( void ) ;
2002-06-16 12:57:31 +02:00
void Close ( void ) ;
2009-12-06 12:57:45 +01:00
cUnbufferedFile * SetOffset ( int Number , off_t Offset = 0 ) ; // yes, Number is int for easier internal calculating
2005-10-31 13:14:26 +01:00
cUnbufferedFile * NextFile ( void ) ;
2002-06-16 12:57:31 +02:00
} ;
2020-12-26 15:49:01 +01:00
class cDoneRecordings {
private :
cString fileName ;
cStringList doneRecordings ;
void Add ( const char * Title ) ;
public :
bool Load ( const char * FileName ) ;
bool Save ( void ) const ;
void Append ( const char * Title ) ;
bool Contains ( const char * Title ) const ;
} ;
extern cDoneRecordings DoneRecordingsPattern ;
2009-01-06 14:41:11 +01:00
cString IndexToHMSF ( int Index , bool WithFrame = false , double FramesPerSecond = DEFAULTFRAMESPERSECOND ) ;
2002-06-16 12:57:31 +02:00
// Converts the given index to a string, optionally containing the frame number.
2009-01-06 14:41:11 +01:00
int HMSFToIndex ( const char * HMSF , double FramesPerSecond = DEFAULTFRAMESPERSECOND ) ;
2002-06-16 12:57:31 +02:00
// Converts the given string (format: "hh:mm:ss.ff") to an index.
2009-01-06 14:41:11 +01:00
int SecondsToFrames ( int Seconds , double FramesPerSecond = DEFAULTFRAMESPERSECOND ) ;
2002-06-16 12:57:31 +02:00
// Returns the number of frames corresponding to the given number of seconds.
2005-10-31 13:14:26 +01:00
int ReadFrame ( cUnbufferedFile * f , uchar * b , int Length , int Max ) ;
2002-06-22 10:11:59 +02:00
2005-09-25 14:31:23 +02:00
char * ExchangeChars ( char * s , bool ToFileSystem ) ;
// Exchanges the characters in the given string to or from a file system
// specific representation (depending on ToFileSystem). The given string will
// be modified and may be reallocated if more space is needed. The return
// value points to the resulting string, which may be different from s.
2015-01-17 15:03:01 +01:00
bool GenerateIndex ( const char * FileName , bool Update = false ) ;
///< Generates the index of the existing recording with the given FileName.
///< If Update is true, an existing index file will be checked whether it is
///< complete, and will be updated if it isn't. Otherwise an existing index
///< file will be removed before a new one is generated.
2010-01-02 14:02:48 +01:00
2017-12-09 18:58:25 +01:00
enum eRecordingsSortDir { rsdAscending , rsdDescending } ;
2012-06-09 14:32:29 +02:00
enum eRecordingsSortMode { rsmName , rsmTime } ;
extern eRecordingsSortMode RecordingsSortMode ;
bool HasRecordingsSortMode ( const char * Directory ) ;
void GetRecordingsSortMode ( const char * Directory ) ;
void SetRecordingsSortMode ( const char * Directory , eRecordingsSortMode SortMode ) ;
void IncRecordingsSortMode ( const char * Directory ) ;
2018-02-13 09:33:41 +01:00
void SetRecordingTimerId ( const char * Directory , const char * TimerId ) ;
cString GetRecordingTimerId ( const char * Directory ) ;
2000-03-11 11:22:37 +01:00
# endif //__RECORDING_H