gst_plugins_base/gst/audioresample/gstaudioresample.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
--- a/gst_plugins_base/gst/audioresample/gstaudioresample.c	Tue Aug 31 15:30:33 2010 +0300
+++ b/gst_plugins_base/gst/audioresample/gstaudioresample.c	Wed Sep 01 12:16:41 2010 +0100
@@ -1,7 +1,6 @@
 /* GStreamer
  * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
  * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
- * Copyright (C) 2007-2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -18,24 +17,25 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+/* Element-Checklist-Version: 5 */
 
 /**
  * SECTION:element-audioresample
  *
- * audioresample resamples raw audio buffers to different sample rates using
+ * <refsect2>
+ * Audioresample resamples raw audio buffers to different sample rates using
  * a configurable windowing function to enhance quality.
- *
- * <refsect2>
  * <title>Example launch line</title>
- * |[
+ * <para>
+ * <programlisting>
  * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw-int, rate=8000 ! alsasink
- * ]| Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
+ * </programlisting>
+ * Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa. 
  * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
+ * </para>
  * </refsect2>
- */
-
-/* TODO:
- *  - Enable SSE/ARM optimizations and select at runtime
+ *
+ * Last reviewed on 2006-03-02 (0.10.4)
  */
 
 #ifdef HAVE_CONFIG_H
@@ -45,436 +45,286 @@
 #include <string.h>
 #include <math.h>
 
+/*#define DEBUG_ENABLED */
 #include "gstaudioresample.h"
 #include <gst/audio/audio.h>
 #include <gst/base/gstbasetransform.h>
 
-#if defined AUDIORESAMPLE_FORMAT_AUTO
-#define OIL_ENABLE_UNSTABLE_API
-#include <liboil/liboilprofile.h>
-#include <liboil/liboil.h>
-#endif
+GST_DEBUG_CATEGORY_STATIC (audioresample_debug);
+#define GST_CAT_DEFAULT audioresample_debug
 
-GST_DEBUG_CATEGORY (audio_resample_debug);
-#define GST_CAT_DEFAULT audio_resample_debug
+/* elementfactory information */
+static const GstElementDetails gst_audioresample_details =
+GST_ELEMENT_DETAILS ("Audio scaler",
+    "Filter/Converter/Audio",
+    "Resample audio",
+    "David Schleef <ds@schleef.org>");
+
+#define DEFAULT_FILTERLEN       16
 
 enum
 {
   PROP_0,
-  PROP_QUALITY,
-  PROP_FILTER_LENGTH
+  PROP_FILTERLEN
 };
 
 #define SUPPORTED_CAPS \
 GST_STATIC_CAPS ( \
-    "audio/x-raw-float, " \
-      "rate = (int) [ 1, MAX ], "	\
-      "channels = (int) [ 1, MAX ], " \
-      "endianness = (int) BYTE_ORDER, " \
-      "width = (int) { 32, 64 }; " \
-    "audio/x-raw-int, " \
-      "rate = (int) [ 1, MAX ], " \
-      "channels = (int) [ 1, MAX ], " \
-      "endianness = (int) BYTE_ORDER, " \
-      "width = (int) 32, " \
-      "depth = (int) 32, " \
-      "signed = (boolean) true; " \
-    "audio/x-raw-int, " \
-      "rate = (int) [ 1, MAX ], " \
-      "channels = (int) [ 1, MAX ], " \
-      "endianness = (int) BYTE_ORDER, " \
-      "width = (int) 24, " \
-      "depth = (int) 24, " \
-      "signed = (boolean) true; " \
     "audio/x-raw-int, " \
       "rate = (int) [ 1, MAX ], " \
       "channels = (int) [ 1, MAX ], " \
       "endianness = (int) BYTE_ORDER, " \
       "width = (int) 16, " \
       "depth = (int) 16, " \
-      "signed = (boolean) true; " \
+      "signed = (boolean) true;" \
     "audio/x-raw-int, " \
       "rate = (int) [ 1, MAX ], " \
       "channels = (int) [ 1, MAX ], " \
       "endianness = (int) BYTE_ORDER, " \
-      "width = (int) 8, " \
-      "depth = (int) 8, " \
-      "signed = (boolean) true" \
+      "width = (int) 32, " \
+      "depth = (int) 32, " \
+      "signed = (boolean) true;" \
+    "audio/x-raw-float, " \
+      "rate = (int) [ 1, MAX ], "	\
+      "channels = (int) [ 1, MAX ], " \
+      "endianness = (int) BYTE_ORDER, " \
+      "width = (int) 32; " \
+    "audio/x-raw-float, " \
+      "rate = (int) [ 1, MAX ], "	\
+      "channels = (int) [ 1, MAX ], " \
+      "endianness = (int) BYTE_ORDER, " \
+      "width = (int) 64" \
 )
 
-/* If TRUE integer arithmetic resampling is faster and will be used if appropiate */
-#if defined AUDIORESAMPLE_FORMAT_INT
-static gboolean gst_audio_resample_use_int = TRUE;
-#elif defined AUDIORESAMPLE_FORMAT_FLOAT
-static gboolean gst_audio_resample_use_int = FALSE;
-#else
-static gboolean gst_audio_resample_use_int = FALSE;
-#endif
-
-static GstStaticPadTemplate gst_audio_resample_sink_template =
+static GstStaticPadTemplate gst_audioresample_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
 
-static GstStaticPadTemplate gst_audio_resample_src_template =
+static GstStaticPadTemplate gst_audioresample_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
 
