From 15bb8ca60db165833441e44da6d8861e9a7df0ad Mon Sep 17 00:00:00 2001
From: Klaus Schmidinger <vdr@tvdr.de>
Date: Mon, 15 Oct 2012 11:23:59 +0200
Subject: If a frame position in the 'marks' file of a recording doesn't point
 to an I-frame, it will now be shifted towards the next I-frame

---
 HISTORY      |  5 ++++-
 UPDATE-2.0.0 |  3 +++
 recording.c  | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 recording.h  | 10 +++++++++-
 vdr.5        | 10 +++++-----
 5 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/HISTORY b/HISTORY
index 5fdc7b47..2f6a560c 100644
--- a/HISTORY
+++ b/HISTORY
@@ -7272,7 +7272,7 @@ Video Disk Recorder Revision History
   ".keep" to prevent a directory from being deleted when it is empty. Currently the
   only file name that is ignored is ".sort".
 
-2012-10-13: Version 1.7.32
+2012-10-15: Version 1.7.32
 
 - Pressing the Play key during normal live viewing mode now opens the Recordings menu
   if there is no "last viewed" recording (thanks to Alexander Wenzel).
@@ -7298,3 +7298,6 @@ Video Disk Recorder Revision History
   Make.config.template.
 - Fixed handling VPS timers in case the running status of an event goes to '1' (not
   running) and later goes to '4' (running).
+- If a frame position in the 'marks' file of a recording doesn't point to an I-frame,
+  it will now be shifted towards the next I-frame (either up or down, whichever is
+  closer).
diff --git a/UPDATE-2.0.0 b/UPDATE-2.0.0
index 30f3cbbd..e65ab45f 100644
--- a/UPDATE-2.0.0
+++ b/UPDATE-2.0.0
@@ -327,6 +327,9 @@ Recordings:
   This obsoletes the CUTTIME patch.
 - An ongoing editing process is now canceled if either the original or the edited
   version of the recording is deleted from the Recordings menu.
+- If a frame position in the 'marks' file of a recording doesn't point to an I-frame,
+  it will now be shifted towards the next I-frame (either up or down, whichever is
+  closer).
 
 SVDRP:
 
diff --git a/recording.c b/recording.c
index 783a46e5..71272fca 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.c 2.66 2012/10/04 12:21:38 kls Exp $
+ * $Id: recording.c 2.67 2012/10/15 10:23:37 kls Exp $
  */
 
 #include "recording.h"
@@ -1358,8 +1358,10 @@ bool cMark::Save(FILE *f)
 
 bool cMarks::Load(const char *RecordingFileName, double FramesPerSecond, bool IsPesRecording)
 {
+  recordingFileName = RecordingFileName;
   fileName = AddDirectory(RecordingFileName, IsPesRecording ? MARKSFILESUFFIX ".vdr" : MARKSFILESUFFIX);
   framesPerSecond = FramesPerSecond;
+  isPesRecording = IsPesRecording;
   nextUpdate = 0;
   lastFileTime = -1; // the first call to Load() must take place!
   lastChange = 0;
@@ -1388,6 +1390,7 @@ bool cMarks::Update(void)
         cMutexLock MutexLock(&MutexMarkFramesPerSecond);
         MarkFramesPerSecond = framesPerSecond;
         if (cConfig<cMark>::Load(fileName)) {
+           Align();
            Sort();
            return true;
            }
@@ -1396,6 +1399,18 @@ bool cMarks::Update(void)
   return false;
 }
 
+void cMarks::Align(void)
+{
+  cIndexFile IndexFile(recordingFileName, isPesRecording);
+  for (cMark *m = First(); m; m = Next(m)) {
+      int p = IndexFile.GetClosestIFrame(m->Position());
+      if (int d = m->Position() - p) {
+         isyslog("aligned editing mark %s to %s (off by %d frame%s)", *IndexToHMSF(m->Position(), true, framesPerSecond), *IndexToHMSF(p, true, framesPerSecond), d, abs(d) > 1 ? "s" : "");
+         m->SetPosition(p);
+         }
+      }
+}
+
 void cMarks::Sort(void)
 {
   for (cMark *m1 = First(); m1; m1 = Next(m1)) {
@@ -1882,6 +1897,34 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber, off
   return -1;
 }
 
+int cIndexFile::GetClosestIFrame(int Index)
+{
+  if (last > 0) {
+     Index = constrain(Index, 0, last - 1);
+     if (index[Index].independent)
+        return Index;
+     int il = Index - 1;
+     int ih = Index + 1;
+     for (;;) {
+         if (il >= 0) {
+            if (index[il].independent)
+               return il;
+            il--;
+            }
+         else if (ih >= last)
+            break;
+         if (ih < last) {
+            if (index[ih].independent)
+               return ih;
+            ih++;
+            }
+         else if (il < 0)
+            break;
+         }
+     }
+  return 0;
+}
+
 int cIndexFile::Get(uint16_t FileNumber, off_t FileOffset)
 {
   if (CatchUp()) {
diff --git a/recording.h b/recording.h
index ac44ad5b..22c5d3a7 100644
--- a/recording.h
+++ b/recording.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: recording.h 2.37 2012/09/17 08:53:23 kls Exp $
+ * $Id: recording.h 2.38 2012/10/15 10:22:27 kls Exp $
  */
 
 #ifndef __RECORDING_H
@@ -222,14 +222,17 @@ public:
 
 class cMarks : public cConfig<cMark> {
 private:
+  cString recordingFileName;
   cString fileName;
   double framesPerSecond;
+  bool isPesRecording;
   time_t nextUpdate;
   time_t lastFileTime;
   time_t lastChange;
 public:
   bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false);
   bool Update(void);
+  void Align(void);
   void Sort(void);
   cMark *Add(int Position);
   cMark *Get(int Position);
@@ -291,6 +294,11 @@ public:
   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);
+  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.
   int Get(uint16_t FileNumber, off_t FileOffset);
   int Last(void) { CatchUp(); return last; }
   int GetResume(void) { return resumeFile.Read(); }
diff --git a/vdr.5 b/vdr.5
index a606dde8..4003a5e9 100644
--- a/vdr.5
+++ b/vdr.5
@@ -8,7 +8,7 @@
 .\" License as specified in the file COPYING that comes with the
 .\" vdr distribution.
 .\"
-.\" $Id: vdr.5 2.29 2012/03/10 14:56:01 kls Exp $
+.\" $Id: vdr.5 2.30 2012/10/15 10:50:23 kls Exp $
 .\"
 .TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
 .SH NAME
@@ -815,13 +815,13 @@ least one blank.
 The lines in this file need not necessarily appear in the correct temporal
 sequence, they will be automatically sorted by time index.
 
+If a frame position doesn't point to an I-frame of the corresponding recording,
+it will be shifted towards the next I-frame (either up or down, whichever is
+closer).
+
 \fBCURRENT RESTRICTIONS:\fR
 
 -\ the comment is currently not used by VDR
-.br
--\ marks must have a frame number, and that frame MUST be an I-frame (this
-means that only marks generated by VDR itself can be used, since they
-will always be guaranteed to mark I-frames).
 .SS EPG DATA
 The file \fIepg.data\fR contains the EPG data in an easily parsable format.
 The first character of each line defines what kind of data this line contains.
-- 
cgit v1.2.3