Errors are now shown as diamond shaped markers in the replay progress display of the default skins

This commit is contained in:
Klaus Schmidinger 2024-09-19 09:49:02 +02:00
parent 32d8e473fb
commit 9e523073aa
15 changed files with 139 additions and 25 deletions

View File

@ -9984,7 +9984,7 @@ Video Disk Recorder Revision History
version numbering. Version numbers are simply counted upwards, with each of the three
parts ("version", "major", "minor") always being a single digit, and '0' being skipped.
2024-09-18:
2024-09-19:
- Fix for compilers that don't like non-constant format strings (thanks to Stefan Hofmann).
- Deprecated code is now marked with [[deprecated]] to issue a compile time warning when
@ -10002,3 +10002,8 @@ Video Disk Recorder Revision History
- Now distinguishing between frames with errors and completely missing frames.
- Recording errors are now marked in the index file.
- Fixed description of cSkinDisplayReplay::SetRecording().
- Errors are now shown as diamond shaped markers in the replay progress display of the
default skins. Plugin authors can switch to the new constructor of cProgressBar to
benefit from this feature. Of course this only works with recordings that have error
information stored in their index file.
APIVERSNUM is now 30004.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 5.20 2024/09/12 12:48:40 kls Exp $
* $Id: config.h 5.21 2024/09/19 09:49:02 kls Exp $
*/
#ifndef __CONFIG_H
@ -27,8 +27,8 @@
// The plugin API's version number:
#define APIVERSION "3"
#define APIVERSNUM 30003
#define APIVERSION "4"
#define APIVERSNUM 30004
// When loading plugins, VDR searches files by their APIVERSION, which
// is different from VDRVERSION. APIVERSION is a plain number, incremented

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbplayer.c 5.3 2022/12/27 15:57:20 kls Exp $
* $Id: dvbplayer.c 5.4 2024/09/19 09:49:02 kls Exp $
*/
#include "dvbplayer.h"
@ -283,6 +283,7 @@ public:
void Goto(int Position, bool Still = false);
virtual double FramesPerSecond(void) { return framesPerSecond; }
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId);
virtual const cErrors *GetErrors(void);
virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
virtual bool GetFrameNumber(int &Current, int &Total);
virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
@ -940,6 +941,13 @@ void cDvbPlayer::SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
resyncAfterPause = true;
}
const cErrors *cDvbPlayer::GetErrors(void)
{
if (index)
return index->GetErrors();
return NULL;
}
bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
{
if (index) {
@ -1047,6 +1055,13 @@ int cDvbPlayerControl::SkipFrames(int Frames)
return -1;
}
const cErrors *cDvbPlayerControl::GetErrors(void)
{
if (player)
return player->GetErrors();
return NULL;
}
bool cDvbPlayerControl::GetIndex(int &Current, int &Total, bool SnapToIFrame)
{
if (player) {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbplayer.h 4.2 2016/12/22 10:36:50 kls Exp $
* $Id: dvbplayer.h 5.1 2024/09/19 09:49:02 kls Exp $
*/
#ifndef __DVBPLAYER_H
@ -47,6 +47,8 @@ public:
// The sign of 'Seconds' determines the direction in which to skip.
// Use a very large negative value to go all the way back to the
// beginning of the recording.
const cErrors *GetErrors(void);
// Returns the frame indexes of errors in the recording (if any).
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
// Returns the current and total frame index, optionally snapped to the
// nearest I-frame.

12
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 5.16 2024/08/30 20:43:26 kls Exp $
* $Id: menu.c 5.17 2024/09/19 09:49:02 kls Exp $
*/
#include "menu.h"
@ -5709,6 +5709,7 @@ cReplayControl::cReplayControl(bool PauseLive)
displayReplay = NULL;
marksModified = false;
visible = modeOnly = shown = displayFrames = false;
lastErrors = 0;
lastCurrent = lastTotal = -1;
lastPlay = lastForward = false;
lastSpeed = -2; // an invalid value
@ -5882,6 +5883,7 @@ bool cReplayControl::ShowProgress(bool Initial)
if (!visible) {
displayReplay = Skins.Current()->DisplayReplay(modeOnly);
displayReplay->SetMarks(&marks);
displayReplay->SetErrors(GetErrors());
SetNeedsFastResponse(true);
visible = true;
}
@ -5893,7 +5895,9 @@ bool cReplayControl::ShowProgress(bool Initial)
}
lastCurrent = lastTotal = -1;
}
if (Current != lastCurrent || Total != lastTotal) {
const cErrors *Errors = GetErrors();
int NumErrors = Errors ? Errors->Size() : 0;
if (Current != lastCurrent || Total != lastTotal || NumErrors != lastErrors) {
if (Setup.ShowRemainingTime || Total != lastTotal) {
int Index = Total;
if (Setup.ShowRemainingTime)
@ -5902,10 +5906,12 @@ bool cReplayControl::ShowProgress(bool Initial)
}
displayReplay->SetProgress(Current, Total);
displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, FramesPerSecond()));
displayReplay->SetErrors(Errors);
displayReplay->Flush();
lastCurrent = Current;
lastTotal = Total;
lastErrors = NumErrors;
}
lastTotal = Total;
ShowMode();
updateTimer.Set(PROGRESSTIMEOUT);
return true;

