Ported to 0.9. Some issues to be solved yet: 1- set correct timestamps 2- seg fault...
authorEdgard Lima <edgard.lima@indt.org.br>
Tue, 8 Nov 2005 13:55:13 +0000 (13:55 +0000)
committerEdgard Lima <edgard.lima@indt.org.br>
Tue, 8 Nov 2005 13:55:13 +0000 (13:55 +0000)
Original commit message from CVS:
Ported to 0.9. Some issues to be solved yet:
1- set correct timestamps
2- seg fault when eos
3- seek is now disabled

ChangeLog
PORTED_09
configure.ac
ext/Makefile.am
ext/ivorbis/vorbis.c
ext/ivorbis/vorbisfile.c

index d7ddb25..702f712 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2005-11-08  Edgard Lima <edgard.lima@indt.org.br>
+
+       configure.ac:
+       PORTED_09:
+       ext/Makefile.am:
+       ext/ivorbis/vorbis.c:
+       ext/ivorbis/vorbisfile.c:
+       Ported to 0.9. Some issues to be solved yet:
+       1- set correct timestamps
+       2- seg fault when eos
+       3- seek is now disabled
+
 2005-11-06  Julien MOUTTE  <julien@moutte.net>
 
        * examples/Makefile.am: Cleanup non existing
index 569cb7b..840565e 100644 (file)
--- a/PORTED_09
+++ b/PORTED_09
@@ -1,6 +1,7 @@
 When porting a plugin start with 0.8 CVS head, not the old code in this module. There are many bugfixes which have gone into 0.8 which you want to keep.
 
 List of ported plugins (update when you commit a ported plugin):
+ivorbis (alima)
 gsmdec  (alima)
 sdl     (alima)
 speed   (fcarvalho)
index 9bdaaba..b2fdddf 100644 (file)
@@ -409,6 +409,19 @@ GST_CHECK_FEATURE(SDL, [SDL plug-in], sdlvideosink, [
   fi
 ])
 
+dnl *** ivorbis ***
+dnl AM_PATH_IVORBIS only takes two options
+translit(dnm, m, l) AM_CONDITIONAL(USE_IVORBIS, true)
+GST_CHECK_FEATURE(IVORBIS, [integer vorbis plug-in], ivorbisdec, [
+  IVORBIS_LIBS=
+  IVORBIS_CFLAGS=
+  AC_CHECK_LIB(vorbisidec, vorbis_block_init,
+    [IVORBIS_LIBS=-lvorbisidec
+     HAVE_IVORBIS=yes],
+    HAVE_IVORBIS=no)
+  AC_SUBST(IVORBIS_LIBS)
+  AC_SUBST(IVORBIS_CFLAGS)
+])
 
 dnl *** gsm ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_GSM, true)
@@ -496,6 +509,7 @@ ext/Makefile
 ext/directfb/Makefile
 ext/faac/Makefile
 ext/faad/Makefile
+ext/ivorbis/Makefile
 ext/gsm/Makefile
 ext/sdl/Makefile
 docs/Makefile
index e20bd18..ded23a7 100644 (file)
@@ -76,11 +76,11 @@ endif
 HERMES_DIR=
 # endif
 
-if USE_IVORBIS
-# IVORBIS_DIR=ivorbis
-else
-IVORBIS_DIR=
-endif
+if USE_IVORBIS
+ IVORBIS_DIR=ivorbis
+else
+ IVORBIS_DIR=
+endif
 
 # if USE_JACK
 # JACK_DIR=jack
index 3394a77..592d9d2 100644 (file)
@@ -30,9 +30,6 @@ extern GType ivorbisfile_get_type (void);
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  if (!gst_library_load ("gstbytestream"))
-    return FALSE;
-
   if (!gst_element_register (plugin, "tremor", GST_RANK_PRIMARY,
           ivorbisfile_get_type ()))
     return FALSE;
index db2b601..6ab2671 100644 (file)
 #include <gst/gst.h>
 #include <tremor/ivorbiscodec.h>
 #include <tremor/ivorbisfile.h>
-#include <gst/bytestream/bytestream.h>
+#include <gst/base/gstadapter.h>
 
 GST_DEBUG_CATEGORY_STATIC (ivorbisfile_debug);
 #define GST_CAT_DEFAULT ivorbisfile_debug
 
-#define GST_TYPE_IVORBISFILE \
+#define GST_TYPE_IVORBISFILE                   \
   (ivorbisfile_get_type())
-#define GST_IVORBISFILE(obj) \
+#define GST_IVORBISFILE(obj)                                           \
   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IVORBISFILE,Ivorbisfile))
