mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	- Fixed a hangup when replaying a TS recording with subtitles activated (reported
  by Timo Helkio).
- Fixed handling the 'new' indicator in the recordings menu for TS recordings
  (thanks to Derek Kelly).
- Added cap_sys_nice to the capabilities that are not dropped (thanks to Rolf
  Ahrenberg).
- Updated the Italian OSD texts (thanks to Diego Pierotto).
- Added cRecordingInfo::GetEvent() (thanks to Marcel Unbehaun).
- Improved synchronizing the progress display, trick modes and subtitle display
  to the actual audio/video. This now works independent of any buffer sizes the
  output device might use.
  + The cBackTrace class has been replaced with cPtsIndex, which keeps track
    of the PTS timestamps of recently played frames.
  + cDevice::GetSTC() is now required to deliver the STC even in trick modes.
    It is sufficient if it returns the PTS of the most recently presented
    audio/video frame.
  + The full-featured DVB cards need an improved firmware in order to return
    proper STC values in trick modes (thanks to Oliver Endriss for enhancing the
    av7110 firmware).
- Adapted cFrameDetector::Analyze() to HD NTSC broadcasts that split frames over
  several payload units (thanks to Derek Kelly for reporting this and helping in
  testing).
- Modified cFrameDetector::Analyze() to make it process whole frames at once, so
  that file I/O overhead is minimized during recording (reported by Günter
  Niedermeier).
- Added command line help for the '-i' option.
- Fixed cDvbPlayer::NextFile() to handle files larger than 2GB (thanks to Jose
  Alberto Reguero).
- Improved replay at the begin and end of a recording. The very first and very last
  frame is now sent to the output device repeatedly until GetSTC() reports that it
  has been played. cDvbPlayer::Action() no longer calls DeviceFlush() (thanks to
  Reinhard Nissl for making sure vdr-xine no longer needs this).
- Added missing '[]' to the delete operator in cMenuEditStrItem::~cMenuEditStrItem().
- Added missing virtual destructor to cPalette.
- Now freeing configDirectory before setting it to a new value in
  cPlugin::SetConfigDirectory().
- Fixed a crash when jumping to an editing mark in an audio recording.
- Fixed the 'VideoOnly' condition in the PlayPes() and PlayTs() calls in
  cDvbPlayer::Action() (thanks to Reinhard Nissl).
- cDevice::PlayTs() now plays as many TS packets as possible in one call.
- Making sure any floating point numbers written use a decimal point (thanks to
  Oliver Endriss for pointing out a problem with the F record in the info file of
  a recording).
- Fixed detecting the frame rate for radio recordings.
- Added missing AUDIO_PAUSE/AUDIO_CONTINUE calls to cDvbDevice (thanks to Oliver
  Endriss).
- No longer writing the video type into channels.conf if VPID is 0 (thanks to
  Oliver Endriss for reporting this).
- Improved efficiency of cEIT::cEIT() (thanks to Tobias Bratfisch).
		
	
		
			
				
	
	
		
			285 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			285 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * recording.h: Recording file handling
 | 
						|
 *
 | 
						|
 * See the main source file 'vdr.c' for copyright information and
 | 
						|
 * how to reach the author.
 | 
						|
 *
 | 
						|
 * $Id: recording.h 2.5 2009/02/28 10:50:12 kls Exp $
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef __RECORDING_H
 | 
						|
#define __RECORDING_H
 | 
						|
 | 
						|
#include <time.h>
 | 
						|
#include "channels.h"
 | 
						|
#include "config.h"
 | 
						|
#include "epg.h"
 | 
						|
#include "thread.h"
 | 
						|
#include "timers.h"
 | 
						|
#include "tools.h"
 | 
						|
 | 
						|
extern bool VfatFileSystem;
 | 
						|
extern int InstanceId;
 | 
						|
 | 
						|
void RemoveDeletedRecordings(void);
 | 
						|