3
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.h 5.3 2024/08/30 09:55:15 kls Exp $
* $Id: menu.h 5.4 2024/09/19 09:49:02 kls Exp $
*/
#ifndef __MENU_H
@ -297,6 +297,7 @@ private:
cMarks marks;
bool marksModified;
bool visible, modeOnly, shown, displayFrames;
int lastErrors;
int lastCurrent, lastTotal;
bool lastPlay, lastForward;
int lastSpeed;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: player.h 5.3 2024/09/09 22:15:59 kls Exp $
* $Id: player.h 5.4 2024/09/19 09:49:02 kls Exp $
*/
#ifndef __PLAYER_H
@ -54,6 +54,8 @@ public:
bool IsAttached(void) { return device != NULL; }
virtual double FramesPerSecond(void) { return DEFAULTFRAMESPERSECOND; }
// Returns the number of frames per second of the currently played material.
virtual const cErrors *GetErrors(void) { return NULL; }
// Returns the frame indexes of errors in the recording (if any).
virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { return false; }
// Returns the current and total frame index, optionally snapped to the
// nearest I-frame.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recorder.c 5.9 2024/09/17 11:30:28 kls Exp $
* $Id: recorder.c 5.10 2024/09/19 09:49:02 kls Exp $
*/
#include "recorder.h"
@ -167,6 +167,15 @@ void cRecorder::Action(void)
{
cTimeMs t(MAXBROKENTIMEOUT);
bool InfoWritten = false;
bool pendIndependentFrame = false;
uint16_t pendNumber = 0;
off_t pendFileSize = 0;
bool pendErrors = false;
bool pendMissing = false;
// Check if this is a resumed recording, in which case we definitely missed frames:
NextFile();
if (fileName->Number() > 1 || oldErrors)
frameDetector->SetMissing();
while (Running()) {
int r;
uchar *b = ringBuffer->Get(r);
@ -197,8 +206,15 @@ void cRecorder::Action(void)
int PreviousErrors = 0;
int MissingFrames = 0;
if (frameDetector->NewFrame(&PreviousErrors, &MissingFrames)) {
if (index)
index->Write(frameDetector->IndependentFrame(), fileName->Number(), fileSize);
if (index) {
if (pendNumber > 0)
index->Write(pendIndependentFrame, pendNumber, pendFileSize, pendErrors, pendMissing);
pendIndependentFrame = frameDetector->IndependentFrame();
pendNumber = fileName->Number();
pendFileSize = fileSize;
pendErrors = PreviousErrors;
pendMissing = MissingFrames;
}
if (PreviousErrors)
errors++;
if (MissingFrames)
@ -226,6 +242,9 @@ void cRecorder::Action(void)
}
}
if (t.TimedOut()) {
if (pendNumber > 0)
index->Write(pendIndependentFrame, pendNumber, pendFileSize, pendErrors, pendMissing);
frameDetector->SetMissing();
errors += MAXBROKENTIMEOUT / 1000 * frameDetector->FramesPerSecond();
HandleErrors(true);
esyslog("ERROR: video data stream broken");
@ -233,5 +252,7 @@ void cRecorder::Action(void)
t.Set(MAXBROKENTIMEOUT);
}
}
if (pendNumber > 0)
index->Write(pendIndependentFrame, pendNumber, pendFileSize, pendErrors, pendMissing);
HandleErrors(true);
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recording.c 5.31 2024/09/18 09:23:07 kls Exp $
* $Id: recording.c 5.32 2024/09/19 09:49:02 kls Exp $
*/
#include "recording.h"
@ -2728,6 +2728,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record, bool IsPesRecording, b
f = -1;
size = 0;
last = -1;
lastErrorIndex = last;
index = NULL;
isPesRecording = IsPesRecording;
indexFileGenerator = NULL;
@ -2948,6 +2949,17 @@ bool cIndexFile::Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *I
return false;
}
const cErrors *cIndexFile::GetErrors(void)
{
for (int Index = lastErrorIndex + 1; Index <= last; Index++) {
tIndexTs *p = &index[Index];
if (p->errors || p->missing)
errors.Append(Index);
}
lastErrorIndex = last;
return &errors;
}
int cIndexFile::GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber, off_t *FileOffset, int *Length)
{
if (CatchUp()) {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recording.h 5.9 2024/09/18 09:23:07 kls Exp $
* $Id: recording.h 5.10 2024/09/19 09:49:02 kls Exp $
*/
#ifndef __RECORDING_H
@ -446,6 +446,9 @@ public:
cMark *GetNextEnd(const cMark *BeginMark) { return const_cast<cMark *>(static_cast<const cMarks *>(this)->GetNextEnd(BeginMark)); }
};
class cErrors : public cVector<int> {
};
#define RUC_BEFORERECORDING "before"
#define RUC_STARTRECORDING "started"
#define RUC_AFTERRECORDING "after"
@ -486,9 +489,11 @@ private:
int f;
cString fileName;
int size, last;
int lastErrorIndex;
tIndexTs *index;
bool isPesRecording;
cResumeFile resumeFile;
cErrors errors;
cIndexFileGenerator *indexFileGenerator;
cMutex mutex;
void ConvertFromPes(tIndexTs *IndexTs, int Count);
@ -500,6 +505,8 @@ public:
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);
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);
int GetClosestIFrame(int Index);
///< Returns the index of the I-frame that is closest to the given Index (or Index itself,

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skinclassic.c 5.2 2023/12/29 10:48:40 kls Exp $
* $Id: skinclassic.c 5.3 2024/09/19 09:49:02 kls Exp $
*/
#include "skinclassic.h"
@ -71,6 +71,7 @@ THEME_CLR(Theme, clrReplayProgressRest, clrWhite);
THEME_CLR(Theme, clrReplayProgressSelected, clrRed);
THEME_CLR(Theme, clrReplayProgressMark, clrBlack);
THEME_CLR(Theme, clrReplayProgressCurrent, clrRed);
THEME_CLR(Theme, clrReplayProgressError, clrBlack);
// --- cSkinClassicDisplayChannel --------------------------------------------
@ -534,7 +535,7 @@ void cSkinClassicDisplayReplay::SetMode(bool Play, bool Forward, int Speed)
void cSkinClassicDisplayReplay::SetProgress(int Current, int Total)
{
cProgressBar pb(x1 - x0, y2 - y1, Current, Total, marks, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent));
cProgressBar pb(x1 - x0, y2 - y1, Current, Total, marks, errors, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent), Theme.Color(clrReplayProgressError));
osd->DrawBitmap(x0, y1, pb);
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skinlcars.c 5.5 2024/07/13 15:25:22 kls Exp $
* $Id: skinlcars.c 5.6 2024/09/19 09:49:02 kls Exp $
*/
// "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures,
@ -188,6 +188,7 @@ THEME_CLR(Theme, clrReplayProgressRest, RgbShade(CLR_WHITE, -0.2));
THEME_CLR(Theme, clrReplayProgressSelected, CLR_EXPOSED);
THEME_CLR(Theme, clrReplayProgressMark, CLR_BLACK);
THEME_CLR(Theme, clrReplayProgressCurrent, CLR_EXPOSED);
THEME_CLR(Theme, clrReplayProgressError, CLR_BLACK);
// Track display:
@ -1928,7 +1929,7 @@ void cSkinLCARSDisplayReplay::SetMode(bool Play, bool Forward, int Speed)
void cSkinLCARSDisplayReplay::SetProgress(int Current, int Total)
{
cProgressBar pb(xp13 - xp03, lineHeight, Current, Total, marks, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent));
cProgressBar pb(xp13 - xp03, lineHeight, Current, Total, marks, errors, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent), Theme.Color(clrReplayProgressError));
osd->DrawBitmap(xp03, yp02, pb);
}

