gst/qtdemux/qtdemux.c: Make sure we we don't clip the segment's stop using the main...
authorJulien Moutte <julien@moutte.net>
Sat, 31 May 2008 15:30:41 +0000 (15:30 +0000)
committerJulien Moutte <julien@moutte.net>
Sat, 31 May 2008 15:30:41 +0000 (15:30 +0000)
Original commit message from CVS:
2008-05-31  Julien Moutte  <julien@fluendo.com>

* gst/qtdemux/qtdemux.c: (gst_qtdemux_find_keyframe),
(gst_qtdemux_find_segment), (gst_qtdemux_perform_seek),
(gst_qtdemux_seek_to_previous_keyframe),
(gst_qtdemux_activate_segment), (gst_qtdemux_loop): Make sure we
we don't clip the segment's stop using the main segment duration
as
that could crop quite some video frames. Make reverse playback
support
more robust and support edit lists. Support seeking to the last
frame,
and fix reverse looping playback. Add some debugging.
* win32/common/config.h: Updated.

ChangeLog
gst/qtdemux/qtdemux.c
win32/common/config.h

index 6cf801d..1f956df 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2008-05-31  Julien Moutte  <julien@fluendo.com>
+
+       * gst/qtdemux/qtdemux.c: (gst_qtdemux_find_keyframe),
+       (gst_qtdemux_find_segment), (gst_qtdemux_perform_seek),
+       (gst_qtdemux_seek_to_previous_keyframe),
+       (gst_qtdemux_activate_segment), (gst_qtdemux_loop): Make sure we
+       we don't clip the segment's stop using the main segment duration as
+       that could crop quite some video frames. Make reverse playback support
+       more robust and support edit lists. Support seeking to the last frame,
+       and fix reverse looping playback. Add some debugging.
+       * win32/common/config.h: Updated.
+
 2008-05-31  Sebastian Dröge  <slomo@circular-chaos.org>
 
        * gst/equalizer/gstiirequalizer.c:
index 5290fb1..6b87dad 100644 (file)
@@ -528,24 +528,35 @@ static guint32
 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
     guint32 index)
 {
-  if (index >= str->n_samples)
-    return str->n_samples;
+  guint32 new_index = index;
+
+  if (index >= str->n_samples) {
+    new_index = str->n_samples;
+    goto beach;
+  }
 
   /* all keyframes, return index */
-  if (str->all_keyframe)
-    return index;
+  if (str->all_keyframe) {
+    new_index = index;
+    goto beach;
+  }
 
   /* else go back until we have a keyframe */
   while (TRUE) {
-    if (str->samples[index].keyframe)
+    if (str->samples[new_index].keyframe)
       break;
 
-    if (index == 0)
+    if (new_index == 0)
       break;
 
-    index--;
+    new_index--;
   }
-  return index;
+
+beach:
+  GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
+      "gave %u", index, new_index);
+
+  return new_index;
 }
 
 /* find the segment for @time_position for @stream
@@ -572,10 +583,19 @@ gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
 
-    if (segment->time <= time_position && time_position < segment->stop_time) {
-      GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
-      seg_idx = i;
-      break;
+    /* For the last segment we include stop_time in the last segment */
+    if (i < stream->n_segments - 1) {
+      if (segment->time <= time_position && time_position < segment->stop_time) {
+        GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
+        seg_idx = i;
+        break;
+      }
+    } else {
+      if (segment->time <= time_position && time_position <= segment->stop_time) {
+        GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
+        seg_idx = i;
+        break;
+      }
     }
   }
   return seg_idx;
@@ -671,8 +691,6 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
       /* find previous keyframe */
       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
 
-      GST_DEBUG_OBJECT (qtdemux, "keyframe at %u", kindex);
-
       /* if the keyframe is at a different position, we need to update the
        * requiested seek time */
       if (index != kindex) {
@@ -1078,16 +1096,17 @@ static GstFlowReturn
 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
 {
   guint8 n = 0;
-  guint32 seg_idx = 0, index = 0, kindex = 0;
-  guint64 desired_offset = 0, last_stop = 0, media_start = 0, seg_time = 0;
+  guint32 seg_idx = 0, k_index = 0;
+  guint64 k_pos = 0, last_stop = 0;
   QtDemuxSegment *seg = NULL;
-  QtDemuxStream *ref_str = NULL, *str = NULL;
+  QtDemuxStream *ref_str = NULL;
 
   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
    * and finally align all the other streams on that timestamp with their 
    * respective keyframes */
   for (n = 0; n < qtdemux->n_streams; n++) {
-    str = qtdemux->streams[n];
+    QtDemuxStream *str = qtdemux->streams[n];
+
     seg_idx = gst_qtdemux_find_segment (qtdemux, str,
         qtdemux->segment.last_stop);
 
@@ -1109,35 +1128,46 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
   }
 
   if (G_UNLIKELY (!ref_str)) {
-    GST_WARNING_OBJECT (qtdemux, "couldn't find any stream");
-    return GST_FLOW_ERROR;
+    GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
+    goto eos;
   }
 
   if (G_UNLIKELY (!ref_str->from_sample)) {
     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
-    return GST_FLOW_UNEXPECTED;
+    goto eos;
   }
 
   /* So that stream has been playing from from_sample to to_sample. We will
    * get the timestamp of the previous sample and search for a keyframe before
    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
   if (ref_str->subtype == FOURCC_vide) {
-    kindex = gst_qtdemux_find_keyframe (qtdemux, ref_str,
+    k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
         ref_str->from_sample - 1);
   } else {
-    kindex = ref_str->from_sample - 10;
+    k_index = ref_str->from_sample - 10;
   }
-  desired_offset = ref_str->samples[kindex].timestamp;
+
+  /* get current segment for that stream */
+  seg = &ref_str->segments[ref_str->segment_index];
+  /* Crawl back through segments to find the one containing this I frame */
+  while (ref_str->samples[k_index].timestamp < seg->media_start) {
+    GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
+        ref_str->segment_index);
+    if (G_UNLIKELY (!ref_str->segment_index)) {
+      /* Reached first segment, let's consider it's EOS */
+      goto eos;
+    }
+    ref_str->segment_index--;
+    seg = &ref_str->segments[ref_str->segment_index];
+  }
+  /* Calculate time position of the keyframe and where we should stop */
+  k_pos = (ref_str->samples[k_index].timestamp - seg->media_start) + seg->time;
   last_stop = ref_str->samples[ref_str->from_sample].timestamp;
-  /* Bring that back to global time */
-  seg = &ref_str->segments[seg_idx];
-  /* Sample global timestamp is timestamp - seg_start + seg_time */
-  desired_offset = (desired_offset - seg->media_start) + seg->time;
   last_stop = (last_stop - seg->media_start) + seg->time;
 
   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
-      kindex, GST_TIME_ARGS (desired_offset));
+      k_index, GST_TIME_ARGS (k_pos));
 
   /* Set last_stop with the keyframe timestamp we pushed of that stream */
   gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