-static void gst_audio_resample_set_property (GObject * object,
+static void gst_audioresample_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_audio_resample_get_property (GObject * object,
+static void gst_audioresample_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec);
 
 /* vmethods */
-static gboolean gst_audio_resample_get_unit_size (GstBaseTransform * base,
+static gboolean audioresample_get_unit_size (GstBaseTransform * base,
     GstCaps * caps, guint * size);
-static GstCaps *gst_audio_resample_transform_caps (GstBaseTransform * base,
+static GstCaps *audioresample_transform_caps (GstBaseTransform * base,
     GstPadDirection direction, GstCaps * caps);
-static void gst_audio_resample_fixate_caps (GstBaseTransform * base,
-    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
-static gboolean gst_audio_resample_transform_size (GstBaseTransform * trans,
+static gboolean audioresample_transform_size (GstBaseTransform * trans,
     GstPadDirection direction, GstCaps * incaps, guint insize,
     GstCaps * outcaps, guint * outsize);
-static gboolean gst_audio_resample_set_caps (GstBaseTransform * base,
+static gboolean audioresample_set_caps (GstBaseTransform * base,
     GstCaps * incaps, GstCaps * outcaps);
-static GstFlowReturn gst_audio_resample_transform (GstBaseTransform * base,
+static GstFlowReturn audioresample_pushthrough (GstAudioresample *
+    audioresample);
+static GstFlowReturn audioresample_transform (GstBaseTransform * base,
     GstBuffer * inbuf, GstBuffer * outbuf);
-static gboolean gst_audio_resample_event (GstBaseTransform * base,
-    GstEvent * event);
-static gboolean gst_audio_resample_start (GstBaseTransform * base);
-static gboolean gst_audio_resample_stop (GstBaseTransform * base);
-static gboolean gst_audio_resample_query (GstPad * pad, GstQuery * query);
-static const GstQueryType *gst_audio_resample_query_type (GstPad * pad);
+static gboolean audioresample_event (GstBaseTransform * base, GstEvent * event);
+static gboolean audioresample_start (GstBaseTransform * base);
+static gboolean audioresample_stop (GstBaseTransform * base);
 
-GST_BOILERPLATE (GstAudioResample, gst_audio_resample, GstBaseTransform,
-    GST_TYPE_BASE_TRANSFORM);
+static gboolean audioresample_query (GstPad * pad, GstQuery * query);
+static const GstQueryType *audioresample_query_type (GstPad * pad);
+
+#define DEBUG_INIT(bla) \
+  GST_DEBUG_CATEGORY_INIT (audioresample_debug, "audioresample", 0, "audio resampling element");
+
+GST_BOILERPLATE_FULL (GstAudioresample, gst_audioresample, GstBaseTransform,
+    GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
 
 static void
-gst_audio_resample_base_init (gpointer g_class)
+gst_audioresample_base_init (gpointer g_class)
 {
   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
 
   gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&gst_audio_resample_src_template));
+      gst_static_pad_template_get (&gst_audioresample_src_template));
   gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&gst_audio_resample_sink_template));
+      gst_static_pad_template_get (&gst_audioresample_sink_template));
 
-  gst_element_class_set_details_simple (gstelement_class, "Audio resampler",
-      "Filter/Converter/Audio", "Resamples audio",
-      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+  gst_element_class_set_details (gstelement_class, &gst_audioresample_details);
 }
 
 static void
-gst_audio_resample_class_init (GstAudioResampleClass * klass)
+gst_audioresample_class_init (GstAudioresampleClass * klass)
 {
-  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GObjectClass *gobject_class;
+
+  gobject_class = (GObjectClass *) klass;
 
-  gobject_class->set_property = gst_audio_resample_set_property;
-  gobject_class->get_property = gst_audio_resample_get_property;
+  gobject_class->set_property = gst_audioresample_set_property;
+  gobject_class->get_property = gst_audioresample_get_property;
 
-  g_object_class_install_property (gobject_class, PROP_QUALITY,
-      g_param_spec_int ("quality", "Quality", "Resample quality with 0 being "
-          "the lowest and 10 being the best",
-          SPEEX_RESAMPLER_QUALITY_MIN, SPEEX_RESAMPLER_QUALITY_MAX,
-          SPEEX_RESAMPLER_QUALITY_DEFAULT,
+  g_object_class_install_property (gobject_class, PROP_FILTERLEN,
+      g_param_spec_int ("filter_length", "filter_length", "filter_length",
+          0, G_MAXINT, DEFAULT_FILTERLEN,
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
-  /* FIXME 0.11: Remove this property, it's just for compatibility
-   * with old audioresample
-   */
-  /**
-   * GstAudioResample:filter-length:
-   *
-   * Length of the resample filter
-   *
-   * Deprectated: Use #GstAudioResample:quality property instead
-   */
-  g_object_class_install_property (gobject_class, PROP_FILTER_LENGTH,
-      g_param_spec_int ("filter-length", "Filter length",
-          "Length of the resample filter", 0, G_MAXINT, 64, G_PARAM_READWRITE));
-
   GST_BASE_TRANSFORM_CLASS (klass)->start =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_start);
+      GST_DEBUG_FUNCPTR (audioresample_start);
   GST_BASE_TRANSFORM_CLASS (klass)->stop =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_stop);
+      GST_DEBUG_FUNCPTR (audioresample_stop);
   GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_transform_size);
+      GST_DEBUG_FUNCPTR (audioresample_transform_size);
   GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_get_unit_size);
+      GST_DEBUG_FUNCPTR (audioresample_get_unit_size);
   GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_transform_caps);
-  GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_fixate_caps);
+      GST_DEBUG_FUNCPTR (audioresample_transform_caps);
   GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_set_caps);
+      GST_DEBUG_FUNCPTR (audioresample_set_caps);
   GST_BASE_TRANSFORM_CLASS (klass)->transform =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_transform);
+      GST_DEBUG_FUNCPTR (audioresample_transform);
   GST_BASE_TRANSFORM_CLASS (klass)->event =
-      GST_DEBUG_FUNCPTR (gst_audio_resample_event);
+      GST_DEBUG_FUNCPTR (audioresample_event);
 
   GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
 }
 
+
 static void
-gst_audio_resample_init (GstAudioResample * resample,
-    GstAudioResampleClass * klass)
+gst_audioresample_init (GstAudioresample * audioresample,
+    GstAudioresampleClass * klass)
 {
-  GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
+  GstBaseTransform *trans;
+
+  trans = GST_BASE_TRANSFORM (audioresample);
 
-  resample->quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
-
-  resample->need_discont = FALSE;
+  /* buffer alloc passthrough is too impossible. FIXME, it
+   * is trivial in the passthrough case. */
+  gst_pad_set_bufferalloc_function (trans->sinkpad, NULL);
 
-  gst_pad_set_query_function (trans->srcpad, gst_audio_resample_query);
-  gst_pad_set_query_type_function (trans->srcpad,
-      gst_audio_resample_query_type);
+  audioresample->filter_length = DEFAULT_FILTERLEN;
+
+  audioresample->need_discont = FALSE;
+
+  gst_pad_set_query_function (trans->srcpad, audioresample_query);
+  gst_pad_set_query_type_function (trans->srcpad, audioresample_query_type);
 }
 
 /* vmethods */
 static gboolean
-gst_audio_resample_start (GstBaseTransform * base)
+audioresample_start (GstBaseTransform * base)
 {
-  GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
+  GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
 
-  resample->next_offset = -1;
-  resample->next_ts = -1;
-  resample->next_upstream_ts = -1;
+  audioresample->resample = resample_new ();
+  audioresample->ts_offset = -1;
+  audioresample->offset = -1;
+  audioresample->next_ts = -1;
+
+  resample_set_filter_length (audioresample->resample,
+      audioresample->filter_length);
 
   return TRUE;
 }
 
 static gboolean
-gst_audio_resample_stop (GstBaseTransform * base)
+audioresample_stop (GstBaseTransform * base)
 {
-  GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
+  GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
 
-  if (resample->state) {
-    resample->funcs->destroy (resample->state);
-    resample->state = NULL;
+  if (audioresample->resample) {
+    resample_free (audioresample->resample);
+    audioresample->resample = NULL;
   }
 
-  resample->funcs = NULL;
-
-  g_free (resample->tmp_in);
-  resample->tmp_in = NULL;
-  resample->tmp_in_size = 0;
-
-  g_free (resample->tmp_out);
-  resample->tmp_out = NULL;
-  resample->tmp_out_size = 0;
-
-  gst_caps_replace (&resample->sinkcaps, NULL);
-  gst_caps_replace (&resample->srccaps, NULL);
+  gst_caps_replace (&audioresample->sinkcaps, NULL);
+  gst_caps_replace (&audioresample->srccaps, NULL);
 
   return TRUE;
 }
 
 static gboolean
-gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
+audioresample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
     guint * size)
 {
   gint width, channels;
   GstStructure *structure;
   gboolean ret;
 
-  g_return_val_if_fail (size != NULL, FALSE);
+  g_assert (size);
 
   /* this works for both float and int */
   structure = gst_caps_get_structure (caps, 0);
   ret = gst_structure_get_int (structure, "width", &width);
   ret &= gst_structure_get_int (structure, "channels", &channels);
+  g_return_val_if_fail (ret, FALSE);
 
-  if (G_UNLIKELY (!ret))
-    return FALSE;
-
-  *size = (width / 8) * channels;
+  *size = width * channels / 8;
 
   return TRUE;
 }
 
 static GstCaps *