-#define GST_IVORBISFILE_CLASS(klass) \
+#define GST_IVORBISFILE_CLASS(klass)                                   \
   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IVORBISFILE,IvorbisfileClass))
-#define GST_IS_IVORBISFILE(obj) \
+#define GST_IS_IVORBISFILE(obj)                                        \
   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IVORBISFILE))
-#define GST_IS_IVORBISFILE_CLASS(obj) \
+#define GST_IS_IVORBISFILE_CLASS(obj)                          \
   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IVORBISFILE))
 
 typedef struct _Ivorbisfile Ivorbisfile;
@@ -48,7 +48,8 @@ struct _Ivorbisfile
   GstElement element;
 
   GstPad *sinkpad, *srcpad;
-  GstByteStream *bs;
+  GstAdapter *adapter;
+  guint64 adapterOffset;
 
   OggVorbis_File vf;
   gint current_link;
@@ -65,6 +66,10 @@ struct _Ivorbisfile
   guint64 total_bytes;
   guint64 offset;
 
+  gint rate;
+  gint channels;
+  gint width;
+
   GstCaps *metadata;
   GstCaps *streaminfo;
 };
@@ -109,30 +114,37 @@ static void gst_ivorbisfile_init (Ivorbisfile * ivorbisfile);
 static GstStateChangeReturn
 gst_ivorbisfile_change_state (GstElement * element, GstStateChange transition);
 
-static const GstFormat *gst_ivorbisfile_get_formats (GstPad * pad);
 static gboolean gst_ivorbisfile_src_convert (GstPad * pad,
     GstFormat src_format,
     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
 static gboolean gst_ivorbisfile_sink_convert (GstPad * pad,
     GstFormat src_format,
     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
-static const GstQueryType *gst_ivorbisfile_get_query_types (GstPad * pad);
+static const GstQueryType *gst_ivorbisfile_get_src_query_types (GstPad * pad);
+
+static gboolean gst_ivorbisfile_src_query (GstPad * pad, GstQuery * query);
 
-static gboolean gst_ivorbisfile_src_query (GstPad * pad,
-    GstQueryType type, GstFormat * format, gint64 * value);
-static const GstEventMask *gst_ivorbisfile_get_event_masks (GstPad * pad);
 static gboolean gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event);
 
+static gboolean gst_ivorbisfile_sink_event (GstPad * pad, GstEvent * event);
+
+static const GstQueryType *gst_ivorbisfile_get_sink_query_types (GstPad * pad);
+
+static gboolean gst_ivorbisfile_sink_query (GstPad * pad, GstQuery * query);
+
 static void gst_ivorbisfile_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec);
 static void gst_ivorbisfile_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec);
 
-static void gst_ivorbisfile_loop (GstElement * element);
+static gboolean gst_ivorbisfile_sink_activate (GstPad * sinkpad);
 
-static GstElementClass *parent_class = NULL;
+static gboolean
+gst_ivorbisfile_sink_activate_pull (GstPad * sinkpad, gboolean active);
+
+static void gst_ivorbisfile_loop (GstPad * pad);
 
-//static guint gst_ivorbisfile_signals[LAST_SIGNAL] = { 0 };
+static GstElementClass *parent_class = NULL;
 
 static GstFormat logical_stream_format;
 
@@ -230,6 +242,9 @@ gst_ivorbisfile_class_init (IvorbisfileClass * klass)
 
   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
+  gobject_class->get_property = gst_ivorbisfile_get_property;
+  gobject_class->set_property = gst_ivorbisfile_set_property;
+
   g_object_class_install_property (gobject_class, ARG_METADATA,
       g_param_spec_boxed ("metadata", "Metadata", "(logical) Stream metadata",
           GST_TYPE_CAPS, G_PARAM_READABLE));
@@ -237,8 +252,6 @@ gst_ivorbisfile_class_init (IvorbisfileClass * klass)
       g_param_spec_boxed ("streaminfo", "stream",
           "(logical) Stream information", GST_TYPE_CAPS, G_PARAM_READABLE));
 
-  gobject_class->get_property = gst_ivorbisfile_get_property;
-  gobject_class->set_property = gst_ivorbisfile_set_property;
 
   gstelement_class->change_state = gst_ivorbisfile_change_state;
 }
@@ -249,26 +262,27 @@ gst_ivorbisfile_init (Ivorbisfile * ivorbisfile)
   ivorbisfile->sinkpad = gst_pad_new_from_template (gst_vorbisdec_sink_template,
       "sink");
   gst_element_add_pad (GST_ELEMENT (ivorbisfile), ivorbisfile->sinkpad);
