ext/ffmpeg/: Fix up demuxer. Works now for all my files that I tried, even quicktime...
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Fri, 14 May 2004 14:11:00 +0000 (14:11 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Fri, 14 May 2004 14:11:00 +0000 (14:11 +0000)
Original commit message from CVS:
* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_src_event),
(gst_ffmpegdemux_src_query), (gst_ffmpegdemux_src_convert),
(gst_ffmpegdemux_open), (gst_ffmpegdemux_loop):
* ext/ffmpeg/gstffmpegprotocol.c: (gst_ffmpegdata_open),
(gst_ffmpegdata_read), (gst_ffmpegdata_write),
(gst_ffmpegdata_seek):
Fix up demuxer. Works now for all my files that I tried, even
quicktime. I basically hack around the super-oversimplistic file
I/O handling in ffmpeg in several ways together, and I also hack
around the fairly annoying EOS-will-pause-the-source-element in
GStreamer itself.
This code is not pretty.

ChangeLog
ext/ffmpeg/gstffmpegdemux.c
ext/ffmpeg/gstffmpegprotocol.c

index dba5dd3..d5c5f92 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2004-05-14  Ronald Bultje  <rbultje@ronald.bitfreak.net>
+
+       * ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_src_event),
+       (gst_ffmpegdemux_src_query), (gst_ffmpegdemux_src_convert),
+       (gst_ffmpegdemux_open), (gst_ffmpegdemux_loop):
+       * ext/ffmpeg/gstffmpegprotocol.c: (gst_ffmpegdata_open),
+       (gst_ffmpegdata_read), (gst_ffmpegdata_write),
+       (gst_ffmpegdata_seek):
+         Fix up demuxer. Works now for all my files that I tried, even
+         quicktime. I basically hack around the super-oversimplistic file
+         I/O handling in ffmpeg in several ways together, and I also hack
+         around the fairly annoying EOS-will-pause-the-source-element in
+         GStreamer itself.
+         This code is not pretty.
+
 2004-05-11  Jeremy Simon  <jesimon@libertysurf.fr>
 
        * ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_codecid_to_caps),
index 26d963e..f48954e 100644 (file)
@@ -288,7 +288,7 @@ gst_ffmpegdemux_src_event (GstPad * pad, GstEvent * event)
   gint64 offset;
 
   if (!stream)