-gst_audio_resample_transform_caps (GstBaseTransform * base,
+audioresample_transform_caps (GstBaseTransform * base,
     GstPadDirection direction, GstCaps * caps)
 {
-  const GValue *val;
-  GstStructure *s;
   GstCaps *res;
-
-  /* transform single caps into input_caps + input_caps with the rate
-   * field set to our supported range. This ensures that upstream knows
-   * about downstream's prefered rate(s) and can negotiate accordingly. */
-  res = gst_caps_copy (caps);
+  GstStructure *structure;
 
-  /* first, however, check if the caps contain a range for the rate field, in
-   * which case that side isn't going to care much about the exact sample rate
-   * chosen and we should just assume things will get fixated to something sane
-   * and we may just as well offer our full range instead of the range in the
-   * caps. If the rate is not an int range value, it's likely to express a
-   * real preference or limitation and we should maintain that structure as
-   * preference by putting it first into the transformed caps, and only add
-   * our full rate range as second option  */
-  s = gst_caps_get_structure (res, 0);
-  val = gst_structure_get_value (s, "rate");
-  if (val == NULL || GST_VALUE_HOLDS_INT_RANGE (val)) {
-    /* overwrite existing range, or add field if it doesn't exist yet */
-    gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
-  } else {
-    /* append caps with full range to existing caps with non-range rate field */
-    s = gst_structure_copy (s);
-    gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
-    gst_caps_append_structure (res, s);
-  }
+  /* transform caps gives one single caps so we can just replace
+   * the rate property with our range. */
+  res = gst_caps_copy (caps);
+  structure = gst_caps_get_structure (res, 0);
+  gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
 
   return res;
 }
 
-/* Fixate rate to the allowed rate that has the smallest difference */
-static void
-gst_audio_resample_fixate_caps (GstBaseTransform * base,
-    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
-{
-  GstStructure *s;
-  gint rate;
-
-  s = gst_caps_get_structure (caps, 0);
-  if (G_UNLIKELY (!gst_structure_get_int (s, "rate", &rate)))
-    return;
-
-  s = gst_caps_get_structure (othercaps, 0);
-  gst_structure_fixate_field_nearest_int (s, "rate", rate);
-}
-
-static const SpeexResampleFuncs *
-gst_audio_resample_get_funcs (gint width, gboolean fp)
-{
-  const SpeexResampleFuncs *funcs = NULL;
-
-  if (gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
-    funcs = &int_funcs;
-  else if ((!gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
-      || (width == 32 && fp))
-    funcs = &float_funcs;
-  else if ((width == 64 && fp) || ((width == 32 || width == 24) && !fp))
-    funcs = &double_funcs;
-  else
-    g_assert_not_reached ();
-
-  return funcs;
-}
-
-static SpeexResamplerState *
-gst_audio_resample_init_state (GstAudioResample * resample, gint width,
-    gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
-{
-  SpeexResamplerState *ret = NULL;
-  gint err = RESAMPLER_ERR_SUCCESS;
-  const SpeexResampleFuncs *funcs = gst_audio_resample_get_funcs (width, fp);
-
-  ret = funcs->init (channels, inrate, outrate, quality, &err);
-
-  if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
-    GST_ERROR_OBJECT (resample, "Failed to create resampler state: %s",
-        funcs->strerror (err));
-    return NULL;
-  }
-
-  funcs->skip_zeros (ret);
-
-  return ret;
-}
-
 static gboolean
-gst_audio_resample_update_state (GstAudioResample * resample, gint width,
-    gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
-{
-  gboolean ret = TRUE;
-  gboolean updated_latency = FALSE;
-
-  updated_latency = (resample->inrate != inrate
-      || quality != resample->quality) && resample->state != NULL;
-
-  if (resample->state == NULL) {
-    ret = TRUE;
-  } else if (resample->channels != channels || fp != resample->fp
-      || width != resample->width) {
-    resample->funcs->destroy (resample->state);
-    resample->state =
-        gst_audio_resample_init_state (resample, width, channels, inrate,
-        outrate, quality, fp);
-
-    resample->funcs = gst_audio_resample_get_funcs (width, fp);
-    ret = (resample->state != NULL);
-  } else if (resample->inrate != inrate || resample->outrate != outrate) {
-    gint err = RESAMPLER_ERR_SUCCESS;
-
-    err = resample->funcs->set_rate (resample->state, inrate, outrate);
-
-    if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
-      GST_ERROR_OBJECT (resample, "Failed to update rate: %s",
-          resample->funcs->strerror (err));
-
-    ret = (err == RESAMPLER_ERR_SUCCESS);
-  } else if (quality != resample->quality) {
-    gint err = RESAMPLER_ERR_SUCCESS;
-
-    err = resample->funcs->set_quality (resample->state, quality);
-
-    if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
-      GST_ERROR_OBJECT (resample, "Failed to update quality: %s",
-          resample->funcs->strerror (err));
-
-    ret = (err == RESAMPLER_ERR_SUCCESS);
-  }
-
-  resample->width = width;
-  resample->channels = channels;
-  resample->fp = fp;
-  resample->quality = quality;
-  resample->inrate = inrate;
-  resample->outrate = outrate;
-
-  if (updated_latency)
-    gst_element_post_message (GST_ELEMENT (resample),
-        gst_message_new_latency (GST_OBJECT (resample)));
-
-  return ret;
-}
-
-static void
-gst_audio_resample_reset_state (GstAudioResample * resample)
-{
-  if (resample->state)
-    resample->funcs->reset_mem (resample->state);
-}
-
-static gboolean
-gst_audio_resample_parse_caps (GstCaps * incaps,
-    GstCaps * outcaps, gint * width, gint * channels, gint * inrate,
-    gint * outrate, gboolean * fp)
+resample_set_state_from_caps (ResampleState * state, GstCaps * incaps,
+    GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate)
 {
   GstStructure *structure;
   gboolean ret;
-  gint mywidth, myinrate, myoutrate, mychannels;
-  gboolean myfp;
+  gint myinrate, myoutrate;
+  int mychannels;
+  gint width, depth;
+  ResampleFormat format;
 
   GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
       GST_PTR_FORMAT, incaps, outcaps);
 
   structure = gst_caps_get_structure (incaps, 0);
 
-  if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float"))
-    myfp = TRUE;
-  else
-    myfp = FALSE;
+  /* get width */
+  ret = gst_structure_get_int (structure, "width", &width);
+  if (!ret)
+    goto no_width;
 
+  /* figure out the format */
+  if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float")) {
+    if (width == 32)
+      format = RESAMPLE_FORMAT_F32;
+    else if (width == 64)
+      format = RESAMPLE_FORMAT_F64;
+    else
+      goto wrong_depth;
+  } else {
+    /* for int, depth and width must be the same */
+    ret = gst_structure_get_int (structure, "depth", &depth);
+    if (!ret || width != depth)
+      goto not_equal;
+
+    if (width == 16)
+      format = RESAMPLE_FORMAT_S16;
+    else if (width == 32)
+      format = RESAMPLE_FORMAT_S32;
+    else
+      goto wrong_depth;
+  }
   ret = gst_structure_get_int (structure, "rate", &myinrate);
   ret &= gst_structure_get_int (structure, "channels", &mychannels);
-  ret &= gst_structure_get_int (structure, "width", &mywidth);
-  if (G_UNLIKELY (!ret))
+  if (!ret)
     goto no_in_rate_channels;
 
   structure = gst_caps_get_structure (outcaps, 0);
   ret = gst_structure_get_int (structure, "rate", &myoutrate);
-  if (G_UNLIKELY (!ret))
+  if (!ret)
     goto no_out_rate;
 
   if (channels)
@@ -483,14 +333,30 @@
     *inrate = myinrate;
   if (outrate)
     *outrate = myoutrate;
-  if (width)
-    *width = mywidth;
-  if (fp)
-    *fp = myfp;
+
+  resample_set_format (state, format);
+  resample_set_n_channels (state, mychannels);
+  resample_set_input_rate (state, myinrate);
+  resample_set_output_rate (state, myoutrate);
 
   return TRUE;
 
   /* ERRORS */
+no_width:
+  {
+    GST_DEBUG ("failed to get width from caps");
+    return FALSE;
+  }
+not_equal:
+  {
+    GST_DEBUG ("width %d and depth %d must be the same", width, depth);
+    return FALSE;
+  }
+wrong_depth:
+  {
+    GST_DEBUG ("unknown depth %d found", depth);
+    return FALSE;
+  }
 no_in_rate_channels:
   {
     GST_DEBUG ("could not get input rate and channels");
@@ -503,29 +369,16 @@
   }
 }
 
-static gint
-_gcd (gint a, gint b)
-{
-  while (b != 0) {
-    int temp = a;
-
-    a = b;
-    b = temp % b;
-  }
-
-  return ABS (a);
-}
-
 static gboolean
-gst_audio_resample_transform_size (GstBaseTransform * base,
+audioresample_transform_size (GstBaseTransform * base,
     GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
     guint * othersize)
 {
+  GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
+  ResampleState *state;
   GstCaps *srccaps, *sinkcaps;
+  gboolean use_internal = FALSE;        /* whether we use the internal state */
   gboolean ret = TRUE;
-  guint32 ratio_den, ratio_num;
-  gint inrate, outrate, gcd;
-  gint bytes_per_samp, channels;
 
   GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
       size, direction == GST_PAD_SINK ? "SINK" : "SRC");
@@ -537,386 +390,216 @@
     srccaps = caps;
   }
 
-  /* Get sample width -> bytes_per_samp, channels, inrate, outrate */
-  ret =
-      gst_audio_resample_parse_caps (caps, othercaps, &bytes_per_samp,
-      &channels, &inrate, &outrate, NULL);
-  if (G_UNLIKELY (!ret)) {
-    GST_ERROR_OBJECT (base, "Wrong caps");
-    return FALSE;
+  /* if the caps are the ones that _set_caps got called with; we can use
+   * our own state; otherwise we'll have to create a state */
+  if (gst_caps_is_equal (sinkcaps, audioresample->sinkcaps) &&
+      gst_caps_is_equal (srccaps, audioresample->srccaps)) {
+    use_internal = TRUE;
+    state = audioresample->resample;
+  } else {
+    GST_DEBUG_OBJECT (audioresample,
+        "caps are not the set caps, creating state");
+    state = resample_new ();
+    resample_set_filter_length (state, audioresample->filter_length);
+    resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL);
   }
-  /* Number of samples in either buffer is size / (width*channels) ->
-   * calculate the factor */
-  bytes_per_samp = bytes_per_samp * channels / 8;
-  /* Convert source buffer size to samples */
-  size /= bytes_per_samp;
-
-  /* Simplify the conversion ratio factors */
-  gcd = _gcd (inrate, outrate);
-  ratio_num = inrate / gcd;
-  ratio_den = outrate / gcd;
 
   if (direction == GST_PAD_SINK) {
-    /* asked to convert size of an incoming buffer. Round up the output size */
-    *othersize = (size * ratio_den + ratio_num - 1) / ratio_num;
-    *othersize *= bytes_per_samp;
+    /* asked to convert size of an incoming buffer */
+    *othersize = resample_get_output_size_for_input (state, size);
   } else {
-    /* asked to convert size of an outgoing buffer. Round down the input size */
-    *othersize = (size * ratio_num) / ratio_den;
-    *othersize *= bytes_per_samp;
+    /* asked to convert size of an outgoing buffer */
+    *othersize = resample_get_input_size_for_output (state, size);
   }
+  g_assert (*othersize % state->sample_size == 0);
 
-  GST_LOG_OBJECT (base, "transformed size %d to %d", size * bytes_per_samp,
-      *othersize);
+  /* we make room for one extra sample, given that the resampling filter
+   * can output an extra one for non-integral i_rate/o_rate */
+  GST_LOG_OBJECT (base, "transformed size %d to %d", size, *othersize);
+
+  if (!use_internal) {
+    resample_free (state);
+  }
 
   return ret;
 }
 
 static gboolean
-gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
+audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
     GstCaps * outcaps)
 {
   gboolean ret;
-  gint width = 0, inrate = 0, outrate = 0, channels = 0;
-  gboolean fp;
-  GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
+  gint inrate, outrate;
+  int channels;
+  GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
 
-  GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %"
+  GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
       GST_PTR_FORMAT, incaps, outcaps);
 
-  ret = gst_audio_resample_parse_caps (incaps, outcaps,
-      &width, &channels, &inrate, &outrate, &fp);
+  ret = resample_set_state_from_caps (audioresample->resample, incaps, outcaps,
+      &channels, &inrate, &outrate);
 
-  if (G_UNLIKELY (!ret))
-    return FALSE;
+  g_return_val_if_fail (ret, FALSE);
 
-  ret =
-      gst_audio_resample_update_state (resample, width, channels, inrate,
-      outrate, resample->quality, fp);
-
-  if (G_UNLIKELY (!ret))
-    return FALSE;
+  audioresample->channels = channels;
+  GST_DEBUG_OBJECT (audioresample, "set channels to %d", channels);
+  audioresample->i_rate = inrate;
+  GST_DEBUG_OBJECT (audioresample, "set i_rate to %d", inrate);
+  audioresample->o_rate = outrate;
+  GST_DEBUG_OBJECT (audioresample, "set o_rate to %d", outrate);
 
   /* save caps so we can short-circuit in the size_transform if the caps
    * are the same */
-  gst_caps_replace (&resample->sinkcaps, incaps);
-  gst_caps_replace (&resample->srccaps, outcaps);
+  gst_caps_replace (&audioresample->sinkcaps, incaps);
+  gst_caps_replace (&audioresample->srccaps, outcaps);
+
+  return TRUE;
+}
+
+static gboolean
+audioresample_event (GstBaseTransform * base, GstEvent * event)
+{
+  GstAudioresample *audioresample;
+
+  audioresample = GST_AUDIORESAMPLE (base);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      resample_input_flush (audioresample->resample);
+      audioresample->ts_offset = -1;
+      audioresample->next_ts = -1;
+      audioresample->offset = -1;
+      break;
+    case GST_EVENT_NEWSEGMENT:
+      resample_input_pushthrough (audioresample->resample);
+      audioresample_pushthrough (audioresample);
+      audioresample->ts_offset = -1;
+      audioresample->next_ts = -1;
+      audioresample->offset = -1;
+      break;
+    case GST_EVENT_EOS:
+      resample_input_eos (audioresample->resample);
+      audioresample_pushthrough (audioresample);
+      break;
+    default:
+      break;
+  }
+  parent_class->event (base, event);
 
   return TRUE;
 }
 