-  gst_pad_set_formats_function (ivorbisfile->sinkpad,
-      gst_ivorbisfile_get_formats);
-  gst_pad_set_convert_function (ivorbisfile->sinkpad,
-      gst_ivorbisfile_sink_convert);
 
-  gst_element_set_loop_function (GST_ELEMENT (ivorbisfile),
-      gst_ivorbisfile_loop);
+  gst_pad_set_query_type_function (ivorbisfile->sinkpad,
+      gst_ivorbisfile_get_sink_query_types);
+  gst_pad_set_query_function (ivorbisfile->sinkpad, gst_ivorbisfile_sink_query);
+
+  gst_pad_set_activate_function (ivorbisfile->sinkpad,
+      gst_ivorbisfile_sink_activate);
+  gst_pad_set_activatepull_function (ivorbisfile->sinkpad,
+      gst_ivorbisfile_sink_activate_pull);
+
+  gst_pad_set_event_function (ivorbisfile->sinkpad, gst_ivorbisfile_sink_event);
+
   ivorbisfile->srcpad =
       gst_pad_new_from_template (gst_vorbisdec_src_template, "src");
   gst_element_add_pad (GST_ELEMENT (ivorbisfile), ivorbisfile->srcpad);
-  gst_pad_set_formats_function (ivorbisfile->srcpad,
-      gst_ivorbisfile_get_formats);
+
   gst_pad_set_query_type_function (ivorbisfile->srcpad,
-      gst_ivorbisfile_get_query_types);
+      gst_ivorbisfile_get_src_query_types);
   gst_pad_set_query_function (ivorbisfile->srcpad, gst_ivorbisfile_src_query);
-  gst_pad_set_event_mask_function (ivorbisfile->srcpad,
-      gst_ivorbisfile_get_event_masks);
+
   gst_pad_set_event_function (ivorbisfile->srcpad, gst_ivorbisfile_src_event);
-  gst_pad_set_convert_function (ivorbisfile->srcpad,
-      gst_ivorbisfile_src_convert);
 
   ivorbisfile->total_bytes = 0;
   ivorbisfile->offset = 0;
@@ -277,6 +291,11 @@ gst_ivorbisfile_init (Ivorbisfile * ivorbisfile)
   ivorbisfile->metadata = NULL;
   ivorbisfile->streaminfo = NULL;
   ivorbisfile->current_link = -1;
+
+  ivorbisfile->rate = -1;
+  ivorbisfile->channels = -1;
+  ivorbisfile->width = -1;
+
 }
 
 /* the next four functions are the ov callbacks we provide to ivorbisfile
@@ -285,15 +304,15 @@ gst_ivorbisfile_init (Ivorbisfile * ivorbisfile)
 static size_t
 gst_ivorbisfile_read (void *ptr, size_t size, size_t nmemb, void *datasource)
 {
-  guint32 got_bytes = 0;
-  guint8 *data;
   size_t read_size = size * nmemb;
-
+  GstBuffer *buf = NULL;
   Ivorbisfile *ivorbisfile = GST_IVORBISFILE (datasource);
+  size_t ret;
 
   GST_DEBUG ("read %d", read_size);
 
   /* make sure we don't go to EOS */
