avidemux: tweak KEY_UNIT SNAP seek handling
authorMark Nauwelaerts <mnauw@users.sourceforge.net>
Thu, 29 Dec 2016 10:26:33 +0000 (11:26 +0100)
committerMark Nauwelaerts <mnauw@users.sourceforge.net>
Thu, 29 Dec 2016 11:48:50 +0000 (12:48 +0100)
Previously, seeking to position y where y is (strictly) within a keyframe
would seek to that keyframe both with SNAP_BEFORE and SNAP_AFTER,
where the latter is now adjusted to really snap to the next keyframe.

gst/avi/gstavidemux.c

index 3964163..bd5ea72 100644 (file)
@@ -72,8 +72,8 @@ static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
 
 #ifndef GST_DISABLE_GST_DEBUG
 static const char *const snap_types[2][2] = {
-  {"any", "before"},
-  {"after", "nearest"},
+  {"any", "after"},
+  {"before", "nearest"},
 };
 #endif
 
@@ -2608,8 +2608,9 @@ gst_avi_demux_index_entry_search (GstAviIndexEntry * entry, guint64 * total)
  * @avi: Avi object
  * @stream: the stream
  * @time: a time position
+ * @next: whether to look for entry before or after @time
  *
- * Finds the index entry which time is less or equal than the requested time.
+ * Finds the index entry which time is less/more or equal than the requested time.
  * Try to avoid binary search when we can convert the time to an index
  * position directly (for example for video frames with a fixed duration).
  *
@@ -2617,7 +2618,7 @@ gst_avi_demux_index_entry_search (GstAviIndexEntry * entry, guint64 * total)
  */
 static guint
 gst_avi_demux_index_for_time (GstAviDemux * avi,
-    GstAviStream * stream, guint64 time)
+    GstAviStream * stream, guint64 time, gboolean next)
 {
   guint index = -1;
   guint64 total;
@@ -2638,6 +2639,14 @@ gst_avi_demux_index_for_time (GstAviDemux * avi,
       total = avi_stream_convert_time_to_frames_unchecked (stream, time);
     } else {
       index = avi_stream_convert_time_to_frames_unchecked (stream, time);
+      /* this entry typically undershoots the target time,
+       * so check a bit more if next needed */
+      if (next) {
+        GstClockTime itime =
+            avi_stream_convert_frames_to_time_unchecked (stream, index);
+        if (itime < time && index + 1 < stream->idx_n)
+          index++;
+      }
     }
   } else if (stream->strh->type == GST_RIFF_FCC_auds) {
     /* constant rate stream */
@@ -2655,7 +2664,7 @@ gst_avi_demux_index_for_time (GstAviDemux * avi,
     entry = gst_util_array_binary_search (stream->index,
         stream->idx_n, sizeof (GstAviIndexEntry),
         (GCompareDataFunc) gst_avi_demux_index_entry_search,
-        GST_SEARCH_MODE_BEFORE, &total, NULL);
+        next ? GST_SEARCH_MODE_AFTER : GST_SEARCH_MODE_BEFORE, &total, NULL);
 
     if (entry == NULL) {
       GST_LOG_OBJECT (avi, "not found, assume index 0");
@@ -4447,6 +4456,7 @@ gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment,
   gboolean keyframe, before, after;
   guint i, index;
   GstAviStream *stream;
+  gboolean next;
 
   seek_time = segment->position;
   keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
@@ -4461,20 +4471,18 @@ gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment,
    * which is mostly correct... */
   stream = &avi->stream[avi->main_stream];
 
+  next = after && !before;
+  if (segment->rate < 0)
+    next = !next;
+
   /* get the entry index for the requested position */
-  index = gst_avi_demux_index_for_time (avi, stream, seek_time);
+  index = gst_avi_demux_index_for_time (avi, stream, seek_time, next);
   GST_DEBUG_OBJECT (avi, "Got entry %u", index);
   if (index == -1)
     return FALSE;
 
   /* check if we are already on a keyframe */
   if (!ENTRY_IS_KEYFRAME (&stream->index[index])) {
-    gboolean next;
-
-    next = after && !before;
-    if (segment->rate < 0)
-      next = !next;
-
     if (next) {
       GST_DEBUG_OBJECT (avi, "not keyframe, searching forward");
       /* now go to the next keyframe, this is where we should start
@@ -4518,7 +4526,7 @@ gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment,
       continue;
 
     /* get the entry index for the requested position */
-    index = gst_avi_demux_index_for_time (avi, ostream, seek_time);
+    index = gst_avi_demux_index_for_time (avi, ostream, seek_time, FALSE);
     if (index == -1)
       continue;
 
@@ -4686,7 +4694,7 @@ avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
   GstSeekFlags flags;
   GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
   gint64 cur, stop;
-  gboolean keyframe, before, after;
+  gboolean keyframe, before, after, next;
   GstAviStream *stream;
   guint index;
   guint n, str_num;
@@ -4746,8 +4754,12 @@ avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
   str_num = avi->main_stream;
   stream = &avi->stream[str_num];
 
+  next = after && !before;
+  if (seeksegment.rate < 0)
+    next = !next;
+
   /* get the entry index for the requested position */
-  index = gst_avi_demux_index_for_time (avi, stream, cur);
+  index = gst_avi_demux_index_for_time (avi, stream, cur, next);
   GST_DEBUG_OBJECT (avi, "str %u: Found entry %u for %" GST_TIME_FORMAT,
       str_num, index, GST_TIME_ARGS (cur));
   if (index == -1)
@@ -4755,12 +4767,6 @@ avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
 
   /* check if we are already on a keyframe */
   if (!ENTRY_IS_KEYFRAME (&stream->index[index])) {
-    gboolean next;
-
-    next = after && !before;
-    if (seeksegment.rate < 0)
-      next = !next;
-
     if (next) {
       GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching forward");
       /* now go to the next keyframe, this is where we should start
@@ -4799,7 +4805,7 @@ avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
       continue;
 
     /* get the entry index for the requested position */
-    idx = gst_avi_demux_index_for_time (avi, str, cur);
+    idx = gst_avi_demux_index_for_time (avi, str, cur, FALSE);
     GST_DEBUG_OBJECT (avi, "str %u: Found entry %u for %" GST_TIME_FORMAT, n,
         idx, GST_TIME_ARGS (cur));
     if (idx == -1)
@@ -4807,7 +4813,7 @@ avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
 
     /* check if we are already on a keyframe */
     if (!ENTRY_IS_KEYFRAME (&str->index[idx])) {
-      if (after && !before) {
+      if (next) {
         GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching forward");
         /* now go to the next keyframe, this is where we should start
          * decoding from. */