-#define GST_MAXINT24 (8388607)
-#define GST_MININT24 (-8388608)
-
-#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
-#define GST_READ_UINT24 GST_READ_UINT24_LE
-#define GST_WRITE_UINT24 GST_WRITE_UINT24_LE
-#else
-#define GST_READ_UINT24 GST_READ_UINT24_BE
-#define GST_WRITE_UINT24 GST_WRITE_UINT24_BE
-#endif
-
-static void
-gst_audio_resample_convert_buffer (GstAudioResample * resample,
-    const guint8 * in, guint8 * out, guint len, gboolean inverse)
+static GstFlowReturn
+audioresample_do_output (GstAudioresample * audioresample, GstBuffer * outbuf)
 {
-  len *= resample->channels;
-
-  if (inverse) {
-    if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
-      gint8 *o = (gint8 *) out;
-      gint16 *i = (gint16 *) in;
-      gint32 tmp;
-
-      while (len) {
-        tmp = *i + (G_MAXINT8 >> 1);
-        *o = CLAMP (tmp >> 8, G_MININT8, G_MAXINT8);
-        o++;
-        i++;
-        len--;
-      }
-    } else if (!gst_audio_resample_use_int && resample->width == 8
-        && !resample->fp) {
-      gint8 *o = (gint8 *) out;
-      gfloat *i = (gfloat *) in;
-      gfloat tmp;
+  int outsize;
+  int outsamples;
+  ResampleState *r;
 
-      while (len) {
-        tmp = *i;
-        *o = (gint8) CLAMP (tmp * G_MAXINT8 + 0.5, G_MININT8, G_MAXINT8);
-        o++;
-        i++;
-        len--;
-      }
-    } else if (!gst_audio_resample_use_int && resample->width == 16
-        && !resample->fp) {
-      gint16 *o = (gint16 *) out;
-      gfloat *i = (gfloat *) in;
-      gfloat tmp;
-
-      while (len) {
-        tmp = *i;
-        *o = (gint16) CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
-        o++;
-        i++;
-        len--;
-      }
-    } else if (resample->width == 24 && !resample->fp) {
-      guint8 *o = (guint8 *) out;
-      gdouble *i = (gdouble *) in;
-      gdouble tmp;
+  r = audioresample->resample;
 
-      while (len) {
-        tmp = *i;
-        GST_WRITE_UINT24 (o, (gint32) CLAMP (tmp * GST_MAXINT24 + 0.5,
-                GST_MININT24, GST_MAXINT24));
-        o += 3;
-        i++;
-        len--;
-      }
-    } else if (resample->width == 32 && !resample->fp) {
-      gint32 *o = (gint32 *) out;
-      gdouble *i = (gdouble *) in;
-      gdouble tmp;
-
-      while (len) {
-        tmp = *i;
-        *o = (gint32) CLAMP (tmp * G_MAXINT32 + 0.5, G_MININT32, G_MAXINT32);
-        o++;
-        i++;
-        len--;
-      }
-    } else {
-      g_assert_not_reached ();
-    }
-  } else {
-    if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
-      gint8 *i = (gint8 *) in;
-      gint16 *o = (gint16 *) out;
-      gint32 tmp;
+  outsize = resample_get_output_size (r);
+  GST_LOG_OBJECT (audioresample, "audioresample can give me %d bytes", outsize);
 
-      while (len) {
-        tmp = *i;
-        *o = tmp << 8;
-        o++;
-        i++;
-        len--;
-      }
-    } else if (!gst_audio_resample_use_int && resample->width == 8
-        && !resample->fp) {
-      gint8 *i = (gint8 *) in;
-      gfloat *o = (gfloat *) out;
-      gfloat tmp;
-
-      while (len) {
-        tmp = *i;
-        *o = tmp / G_MAXINT8;
-        o++;
-        i++;
-        len--;
-      }
-    } else if (!gst_audio_resample_use_int && resample->width == 16
-        && !resample->fp) {
-      gint16 *i = (gint16 *) in;
-      gfloat *o = (gfloat *) out;
-      gfloat tmp;
-
-      while (len) {
-        tmp = *i;
-        *o = tmp / G_MAXINT16;
-        o++;
-        i++;
-        len--;
-      }
-    } else if (resample->width == 24 && !resample->fp) {
-      guint8 *i = (guint8 *) in;
-      gdouble *o = (gdouble *) out;
-      gdouble tmp;
-      guint32 tmp2;
-
-      while (len) {
-        tmp2 = GST_READ_UINT24 (i);
-        if (tmp2 & 0x00800000)
-          tmp2 |= 0xff000000;
-        tmp = (gint32) tmp2;
-        *o = tmp / GST_MAXINT24;
-        o++;
-        i += 3;
-        len--;
-      }
-    } else if (resample->width == 32 && !resample->fp) {
-      gint32 *i = (gint32 *) in;
-      gdouble *o = (gdouble *) out;
-      gdouble tmp;
-
-      while (len) {
-        tmp = *i;
-        *o = tmp / G_MAXINT32;
-        o++;
-        i++;
-        len--;
-      }
-    } else {
-      g_assert_not_reached ();
-    }
+  /* protect against mem corruption */
+  if (outsize > GST_BUFFER_SIZE (outbuf)) {
+    GST_WARNING_OBJECT (audioresample,
+        "overriding audioresample's outsize %d with outbuffer's size %d",
+        outsize, GST_BUFFER_SIZE (outbuf));
+    outsize = GST_BUFFER_SIZE (outbuf);
   }
