mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	The info file of an edited recording now contains the number of errors in the edited version
This commit is contained in:
		
							
								
								
									
										5
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -10009,3 +10009,8 @@ Video Disk Recorder Revision History | ||||
|   APIVERSNUM is now 30004. | ||||
| - When the index file of a recording is regenerated, errors in the recording are now | ||||
|   stored in the index file. | ||||
| - The info file of an edited recording now contains the number of errors in the edited | ||||
|   version. Note that this applies only to recordings that have errors stored in their | ||||
|   index file. If errors are not stored in the index file, the edited version will have | ||||
|   its number of errors set to zero. | ||||
|   APIVERSNUM is now 30005. | ||||
|   | ||||
							
								
								
									
										6
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								config.h
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: config.h 5.21 2024/09/19 09:49:02 kls Exp $ | ||||
|  * $Id: config.h 5.22 2024/09/19 20:21:58 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __CONFIG_H | ||||
| @@ -27,8 +27,8 @@ | ||||
|  | ||||
| // The plugin API's version number: | ||||
|  | ||||
| #define APIVERSION      "4" | ||||
| #define APIVERSNUM   30004 | ||||
| #define APIVERSION      "5" | ||||
| #define APIVERSNUM   30005 | ||||
|  | ||||
| // When loading plugins, VDR searches files by their APIVERSION, which | ||||
| // is different from VDRVERSION. APIVERSION is a plain number, incremented | ||||
|   | ||||
							
								
								
									
										53
									
								
								cutter.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								cutter.c
									
									
									
									
									
								
							| @@ -4,12 +4,11 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: cutter.c 5.1 2022/11/06 11:25:13 kls Exp $ | ||||