+
   if (!ivorbisfile->may_eos && ivorbisfile->total_bytes &&
       ivorbisfile->offset + read_size > ivorbisfile->total_bytes) {
     read_size = ivorbisfile->total_bytes - ivorbisfile->offset;
@@ -302,50 +321,25 @@ gst_ivorbisfile_read (void *ptr, size_t size, size_t nmemb, void *datasource)
   if (read_size == 0 || ivorbisfile->eos)
     return 0;
 
-  while (got_bytes == 0) {
-    got_bytes = gst_bytestream_peek_bytes (ivorbisfile->bs, &data, read_size);
-    if (got_bytes < read_size) {
-      GstEvent *event;
-      guint32 avail;
-
-      gst_bytestream_get_status (ivorbisfile->bs, &avail, &event);
-
-      switch (GST_EVENT_TYPE (event)) {
-        case GST_EVENT_EOS:
-          GST_DEBUG ("eos");
-          ivorbisfile->eos = TRUE;
-          if (avail == 0) {
-            gst_event_unref (event);
-            return 0;
-          }
-          break;
-        case GST_EVENT_DISCONTINUOUS:
-          GST_DEBUG ("discont");
-          ivorbisfile->need_discont = TRUE;
-        default:
-          break;
-      }
-      gst_event_unref (event);
-      if (avail > 0)
-        got_bytes = gst_bytestream_peek_bytes (ivorbisfile->bs, &data, avail);
-      else
-        got_bytes = 0;
-    }
+  if (GST_FLOW_OK != gst_pad_pull_range (ivorbisfile->sinkpad,
+          ivorbisfile->offset, read_size, &buf)) {
+    return 0;
   }
 
-  memcpy (ptr, data, got_bytes);
-  gst_bytestream_flush_fast (ivorbisfile->bs, got_bytes);
+  memcpy (ptr, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
 
-  ivorbisfile->offset += got_bytes;
+  ivorbisfile->offset += GST_BUFFER_SIZE (buf);
 
-  return got_bytes / size;
+  ret = GST_BUFFER_SIZE (buf) / size;
+  gst_buffer_unref (buf);
+
+  return ret;
 }
 
 static int
 gst_ivorbisfile_seek (void *datasource, int64_t offset, int whence)
 {
   Ivorbisfile *ivorbisfile = GST_IVORBISFILE (datasource);
-  GstSeekType method;
   guint64 pending_offset = ivorbisfile->offset;
   gboolean need_total = FALSE;
 
@@ -357,24 +351,22 @@ gst_ivorbisfile_seek (void *datasource, int64_t offset, int whence)
   GST_DEBUG ("seek %" G_GINT64_FORMAT " %d", offset, whence);
 
   if (whence == SEEK_SET) {
-    method = GST_SEEK_METHOD_SET;
     pending_offset = offset;
+    ivorbisfile->adapterOffset = offset;
   } else if (whence == SEEK_CUR) {
-    method = GST_SEEK_METHOD_CUR;
     pending_offset += offset;
+    ivorbisfile->adapterOffset += offset;
   } else if (whence == SEEK_END) {
-    method = GST_SEEK_METHOD_END;
     need_total = TRUE;
     pending_offset = ivorbisfile->total_bytes - offset;
+    ivorbisfile->adapterOffset = ivorbisfile->total_bytes - offset;
   } else
     return -1;
 
-  if (!gst_bytestream_seek (ivorbisfile->bs, offset, method))
-    return -1;
 
   ivorbisfile->offset = pending_offset;
   if (need_total)
-    ivorbisfile->total_bytes = gst_bytestream_tell (ivorbisfile->bs) + offset;
+    ivorbisfile->total_bytes = ivorbisfile->adapterOffset + offset;
 
   return 0;
 }
@@ -392,7 +384,7 @@ gst_ivorbisfile_tell (void *datasource)
   Ivorbisfile *ivorbisfile = GST_IVORBISFILE (datasource);
   long result;
 
-  result = gst_bytestream_tell (ivorbisfile->bs);
+  result = ivorbisfile->adapterOffset;
 
   GST_DEBUG ("tell %ld", result);
 
@@ -513,40 +505,89 @@ gst_ivorbisfile_new_link (Ivorbisfile * ivorbisfile, gint link)
       "depth", G_TYPE_INT, 16,
       "rate", G_TYPE_INT, vi->rate, "channels", G_TYPE_INT, vi->channels, NULL);
 
-  if (gst_pad_try_set_caps (ivorbisfile->srcpad, caps) <= 0) {
+  ivorbisfile->rate = vi->rate;
+  ivorbisfile->channels = vi->channels;
+  ivorbisfile->width = 16;
+
+  if (gst_pad_set_caps (ivorbisfile->srcpad, caps) <= 0) {
     res = FALSE;
   }
 
-  gst_caps_free (caps);
+  gst_caps_unref (caps);
 
   return TRUE;
 }
 
+
+static gboolean
+gst_ivorbisfile_sink_activate (GstPad * sinkpad)
+{
+
+  Ivorbisfile *ivorbisfile;
+
+  ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (sinkpad));
+
+  if (gst_pad_check_pull_range (sinkpad)) {
+    /* FIX ME */
+    /* ivorbisfile->vf.seekable = TRUE; */
+    ivorbisfile->vf.seekable = FALSE;
+    return gst_pad_activate_pull (sinkpad, TRUE);
+  }
+
+  ivorbisfile->vf.seekable = FALSE;
+  return FALSE;
+
+
+}
+
+
+static gboolean
+gst_ivorbisfile_sink_activate_pull (GstPad * sinkpad, gboolean active)
+{
+
+  gboolean result;
+
+  if (active) {
+    /* if we have a scheduler we can start the task */
+    result = gst_pad_start_task (sinkpad,
+        (GstTaskFunction) gst_ivorbisfile_loop, sinkpad);
+  } else {
+    result = gst_pad_stop_task (sinkpad);
+  }
+
+  return result;
+}
+
+
+
 static void