-}
-
-static void
-gst_audio_resample_push_drain (GstAudioResample * resample)
-{
-  GstBuffer *buf;
-  GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
-  GstFlowReturn res;
-  gint outsize;
-  guint out_len, out_processed;
-  gint err;
-  guint num, den, len;
-  guint8 *outtmp = NULL;
-  gboolean need_convert = FALSE;
-
-  if (!resample->state)
-    return;
-
-  /* Don't drain samples if we were resetted. */
-  if (resample->next_ts == -1)
-    return;
-
-  need_convert = (resample->funcs->width != resample->width);
-
-  resample->funcs->get_ratio (resample->state, &num, &den);
-
-  out_len = resample->funcs->get_input_latency (resample->state);
-  out_len = out_processed = (out_len * den + num - 1) / num;
-  outsize = (resample->width / 8) * out_len * resample->channels;
-
-  if (need_convert) {
-    guint outsize_tmp =
-        (resample->funcs->width / 8) * out_len * resample->channels;
-    if (outsize_tmp <= resample->tmp_out_size) {
-      outtmp = resample->tmp_out;
-    } else {
-      resample->tmp_out_size = outsize_tmp;
-      resample->tmp_out = outtmp = g_realloc (resample->tmp_out, outsize_tmp);
-    }
+  /* catch possibly wrong size differences */
+  if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
+    GST_WARNING_OBJECT (audioresample,
+        "audioresample's outsize %d too far from outbuffer's size %d",
+        outsize, GST_BUFFER_SIZE (outbuf));
   }
 
-  res =
-      gst_pad_alloc_buffer_and_set_caps (trans->srcpad, GST_BUFFER_OFFSET_NONE,
-      outsize, GST_PAD_CAPS (trans->srcpad), &buf);
+  outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize);
+  outsamples = outsize / r->sample_size;
+  GST_LOG_OBJECT (audioresample, "resample gave me %d bytes or %d samples",
+      outsize, outsamples);
 
-  if (G_UNLIKELY (res != GST_FLOW_OK)) {
-    GST_WARNING_OBJECT (resample, "failed allocating buffer of %d bytes",
-        outsize);
-    return;
-  }
-
-  len = resample->funcs->get_input_latency (resample->state);
+  GST_BUFFER_OFFSET (outbuf) = audioresample->offset;
+  GST_BUFFER_TIMESTAMP (outbuf) = audioresample->next_ts;
 
-  err =
-      resample->funcs->process (resample->state,
-      NULL, &len, (need_convert) ? outtmp : GST_BUFFER_DATA (buf),
-      &out_processed);
+  if (audioresample->ts_offset != -1) {
+    audioresample->offset += outsamples;
+    audioresample->ts_offset += outsamples;
+    audioresample->next_ts =
+        gst_util_uint64_scale_int (audioresample->ts_offset, GST_SECOND,
+        audioresample->o_rate);
+    GST_BUFFER_OFFSET_END (outbuf) = audioresample->offset;
 
-  if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
-    GST_WARNING_OBJECT (resample, "Failed to process drain: %s",
-        resample->funcs->strerror (err));
-    gst_buffer_unref (buf);
-    return;
-  }
-
-  if (G_UNLIKELY (out_processed == 0)) {
-    GST_WARNING_OBJECT (resample, "Failed to get drain, dropping buffer");
-    gst_buffer_unref (buf);
-    return;
+    /* we calculate DURATION as the difference between "next" timestamp
+     * and current timestamp so we ensure a contiguous stream, instead of
+     * having rounding errors. */
+    GST_BUFFER_DURATION (outbuf) = audioresample->next_ts -
+        GST_BUFFER_TIMESTAMP (outbuf);
+  } else {
+    /* no valid offset know, we can still sortof calculate the duration though */
+    GST_BUFFER_DURATION (outbuf) =
+        gst_util_uint64_scale_int (outsamples, GST_SECOND,
+        audioresample->o_rate);
   }
 
-  /* If we wrote more than allocated something is really wrong now
-   * and we should better abort immediately */
-  g_assert (out_len >= out_processed);
-
-  if (need_convert)
-    gst_audio_resample_convert_buffer (resample, outtmp, GST_BUFFER_DATA (buf),
-        out_processed, TRUE);
+  /* check for possible mem corruption */
+  if (outsize > GST_BUFFER_SIZE (outbuf)) {
+    /* this is an error that when it happens, would need fixing in the
+     * resample library; we told it we wanted only GST_BUFFER_SIZE (outbuf),
+     * and it gave us more ! */
+    GST_WARNING_OBJECT (audioresample,
+        "audioresample, you memory corrupting bastard. "
+        "you gave me outsize %d while my buffer was size %d",
+        outsize, GST_BUFFER_SIZE (outbuf));
+    return GST_FLOW_ERROR;
+  }
+  /* catch possibly wrong size differences */
+  if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
+    GST_WARNING_OBJECT (audioresample,
+        "audioresample's written outsize %d too far from outbuffer's size %d",
+        outsize, GST_BUFFER_SIZE (outbuf));
+  }
+  GST_BUFFER_SIZE (outbuf) = outsize;
 