@@ -1146,14 +1176,16 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
 
   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
-    return GST_FLOW_UNEXPECTED;
+    goto eos;
   }
 
   /* Align them all on this */
   for (n = 0; n < qtdemux->n_streams; n++) {
-    str = qtdemux->streams[n];
+    guint32 index = 0;
+    guint64 media_start = 0, seg_time = 0;
+    QtDemuxStream *str = qtdemux->streams[n];
 
-    seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_offset);
+    seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
 
     /* segment not found, continue with normal flow */
@@ -1162,7 +1194,7 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
 
     /* get segment and time in the segment */
     seg = &str->segments[seg_idx];
-    seg_time = desired_offset - seg->time;
+    seg_time = k_pos - seg->time;
 
     /* get the media time in the segment */
     media_start = seg->media_start + seg_time;
@@ -1173,21 +1205,24 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
         GST_TIME_ARGS (media_start), index);
 
     /* find previous keyframe */
-    kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
+    k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
 
     /* Remember until where we want to go */
     str->to_sample = str->from_sample - 1;
     /* Define our time position */
     str->time_position =
-        (str->samples[kindex].timestamp - seg->media_start) + seg->time;
+        (str->samples[k_index].timestamp - seg->media_start) + seg->time;
     /* Now seek back in time */
-    gst_qtdemux_move_stream (qtdemux, str, kindex);
+    gst_qtdemux_move_stream (qtdemux, str, k_index);
     GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
-        GST_TIME_FORMAT " playing from sample %u to %u", kindex,
+        GST_TIME_FORMAT " playing from sample %u to %u", k_index,
         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
   }
 
   return GST_FLOW_OK;
+
+eos:
+  return GST_FLOW_UNEXPECTED;
 }
 
 /* activate the given segment number @seg_idx of @stream at time @offset.
@@ -1235,18 +1270,14 @@ gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
     return FALSE;
   }
 
-  /* calc media start/stop */
-  if (qtdemux->segment.stop == -1)
-    stop = segment->media_stop;
-  else
-    stop = MIN (segment->media_stop, qtdemux->segment.stop);
+  stop = segment->media_stop;
   if (qtdemux->segment.rate >= 0) {
     start = MIN (segment->media_start + seg_time, stop);
     time = offset;
   } else {
     start = segment->media_start;
     stop = MIN (segment->media_start + seg_time, stop);
-    time = segment->media_start;
+    time = segment->time;
   }
 
   GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
@@ -1837,6 +1868,11 @@ pause:
         if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
           gint64 stop;
 
+          /* FIXME: I am not sure this is the right fix. If the sinks are
+           * supposed to detect the segment is complete and accumulate 
+           * automatically, it does not seem to work here. Need more work */
+          qtdemux->segment_running = TRUE;
+
           if ((stop = qtdemux->segment.stop) == -1)
             stop = qtdemux->segment.duration;
 
index fa1afc4..8103c7b 100644 (file)
@@ -36,7 +36,7 @@
 #define GST_LICENSE "LGPL"
 
 /* package name in plugins */
-#define GST_PACKAGE_NAME "GStreamer Good Plug-ins source release"
+#define GST_PACKAGE_NAME "GStreamer Good Plug-ins CVS/prerelease"
 
 /* package origin */
 #define GST_PACKAGE_ORIGIN "Unknown package origin"
 #define PACKAGE_NAME "GStreamer Good Plug-ins"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "GStreamer Good Plug-ins 0.10.8"
+#define PACKAGE_STRING "GStreamer Good Plug-ins 0.10.8.1"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "gst-plugins-good"
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "0.10.8"
+#define PACKAGE_VERSION "0.10.8.1"
 
 /* Define the plugin directory */
 #ifdef _DEBUG
 #undef STDC_HEADERS
 
 /* Version number of package */
-#define VERSION "0.10.8"
+#define VERSION "0.10.8.1"
 
 /* Define to 1 if your processor stores words with the most significant byte
    first (like Motorola and SPARC, unlike Intel and VAX). */