|  * $Id: cutter.c 5.2 2024/09/19 20:21:58 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "cutter.h" | ||||
| #include "menu.h" | ||||
| #include "recording.h" | ||||
| #include "remux.h" | ||||
| #include "videodir.h" | ||||
|  | ||||
| @@ -232,6 +231,10 @@ private: | ||||
|   int numSequences; | ||||
|   off_t maxVideoFileSize; | ||||
|   off_t fileSize; | ||||
|   int frameErrors; | ||||
|   time_t lastErrorHandling; | ||||
|   cString editedRecordingName; | ||||
|   cRecordingInfo *recordingInfo; | ||||
|   bool suspensionLogged; | ||||
|   int sequence;          // cutting sequence | ||||
|   int delta;             // time between two frames (PTS ticks) | ||||
| @@ -246,7 +249,7 @@ private: | ||||
|   cPatPmtParser patPmtParser; | ||||
|   bool Throttled(void); | ||||
|   bool SwitchFile(bool Force = false); | ||||
|   bool LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length); | ||||
|   bool LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length, bool *Errors = NULL, bool *Missing = NULL); | ||||
|   bool FramesAreEqual(int Index1, int Index2); | ||||
|   void GetPendingPackets(uchar *Buffer, int &Length, int Index); | ||||
|        // Gather all non-video TS packets from Index upward that either belong to | ||||
| @@ -254,15 +257,16 @@ private: | ||||
|        // and add them to the end of the given Data. | ||||
|   bool FixFrame(uchar *Data, int &Length, bool Independent, int Index, bool CutIn, bool CutOut); | ||||
|   bool ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex); | ||||
|   void HandleErrors(bool Force = false); | ||||
| protected: | ||||
|   virtual void Action(void); | ||||
| public: | ||||
|   cCuttingThread(const char *FromFileName, const char *ToFileName); | ||||
|   cCuttingThread(const char *FromFileName, const char *ToFileName, cRecordingInfo *RecordingInfo); | ||||
|   virtual ~cCuttingThread(); | ||||
|   const char *Error(void) { return error; } | ||||
|   }; | ||||
|  | ||||
| cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName) | ||||
| cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName, cRecordingInfo *RecordingInfo) | ||||
| :cThread("video cutting", true) | ||||
| { | ||||
|   error = NULL; | ||||
| @@ -274,6 +278,10 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName) | ||||
|   framesPerSecond = Recording.FramesPerSecond(); | ||||
|   suspensionLogged = false; | ||||
|   fileSize = 0; | ||||
|   frameErrors = 0; | ||||
|   lastErrorHandling = 0; | ||||
|   editedRecordingName = ToFileName; | ||||
|   recordingInfo = RecordingInfo; | ||||
|   sequence = 0; | ||||
|   delta = int(round(PTSTICKS / framesPerSecond)); | ||||
|   lastVidPts = -1; | ||||
| @@ -328,11 +336,11 @@ bool cCuttingThread::Throttled(void) | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cCuttingThread::LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length) | ||||
| bool cCuttingThread::LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length, bool *Errors, bool *Missing) | ||||
| { | ||||
|   uint16_t FileNumber; | ||||
|   off_t FileOffset; | ||||
|   if (fromIndex->Get(Index, &FileNumber, &FileOffset, &Independent, &Length)) { | ||||
|   if (fromIndex->Get(Index, &FileNumber, &FileOffset, &Independent, &Length, Errors, Missing)) { | ||||
|      fromFile = fromFileName->SetOffset(FileNumber, FileOffset); | ||||
|      if (fromFile) { | ||||
|         fromFile->SetReadAhead(MEGABYTE(20)); | ||||
| @@ -555,7 +563,9 @@ bool cCuttingThread::ProcessSequence(int LastEndIndex, int BeginIndex, int EndIn | ||||
|   for (int Index = BeginIndex; Running() && Index < EndIndex; Index++) { | ||||
|       bool Independent; | ||||
|       int Length; | ||||
|       if (LoadFrame(Index, Buffer, Independent, Length)) { | ||||
|       bool Errors; | ||||
|       bool Missing; | ||||
|       if (LoadFrame(Index, Buffer, Independent, Length, &Errors, &Missing)) { | ||||
|          // Make sure there is enough disk space: | ||||
|          AssertFreeDiskSpace(-1); | ||||
|          bool CutIn = !SeamlessBegin && Index == BeginIndex; | ||||
| @@ -572,10 +582,12 @@ bool cCuttingThread::ProcessSequence(int LastEndIndex, int BeginIndex, int EndIn | ||||
|                return false; | ||||
|             } | ||||
|          // Write index: | ||||
|          if (!DeletedFrame && !toIndex->Write(Independent, toFileName->Number(), fileSize)) { | ||||
|          if (!DeletedFrame && !toIndex->Write(Independent, toFileName->Number(), fileSize, Errors, Missing)) { | ||||
|             error = "toIndex"; | ||||
|             return false; | ||||
|             } | ||||
|          frameErrors += Errors + Missing; | ||||
|          HandleErrors(); | ||||
|          // Write data: | ||||
|          if (toFile->Write(Buffer, Length) < 0) { | ||||
|             error = "safe_write"; | ||||
| @@ -596,6 +608,21 @@ bool cCuttingThread::ProcessSequence(int LastEndIndex, int BeginIndex, int EndIn | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| #define ERROR_HANDLING_DELTA 1 // seconds between handling errors | ||||
|  | ||||
| void cCuttingThread::HandleErrors(bool Force) | ||||
| { | ||||
|   if (Force || time(NULL) - lastErrorHandling >= ERROR_HANDLING_DELTA) { | ||||
|      if (frameErrors > recordingInfo->Errors()) { | ||||
|         recordingInfo->SetErrors(frameErrors); | ||||
|         recordingInfo->Write(); | ||||
|         LOCK_RECORDINGS_WRITE; | ||||
|         Recordings->UpdateByName(editedRecordingName); | ||||
|         } | ||||
|      lastErrorHandling = time(NULL); | ||||
|      } | ||||
| } | ||||
|  | ||||
| void cCuttingThread::Action(void) | ||||
| { | ||||
|   if (cMark *BeginMark = fromMarks.GetNextBegin()) { | ||||
| @@ -634,6 +661,7 @@ void cCuttingThread::Action(void) | ||||
|                  } | ||||
|               } | ||||
|            } | ||||
|      HandleErrors(true); | ||||
|      } | ||||
|   else | ||||
|      esyslog("no editing marks found!"); | ||||
| @@ -642,6 +670,7 @@ void cCuttingThread::Action(void) | ||||
| // --- cCutter --------------------------------------------------------------- | ||||
|  | ||||
| cCutter::cCutter(const char *FileName) | ||||
| :recordingInfo(FileName) | ||||
| { | ||||
|   cuttingThread = NULL; | ||||
|   error = false; | ||||
| @@ -676,9 +705,11 @@ bool cCutter::Start(void) | ||||
|            if (strcmp(originalVersionName, editedVersionName) != 0) { // names must be different! | ||||
|               cRecordingUserCommand::InvokeCommand(RUC_EDITINGRECORDING, editedVersionName, originalVersionName); | ||||
|               if (cVideoDirectory::RemoveVideoFile(editedVersionName) && MakeDirs(editedVersionName, true)) { | ||||
|                  Recording.WriteInfo(editedVersionName); | ||||
|                  recordingInfo.Read(); | ||||
|                  recordingInfo.SetErrors(0); | ||||
|                  recordingInfo.SetFileName(editedVersionName); | ||||
|                  SetRecordingTimerId(editedVersionName, cString::sprintf("%d@%s", 0, Setup.SVDRPHostName)); | ||||
|                  cuttingThread = new cCuttingThread(originalVersionName, editedVersionName); | ||||
|                  cuttingThread = new cCuttingThread(originalVersionName, editedVersionName, &recordingInfo); | ||||
|                  return true; | ||||
|                  } | ||||
|               } | ||||
|   | ||||
							
								
								
									
										4
									
								
								cutter.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								cutter.h
									
									
									
									
									
								
							| @@ -4,12 +4,13 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: cutter.h 3.1 2013/10/05 11:34:55 kls Exp $ | ||||
|  * $Id: cutter.h 5.1 2024/09/19 20:21:58 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __CUTTER_H | ||||
| #define __CUTTER_H | ||||
|  | ||||
| #include "recording.h" | ||||
| #include "thread.h" | ||||
| #include "tools.h" | ||||
|  | ||||
| @@ -19,6 +20,7 @@ class cCutter { | ||||
| private: | ||||
|   cString originalVersionName; | ||||
|   cString editedVersionName; | ||||
|   cRecordingInfo recordingInfo; | ||||
|   cCuttingThread *cuttingThread; | ||||
|   bool error; | ||||
| public: | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: recording.c 5.33 2024/09/19 12:06:55 kls Exp $ | ||||
|  * $Id: recording.c 5.34 2024/09/19 20:21:58 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "recording.h" | ||||
| @@ -2946,7 +2946,7 @@ bool cIndexFile::Write(bool Independent, uint16_t FileNumber, off_t FileOffset, | ||||
|   return f >= 0; | ||||
| } | ||||
|  | ||||
| bool cIndexFile::Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent, int *Length) | ||||
| bool cIndexFile::Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent, int *Length, bool *Errors, bool *Missing) | ||||
| { | ||||
|   if (CatchUp(Index)) { | ||||
|      if (Index >= 0 && Index <= last) { | ||||
| @@ -2966,6 +2966,10 @@ bool cIndexFile::Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *I | ||||
|            else | ||||
|               *Length = -1; | ||||
|            } | ||||
|         if (Errors) | ||||
|            *Errors = index[Index].errors; | ||||
|         if (Missing) | ||||
|            *Missing = index[Index].missing; | ||||
|         return true; | ||||
|         } | ||||
|      } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: recording.h 5.10 2024/09/19 09:49:02 kls Exp $ | ||||
|  * $Id: recording.h 5.11 2024/09/19 20:21:58 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __RECORDING_H | ||||
| @@ -504,7 +504,7 @@ public: | ||||
|   ~cIndexFile(); | ||||
|   bool Ok(void) { return index != NULL; } | ||||
|   bool Write(bool Independent, uint16_t FileNumber, off_t FileOffset, bool Errors = false, bool Missing = false); | ||||
|   bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent = NULL, int *Length = NULL); | ||||
|   bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent = NULL, int *Length = NULL, bool *Errors = NULL, bool *Missing = NULL); | ||||
|   const cErrors *GetErrors(void); | ||||
|        ///< Returns the frame indexes of errors in the recording (if any). | ||||
|   int GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber = NULL, off_t *FileOffset = NULL, int *Length = NULL); | ||||
|   | ||||
							
								
								
									
										4
									
								
								vdr.5
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								vdr.5
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ | ||||
| .\" License as specified in the file COPYING that comes with the | ||||
| .\" vdr distribution. | ||||
| .\" | ||||
| .\" $Id: vdr.5 5.10 2024/09/09 10:58:55 kls Exp $ | ||||
| .\" $Id: vdr.5 5.11 2024/09/19 20:21:58 kls Exp $ | ||||
| .\" | ||||
| .TH vdr 5 "27 Dec 2021" "2.7" "Video Disk Recorder Files" | ||||
| .SH NAME | ||||
| @@ -824,7 +824,7 @@ l l. | ||||
| The 'O' tag contains the number of errors that occurred during recording. | ||||
| If it is zero, the recording can be safely considered error free. The higher the value, | ||||
| the more damaged the recording is. | ||||
| If this is an edited recording, the number of errors is that of the original | ||||
| If this is an edited recording, the number of errors is that of the edited | ||||
| recording. | ||||
| .SS RESUME | ||||
| The file \fIresume\fR (if present in a recording directory) contains | ||||
|   | ||||
		Reference in New Issue
	
	Block a user