void AssertFreeDiskSpace(int Priority = 0, bool Force = false);
 | 
						|
     ///< The special Priority value -1 means that we shall get rid of any
 | 
						|
     ///< deleted recordings faster than normal (because we're cutting).
 | 
						|
     ///< If Force is true, the check will be done even if the timeout
 | 
						|
     ///< hasn't expired yet.
 | 
						|
 | 
						|
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);
 | 
						|
  };
 | 
						|
 | 
						|
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);
 | 
						|
  void SetData(const char *Title, const char *ShortText, const char *Description);
 | 
						|
  void SetAux(const char *Aux);
 | 
						|
public:
 | 
						|
  cRecordingInfo(const char *FileName);
 | 
						|
  ~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 Read(FILE *f);
 | 
						|
  bool Write(FILE *f, const char *Prefix = "") const;
 | 
						|
  bool Read(void);
 | 
						|
  bool Write(void) const;
 | 
						|
  };
 | 
						|
 | 
						|
class cRecording : public cListObject {
 | 
						|
  friend class cRecordings;
 | 
						|
private:
 | 
						|
  mutable int resume;
 | 
						|
  mutable char *titleBuffer;
 | 
						|
  mutable 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;
 | 
						|
public:
 | 
						|
  time_t start;
 | 
						|
  int priority;
 | 
						|
  int lifetime;
 | 
						|
  time_t deleted;
 | 
						|
  cRecording(cTimer *Timer, const cEvent *Event);
 | 
						|
  cRecording(const char *FileName);
 | 
						|
  virtual ~cRecording();
 | 
						|
  virtual int Compare(const cListObject &ListObject) const;
 | 
						|
  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 cRecordingInfo *Info(void) const { return info; }
 | 
						|
  const char *PrefixFileName(char Prefix);
 | 
						|
  int HierarchyLevels(void) const;
 | 
						|
  void ResetResume(void) const;
 | 
						|
  double FramesPerSecond(void) { return framesPerSecond; }
 | 
						|
  bool IsNew(void) const { return GetResume() <= 0; }
 | 
						|
  bool IsEdited(void) const;
 | 
						|
  bool IsPesRecording(void) const { return isPesRecording; }
 | 
						|
  bool WriteInfo(void);
 | 
						|
  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 Undelete(void);
 | 
						|
       // 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
 | 
						|
  };
 | 
						|
 | 
						|
class cRecordings : public cList<cRecording>, public cThread {
 | 
						|
private:
 | 
						|
  static char *updateFileName;
 | 
						|
  bool deleted;
 | 
						|
  time_t lastUpdate;
 | 
						|
  int state;
 | 
						|
  const char *UpdateFileName(void);
 | 
						|
  void Refresh(bool Foreground = false);
 | 
						|
  void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0);
 | 
						|
protected:
 | 
						|
  void Action(void);
 | 
						|
public:
 | 
						|
  cRecordings(bool Deleted = false);
 | 
						|
  virtual ~cRecordings();
 | 
						|
  bool Load(void) { return Update(true); }
 | 
						|
       ///< Loads the current list of recordings and returns true if there
 | 
						|
       ///< is anything in it (for compatibility with older plugins - use
 | 
						|
       ///< Update(true) instead).
 | 
						|
  bool Update(bool Wait = false);
 | 
						|
       ///< 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.
 | 
						|
       ///< Returns true if Wait is true and there is anyting in the list
 | 
						|
       ///< of recordings, false otherwise.
 | 
						|
  void TouchUpdate(void);
 | 
						|
       ///< 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.
 | 
						|
  bool NeedsUpdate(void);
 | 
						|
  void ChangeState(void) { state++; }
 | 
						|
  bool StateChanged(int &State);
 | 
						|
  void ResetResume(const char *ResumeFileName = NULL);
 | 
						|
  cRecording *GetByName(const char *FileName);
 | 
						|
  void AddByName(const char *FileName, bool TriggerUpdate = true);
 | 
						|
  void DelByName(const char *FileName);
 | 
						|
  int TotalFileSizeMB(void); ///< Only for deleted recordings!
 | 
						|
  };
 | 
						|
 | 
						|
extern cRecordings Recordings;
 | 
						|