-gst_ivorbisfile_loop (GstElement * element)
+gst_ivorbisfile_loop (GstPad * pad)
 {
-  Ivorbisfile *ivorbisfile = GST_IVORBISFILE (element);
+  Ivorbisfile *ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad));
   GstBuffer *outbuf;
   long ret;
   GstClockTime time;
   gint64 samples;
   gint link;
 
+  if (ivorbisfile->eos)
+    return;
+
   /* this function needs to go first since you don't want to be messing
    * with an unset vf ;) */
   if (ivorbisfile->restart) {
+
     ivorbisfile->offset = 0;
     ivorbisfile->total_bytes = 0;
     ivorbisfile->may_eos = FALSE;
-    ivorbisfile->vf.seekable = gst_bytestream_seek (ivorbisfile->bs, 0,
-        GST_SEEK_METHOD_SET);
+    ivorbisfile->adapterOffset = 0;
     GST_DEBUG ("ivorbisfile: seekable: %s\n",
         ivorbisfile->vf.seekable ? "yes" : "no");
 
     /* open our custom ivorbisfile data object with the callbacks we provide */
     if (ov_open_callbacks (ivorbisfile, &ivorbisfile->vf, NULL, 0,
             ivorbisfile_ov_callbacks) < 0) {
-      GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), (NULL));
+      GST_ELEMENT_ERROR (ivorbisfile, STREAM, DECODE, (NULL), (NULL));
       return;
     }
     ivorbisfile->need_discont = TRUE;
@@ -615,24 +656,21 @@ gst_ivorbisfile_loop (GstElement * element)
   GST_BUFFER_DATA (outbuf) = g_malloc (4096);
   GST_BUFFER_SIZE (outbuf) = 4096;
 
+  ret = ov_read (&ivorbisfile->vf,
+      (char *) GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), &link);
+
   /* get current time for discont and buffer timestamp */
   time = (GstClockTime) (ov_time_tell (&ivorbisfile->vf) * GST_SECOND);
 
-  ret = ov_read (&ivorbisfile->vf,
-      GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), &link);
-
   if (ret == 0) {
     GST_DEBUG ("eos");
     /* send EOS event */
-    /*ov_clear (&ivorbisfile->vf); */
+
     ivorbisfile->restart = TRUE;
     gst_buffer_unref (outbuf);
     /* if the pad is not usable, don't push it out */
-    if (GST_PAD_IS_USABLE (ivorbisfile->srcpad)) {
-      gst_pad_push (ivorbisfile->srcpad,
-          GST_DATA (gst_event_new (GST_EVENT_EOS)));
-    }
-    gst_element_set_eos (element);
+    gst_pad_push_event (ivorbisfile->srcpad, gst_event_new_eos ());
+
     return;
   } else if (ret < 0) {
     g_warning ("ivorbisfile: decoding error");
@@ -640,24 +678,30 @@ gst_ivorbisfile_loop (GstElement * element)
     return;
   } else {
     if (ivorbisfile->need_discont) {
-      GstEvent *discont;
+      GstEvent *event;
 
       ivorbisfile->need_discont = FALSE;
 
-      /* if the pad is not usable, don't push it out */
-      if (GST_PAD_IS_USABLE (ivorbisfile->srcpad)) {
-        /* get stream stats */
-        samples = (gint64) (ov_pcm_tell (&ivorbisfile->vf));
+      /* get stream stats */
+      samples = (gint64) (ov_pcm_tell (&ivorbisfile->vf));
 
-        discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time,
-            GST_FORMAT_DEFAULT, samples, NULL);
+      event =
+          gst_event_new_newsegment (FALSE, 1.0, GST_FORMAT_TIME, time,
+          GST_CLOCK_TIME_NONE, 0);
+
+      gst_pad_push_event (ivorbisfile->srcpad, event);
 
-        gst_pad_push (ivorbisfile->srcpad, GST_DATA (discont));
-      }
     }
 
+    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ivorbisfile->srcpad));
+
     GST_BUFFER_SIZE (outbuf) = ret;
-    GST_BUFFER_TIMESTAMP (outbuf) = time;
+    /* FIX ME TO SET RIGHT TIMESTAMP
+       gint bufsize = ret / (ivorbisfile->width / 8);
+       GST_BUFFER_TIMESTAMP (outbuf) = time;
+       GST_BUFFER_DURATION (outbuf) =  GST_SECOND * bufsize / (ivorbisfile->rate * ivorbisfile->channels);
+     */
+
 
     ivorbisfile->may_eos = TRUE;
 