-  GST_BUFFER_DURATION (buf) =
-      GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate);
-  GST_BUFFER_SIZE (buf) =
-      out_processed * resample->channels * (resample->width / 8);
-
-  if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) {
-    GST_BUFFER_OFFSET (buf) = resample->next_offset;
-    GST_BUFFER_OFFSET_END (buf) = resample->next_offset + out_processed;
-    GST_BUFFER_TIMESTAMP (buf) = resample->next_ts;
-
-    resample->next_ts += GST_BUFFER_DURATION (buf);
-    resample->next_offset += out_processed;
+  if (G_UNLIKELY (audioresample->need_discont)) {
+    GST_DEBUG_OBJECT (audioresample,
+        "marking this buffer with the DISCONT flag");
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    audioresample->need_discont = FALSE;
   }
 
-  GST_LOG_OBJECT (resample,
-      "Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT
-      " duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT " offset_end %"
-      G_GUINT64_FORMAT, GST_BUFFER_SIZE (buf),
-      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
-      GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
-      GST_BUFFER_OFFSET_END (buf));
+  GST_LOG_OBJECT (audioresample, "transformed to buffer of %d bytes, ts %"
+      GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
+      G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
+      outsize, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+      GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
+      GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
 
-  res = gst_pad_push (trans->srcpad, buf);
 
-  if (G_UNLIKELY (res != GST_FLOW_OK))
-    GST_WARNING_OBJECT (resample, "Failed to push drain: %s",
-        gst_flow_get_name (res));
-
-  return;
+  return GST_FLOW_OK;
 }
 
 static gboolean
-gst_audio_resample_event (GstBaseTransform * base, GstEvent * event)
-{
-  GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_FLUSH_STOP:
-      gst_audio_resample_reset_state (resample);
-      resample->next_offset = -1;
-      resample->next_ts = -1;
-      resample->next_upstream_ts = -1;
-      break;
-    case GST_EVENT_NEWSEGMENT:
-      gst_audio_resample_push_drain (resample);
-      gst_audio_resample_reset_state (resample);
-      resample->next_offset = -1;
-      resample->next_ts = -1;
-      resample->next_upstream_ts = -1;
-      break;
-    case GST_EVENT_EOS:
-      gst_audio_resample_push_drain (resample);
-      gst_audio_resample_reset_state (resample);
-      break;
-    default:
-      break;
-  }
-
-  return parent_class->event (base, event);
-}
-
-static gboolean
-gst_audio_resample_check_discont (GstAudioResample * resample,
+audioresample_check_discont (GstAudioresample * audioresample,
     GstClockTime timestamp)
 {
   if (timestamp != GST_CLOCK_TIME_NONE &&
-      resample->next_upstream_ts != GST_CLOCK_TIME_NONE &&
-      timestamp != resample->next_upstream_ts) {
+      audioresample->prev_ts != GST_CLOCK_TIME_NONE &&
+      audioresample->prev_duration != GST_CLOCK_TIME_NONE &&
+      timestamp != audioresample->prev_ts + audioresample->prev_duration) {
     /* Potentially a discontinuous buffer. However, it turns out that many
      * elements generate imperfect streams due to rounding errors, so we permit
      * a small error (up to one sample) without triggering a filter 
      * flush/restart (if triggered incorrectly, this will be audible) */
-    GstClockTimeDiff diff = timestamp - resample->next_upstream_ts;
+    GstClockTimeDiff diff = timestamp -
+        (audioresample->prev_ts + audioresample->prev_duration);
 
-    if (ABS (diff) > (GST_SECOND + resample->inrate - 1) / resample->inrate) {
-      GST_WARNING_OBJECT (resample,
-          "encountered timestamp discontinuity of %s%" GST_TIME_FORMAT,
-          (diff < 0) ? "-" : "", GST_TIME_ARGS ((GstClockTime) ABS (diff)));
+    if (ABS (diff) > GST_SECOND / audioresample->i_rate) {
+      GST_WARNING_OBJECT (audioresample,
+          "encountered timestamp discontinuity of %" G_GINT64_FORMAT, diff);
       return TRUE;
     }
   }
@@ -925,136 +608,23 @@
 }
 
 static GstFlowReturn
-gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
+audioresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
     GstBuffer * outbuf)
 {
-  guint32 in_len, in_processed;
-  guint32 out_len, out_processed;
-  gint err = RESAMPLER_ERR_SUCCESS;
-  guint8 *in_tmp = NULL, *out_tmp = NULL;
-  gboolean need_convert = (resample->funcs->width != resample->width);
-
-  in_len = GST_BUFFER_SIZE (inbuf) / resample->channels;
-  out_len = GST_BUFFER_SIZE (outbuf) / resample->channels;
-
-  in_len /= (resample->width / 8);
-  out_len /= (resample->width / 8);
-
-  in_processed = in_len;
-  out_processed = out_len;
-
-  if (need_convert) {
-    guint in_size_tmp =
-        in_len * resample->channels * (resample->funcs->width / 8);
-    guint out_size_tmp =
-        out_len * resample->channels * (resample->funcs->width / 8);
-
-    if (in_size_tmp <= resample->tmp_in_size) {
-      in_tmp = resample->tmp_in;
-    } else {
-      resample->tmp_in = in_tmp = g_realloc (resample->tmp_in, in_size_tmp);
-      resample->tmp_in_size = in_size_tmp;
-    }
-
-    gst_audio_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf),
-        in_tmp, in_len, FALSE);
-
-    if (out_size_tmp <= resample->tmp_out_size) {
-      out_tmp = resample->tmp_out;
-    } else {
-      resample->tmp_out = out_tmp = g_realloc (resample->tmp_out, out_size_tmp);
-      resample->tmp_out_size = out_size_tmp;
-    }
-  }
-
-  if (need_convert) {
-    err = resample->funcs->process (resample->state,
-        in_tmp, &in_processed, out_tmp, &out_processed);
-  } else {
-    err = resample->funcs->process (resample->state,
-        (const guint8 *) GST_BUFFER_DATA (inbuf), &in_processed,
-        (guint8 *) GST_BUFFER_DATA (outbuf), &out_processed);
-  }
-
-  if (G_UNLIKELY (in_len != in_processed))
-    GST_WARNING_OBJECT (resample, "Converted %d of %d input samples",
-        in_processed, in_len);
-
-  if (out_len != out_processed) {
-    if (out_processed == 0) {
-      GST_DEBUG_OBJECT (resample, "Converted to 0 samples, buffer dropped");
-
-      return GST_BASE_TRANSFORM_FLOW_DROPPED;
-    }
-
-    /* If we wrote more than allocated something is really wrong now
-     * and we should better abort immediately */
-    g_assert (out_len >= out_processed);
-  }
-
-  if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
-    GST_ERROR_OBJECT (resample, "Failed to convert data: %s",
-        resample->funcs->strerror (err));
-    return GST_FLOW_ERROR;
-  } else {
-
-    if (need_convert)
-      gst_audio_resample_convert_buffer (resample, out_tmp,
-          GST_BUFFER_DATA (outbuf), out_processed, TRUE);
-
-    GST_BUFFER_DURATION (outbuf) =
-        GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate);
-    GST_BUFFER_SIZE (outbuf) =
-        out_processed * resample->channels * (resample->width / 8);
-
-    if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) {
-      GST_BUFFER_TIMESTAMP (outbuf) = resample->next_ts;
-      GST_BUFFER_OFFSET (outbuf) = resample->next_offset;
-      GST_BUFFER_OFFSET_END (outbuf) = resample->next_offset + out_processed;
-
-      resample->next_ts += GST_BUFFER_DURATION (outbuf);
-      resample->next_offset += out_processed;
-    }
-
-    GST_LOG_OBJECT (resample,
-        "Converted to buffer of %u bytes with timestamp %" GST_TIME_FORMAT
-        ", duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
-        ", offset_end %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (outbuf),
-        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
-        GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
-        GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
-
-    return GST_FLOW_OK;
-  }
-}
-
-static GstFlowReturn
-gst_audio_resample_transform (GstBaseTransform * base, GstBuffer * inbuf,
-    GstBuffer * outbuf)
-{
-  GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
-  guint8 *data;
+  GstAudioresample *audioresample;
+  ResampleState *r;
+  guchar *data, *datacopy;
   gulong size;
   GstClockTime timestamp;
-  guint outsamples, insamples;
-  GstFlowReturn ret;
 
-  if (resample->state == NULL) {
-    if (G_UNLIKELY (!(resample->state =
-                gst_audio_resample_init_state (resample, resample->width,
-                    resample->channels, resample->inrate, resample->outrate,
-                    resample->quality, resample->fp))))
-      return GST_FLOW_ERROR;
-
-    resample->funcs =
-        gst_audio_resample_get_funcs (resample->width, resample->fp);
-  }
+  audioresample = GST_AUDIORESAMPLE (base);
+  r = audioresample->resample;
 
   data = GST_BUFFER_DATA (inbuf);
   size = GST_BUFFER_SIZE (inbuf);
   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
 
-  GST_LOG_OBJECT (resample, "transforming buffer of %ld bytes, ts %"
+  GST_LOG_OBJECT (audioresample, "transforming buffer of %ld bytes, ts %"
       GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
       G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
       size, GST_TIME_ARGS (timestamp),
@@ -1062,57 +632,88 @@
       GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
 
   /* check for timestamp discontinuities and flush/reset if needed */
-  if (G_UNLIKELY (gst_audio_resample_check_discont (resample, timestamp)
-          || GST_BUFFER_IS_DISCONT (inbuf))) {
+  if (G_UNLIKELY (audioresample_check_discont (audioresample, timestamp))) {
     /* Flush internal samples */
-    gst_audio_resample_reset_state (resample);
+    audioresample_pushthrough (audioresample);
     /* Inform downstream element about discontinuity */
-    resample->need_discont = TRUE;
-    /* We want to recalculate the timestamps */
-    resample->next_ts = -1;
-    resample->next_upstream_ts = -1;
-    resample->next_offset = -1;
+    audioresample->need_discont = TRUE;
+    /* We want to recalculate the offset */
+    audioresample->ts_offset = -1;
   }
 
-  insamples = GST_BUFFER_SIZE (inbuf) / resample->channels;
-  insamples /= (resample->width / 8);
+  if (audioresample->ts_offset == -1) {
+    /* if we don't know the initial offset yet, calculate it based on the 
+     * input timestamp. */
+    if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+      GstClockTime stime;
 
-  outsamples = GST_BUFFER_SIZE (outbuf) / resample->channels;
-  outsamples /= (resample->width / 8);
+      /* offset used to calculate the timestamps. We use the sample offset for
+       * this to make it more accurate. We want the first buffer to have the
+       * same timestamp as the incoming timestamp. */
+      audioresample->next_ts = timestamp;
+      audioresample->ts_offset =
+          gst_util_uint64_scale_int (timestamp, r->o_rate, GST_SECOND);
+      /* offset used to set as the buffer offset, this offset is always
+       * relative to the stream time, note that timestamp is not... */
+      stime = (timestamp - base->segment.start) + base->segment.time;
+      audioresample->offset =
+          gst_util_uint64_scale_int (stime, r->o_rate, GST_SECOND);
+    }
+  }
+  audioresample->prev_ts = timestamp;
+  audioresample->prev_duration = GST_BUFFER_DURATION (inbuf);
 
-  if (GST_CLOCK_TIME_IS_VALID (timestamp)
-      && !GST_CLOCK_TIME_IS_VALID (resample->next_ts)) {
-    resample->next_ts = timestamp;
-    resample->next_offset =
-        GST_CLOCK_TIME_TO_FRAMES (timestamp, resample->outrate);
+  /* need to memdup, resample takes ownership. */
+  datacopy = g_memdup (data, size);
+  resample_add_input_data (r, datacopy, size, g_free, datacopy);
+
+  return audioresample_do_output (audioresample, outbuf);
+}
+
+/* push remaining data in the buffers out */
+static GstFlowReturn
+audioresample_pushthrough (GstAudioresample * audioresample)
+{
+  int outsize;
+  ResampleState *r;
+  GstBuffer *outbuf;
+  GstFlowReturn res = GST_FLOW_OK;
+  GstBaseTransform *trans;
+
+  r = audioresample->resample;
+
+  outsize = resample_get_output_size (r);
+  if (outsize == 0) {
+    GST_DEBUG_OBJECT (audioresample, "no internal buffers needing flush");
+    goto done;
   }
 
-  if (G_UNLIKELY (resample->need_discont)) {
-    GST_DEBUG_OBJECT (resample, "marking this buffer with the DISCONT flag");
-    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
-    resample->need_discont = FALSE;
+  trans = GST_BASE_TRANSFORM (audioresample);
+
+  res = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET_NONE, outsize,
+      GST_PAD_CAPS (trans->srcpad), &outbuf);
+  if (G_UNLIKELY (res != GST_FLOW_OK)) {
+    GST_WARNING_OBJECT (audioresample, "failed allocating buffer of %d bytes",
+        outsize);
+    goto done;
   }
 
-  ret = gst_audio_resample_process (resample, inbuf, outbuf);
-  if (G_UNLIKELY (ret != GST_FLOW_OK))
-    return ret;
+  res = audioresample_do_output (audioresample, outbuf);
+  if (G_UNLIKELY (res != GST_FLOW_OK))
+    goto done;
 
-  if (GST_CLOCK_TIME_IS_VALID (timestamp)
-      && !GST_CLOCK_TIME_IS_VALID (resample->next_upstream_ts))
-    resample->next_upstream_ts = timestamp;
+  res = gst_pad_push (trans->srcpad, outbuf);
 
-  if (GST_CLOCK_TIME_IS_VALID (resample->next_upstream_ts))
-    resample->next_upstream_ts +=
-        GST_FRAMES_TO_CLOCK_TIME (insamples, resample->inrate);
-
-  return GST_FLOW_OK;
+done:
+  return res;
 }
 
 static gboolean
-gst_audio_resample_query (GstPad * pad, GstQuery * query)
+audioresample_query (GstPad * pad, GstQuery * query)
 {
-  GstAudioResample *resample = GST_AUDIO_RESAMPLE (gst_pad_get_parent (pad));
-  GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
+  GstAudioresample *audioresample =
+      GST_AUDIORESAMPLE (gst_pad_get_parent (pad));
+  GstBaseTransform *trans = GST_BASE_TRANSFORM (audioresample);
   gboolean res = TRUE;
 
   switch (GST_QUERY_TYPE (query)) {
@@ -1122,14 +723,8 @@
       gboolean live;
       guint64 latency;
       GstPad *peer;
-      gint rate = resample->inrate;
-      gint resampler_latency;
-
-      if (resample->state)
-        resampler_latency =
-            resample->funcs->get_input_latency (resample->state);
-      else
-        resampler_latency = 0;
+      gint rate = audioresample->i_rate;
+      gint resampler_latency = audioresample->filter_length / 2;
 
       if (gst_base_transform_is_passthrough (trans))
         resampler_latency = 0;
@@ -1138,7 +733,7 @@
         if ((res = gst_pad_query (peer, query))) {
           gst_query_parse_latency (query, &live, &min, &max);
 
-          GST_DEBUG_OBJECT (resample, "Peer latency: min %"
+          GST_DEBUG ("Peer latency: min %"
               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
 
@@ -1149,14 +744,13 @@
           else
             latency = 0;
 
-          GST_DEBUG_OBJECT (resample, "Our latency: %" GST_TIME_FORMAT,
-              GST_TIME_ARGS (latency));
+          GST_DEBUG ("Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
 
           min += latency;
           if (max != GST_CLOCK_TIME_NONE)
             max += latency;
 
-          GST_DEBUG_OBJECT (resample, "Calculated total latency : min %"
+          GST_DEBUG ("Calculated total latency : min %"
               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
 
@@ -1170,12 +764,12 @@
       res = gst_pad_query_default (pad, query);
       break;
   }
-  gst_object_unref (resample);
+  gst_object_unref (audioresample);
   return res;
 }
 
 static const GstQueryType *
-gst_audio_resample_query_type (GstPad * pad)
+audioresample_query_type (GstPad * pad)
 {
   static const GstQueryType types[] = {
     GST_QUERY_LATENCY,
@@ -1186,112 +780,23 @@
 }
 
 static void
-gst_audio_resample_set_property (GObject * object, guint prop_id,
+gst_audioresample_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
-  GstAudioResample *resample;
+  GstAudioresample *audioresample;
 
-  resample = GST_AUDIO_RESAMPLE (object);
+  audioresample = GST_AUDIORESAMPLE (object);
 
   switch (prop_id) {
-    case PROP_QUALITY:
-      GST_BASE_TRANSFORM_LOCK (resample);
-      resample->quality = g_value_get_int (value);
-      GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
-
-      gst_audio_resample_update_state (resample, resample->width,
-          resample->channels, resample->inrate, resample->outrate,
-          resample->quality, resample->fp);
-      GST_BASE_TRANSFORM_UNLOCK (resample);
-      break;
-    case PROP_FILTER_LENGTH:{
-      gint filter_length = g_value_get_int (value);
-
-      GST_BASE_TRANSFORM_LOCK (resample);
-      if (filter_length <= 8)
-        resample->quality = 0;
-      else if (filter_length <= 16)
-        resample->quality = 1;
-      else if (filter_length <= 32)
-        resample->quality = 2;
-      else if (filter_length <= 48)
-        resample->quality = 3;
-      else if (filter_length <= 64)
-        resample->quality = 4;
-      else if (filter_length <= 80)
-        resample->quality = 5;
-      else if (filter_length <= 96)
-        resample->quality = 6;
-      else if (filter_length <= 128)
-        resample->quality = 7;
-      else if (filter_length <= 160)
-        resample->quality = 8;
-      else if (filter_length <= 192)
-        resample->quality = 9;
-      else
-        resample->quality = 10;
-
-      GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
-
-      gst_audio_resample_update_state (resample, resample->width,
-          resample->channels, resample->inrate, resample->outrate,
-          resample->quality, resample->fp);
-      GST_BASE_TRANSFORM_UNLOCK (resample);
-      break;
-    }
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_audio_resample_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec)
-{
-  GstAudioResample *resample;
-
-  resample = GST_AUDIO_RESAMPLE (object);
-
-  switch (prop_id) {
-    case PROP_QUALITY:
-      g_value_set_int (value, resample->quality);
-      break;
-    case PROP_FILTER_LENGTH:
-      switch (resample->quality) {
-        case 0:
-          g_value_set_int (value, 8);
-          break;
-        case 1:
-          g_value_set_int (value, 16);
-          break;
-        case 2:
-          g_value_set_int (value, 32);
-          break;
-        case 3:
-          g_value_set_int (value, 48);
-          break;
-        case 4:
-          g_value_set_int (value, 64);
-          break;
-        case 5:
-          g_value_set_int (value, 80);
-          break;
-        case 6:
-          g_value_set_int (value, 96);
-          break;
-        case 7:
-          g_value_set_int (value, 128);
-          break;
-        case 8:
-          g_value_set_int (value, 160);
-          break;
-        case 9:
-          g_value_set_int (value, 192);
-          break;
-        case 10:
-          g_value_set_int (value, 256);
-          break;
+    case PROP_FILTERLEN:
+      audioresample->filter_length = g_value_get_int (value);
+      GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d",
+          audioresample->filter_length);
+      if (audioresample->resample) {
+        resample_set_filter_length (audioresample->resample,
+            audioresample->filter_length);
+        gst_element_post_message (GST_ELEMENT (audioresample),
+            gst_message_new_latency (GST_OBJECT (audioresample)));
       }
       break;
     default:
@@ -1300,133 +805,32 @@
   }
 }
 
-#if defined AUDIORESAMPLE_FORMAT_AUTO
-#define BENCHMARK_SIZE 512
-
-static gboolean
-_benchmark_int_float (SpeexResamplerState * st)
+static void
+gst_audioresample_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
 {
-  gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
-  gfloat in_tmp[BENCHMARK_SIZE], out_tmp[BENCHMARK_SIZE / 2];
-  gint i;
-  guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
+  GstAudioresample *audioresample;
 
-  for (i = 0; i < BENCHMARK_SIZE; i++) {
-    gfloat tmp = in[i];
-    in_tmp[i] = tmp / G_MAXINT16;
-  }
-
-  resample_float_resampler_process_interleaved_float (st,
-      (const guint8 *) in_tmp, &inlen, (guint8 *) out_tmp, &outlen);
-
-  if (outlen == 0) {
-    GST_ERROR ("Failed to use float resampler");
-    return FALSE;
-  }
+  audioresample = GST_AUDIORESAMPLE (object);
 
-  for (i = 0; i < outlen; i++) {
-    gfloat tmp = out_tmp[i];
-    out[i] = CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
+  switch (prop_id) {
+    case PROP_FILTERLEN:
+      g_value_set_int (value, audioresample->filter_length);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
   }
-
-  return TRUE;
-}
-
-static gboolean
-_benchmark_int_int (SpeexResamplerState * st)
-{
-  gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
-  guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
-
-  resample_int_resampler_process_interleaved_int (st, (const guint8 *) in,
-      &inlen, (guint8 *) out, &outlen);
-
-  if (outlen == 0) {
-    GST_ERROR ("Failed to use int resampler");
-    return FALSE;
-  }
-
-  return TRUE;
 }
 
-static gboolean
-_benchmark_integer_resampling (void)
-{
-  OilProfile a, b;
-  gdouble av, bv;
-  SpeexResamplerState *sta, *stb;
-  int i;
-
-  oil_profile_init (&a);
-  oil_profile_init (&b);
-
-  sta = resample_float_resampler_init (1, 48000, 24000, 4, NULL);
-  if (sta == NULL) {
-    GST_ERROR ("Failed to create float resampler state");
-    return FALSE;
-  }
-
-  stb = resample_int_resampler_init (1, 48000, 24000, 4, NULL);
-  if (stb == NULL) {
-    resample_float_resampler_destroy (sta);
-    GST_ERROR ("Failed to create int resampler state");
-    return FALSE;
-  }
-
-  /* Benchmark */
-  for (i = 0; i < 10; i++) {
-    oil_profile_start (&a);
-    if (!_benchmark_int_float (sta))
-      goto error;
-    oil_profile_stop (&a);
-  }
-
-  /* Benchmark */
-  for (i = 0; i < 10; i++) {
-    oil_profile_start (&b);
-    if (!_benchmark_int_int (stb))
-      goto error;
-    oil_profile_stop (&b);
-  }
-
-  /* Handle results */
-  oil_profile_get_ave_std (&a, &av, NULL);
-  oil_profile_get_ave_std (&b, &bv, NULL);
-
-  /* Remember benchmark result in global variable */
-  gst_audio_resample_use_int = (av > bv);
-  resample_float_resampler_destroy (sta);
-  resample_int_resampler_destroy (stb);
-
-  if (av > bv)
-    GST_INFO ("Using integer resampler if appropiate: %lf < %lf", bv, av);
-  else
-    GST_INFO ("Using float resampler for everything: %lf <= %lf", av, bv);
-
-  return TRUE;
-
-error:
-  resample_float_resampler_destroy (sta);
-  resample_int_resampler_destroy (stb);
-
-  return FALSE;
-}
-#endif
 
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  GST_DEBUG_CATEGORY_INIT (audio_resample_debug, "audioresample", 0,
-      "audio resampling element");
-#if defined AUDIORESAMPLE_FORMAT_AUTO
-  oil_init ();
-
-  if (!_benchmark_integer_resampling ())
-    return FALSE;
-#endif
+  resample_init ();
 
   if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
-          GST_TYPE_AUDIO_RESAMPLE)) {
+          GST_TYPE_AUDIORESAMPLE)) {
     return FALSE;
   }