avidemux: Drop video frames up to the desired keyframe after a seek
authorRobert Swain <robert.swain@collabora.co.uk>
Thu, 21 Jan 2010 10:55:15 +0000 (11:55 +0100)
committerRobert Swain <robert.swain@collabora.co.uk>
Fri, 12 Feb 2010 14:56:18 +0000 (15:56 +0100)
The audio packets in AVI are generally muxed ~0.5s before the
corresponding video packet. This changes causes downstream to only
receive packets with roughly corresponding timestamps.

gst/avi/gstavidemux.c
gst/avi/gstavidemux.h

index 9758861030ed83f4af745494f4d2b26460dfb195..b87ee6c1e0614c9fe16d06cfaca888f3456cee26 100644 (file)
@@ -4191,7 +4191,7 @@ avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
   /* re-use cur to be the timestamp of the seek as it _will_ be */
   cur = stream->current_timestamp;
 
-  min_offset = stream->index[index].offset;
+  min_offset = avi->seek_kf_offset = stream->index[index].offset;
 
   GST_DEBUG_OBJECT (avi,
       "Seek to: ts %" GST_TIME_FORMAT " (on str %u, idx %u, offset %"
@@ -4838,15 +4838,28 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
     } else {
       GstAviStream *stream;
       GstClockTime next_ts = 0;
-      GstBuffer *buf;
+      GstBuffer *buf = NULL;
       guint64 offset;
+      gboolean saw_desired_kf = stream_nr != avi->main_stream
+          || avi->offset >= avi->seek_kf_offset;
 
-      gst_adapter_flush (avi->adapter, 8);
+      if (stream_nr == avi->main_stream && avi->offset == avi->seek_kf_offset) {
+        GST_DEBUG_OBJECT (avi, "Desired keyframe reached");
+        avi->seek_kf_offset = 0;
+      }
+
+      if (saw_desired_kf) {
+        gst_adapter_flush (avi->adapter, 8);
+        /* get buffer */
+        buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size));
+        /* patch the size */
+        GST_BUFFER_SIZE (buf) = size;
+      } else {
+        GST_DEBUG_OBJECT (avi,
+            "Desired keyframe not yet reached, flushing chunk");
+        gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
+      }
 
-      /* get buffer */
-      buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size));
-      /* patch the size */
-      GST_BUFFER_SIZE (buf) = size;
       offset = avi->offset;
       avi->offset += 8 + GST_ROUND_UP_2 (size);
 
@@ -4862,10 +4875,9 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
       if (G_UNLIKELY (!stream->pad)) {
         GST_WARNING_OBJECT (avi, "no pad for stream ID %" GST_FOURCC_FORMAT,
             GST_FOURCC_ARGS (tag));
-        gst_buffer_unref (buf);
+        if (buf)
+          gst_buffer_unref (buf);
       } else {
-        GstClockTime dur_ts = 0;
-
         /* get time of this buffer */
         gst_pad_query_position (stream->pad, &format, (gint64 *) & next_ts);
         if (G_UNLIKELY (format != GST_FORMAT_TIME))
@@ -4877,47 +4889,51 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
         stream->current_entry++;
         stream->current_total += size;
 
-        /* invert the picture if needed */
-        buf = gst_avi_demux_invert (stream, buf);
+        /* update current position in the segment */
+        gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, next_ts);
 
-        gst_pad_query_position (stream->pad, &format, (gint64 *) & dur_ts);
-        if (G_UNLIKELY (format != GST_FORMAT_TIME))
-          goto wrong_format;
+        if (saw_desired_kf && buf) {
+          GstClockTime dur_ts = 0;
 
-        GST_BUFFER_TIMESTAMP (buf) = next_ts;
-        GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
-        if (stream->strh->type == GST_RIFF_FCC_vids) {
-          GST_BUFFER_OFFSET (buf) = stream->current_entry - 1;
-          GST_BUFFER_OFFSET_END (buf) = stream->current_entry;
-        } else {
-          GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
-          GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
-        }
+          /* invert the picture if needed */
+          buf = gst_avi_demux_invert (stream, buf);
 
-        gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
-        GST_DEBUG_OBJECT (avi,
-            "Pushing buffer with time=%" GST_TIME_FORMAT ", duration %"
-            GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
-            " and size %d over pad %s", GST_TIME_ARGS (next_ts),
-            GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
-            size, GST_PAD_NAME (stream->pad));
+          gst_pad_query_position (stream->pad, &format, (gint64 *) & dur_ts);
+          if (G_UNLIKELY (format != GST_FORMAT_TIME))
+            goto wrong_format;
 
-        /* update current position in the segment */
-        gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, next_ts);
+          GST_BUFFER_TIMESTAMP (buf) = next_ts;
+          GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
+          if (stream->strh->type == GST_RIFF_FCC_vids) {
+            GST_BUFFER_OFFSET (buf) = stream->current_entry - 1;
+            GST_BUFFER_OFFSET_END (buf) = stream->current_entry;
+          } else {
+            GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
+            GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
+          }
 
-        /* mark discont when pending */
-        if (G_UNLIKELY (stream->discont)) {
-          GST_DEBUG_OBJECT (avi, "Setting DISCONT");
-          GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
-          stream->discont = FALSE;
-        }
-        res = gst_pad_push (stream->pad, buf);
+          gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
+          GST_DEBUG_OBJECT (avi,
+              "Pushing buffer with time=%" GST_TIME_FORMAT ", duration %"
+              GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
+              " and size %d over pad %s", GST_TIME_ARGS (next_ts),
+              GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
+              GST_BUFFER_OFFSET (buf), size, GST_PAD_NAME (stream->pad));
+
+          /* mark discont when pending */
+          if (G_UNLIKELY (stream->discont)) {
+            GST_DEBUG_OBJECT (avi, "Setting DISCONT");
+            GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+            stream->discont = FALSE;
+          }
+          res = gst_pad_push (stream->pad, buf);
 
-        /* combine flows */
-        res = gst_avi_demux_combine_flows (avi, stream, res);
-        if (G_UNLIKELY (res != GST_FLOW_OK)) {
-          GST_DEBUG ("Push failed; %s", gst_flow_get_name (res));
-          return res;
+          /* combine flows */
+          res = gst_avi_demux_combine_flows (avi, stream, res);
+          if (G_UNLIKELY (res != GST_FLOW_OK)) {
+            GST_DEBUG ("Push failed; %s", gst_flow_get_name (res));
+            return res;
+          }
         }
       }
     }
index c70ac286b0efcd815f3095cd4ae554c6a4b5bba6..8216d9fd3c5434c895024570a7e5fe55fc79014f 100644 (file)
@@ -199,6 +199,8 @@ typedef struct _GstAviDemux {
   guint          odml_stream;
   guint          odml_subidx;
   guint64       *odml_subidxs;
+
+  guint64        seek_kf_offset; /* offset of the keyframe to which we want to seek */
 } GstAviDemux;
 
 typedef struct _GstAviDemuxClass {