@@ -665,34 +709,10 @@ gst_ivorbisfile_loop (GstElement * element)
       ivorbisfile->total_bytes += GST_BUFFER_SIZE (outbuf);
     }
 
-    if (GST_PAD_IS_USABLE (ivorbisfile->srcpad))
-      gst_pad_push (ivorbisfile->srcpad, GST_DATA (outbuf));
-    else
-      gst_buffer_unref (outbuf);
-  }
-}
-
-static const GstFormat *
-gst_ivorbisfile_get_formats (GstPad * pad)
-{
-  static GstFormat src_formats[] = {
-    GST_FORMAT_TIME,
-    GST_FORMAT_BYTES,
-    GST_FORMAT_DEFAULT,
-    0,
-    0
-  };
-  static GstFormat sink_formats[] = {
-    GST_FORMAT_TIME,
-    GST_FORMAT_BYTES,
-    0,
-    0
-  };
+    gst_pad_push (ivorbisfile->srcpad, outbuf);
 
-  src_formats[3] = logical_stream_format;
-  sink_formats[2] = logical_stream_format;
+  }
 
-  return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
 }
 
 static gboolean
@@ -706,7 +726,7 @@ gst_ivorbisfile_src_convert (GstPad * pad,
   Ivorbisfile *ivorbisfile;
   vorbis_info *vi;
 
-  ivorbisfile = GST_IVORBISFILE (gst_pad_get_parent (pad));
+  ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad));
 
   vi = ov_info (&ivorbisfile->vf, -1);
   bytes_per_sample = vi->channels * 2;
@@ -804,6 +824,32 @@ gst_ivorbisfile_src_convert (GstPad * pad,
 }
 
 static gboolean
+gst_ivorbisfile_sink_query (GstPad * pad, GstQuery * query)
+{
+  gboolean res;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      /* peel off input */
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      if ((res = gst_ivorbisfile_sink_convert (pad, src_fmt, src_val,
+                  &dest_fmt, &dest_val))) {
+        gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      }
+      break;
+    }
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+static gboolean
 gst_ivorbisfile_sink_convert (GstPad * pad,
     GstFormat src_format, gint64 src_value,
     GstFormat * dest_format, gint64 * dest_value)
@@ -811,7 +857,7 @@ gst_ivorbisfile_sink_convert (GstPad * pad,
   gboolean res = TRUE;
   Ivorbisfile *ivorbisfile;
 
-  ivorbisfile = GST_IVORBISFILE (gst_pad_get_parent (pad));
+  ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad));
 
   switch (src_format) {
     case GST_FORMAT_BYTES:
@@ -851,11 +897,23 @@ gst_ivorbisfile_sink_convert (GstPad * pad,
 }
 
 static const GstQueryType *
-gst_ivorbisfile_get_query_types (GstPad * pad)
+gst_ivorbisfile_get_sink_query_types (GstPad * pad)
+{
+  static const GstQueryType types[] = {
+    GST_QUERY_CONVERT,
+    0
+  };
+
+  return types;
+}
+
+static const GstQueryType *
+gst_ivorbisfile_get_src_query_types (GstPad * pad)
 {
   static const GstQueryType types[] = {
-    GST_QUERY_TOTAL,
     GST_QUERY_POSITION,
+    GST_QUERY_DURATION,
+    GST_QUERY_CONVERT,
     0
   };
 
@@ -864,103 +922,194 @@ gst_ivorbisfile_get_query_types (GstPad * pad)
 
 /* handles queries for location in the stream in the requested format */
 static gboolean
-gst_ivorbisfile_src_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value)
+gst_ivorbisfile_src_query (GstPad * pad, GstQuery * query)
 {
   gboolean res = TRUE;
   Ivorbisfile *ivorbisfile;
   vorbis_info *vi;
 
-  ivorbisfile = GST_IVORBISFILE (gst_pad_get_parent (pad));
+  ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad));
 
   vi = ov_info (&ivorbisfile->vf, -1);
 
