The info file of an edited recording now contains the number of errors in the edited version

This commit is contained in:
Klaus Schmidinger 2024-09-19 20:21:58 +02:00
parent 3d6b31b115
commit 292af5d4f4
7 changed files with 63 additions and 21 deletions

View File

@ -10009,3 +10009,8 @@ Video Disk Recorder Revision History
APIVERSNUM is now 30004. APIVERSNUM is now 30004.
- When the index file of a recording is regenerated, errors in the recording are now - When the index file of a recording is regenerated, errors in the recording are now
stored in the index file. 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.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __CONFIG_H
@ -27,8 +27,8 @@
// The plugin API's version number: // The plugin API's version number:
#define APIVERSION "4" #define APIVERSION "5"
#define APIVERSNUM 30004 #define APIVERSNUM 30005
// When loading plugins, VDR searches files by their APIVERSION, which // When loading plugins, VDR searches files by their APIVERSION, which
// is different from VDRVERSION. APIVERSION is a plain number, incremented // is different from VDRVERSION. APIVERSION is a plain number, incremented

View File

@ -4,12 +4,11 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 "cutter.h"
#include "menu.h" #include "menu.h"
#include "recording.h"
#include "remux.h" #include "remux.h"
#include "videodir.h" #include "videodir.h"
@ -232,6 +231,10 @@ private:
int numSequences; int numSequences;
off_t maxVideoFileSize; off_t maxVideoFileSize;
off_t fileSize; off_t fileSize;
int frameErrors;
time_t lastErrorHandling;
cString editedRecordingName;
cRecordingInfo *recordingInfo;
bool suspensionLogged; bool suspensionLogged;
int sequence; // cutting sequence int sequence; // cutting sequence
int delta; // time between two frames (PTS ticks) int delta; // time between two frames (PTS ticks)
@ -246,7 +249,7 @@ private:
cPatPmtParser patPmtParser; cPatPmtParser patPmtParser;
bool Throttled(void); bool Throttled(void);
bool SwitchFile(bool Force = false); 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); bool FramesAreEqual(int Index1, int Index2);
void GetPendingPackets(uchar *Buffer, int &Length, int Index); void GetPendingPackets(uchar *Buffer, int &Length, int Index);
// Gather all non-video TS packets from Index upward that either belong to // 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. // 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 FixFrame(uchar *Data, int &Length, bool Independent, int Index, bool CutIn, bool CutOut);
bool ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex); bool ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex);
void HandleErrors(bool Force = false);
protected: protected:
virtual void Action(void); virtual void Action(void);
public: public:
cCuttingThread(const char *FromFileName, const char *ToFileName); cCuttingThread(const char *FromFileName, const char *ToFileName, cRecordingInfo *RecordingInfo);
virtual ~cCuttingThread(); virtual ~cCuttingThread();
const char *Error(void) { return error; } 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) :cThread("video cutting", true)
{ {
error = NULL; error = NULL;
@ -274,6 +278,10 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
framesPerSecond = Recording.FramesPerSecond(); framesPerSecond = Recording.FramesPerSecond();
suspensionLogged = false; suspensionLogged = false;
fileSize = 0; fileSize = 0;
frameErrors = 0;
lastErrorHandling = 0;
editedRecordingName = ToFileName;
recordingInfo = RecordingInfo;
sequence = 0; sequence = 0;
delta = int(round(PTSTICKS / framesPerSecond)); delta = int(round(PTSTICKS / framesPerSecond));
lastVidPts = -1; lastVidPts = -1;
@ -328,11 +336,11 @@ bool cCuttingThread::Throttled(void)
return false; 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; uint16_t FileNumber;
off_t FileOffset; 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); fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
if (fromFile) { if (fromFile) {
fromFile->SetReadAhead(MEGABYTE(20)); 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++) { for (int Index = BeginIndex; Running() && Index < EndIndex; Index++) {
bool Independent; bool Independent;
int Length; 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: // Make sure there is enough disk space:
AssertFreeDiskSpace(-1); AssertFreeDiskSpace(-1);
bool CutIn = !SeamlessBegin && Index == BeginIndex; bool CutIn = !SeamlessBegin && Index == BeginIndex;
@ -572,10 +582,12 @@ bool cCuttingThread::ProcessSequence(int LastEndIndex, int BeginIndex, int EndIn
return false; return false;
} }
// Write index: // Write index:
if (!DeletedFrame && !toIndex->Write(Independent, toFileName->Number(), fileSize)) { if (!DeletedFrame && !toIndex->Write(Independent, toFileName->Number(), fileSize, Errors, Missing)) {
error = "toIndex"; error = "toIndex";
return false; return false;
} }
frameErrors += Errors + Missing;
HandleErrors();
// Write data: // Write data:
if (toFile->Write(Buffer, Length) < 0) { if (toFile->Write(Buffer, Length) < 0) {
error = "safe_write"; error = "safe_write";
@ -596,6 +608,21 @@ bool cCuttingThread::ProcessSequence(int LastEndIndex, int BeginIndex, int EndIn
return true; 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) void cCuttingThread::Action(void)
{ {
if (cMark *BeginMark = fromMarks.GetNextBegin()) { if (cMark *BeginMark = fromMarks.GetNextBegin()) {
@ -634,6 +661,7 @@ void cCuttingThread::Action(void)
} }
} }
} }
HandleErrors(true);
} }
else else
esyslog("no editing marks found!"); esyslog("no editing marks found!");
@ -642,6 +670,7 @@ void cCuttingThread::Action(void)
// --- cCutter --------------------------------------------------------------- // --- cCutter ---------------------------------------------------------------
cCutter::cCutter(const char *FileName) cCutter::cCutter(const char *FileName)
:recordingInfo(FileName)
{ {
cuttingThread = NULL; cuttingThread = NULL;
error = false; error = false;
@ -676,9 +705,11 @@ bool cCutter::Start(void)
if (strcmp(originalVersionName, editedVersionName) != 0) { // names must be different! if (strcmp(originalVersionName, editedVersionName) != 0) { // names must be different!
cRecordingUserCommand::InvokeCommand(RUC_EDITINGRECORDING, editedVersionName, originalVersionName); cRecordingUserCommand::InvokeCommand(RUC_EDITINGRECORDING, editedVersionName, originalVersionName);
if (cVideoDirectory::RemoveVideoFile(editedVersionName) && MakeDirs(editedVersionName, true)) { 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)); SetRecordingTimerId(editedVersionName, cString::sprintf("%d@%s", 0, Setup.SVDRPHostName));
cuttingThread = new cCuttingThread(originalVersionName, editedVersionName); cuttingThread = new cCuttingThread(originalVersionName, editedVersionName, &recordingInfo);
return true; return true;
} }
} }