extern cRecordings DeletedRecordings;
 | 
						|
 | 
						|
#define DEFAULTFRAMESPERSECOND 25.0
 | 
						|
 | 
						|
class cMark : public cListObject {
 | 
						|
private:
 | 
						|
  double framesPerSecond;
 | 
						|
public:
 | 
						|
  int position;
 | 
						|
  char *comment;
 | 
						|
  cMark(int Position = 0, const char *Comment = NULL, double FramesPerSecond = DEFAULTFRAMESPERSECOND);
 | 
						|
  virtual ~cMark();
 | 
						|
  cString ToText(void);
 | 
						|
  bool Parse(const char *s);
 | 
						|
  bool Save(FILE *f);
 | 
						|
  };
 | 
						|
 | 
						|
class cMarks : public cConfig<cMark> {
 | 
						|
private:
 | 
						|
  double framesPerSecond;
 | 
						|
public:
 | 
						|
  bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false);
 | 
						|
  void Sort(void);
 | 
						|
  cMark *Add(int Position);
 | 
						|
  cMark *Get(int Position);
 | 
						|
  cMark *GetPrev(int Position);
 | 
						|
  cMark *GetNext(int Position);
 | 
						|
  };
 | 
						|
 | 
						|
#define RUC_BEFORERECORDING "before"
 | 
						|
#define RUC_AFTERRECORDING  "after"
 | 
						|
#define RUC_EDITEDRECORDING "edited"
 | 
						|
 | 
						|
class cRecordingUserCommand {
 | 
						|
private:
 | 
						|
  static const char *command;
 | 
						|
public:
 | 
						|
  static void SetCommand(const char *Command) { command = Command; }
 | 
						|
  static void InvokeCommand(const char *State, const char *RecordingFileName);
 | 
						|
  };
 | 
						|
 | 
						|
// The maximum size of a single frame (up to HDTV 1920x1080):
 | 
						|
#define MAXFRAMESIZE  KILOBYTE(512)
 | 
						|
 | 
						|
// The maximum file size is limited by the range that can be covered
 | 
						|
// 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
 | 
						|
 | 
						|
struct tIndexTs;
 | 
						|
 | 
						|
class cIndexFile {
 | 
						|
private:
 | 
						|
  int f;
 | 
						|
  char *fileName;
 | 
						|
  int size, last;
 | 
						|
  tIndexTs *index;
 | 
						|
  bool isPesRecording;
 | 
						|
  cResumeFile resumeFile;
 | 
						|
  cMutex mutex;
 | 
						|
  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); }
 | 
						|
  bool IsStillRecording(void);
 | 
						|
  };
 | 
						|
 | 
						|
class cFileName {
 | 
						|
private:
 | 
						|
  cUnbufferedFile *file;
 | 
						|
  int fileNumber;
 | 
						|
  char *fileName, *pFileNumber;
 | 
						|
  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; }
 | 
						|
  int Number(void) { return fileNumber; }
 | 
						|
  cUnbufferedFile *Open(void);
 | 
						|
  void Close(void);
 | 
						|
  cUnbufferedFile *SetOffset(int Number, off_t Offset = 0);
 | 
						|
  cUnbufferedFile *NextFile(void);
 | 
						|
  };
 | 
						|
 | 
						|
cString IndexToHMSF(int Index, bool WithFrame = false, double FramesPerSecond = DEFAULTFRAMESPERSECOND);
 | 
						|
      // Converts the given index to a string, optionally containing the frame number.
 | 
						|
int HMSFToIndex(const char *HMSF, double FramesPerSecond = DEFAULTFRAMESPERSECOND);
 | 
						|
      // Converts the given string (format: "hh:mm:ss.ff") to an index.
 | 
						|
int SecondsToFrames(int Seconds, double FramesPerSecond = DEFAULTFRAMESPERSECOND);
 | 
						|
      // Returns the number of frames corresponding to the given number of seconds.
 | 
						|
 | 
						|
int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max);
 | 
						|
 | 
						|
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.
 | 
						|
 | 
						|
#endif //__RECORDING_H
 |