-  switch (type) {
-    case GST_QUERY_TOTAL:
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
     {
-      switch (*format) {
+
+      GstFormat format;
+      GstFormat rformat = GST_FORMAT_TIME;
+      gint64 cur;
+      GstPad *peer;
+
+      /* save requested format */
+      gst_query_parse_position (query, &format, NULL);
+
+      /* query peer for current position in time */
+      gst_query_set_position (query, GST_FORMAT_TIME, -1);
+
+      if ((peer = gst_pad_get_peer (ivorbisfile->sinkpad)) == NULL)
+        goto error;
+
+      if (!gst_pad_query_position (peer, &rformat, &cur)) {
+        GST_LOG_OBJECT (ivorbisfile, "query on peer pad failed");
+        gst_object_unref (peer);
+        goto error;
+      }
+      gst_object_unref (peer);
+
+      if (format != rformat) {
+        gst_ivorbisfile_src_convert (pad, rformat, cur, &format, &cur);
+      }
+
+      switch (format) {
         case GST_FORMAT_DEFAULT:
           if (ivorbisfile->vf.seekable)
-            *value = ov_pcm_total (&ivorbisfile->vf, -1);
+            cur = ov_pcm_tell (&ivorbisfile->vf);
           else
-            return FALSE;
+            cur = ivorbisfile->total_bytes / (vi->channels * 2);
           break;
-        case GST_FORMAT_BYTES:
+        case GST_FORMAT_TIME:
           if (ivorbisfile->vf.seekable)
-            *value = ov_pcm_total (&ivorbisfile->vf, -1) * vi->channels * 2;
+            cur = (gint64) (ov_time_tell (&ivorbisfile->vf) * GST_SECOND);
           else
-            return FALSE;
+            cur = ivorbisfile->total_bytes * GST_SECOND
+                / (vi->rate * vi->channels * 2);
           break;
-        case GST_FORMAT_TIME:
+        case GST_FORMAT_BYTES:
           if (ivorbisfile->vf.seekable)
-            *value =
-                (gint64) (ov_time_total (&ivorbisfile->vf, -1) * GST_SECOND);
+            cur = ov_pcm_tell (&ivorbisfile->vf) * vi->channels * 2;
           else
-            return FALSE;
+            cur = ivorbisfile->total_bytes;
           break;
         default:
-          if (*format == logical_stream_format) {
+          if (format == logical_stream_format) {
             if (ivorbisfile->vf.seekable)
-              *value = ivorbisfile->vf.links;
+              cur = ivorbisfile->current_link;
             else
               return FALSE;
           } else
             res = FALSE;
           break;
       }
+
+      gst_query_set_position (query, format, cur);
+
       break;
     }
-    case GST_QUERY_POSITION:
-      switch (*format) {
-        case GST_FORMAT_TIME:
+    case GST_QUERY_DURATION:
+    {
+
+      GstFormat format;
+      GstFormat rformat = GST_FORMAT_TIME;
+      gint64 cur;
+      GstPad *peer;
+
+      /* save requested format */
+      gst_query_parse_position (query, &format, NULL);
+
+      /* query peer for current position in time */
+      gst_query_set_position (query, GST_FORMAT_TIME, -1);
+
+      if ((peer = gst_pad_get_peer (ivorbisfile->sinkpad)) == NULL)
+        goto error;
+
+      if (!gst_pad_query_position (peer, &rformat, &cur)) {
+        GST_LOG_OBJECT (ivorbisfile, "query on peer pad failed");
+        gst_object_unref (peer);
+        goto error;
+      }
+      gst_object_unref (peer);
+
+      if (format != rformat) {
+        gst_ivorbisfile_src_convert (pad, rformat, cur, &format, &cur);
+      }
+
+      switch (format) {
+        case GST_FORMAT_DEFAULT:
           if (ivorbisfile->vf.seekable)
-            *value = (gint64) (ov_time_tell (&ivorbisfile->vf) * GST_SECOND);
+            cur = ov_pcm_total (&ivorbisfile->vf, -1);
           else
-            *value = ivorbisfile->total_bytes * GST_SECOND
-                / (vi->rate * vi->channels * 2);
+            return FALSE;
           break;
         case GST_FORMAT_BYTES:
           if (ivorbisfile->vf.seekable)
-            *value = ov_pcm_tell (&ivorbisfile->vf) * vi->channels * 2;
+            cur = ov_pcm_total (&ivorbisfile->vf, -1) * vi->channels * 2;
           else
-            *value = ivorbisfile->total_bytes;
+            return FALSE;
           break;
-        case GST_FORMAT_DEFAULT:
+        case GST_FORMAT_TIME:
           if (ivorbisfile->vf.seekable)
-            *value = ov_pcm_tell (&ivorbisfile->vf);
+            cur = (gint64) (ov_time_total (&ivorbisfile->vf, -1) * GST_SECOND);
           else
-            *value = ivorbisfile->total_bytes / (vi->channels * 2);
+            return FALSE;
           break;
         default:
-          if (*format == logical_stream_format) {
+          if (format == logical_stream_format) {
             if (ivorbisfile->vf.seekable)
-              *value = ivorbisfile->current_link;
+              cur = ivorbisfile->vf.links;
             else
               return FALSE;
           } else
             res = FALSE;
           break;
       }
+
+      gst_query_set_position (query, format, cur);
+
+      break;
+    }
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      /* peel off input */
+      gst_query_parse_convert (query, &src_fmt, &src_val, NULL, NULL);
+      if ((res = gst_ivorbisfile_src_convert (pad, src_fmt, src_val,
+                  &dest_fmt, &dest_val))) {
+        gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      }
       break;
+    }
     default:
       res = FALSE;
       break;
   }
 
   return res;
+
+error:
+
+  return FALSE;
+
 }
 
-static const GstEventMask *
-gst_ivorbisfile_get_event_masks (GstPad * pad)
+
+static gboolean
+gst_ivorbisfile_sink_event (GstPad * pad, GstEvent * event)
 {
-  static const GstEventMask masks[] = {
-    {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_ACCURATE},
-    {0,}
-  };
 
-  return masks;
+  Ivorbisfile *ivorbisfile;
+
+  ivorbisfile = GST_IVORBISFILE (GST_PAD_PARENT (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      GST_DEBUG ("eos");
+      ov_clear (&ivorbisfile->vf);
+      ivorbisfile->eos = TRUE;
+      break;
+    case GST_EVENT_NEWSEGMENT:
+      GST_DEBUG ("discont");
+      ivorbisfile->need_discont = TRUE;
+    default:
+      break;
+  }
+
+  return gst_pad_event_default (pad, event);
 }
 
+
 /* handle events on src pad */
 static gboolean
 gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event)
@@ -976,6 +1125,7 @@ gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event)
       gint64 offset;
       vorbis_info *vi;
       GstFormat format;
+      GstSeekFlags flags;
 
       GST_DEBUG ("ivorbisfile: handling seek event on pad %s:%s",
           GST_DEBUG_PAD_NAME (pad));
@@ -985,16 +1135,15 @@ gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event)
         return FALSE;
       }
 