View File

@ -4,12 +4,13 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __CUTTER_H
#define __CUTTER_H #define __CUTTER_H
#include "recording.h"
#include "thread.h" #include "thread.h"
#include "tools.h" #include "tools.h"
@ -19,6 +20,7 @@ class cCutter {
private: private:
cString originalVersionName; cString originalVersionName;
cString editedVersionName; cString editedVersionName;
cRecordingInfo recordingInfo;
cCuttingThread *cuttingThread; cCuttingThread *cuttingThread;
bool error; bool error;
public: public:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "recording.h"
@ -2946,7 +2946,7 @@ bool cIndexFile::Write(bool Independent, uint16_t FileNumber, off_t FileOffset,
return f >= 0; 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 (CatchUp(Index)) {
if (Index >= 0 && Index <= last) { if (Index >= 0 && Index <= last) {
@ -2966,6 +2966,10 @@ bool cIndexFile::Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *I
else else
*Length = -1; *Length = -1;
} }
if (Errors)
*Errors = index[Index].errors;
if (Missing)
*Missing = index[Index].missing;
return true; return true;
} }
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __RECORDING_H
@ -504,7 +504,7 @@ public:
~cIndexFile(); ~cIndexFile();
bool Ok(void) { return index != NULL; } bool Ok(void) { return index != NULL; }
bool Write(bool Independent, uint16_t FileNumber, off_t FileOffset, bool Errors = false, bool Missing = false); 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); const cErrors *GetErrors(void);
///< Returns the frame indexes of errors in the recording (if any). ///< 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); int GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber = NULL, off_t *FileOffset = NULL, int *Length = NULL);

4
vdr.5
View File

@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the .\" License as specified in the file COPYING that comes with the
.\" vdr distribution. .\" 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" .TH vdr 5 "27 Dec 2021" "2.7" "Video Disk Recorder Files"
.SH NAME .SH NAME
@ -824,7 +824,7 @@ l l.
The 'O' tag contains the number of errors that occurred during recording. 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, If it is zero, the recording can be safely considered error free. The higher the value,
the more damaged the recording is. 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. recording.
.SS RESUME .SS RESUME
The file \fIresume\fR (if present in a recording directory) contains The file \fIresume\fR (if present in a recording directory) contains