36
skins.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skins.c 5.2 2024/07/13 09:12:18 kls Exp $
* $Id: skins.c 5.3 2024/09/19 09:49:02 kls Exp $
*/
#include "skins.h"
@ -147,6 +147,11 @@ const cFont *cSkinDisplayMenu::GetTextAreaFont(bool FixedFont) const
// --- cSkinDisplayReplay::cProgressBar --------------------------------------
cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent)
:cSkinDisplayReplay::cProgressBar::cProgressBar(Width, Height, Current, Total, Marks, NULL, ColorSeen, ColorRest, ColorSelected, ColorMark, ColorCurrent, clrBlack)
{
}
cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, const cErrors *Errors, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent, tColor ColorError)
:cBitmap(Width, Height, 2)
{
total = Total;
@ -168,6 +173,16 @@ cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Curren
Start = !Start;
}
}
if (Errors) {
int LastPos = -1;
for (int i = 0; i < Errors->Size(); i++) {
int p1 = Errors->At(i);
if (p1 != LastPos) {
Error(Pos(Errors->At(i)), ColorError);
LastPos = p1;
}
}
}
}
}
@ -181,11 +196,25 @@ void cSkinDisplayReplay::cProgressBar::Mark(int x, bool Start, bool Current, tCo
}
}
void cSkinDisplayReplay::cProgressBar::Error(int x, tColor ColorError)
{
const int d = (Height() / 9) & ~0x01; // must be even
const int h = Height() / 2;
const int e = Height() / 4;
DrawRectangle(x, e, x, Height() -e - 1, ColorError);
DrawRectangle(x - d, h, x + d, h, ColorError);
for (int i = 1; i <= d; i++) {
DrawRectangle(x - d + i, h - i, x + d - i, h - i, ColorError);
DrawRectangle(x - d + i, h + i, x + d - i, h + i, ColorError);
}
}
// --- cSkinDisplayReplay ----------------------------------------------------
cSkinDisplayReplay::cSkinDisplayReplay(void)
{
marks = NULL;
errors = NULL;
}
void cSkinDisplayReplay::SetRecording(const cRecording *Recording)
@ -198,6 +227,11 @@ void cSkinDisplayReplay::SetMarks(const cMarks *Marks)
marks = Marks;
}
void cSkinDisplayReplay::SetErrors(const cErrors *Errors)
{
errors = Errors;
}
// --- cSkin -----------------------------------------------------------------
cSkin::cSkin(const char *Name, cTheme *Theme)