-      offset = GST_EVENT_SEEK_OFFSET (event);
-      format = GST_EVENT_SEEK_FORMAT (event);
+      gst_event_parse_seek (event, NULL, &format, &flags, NULL, &offset, NULL,
+          NULL);
 
       switch (format) {
         case GST_FORMAT_TIME:
           ivorbisfile->seek_pending = TRUE;
           ivorbisfile->seek_value = offset;
           ivorbisfile->seek_format = format;
-          ivorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event)
-              & GST_SEEK_FLAG_ACCURATE;
+          ivorbisfile->seek_accurate = flags & GST_SEEK_FLAG_ACCURATE;
           break;
         case GST_FORMAT_BYTES:
           vi = ov_info (&ivorbisfile->vf, -1);
@@ -1009,16 +1158,14 @@ gst_ivorbisfile_src_event (GstPad * pad, GstEvent * event)
           ivorbisfile->seek_pending = TRUE;
           ivorbisfile->seek_value = offset;
           ivorbisfile->seek_format = format;
-          ivorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event)
-              & GST_SEEK_FLAG_ACCURATE;
+          ivorbisfile->seek_accurate = flags & GST_SEEK_FLAG_ACCURATE;
           break;
         default:
           if (format == logical_stream_format) {
             ivorbisfile->seek_pending = TRUE;
             ivorbisfile->seek_value = offset;
             ivorbisfile->seek_format = format;
-            ivorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event)
-                & GST_SEEK_FLAG_ACCURATE;
+            ivorbisfile->seek_accurate = flags & GST_SEEK_FLAG_ACCURATE;
           } else {
             GST_DEBUG ("unhandled seek format");
             res = FALSE;
@@ -1040,31 +1187,39 @@ done:
 static GstStateChangeReturn
 gst_ivorbisfile_change_state (GstElement * element, GstStateChange transition)
 {
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
   Ivorbisfile *ivorbisfile = GST_IVORBISFILE (element);
 
   switch (transition) {
     case GST_STATE_CHANGE_NULL_TO_READY:
+      /* fall through */
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       ivorbisfile->restart = TRUE;
-      ivorbisfile->bs = gst_bytestream_new (ivorbisfile->sinkpad);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       ivorbisfile->eos = FALSE;
+      break;
+    default:
+      break;
+  }
+
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       ov_clear (&ivorbisfile->vf);
-      gst_bytestream_destroy (ivorbisfile->bs);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
     default:
       break;
   }
 
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
-  return GST_STATE_CHANGE_SUCCESS;
+
+  return ret;
 }
 
 static void