-    return;
+    return FALSE;
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
@@ -358,7 +358,6 @@ gst_ffmpegdemux_src_query (GstPad * pad,
   GstFFMpegDemux *demux = (GstFFMpegDemux *) gst_pad_get_parent (pad);
   AVStream *stream = gst_ffmpegdemux_stream_from_pad (pad);
   gboolean res = TRUE;
-  gint n;
 
   if (!stream || (*fmt == GST_FORMAT_DEFAULT &&
           stream->codec.codec_type != CODEC_TYPE_VIDEO))
@@ -407,7 +406,7 @@ gst_ffmpegdemux_src_convert (GstPad * pad,
     GstFormat src_fmt,
     gint64 src_value, GstFormat * dest_fmt, gint64 * dest_value)
 {
-  GstFFMpegDemux *demux = (GstFFMpegDemux *) gst_pad_get_parent (pad);
+  /*GstFFMpegDemux *demux = (GstFFMpegDemux *) gst_pad_get_parent (pad);*/
   AVStream *stream = gst_ffmpegdemux_stream_from_pad (pad);
   gboolean res = TRUE;
 
@@ -513,6 +512,8 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux)
   location = g_strdup_printf ("gstreamer://%p", demux->sinkpad);
   res = av_open_input_file (&demux->context, location,
       oclass->in_plugin, 0, NULL);
+  if (res >= 0)
+    res = av_find_stream_info (demux->context);
   g_free (location);
   if (res < 0) {
     GST_ELEMENT_ERROR (demux, LIBRARY, FAILED, (NULL),
@@ -574,13 +575,34 @@ gst_ffmpegdemux_loop (GstElement * element)
   /* read a package */
   res = av_read_packet (demux->context, &pkt);
   if (res < 0) {
+#if 0
+    /* This doesn't work - FIXME */
     if (url_feof (&demux->context->pb)) {
-      gst_pad_event_default (demux->sinkpad, gst_event_new (GST_EVENT_EOS));
       gst_ffmpegdemux_close (demux);
+      gst_pad_event_default (demux->sinkpad, gst_event_new (GST_EVENT_EOS));
     } else {
       GST_ELEMENT_ERROR (demux, LIBRARY, FAILED, (NULL),
           (gst_ffmpegdemux_averror (res)));
     }
+#endif
+
+    /* so, we do it the hacky way. */
+    GstData *data = NULL;
+
+    do {
+      data = gst_pad_pull (demux->sinkpad);
+
+      if (!GST_IS_EVENT (data) ||
+          GST_EVENT_TYPE (GST_EVENT (data)) != GST_EVENT_EOS) {
+        gst_data_unref (data);
+        data = NULL;
+        continue;
+      }
+    } while (!data);
+
+    gst_ffmpegdemux_close (demux);
+    gst_pad_event_default (demux->sinkpad, GST_EVENT (data));
+
     return;
   }
 
index a03013f..6a4db03 100644 (file)
@@ -81,6 +81,9 @@ gst_ffmpegdata_open (URLContext * h, const char *filename, int flags)
   info->pad = pad;
 
   h->priv_data = (void *) info;
+  h->is_streamed = FALSE;
+  h->flags = 0;
+  h->max_packet_size = 0;
 
   return 0;
 }
@@ -104,15 +107,18 @@ gst_ffmpegdata_read (URLContext * h, unsigned char *buf, int size)
 
   do {
     /* prevent EOS */
-    if (gst_bytestream_tell (bs) + size > gst_bytestream_length (bs))
-      request = gst_bytestream_length (bs) - gst_bytestream_tell (bs);
-    else
+    if (gst_bytestream_tell (bs) + size > gst_bytestream_length (bs)) {
+      request = (int) (gst_bytestream_length (bs) - gst_bytestream_tell (bs));
+      info->eos = TRUE;
+    } else {
       request = size;
+    }
 
-    if (request)
+    if (request > 0) {
       total = gst_bytestream_peek_bytes (bs, &data, request);
-    else
+    } else {
       total = 0;
+    }
 
     if (total < request) {
       GstEvent *event;
@@ -131,6 +137,7 @@ gst_ffmpegdata_read (URLContext * h, unsigned char *buf, int size)
           gst_event_unref (event);
           break;
         case GST_EVENT_EOS:
+          g_warning ("Unexpected/unwanted eos in data function");
           info->eos = TRUE;
           gst_event_unref (event);
           break;
@@ -142,7 +149,7 @@ gst_ffmpegdata_read (URLContext * h, unsigned char *buf, int size)
   } while (!info->eos && total != request);
 
   memcpy (buf, data, total);
-  gst_bytestream_flush (bs, total);
+  gst_bytestream_flush_fast (bs, total);
 
   return total;
 }
@@ -164,7 +171,7 @@ gst_ffmpegdata_write (URLContext * h, unsigned char *buf, int size)
 
   gst_pad_push (info->pad, GST_DATA (outbuf));
 
-  return 0;
+  return size;
 }
 
 static offset_t
@@ -172,9 +179,19 @@ gst_ffmpegdata_seek (URLContext * h, offset_t pos, int whence)
 {
   GstSeekType seek_type = 0;
   GstProtocolInfo *info;
+  guint64 newpos;
 
   info = (GstProtocolInfo *) h->priv_data;
 
+  /* hack in ffmpeg to get filesize... */
+  if (whence == SEEK_END && pos == -1)
+    return gst_bytestream_length (info->bs) - 1;
+  /* another hack to get the current position... */
+  else if (whence == SEEK_CUR && pos == 0)
+    return gst_bytestream_tell (info->bs);
+  else
+    g_assert (pos >= 0);
+
   switch (whence) {
     case SEEK_SET:
       seek_type = GST_SEEK_METHOD_SET;
@@ -191,12 +208,57 @@ gst_ffmpegdata_seek (URLContext * h, offset_t pos, int whence)
   }
 
   switch (info->flags) {
-    case URL_RDONLY:
+    case URL_RDONLY: {
+      GstEvent *event;
+      guint8 *data;
+      guint32 remaining;
+
+      /* handle discont */
       gst_bytestream_seek (info->bs, pos, seek_type);
+      /* prevent eos */
+      if (gst_bytestream_tell (info->bs) ==
+              gst_bytestream_length (info->bs)) {
+        info->eos = TRUE;
+        break;
+      }
+      info->eos = FALSE;
+      while (gst_bytestream_peek_bytes (info->bs, &data, 1) == 0) {
+        gst_bytestream_get_status (info->bs, &remaining, &event);
+
+        if (!event) {
+          g_warning ("no data, no event - panic!");
+          return -1;
+        }
+
+        switch (GST_EVENT_TYPE (event)) {
+          case GST_EVENT_EOS:
+            g_warning ("unexpected/unwanted EOS event after seek");
+            info->eos = TRUE;
+            gst_event_unref (event);
+            break;
+          case GST_EVENT_DISCONTINUOUS:
+            gst_bytestream_flush_fast (info->bs, remaining);
+            gst_event_unref (event); /* we expect this */
+            break;
+          default:
+            gst_pad_event_default (info->pad, event);
+            break;
+        }
+      }
+      newpos = gst_bytestream_tell (info->bs);
       break;
+    }
 
     case URL_WRONLY:
       gst_pad_push (info->pad, GST_DATA (gst_event_new_seek (seek_type, pos)));
+      /* this is screwy because there might be queues or scheduler-queued
+       * buffers... Argh! */
+      if (whence == SEEK_SET) {
+        newpos = pos;
+      } else {
+        g_warning ("Writer reposition: implement me\n");
+        newpos = 0;
+      }
       break;
 
     default:
@@ -204,7 +266,7 @@ gst_ffmpegdata_seek (URLContext * h, offset_t pos, int whence)
       break;
   }
 
-  return 0;
+  return newpos;
 }
 
 static int