10
skins.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skins.h 5.5 2024/09/18 11:06:39 kls Exp $
* $Id: skins.h 5.6 2024/09/19 09:49:02 kls Exp $
*/
#ifndef __SKINS_H
@ -311,19 +311,25 @@ class cSkinDisplayReplay : public cSkinDisplay {
///< a recording.
protected:
const cMarks *marks;
const cErrors *errors;
class cProgressBar : public cBitmap {
protected:
int total;
int Pos(int p) { return int(int64_t(p) * Width() / total); }
void Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent);
void Error(int x, tColor ColorError);
public:
cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent);
cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent); // for backwards compatibility
cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, const cErrors *Errors, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent, tColor ColorError);
};
public:
cSkinDisplayReplay(void);
virtual void SetMarks(const cMarks *Marks);
///< Sets the editing marks to Marks, which shall be used to display the
///< progress bar through a cProgressBar object.
virtual void SetErrors(const cErrors *Errors);
///< Sets the errors found in the recording to Errors, which shall be used to display the
///< progress bar through a cProgressBar object.
virtual void SetRecording(const cRecording *Recording);
///< Sets the recording that is currently being played.
///< The default implementation calls SetTitle() with the title

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skinsttng.c 5.2 2023/12/29 10:48:40 kls Exp $
* $Id: skinsttng.c 5.3 2024/09/19 09:49:02 kls Exp $
*/
// "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures
@ -122,6 +122,7 @@ THEME_CLR(Theme, clrReplayProgressRest, clrWhite);
THEME_CLR(Theme, clrReplayProgressSelected, clrRed);
THEME_CLR(Theme, clrReplayProgressMark, clrBlack);
THEME_CLR(Theme, clrReplayProgressCurrent, clrRed);
THEME_CLR(Theme, clrReplayProgressError, clrBlack);
// --- cSkinSTTNGDisplayChannel ----------------------------------------------
@ -904,7 +905,7 @@ void cSkinSTTNGDisplayReplay::SetMode(bool Play, bool Forward, int Speed)
void cSkinSTTNGDisplayReplay::SetProgress(int Current, int Total)
{
cProgressBar pb(x4 - x3, y4 - y3, Current, Total, marks, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent));
cProgressBar pb(x4 - x3, y4 - y3, Current, Total, marks, errors, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent), Theme.Color(clrReplayProgressError));
osd->DrawBitmap(x3, y3, pb);
}