gst/audioconvert/: Cleanups, librarify a bit, optimize, better negotiation and more.
authorWim Taymans <wim.taymans@gmail.com>
Fri, 26 Aug 2005 15:43:56 +0000 (15:43 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 26 Aug 2005 15:43:56 +0000 (15:43 +0000)
Original commit message from CVS:
* gst/audioconvert/Makefile.am:
* gst/audioconvert/audioconvert.c: (if), (float),
(audio_convert_get_func_index), (check_default),
(audio_convert_clean_fmt), (audio_convert_prepare_context),
(audio_convert_clean_context), (audio_convert_get_sizes),
(get_temp_buffer), (audio_convert_convert):
* gst/audioconvert/audioconvert.h:
* gst/audioconvert/gstaudioconvert.c:
(gst_audio_convert_class_init), (gst_audio_convert_init),
(gst_audio_convert_dispose), (gst_audio_convert_parse_caps),
(gst_audio_convert_get_unit_size),
(gst_audio_convert_transform_caps),
(gst_audio_convert_fixate_caps), (gst_audio_convert_set_caps),
(gst_audio_convert_transform_ip), (gst_audio_convert_transform):
* gst/audioconvert/gstaudioconvert.h:
* gst/audioconvert/gstchannelmix.c: (gst_channel_mix_unset_matrix),
(gst_channel_mix_fill_identical),
(gst_channel_mix_fill_compatible), (gst_channel_mix_detect_pos),
(gst_channel_mix_fill_one_other), (gst_channel_mix_fill_others),
(gst_channel_mix_fill_normalize), (gst_channel_mix_fill_matrix),
(gst_channel_mix_setup_matrix), (gst_channel_mix_passthrough),
(gst_channel_mix_mix):
* gst/audioconvert/gstchannelmix.h:
Cleanups, librarify a bit, optimize, better negotiation and more.

ChangeLog
gst/audioconvert/Makefile.am
gst/audioconvert/audioconvert.c [new file with mode: 0644]
gst/audioconvert/audioconvert.h [new file with mode: 0644]
gst/audioconvert/gstaudioconvert.c
gst/audioconvert/gstaudioconvert.h [new file with mode: 0644]
gst/audioconvert/gstchannelmix.c
gst/audioconvert/gstchannelmix.h

index 873e101..6012320 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2005-08-26  Wim Taymans  <wim@fluendo.com>
+
+       * gst/audioconvert/Makefile.am:
+       * gst/audioconvert/audioconvert.c: (if), (float),
+       (audio_convert_get_func_index), (check_default),
+       (audio_convert_clean_fmt), (audio_convert_prepare_context),
+       (audio_convert_clean_context), (audio_convert_get_sizes),
+       (get_temp_buffer), (audio_convert_convert):
+       * gst/audioconvert/audioconvert.h:
+       * gst/audioconvert/gstaudioconvert.c:
+       (gst_audio_convert_class_init), (gst_audio_convert_init),
+       (gst_audio_convert_dispose), (gst_audio_convert_parse_caps),
+       (gst_audio_convert_get_unit_size),
+       (gst_audio_convert_transform_caps),
+       (gst_audio_convert_fixate_caps), (gst_audio_convert_set_caps),
+       (gst_audio_convert_transform_ip), (gst_audio_convert_transform):
+       * gst/audioconvert/gstaudioconvert.h:
+       * gst/audioconvert/gstchannelmix.c: (gst_channel_mix_unset_matrix),
+       (gst_channel_mix_fill_identical),
+       (gst_channel_mix_fill_compatible), (gst_channel_mix_detect_pos),
+       (gst_channel_mix_fill_one_other), (gst_channel_mix_fill_others),
+       (gst_channel_mix_fill_normalize), (gst_channel_mix_fill_matrix),
+       (gst_channel_mix_setup_matrix), (gst_channel_mix_passthrough),
+       (gst_channel_mix_mix):
+       * gst/audioconvert/gstchannelmix.h:
+       Cleanups, librarify a bit, optimize, better negotiation and more.
+
 2005-08-26  Jan Schmidt  <thaytan@mad.scientist.com>
 
        * ext/ogg/gstoggdemux.c: (ogg_find_peek):
index 86ab480..a13d175 100644 (file)
@@ -2,6 +2,7 @@ plugin_LTLIBRARIES = libgstaudioconvert.la
 
 libgstaudioconvert_la_SOURCES = \
        gstaudioconvert.c \
+       audioconvert.c \
        gstchannelmix.c \
        bufferframesconvert.c \
        plugin.c
@@ -13,6 +14,8 @@ libgstaudioconvert_la_LIBADD = \
        $(GST_LIBS)
 
 noinst_HEADERS = \
+       gstaudioconvert.h \
+       audioconvert.h \
        gstchannelmix.h \
        plugin.h
 
diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c
new file mode 100644 (file)
index 0000000..8ec67dd
--- /dev/null
@@ -0,0 +1,393 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
+ *
+ * audioconvert.c: Convert audio to different audio formats automatically
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstchannelmix.h"
+#include "audioconvert.h"
+
+/* int to float conversion: int2float(i) = 1 / (2^31-1) * i */
+#define INT2FLOAT(i) (4.6566128752457969e-10 * ((gfloat)i))
+
+#define UNPACK_CODE(type, corr, E_FUNC)                                        \
+  type* p = (type *) src;                                              \
+  gint64 tmp;                                                          \
+  for (;count; count--) {                                              \
+    tmp = ((gint64) E_FUNC (*p) - corr) * scale;                       \
+    *dst++ = CLAMP (tmp, -((gint64) 1 << 32), (gint64) 0x7FFFFFFF);    \
+    p++;                                                               \
+  }
+
+#define MAKE_UNPACK_FUNC_NAME(name)                                    \
+audio_convert_unpack_##name
+
+/* unsigned case */
+#define MAKE_UNPACK_FUNC_U(name, type, E_FUNC)                         \
+static void                                                            \
+MAKE_UNPACK_FUNC_NAME (name) (gpointer src, gint32 *dst,               \
+       gint64 scale, gint count)                                       \
+{                                                                      \
+  UNPACK_CODE(type, (1 << (sizeof (type) * 8 - 1)), E_FUNC);           \
+}
+
+/* signed case */
+#define MAKE_UNPACK_FUNC_S(name, type, E_FUNC)                         \
+static void                                                            \
+MAKE_UNPACK_FUNC_NAME (name) (gpointer src, gint32 *dst,               \
+       gint64 scale, gint count)                                       \
+{                                                                      \
+  UNPACK_CODE(type, 0, E_FUNC);                                                \
+}
+
+MAKE_UNPACK_FUNC_U (u8, guint8, /* nothing */ )
+    MAKE_UNPACK_FUNC_S (s8, gint8, /* nothing */ )
+    MAKE_UNPACK_FUNC_U (u16_le, guint16, GUINT16_FROM_LE)
+    MAKE_UNPACK_FUNC_S (s16_le, gint16, GINT16_FROM_LE)
+    MAKE_UNPACK_FUNC_U (u16_be, guint16, GUINT16_FROM_BE)
+    MAKE_UNPACK_FUNC_S (s16_be, gint16, GINT16_FROM_BE)
+    MAKE_UNPACK_FUNC_U (u32_le, guint32, GUINT32_FROM_LE)
+    MAKE_UNPACK_FUNC_S (s32_le, gint32, GINT32_FROM_LE)
+    MAKE_UNPACK_FUNC_U (u32_be, guint32, GUINT32_FROM_BE)
+    MAKE_UNPACK_FUNC_S (s32_be, gint32, GINT32_FROM_BE)
+
+/* FIXME 24 bits */
+#if 0
+     gint64 cur = 0;
+
+        /* FIXME */
+
+        /* Read 24-bits LE/BE into signed 64 host-endian */
+if (this->sinkcaps.endianness == G_LITTLE_ENDIAN)
+{
+cur = src[0] | (src[1] << 8) | (src[2] << 16);
+} else {
+  cur = src[2] | (src[1] << 8) | (src[0] << 16);
+}
+
+        /* Sign extend */
+if ((this->sinkcaps.sign)
+    && (cur & (1 << (this->sinkcaps.depth - 1))))
+  cur |= ((gint64) (-1)) ^ ((1 << this->sinkcaps.depth) - 1);
+
+src -= 3;
+#endif
+
+static void
+MAKE_UNPACK_FUNC_NAME (float) (gpointer src, gint32 * dst,
+    gint64 scale, gint count)
+{
+  gfloat *p = (gfloat *) src;
+  gfloat temp;
+
+  for (; count; count--) {
+    temp = *p++ * 2147483647.0f + .5;
+    *dst++ = (gint32) CLAMP (temp, -2147483648ll, 2147483647ll);
+  }
+}
+
+#define PACK_CODE(type, corr, E_FUNC)                                  \
+  type* p = (type *) dst;                                              \
+  gint32 scale = (32 - depth);                                         \
+  for (;count; count--) {                                              \
+    *p = E_FUNC ((type)((*src) >> scale) + corr);                      \
+    p++; src++;                                                                \
+  }
+
+#define MAKE_PACK_FUNC_NAME(name)                                      \
+audio_convert_pack_##name
+
+#define MAKE_PACK_FUNC_U(name, type, E_FUNC)                           \
+static void                                                            \
+MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst,                 \
+       gint depth, gint count)                                         \
+{                                                                      \
+  PACK_CODE (type, (1 << (depth - 1)), E_FUNC);                                \
+}
+
+#define MAKE_PACK_FUNC_S(name, type, E_FUNC)                           \
+static void                                                            \
+MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst,                         \
+       gint depth, gint count)                                         \
+{                                                                      \
+  PACK_CODE (type, 0, E_FUNC);                                         \
+}
+
+MAKE_PACK_FUNC_U (u8, guint8, /* nothing */ );
+MAKE_PACK_FUNC_S (s8, gint8, /* nothing */ );
+MAKE_PACK_FUNC_U (u16_le, guint16, GUINT16_TO_LE);
+MAKE_PACK_FUNC_S (s16_le, gint16, GINT16_TO_LE);
+MAKE_PACK_FUNC_U (u16_be, guint16, GUINT16_TO_BE);
+MAKE_PACK_FUNC_S (s16_be, gint16, GINT16_TO_BE);
+MAKE_PACK_FUNC_U (u32_le, guint32, GUINT32_TO_LE);
+MAKE_PACK_FUNC_S (s32_le, gint32, GINT32_TO_LE);
+MAKE_PACK_FUNC_U (u32_be, guint32, GUINT32_TO_BE);
+MAKE_PACK_FUNC_S (s32_be, gint32, GINT32_TO_BE);
+
+static void
+MAKE_PACK_FUNC_NAME (float) (gint32 * src, gpointer dst, gint depth, gint count)
+{
+  gfloat *p = (gfloat *) dst;
+
+  for (; count; count--) {
+    *p++ = INT2FLOAT (*src++);
+  }
+}
+
+static AudioConvertUnpack unpack_funcs[] = {
+  MAKE_UNPACK_FUNC_NAME (u8),
+  MAKE_UNPACK_FUNC_NAME (s8),
+  MAKE_UNPACK_FUNC_NAME (u8),
+  MAKE_UNPACK_FUNC_NAME (s8),
+  MAKE_UNPACK_FUNC_NAME (u16_le),
+  MAKE_UNPACK_FUNC_NAME (s16_le),
+  MAKE_UNPACK_FUNC_NAME (u16_be),
+  MAKE_UNPACK_FUNC_NAME (s16_be),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  MAKE_UNPACK_FUNC_NAME (u32_le),
+  MAKE_UNPACK_FUNC_NAME (s32_le),
+  MAKE_UNPACK_FUNC_NAME (u32_be),
+  MAKE_UNPACK_FUNC_NAME (s32_be),
+  MAKE_UNPACK_FUNC_NAME (float),
+};
+
+static AudioConvertPack pack_funcs[] = {
+  MAKE_PACK_FUNC_NAME (u8),
+  MAKE_PACK_FUNC_NAME (s8),
+  MAKE_PACK_FUNC_NAME (u8),
+  MAKE_PACK_FUNC_NAME (s8),
+  MAKE_PACK_FUNC_NAME (u16_le),
+  MAKE_PACK_FUNC_NAME (s16_le),
+  MAKE_PACK_FUNC_NAME (u16_be),
+  MAKE_PACK_FUNC_NAME (s16_be),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  MAKE_PACK_FUNC_NAME (u32_le),
+  MAKE_PACK_FUNC_NAME (s32_le),
+  MAKE_PACK_FUNC_NAME (u32_be),
+  MAKE_PACK_FUNC_NAME (s32_be),
+  MAKE_PACK_FUNC_NAME (float),
+};
+
+static gint
+audio_convert_get_func_index (AudioConvertFmt * fmt)
+{
+  gint index = 0;
+
+  if (fmt->is_int) {
+    index += (fmt->width / 8 - 1) * 4;
+    index += fmt->endianness == G_LITTLE_ENDIAN ? 0 : 2;
+    index += fmt->sign ? 1 : 0;
+  } else {
+    index = 16;
+  }
+  return index;
+}
+
+static gboolean
+check_default (AudioConvertFmt * fmt)
+{
+  return (fmt->width == 32 && fmt->depth == 32 &&
+      fmt->endianness == G_BYTE_ORDER && fmt->sign == TRUE);
+}
+
+gboolean
+audio_convert_clean_fmt (AudioConvertFmt * fmt)
+{
+  g_return_val_if_fail (fmt != NULL, FALSE);
+
+  g_free (fmt->pos);
+  fmt->pos = NULL;
+
+  return TRUE;
+}
+
+
+gboolean
+audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in,
+    AudioConvertFmt * out)
+{
+  gint idx;
+
+  g_return_val_if_fail (ctx != NULL, FALSE);
+  g_return_val_if_fail (in != NULL, FALSE);
+  g_return_val_if_fail (out != NULL, FALSE);
+
+  /* first clean the existing context */
+  audio_convert_clean_context (ctx);
+
+  ctx->in = *in;
+  ctx->out = *out;
+
+  gst_channel_mix_setup_matrix (ctx);
+
+  idx = audio_convert_get_func_index (in);
+  if (!(ctx->unpack = unpack_funcs[idx]))
+    goto not_supported;
+
+  idx = audio_convert_get_func_index (out);
+  if (!(ctx->pack = pack_funcs[idx]))
+    goto not_supported;
+
+  /* check if input is in default format */
+  ctx->in_default = check_default (in);
+  /* check if channel mixer is passthrough */
+  ctx->mix_passthrough = gst_channel_mix_passthrough (ctx);
+  /* check if output is in default format */
+  ctx->out_default = check_default (out);
+
+  ctx->scale = ((gint64) 1 << (32 - in->depth));
+  ctx->depth = out->depth;
+
+  return TRUE;
+
+not_supported:
+  {
+    return FALSE;
+  }
+}
+
+gboolean
+audio_convert_clean_context (AudioConvertCtx * ctx)
+{
+  g_return_val_if_fail (ctx != NULL, FALSE);
+
+  audio_convert_clean_fmt (&ctx->in);
+  audio_convert_clean_fmt (&ctx->out);
+  gst_channel_mix_unset_matrix (ctx);
+
+  g_free (ctx->tmpbuf);
+  ctx->tmpbuf = NULL;
+
+  return TRUE;
+}
+
+gboolean
+audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize,
+    gint * dstsize)
+{
+  g_return_val_if_fail (ctx != NULL, FALSE);
+
+  if (srcsize)
+    *srcsize = samples * ctx->in.unit_size;
+  if (dstsize)
+    *dstsize = samples * ctx->out.unit_size;
+
+  return TRUE;
+}
+
+static gpointer
+get_temp_buffer (AudioConvertCtx * ctx, gpointer src, gint srcsize,
+    gboolean writable, gint tmpsize)
+{
+  gpointer result;
+
+  if (srcsize >= tmpsize && writable) {
+    result = src;
+  } else {
+    if (ctx->tmpbufsize < tmpsize) {
+      ctx->tmpbuf = g_realloc (ctx->tmpbuf, tmpsize);
+      ctx->tmpbufsize = tmpsize;
+    }
+    result = ctx->tmpbuf;
+  }
+  return result;
+}
+
+gboolean
+audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
+    gpointer dst, gint samples, gboolean src_writable)
+{
+  gint insize;
+  gboolean final;
+  gpointer buf;
+  gint bufsize;
+  gboolean bufwritable;
+  gpointer tmpdst;
+  gint tmpsize;
+
+  g_return_val_if_fail (ctx != NULL, FALSE);
+  g_return_val_if_fail (src != NULL, FALSE);
+  g_return_val_if_fail (dst != NULL, FALSE);
+  g_return_val_if_fail (samples >= 0, FALSE);
+
+  if (samples == 0)
+    return TRUE;
+
+  insize = ctx->in.unit_size * samples;
+  tmpsize = insize * 32 / ctx->in.width;
+
+  /* this is our source data, we start with the input src data. */
+  buf = src;
+  bufsize = insize;
+  bufwritable = src_writable;
+
+  if (!ctx->in_default) {
+    /* check if final conversion */
+    final = (ctx->out_default && ctx->mix_passthrough);
+
+    if (final)
+      tmpdst = dst;
+    else
+      tmpdst = get_temp_buffer (ctx, buf, bufsize, bufwritable, tmpsize);
+
+    ctx->unpack (buf, tmpdst, ctx->scale, samples * ctx->in.channels);
+
+    if (!final) {
+      /* new source data, it is writable */
+      buf = tmpdst;
+      bufsize = tmpsize;
+      bufwritable = TRUE;
+    }
+  }
+
+  if (!ctx->mix_passthrough) {
+    /* see if we need an intermediate step */
+    final = ctx->out_default;
+
+    if (final)
+      tmpdst = dst;
+    else
+      tmpdst = get_temp_buffer (ctx, buf, bufsize, bufwritable, tmpsize);
+
+    /* convert */
+    gst_channel_mix_mix (ctx, buf, tmpdst, samples);
+
+    if (!final) {
+      buf = tmpdst;
+    }
+  }
+
+  if (!ctx->out_default) {
+    /* output always to dst buffer */
+    ctx->pack (buf, dst, ctx->depth, samples * ctx->out.channels);
+  }
+
+  return TRUE;
+}
diff --git a/gst/audioconvert/audioconvert.h b/gst/audioconvert/audioconvert.h
new file mode 100644 (file)
index 0000000..736745e
--- /dev/null
@@ -0,0 +1,89 @@
+/* GStreamer
+ * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * audioconvert.h: audio format conversion library
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __AUDIO_CONVERT_H__
+#define __AUDIO_CONVERT_H__
+
+#include <gst/gst.h>
+#include <gst/audio/multichannel.h>
+
+typedef struct _AudioConvertCtx AudioConvertCtx;
+typedef struct _AudioConvertFmt AudioConvertFmt;
+
+struct _AudioConvertFmt
+{
+  /* general caps */
+  gboolean is_int;
+  gint endianness;
+  gint width;
+  gint rate;
+  gint channels;
+  GstAudioChannelPosition *pos;
+
+  /* int audio caps */
+  gboolean sign;
+  gint depth;
+
+  /* float audio caps */
+  gint buffer_frames;
+
+  gint unit_size;
+};
+
+typedef void (*AudioConvertUnpack) (gpointer src, gint32 *dst, gint64 scale, gint count);
+typedef void (*AudioConvertPack) (gint32 *src, gpointer dst, gint depth, gint count);
+
+struct _AudioConvertCtx
+{
+  AudioConvertFmt in;
+  AudioConvertFmt out;
+
+  AudioConvertUnpack unpack;
+  AudioConvertPack pack;
+
+  /* channel conversion matrix, m[in_channels][out_channels].
+   * If identity matrix, passthrough applies. */
+  gfloat **matrix;
+
+  gboolean in_default;
+  gboolean mix_passthrough;
+  gboolean out_default;
+
+  gpointer tmpbuf;
+  gint tmpbufsize;
+
+  gint64 scale;
+  gint depth;
+};
+
+gboolean       audio_convert_clean_fmt         (AudioConvertFmt *fmt); 
+
+gboolean       audio_convert_prepare_context   (AudioConvertCtx *ctx, AudioConvertFmt *in, 
+                                                AudioConvertFmt *out);
+gboolean       audio_convert_get_sizes         (AudioConvertCtx *ctx, gint samples, gint *srcsize,
+                                                gint *dstsize);
+
+gboolean       audio_convert_clean_context     (AudioConvertCtx *ctx);
+
+gboolean       audio_convert_convert           (AudioConvertCtx *ctx, gpointer src, 
+                                                gpointer dst, gint samples, gboolean src_writable);
+
+#endif /* __AUDIO_CONVERT_H__ */
index 1f8420c..7c91aec 100644 (file)
@@ -1,6 +1,7 @@
 /* GStreamer
  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
  * Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org>
+ * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
  *
  * gstaudioconvert.c: Convert audio to different audio formats automatically
  *
 #include "config.h"
 #endif
 
-#include <gst/gst.h>
-#include <gst/base/gstbasetransform.h>
-#include <gst/audio/multichannel.h>
 #include <string.h>
+
+#include "gstaudioconvert.h"
 #include "gstchannelmix.h"
 #include "plugin.h"
 
@@ -65,28 +65,18 @@ static void gst_audio_convert_init (GstAudioConvert * audio_convert);
 static void gst_audio_convert_dispose (GObject * obj);
 
 /* gstreamer functions */
-static GstBuffer *gst_audio_convert_buffer_to_default_format (GstAudioConvert *
-    this, GstBuffer * buf);
-static GstBuffer *gst_audio_convert_buffer_from_default_format (GstAudioConvert
-    * this, GstBuffer * buf);
-
-static GstBuffer *gst_audio_convert_channels (GstAudioConvert * this,
-    GstBuffer * buf);
-
-static gboolean gst_audio_convert_parse_caps (const GstCaps * gst_caps,
-    GstAudioConvertCaps * caps);
-
-gboolean audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
-    guint * size);
-GstCaps *audio_convert_transform_caps (GstBaseTransform * base,
+static gboolean gst_audio_convert_get_unit_size (GstBaseTransform * base,
+    GstCaps * caps, guint * size);
+static GstCaps *gst_audio_convert_transform_caps (GstBaseTransform * base,
     GstPadDirection direction, GstCaps * caps);
-void audio_convert_fixate_caps (GstBaseTransform * base,
+static void gst_audio_convert_fixate_caps (GstBaseTransform * base,
     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
-gboolean audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
-    GstCaps * outcaps);
-static GstFlowReturn
-audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
-    GstBuffer * outbuf);
+static gboolean gst_audio_convert_set_caps (GstBaseTransform * base,
+    GstCaps * incaps, GstCaps * outcaps);
+static GstFlowReturn gst_audio_convert_transform (GstBaseTransform * base,
+    GstBuffer * inbuf, GstBuffer * outbuf);
+static GstFlowReturn gst_audio_convert_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
 
 /* AudioConvert signals and args */
 enum
@@ -191,25 +181,22 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
     supported_positions[i] = i;
 
   GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
-      GST_DEBUG_FUNCPTR (audio_convert_get_unit_size);
+      GST_DEBUG_FUNCPTR (gst_audio_convert_get_unit_size);
   GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
-      GST_DEBUG_FUNCPTR (audio_convert_transform_caps);
+      GST_DEBUG_FUNCPTR (gst_audio_convert_transform_caps);
   GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
-      GST_DEBUG_FUNCPTR (audio_convert_fixate_caps);
+      GST_DEBUG_FUNCPTR (gst_audio_convert_fixate_caps);
   GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
-      GST_DEBUG_FUNCPTR (audio_convert_set_caps);
+      GST_DEBUG_FUNCPTR (gst_audio_convert_set_caps);
+  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_convert_transform_ip);
   GST_BASE_TRANSFORM_CLASS (klass)->transform =
-      GST_DEBUG_FUNCPTR (audio_convert_transform);
+      GST_DEBUG_FUNCPTR (gst_audio_convert_transform);
 }
 
 static void
 gst_audio_convert_init (GstAudioConvert * this)
 {
-  /* clear important variables */
-  this->convert_internal = NULL;
-  this->sinkcaps.pos = NULL;
-  this->srccaps.pos = NULL;
-  this->matrix = NULL;
 }
 
 static void
@@ -217,42 +204,105 @@ gst_audio_convert_dispose (GObject * obj)
 {
   GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
 
-  if (this->sinkcaps.pos) {
-    g_free (this->sinkcaps.pos);
-    this->sinkcaps.pos = NULL;
-  }
-
-  if (this->srccaps.pos) {
-    g_free (this->srccaps.pos);
-    this->srccaps.pos = NULL;
-  }
-
-  gst_audio_convert_unset_matrix (this);
+  audio_convert_clean_context (&this->ctx);
 
   G_OBJECT_CLASS (parent_class)->dispose (obj);
 }
 
 /*** GSTREAMER FUNCTIONS ******************************************************/
 
+/* convert the given GstCaps to our format */
+static gboolean
+gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
+{
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+
+  GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps);
+
+  g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
+  g_return_val_if_fail (fmt != NULL, FALSE);
+
+  /* cleanup old */
+  audio_convert_clean_fmt (fmt);
+
+  fmt->endianness = G_BYTE_ORDER;
+  fmt->is_int =
+      (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0);
+
+  /* parse common fields */
+  if (!gst_structure_get_int (structure, "channels", &fmt->channels))
+    goto no_values;
+  if (!(fmt->pos = gst_audio_get_channel_positions (structure)))
+    goto no_values;
+  if (!gst_structure_get_int (structure, "width", &fmt->width))
+    goto no_values;
+  if (!gst_structure_get_int (structure, "rate", &fmt->rate))
+    goto no_values;
+
+  if (fmt->is_int) {
+    /* int specific fields */
+    if (!gst_structure_get_boolean (structure, "signed", &fmt->sign))
+      goto no_values;
+    if (!gst_structure_get_int (structure, "depth", &fmt->depth))
+      goto no_values;
+
+    /* width != 8 can have an endianness field */
+    if (fmt->width != 8) {
+      if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
+        goto no_values;
+    }
+    /* depth cannot be bigger than the width */
+    if (fmt->depth > fmt->width)
+      goto not_allowed;
+  } else {
+    /* float specific fields */
+    if (!gst_structure_get_int (structure, "buffer-frames",
+            &fmt->buffer_frames))
+      goto no_values;
+  }
+
+  fmt->unit_size = (fmt->width * fmt->channels) / 8;
+
+  return TRUE;
+
+  /* ERRORS */
+no_values:
+  {
+    GST_DEBUG ("could not get some values from structure");
+    audio_convert_clean_fmt (fmt);
+    return FALSE;
+  }
+not_allowed:
+  {
+    GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt");
+    audio_convert_clean_fmt (fmt);
+    return FALSE;
+  }
+}
+
 /* BaseTransform vmethods */
-gboolean
-audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
+static gboolean
+gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
     guint * size)
 {
-  GstAudioConvertCaps ac_caps;
+  AudioConvertFmt ac_caps = { 0 };
 
   g_return_val_if_fail (size, FALSE);
 
-  memset (&ac_caps, 0, sizeof (ac_caps));
+  if (!gst_audio_convert_parse_caps (caps, &ac_caps))
+    goto parse_error;
 
-  if (!gst_audio_convert_parse_caps (caps, &ac_caps)) {
-    g_free (ac_caps.pos);
-    return FALSE;
-  }
   g_free (ac_caps.pos);
 
-  *size = ac_caps.width * ac_caps.channels / 8;
+  *size = ac_caps.unit_size;
+
   return TRUE;
+
+parse_error:
+  {
+    g_free (ac_caps.pos);
+    return FALSE;
+  }
 }
 
 /* audioconvert can convert anything except sample rate; so return template
@@ -260,25 +310,27 @@ audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
 /* FIXME:
  * it would be smart here to return the caps with the same width as the first
  */
-GstCaps *
-audio_convert_transform_caps (GstBaseTransform * base,
+static GstCaps *
+gst_audio_convert_transform_caps (GstBaseTransform * base,
     GstPadDirection direction, GstCaps * caps)
 {
   int i;
   const GValue *rate;
+  GstCaps *ret;
+  GstStructure *structure;
 
   g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
 
-  GstStructure *structure = gst_caps_get_structure (caps, 0);
-
-  GstCaps *ret = gst_static_caps_get (&gst_audio_convert_static_caps);
+  structure = gst_caps_get_structure (caps, 0);
 
-  ret = gst_caps_make_writable (ret);
+  ret = gst_static_caps_get (&gst_audio_convert_static_caps);
 
-  rate = gst_structure_get_value (structure, "rate");
-  if (!rate) {
+  /* if rate not set, we return the template */
+  if (!(rate = gst_structure_get_value (structure, "rate")))
     return ret;
-  }
+
+  /* else, write rate in the template caps */
+  ret = gst_caps_make_writable (ret);
 
   for (i = 0; i < gst_caps_get_size (ret); ++i) {
     structure = gst_caps_get_structure (ret, i);
@@ -290,12 +342,12 @@ audio_convert_transform_caps (GstBaseTransform * base,
 /* try to keep as many of the structure members the same by fixating the
  * possible ranges; this way we convert the least amount of things as possible
  */
-void
-audio_convert_fixate_caps (GstBaseTransform * base,
+static void
+gst_audio_convert_fixate_caps (GstBaseTransform * base,
     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
 {
   GstStructure *ins, *outs;
-  gint rate, endianness, depth;
+  gint rate, endianness, depth, width, channels;
   gboolean signedness;
 
   g_return_if_fail (gst_caps_is_fixed (caps));
@@ -306,6 +358,11 @@ audio_convert_fixate_caps (GstBaseTransform * base,
   ins = gst_caps_get_structure (caps, 0);
   outs = gst_caps_get_structure (othercaps, 0);
 
+  if (gst_structure_get_int (ins, "channels", &channels)) {
+    if (gst_structure_has_field (outs, "channels")) {
+      gst_caps_structure_fixate_field_nearest_int (outs, "channels", channels);
+    }
+  }
   if (gst_structure_get_int (ins, "rate", &rate)) {
     if (gst_structure_has_field (outs, "rate")) {
       gst_caps_structure_fixate_field_nearest_int (outs, "rate", rate);
@@ -317,11 +374,25 @@ audio_convert_fixate_caps (GstBaseTransform * base,
           endianness);
     }
   }
+  if (gst_structure_get_int (ins, "width", &width)) {
+    if (gst_structure_has_field (outs, "width")) {
+      gst_caps_structure_fixate_field_nearest_int (outs, "width", width);
+    }
+  } else {
+    /* this is not allowed */
+  }
+
   if (gst_structure_get_int (ins, "depth", &depth)) {
     if (gst_structure_has_field (outs, "depth")) {
       gst_caps_structure_fixate_field_nearest_int (outs, "depth", depth);
     }
+  } else {
+    /* set depth as width */
+    if (gst_structure_has_field (outs, "depth")) {
+      gst_caps_structure_fixate_field_nearest_int (outs, "depth", width);
+    }
   }
+
   if (gst_structure_get_boolean (ins, "signed", &signedness)) {
     if (gst_structure_has_field (outs, "signed")) {
       gst_caps_structure_fixate_field_boolean (outs, "signed", signedness);
@@ -331,424 +402,82 @@ audio_convert_fixate_caps (GstBaseTransform * base,
   GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
 }
 
-gboolean
-audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
+static gboolean
+gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
     GstCaps * outcaps)
 {
-  GstAudioConvertCaps in_ac_caps = { 0 };
-  GstAudioConvertCaps out_ac_caps = { 0 };
+  AudioConvertFmt in_ac_caps = { 0 };
+  AudioConvertFmt out_ac_caps = { 0 };
   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
 
   GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
       GST_PTR_FORMAT, incaps, outcaps);
 
-  in_ac_caps.pos = NULL;
   if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
     return FALSE;
-
-  out_ac_caps.pos = NULL;
   if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
     return FALSE;
 
-  this->sinkcaps = in_ac_caps;
-  this->srccaps = out_ac_caps;
-
-  GST_DEBUG ("setting up matrix");
-  gst_audio_convert_setup_matrix (this);
-  GST_DEBUG ("set up matrix, %p", this->matrix);
+  if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps))
+    goto no_converter;
 
   return TRUE;
-}
-
-static GstFlowReturn
-audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
-    GstBuffer * outbuf)
-{
-  GstAudioConvert *this = GST_AUDIO_CONVERT (base);
-  GstBuffer *buf;
-
-  /*
-   * Theory of operation:
-   * - convert the format (endianness, signedness, width, depth) to
-   *   (G_BYTE_ORDER, TRUE, 32, 32)
-   * - convert rate and channels
-   * - convert back to output format
-   */
-
-  /* FIXME: optimize for copying */
-  buf = gst_buffer_copy (inbuf);
-  buf = gst_audio_convert_buffer_to_default_format (this, buf);
-  buf = gst_audio_convert_channels (this, buf);
-  buf = gst_audio_convert_buffer_from_default_format (this, buf);
-  memcpy (GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (buf),
-      GST_BUFFER_SIZE (outbuf));
-  gst_buffer_unref (buf);
-
-  return GST_FLOW_OK;
-}
-
-/* convert the given GstCaps to our ghetto format */
-static gboolean
-gst_audio_convert_parse_caps (const GstCaps * gst_caps,
-    GstAudioConvertCaps * caps)
-{
-  GstStructure *structure = gst_caps_get_structure (gst_caps, 0);
-
-  GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, gst_caps, gst_caps);
 
-  g_return_val_if_fail (gst_caps_is_fixed (gst_caps), FALSE);
-  g_return_val_if_fail (caps != NULL, FALSE);
-
-  /* cleanup old */
-  if (caps->pos) {
-    g_free (caps->pos);
-    caps->pos = NULL;
-  }
-
-  caps->endianness = G_BYTE_ORDER;
-  caps->is_int =
-      (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0);
-  if (!gst_structure_get_int (structure, "channels", &caps->channels)
-      || !(caps->pos = gst_audio_get_channel_positions (structure))
-      || !gst_structure_get_int (structure, "width", &caps->width)
-      || !gst_structure_get_int (structure, "rate", &caps->rate)
-      || (caps->is_int
-          && (!gst_structure_get_boolean (structure, "signed", &caps->sign)
-              || !gst_structure_get_int (structure, "depth", &caps->depth)
-              || (caps->width != 8
-                  && !gst_structure_get_int (structure, "endianness",
-                      &caps->endianness)))) || (!caps->is_int
-          && !gst_structure_get_int (structure, "buffer-frames",
-              &caps->buffer_frames))) {
-    GST_DEBUG ("could not get some values from structure");
-    g_free (caps->pos);
-    caps->pos = NULL;
-    return FALSE;
-  }
-  if (caps->is_int && caps->depth > caps->width) {
-    GST_DEBUG ("width > depth, not allowed - make us advertise correct caps");
-    g_free (caps->pos);
-    caps->pos = NULL;
+no_converter:
+  {
     return FALSE;
   }
-  return TRUE;
-}
-
-/* return a writable buffer of size which ideally is the same as before
-   - You must unref the new buffer
-   - The size of the old buffer is undefined after this operation */
-static GstBuffer *
-gst_audio_convert_get_buffer (GstBuffer * buf, guint size)
-{
-  GstBuffer *ret;
-
-  g_assert (GST_IS_BUFFER (buf));
-
-  GST_LOG
-      ("new buffer of size %u requested. Current is: data: %p - size: %u",
-      size, buf->data, buf->size);
-  if (buf->size >= size && gst_buffer_is_writable (buf)) {
-    gst_buffer_ref (buf);
-    buf->size = size;
-    GST_LOG
-        ("returning same buffer with adjusted values. data: %p - size: %u",
-        buf->data, buf->size);
-    return buf;
-  } else {
-    ret = gst_buffer_new_and_alloc (size);
-    g_assert (ret);
-    gst_buffer_stamp (ret, buf);
-    GST_LOG ("returning new buffer. data: %p - size: %u", ret->data, ret->size);
-    return ret;
-  }
 }
 
-static inline guint8
-GUINT8_IDENTITY (guint8 x)
-{
-  return x;
-}
-static inline guint8
-GINT8_IDENTITY (gint8 x)
+static GstFlowReturn
+gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
 {
-  return x;
+  /* nothing to do here */
+  return GST_FLOW_OK;
 }
 
-#define CONVERT_TO(to, from, type, sign, endianness, LE_FUNC, BE_FUNC) \
-G_STMT_START {                                                         \
-  type value;                                                          \
-  memcpy (&value, from, sizeof (type));                                        \
-  from -= sizeof (type);                                               \
-  value = (endianness == G_LITTLE_ENDIAN) ?                            \
-      LE_FUNC (value) : BE_FUNC (value);                               \
-  if (sign) {                                                          \
-    to = value;                                                                \
-  } else {                                                             \
-    to = (gint64) value - (1 << (sizeof (type) * 8 - 1));              \
-  }                                                                    \
-} G_STMT_END;
-
-static GstBuffer *
-gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
-    GstBuffer * buf)
+static GstFlowReturn
+gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
+    GstBuffer * outbuf)
 {
-  GstBaseTransform *base = GST_BASE_TRANSFORM (this);
-  GstBuffer *ret;
-  gint i, count;
-  gint64 cur = 0;
-  gint32 write;
-  gint32 *dest;
-  guint8 *src;
-
-  GST_LOG_OBJECT (base, "converting buffer of size %d to default format",
-      GST_BUFFER_SIZE (buf));
-  if (this->sinkcaps.is_int) {
-    if (this->sinkcaps.width == 32 && this->sinkcaps.depth == 32 &&
-        this->sinkcaps.endianness == G_BYTE_ORDER
-        && this->sinkcaps.sign == TRUE)
-      return buf;
-
-    ret =
-        gst_audio_convert_get_buffer (buf,
-        buf->size * 32 / this->sinkcaps.width);
-    gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
-
-    count = ret->size / 4;
-    src = buf->data + (count - 1) * (this->sinkcaps.width / 8);
-    dest = (gint32 *) ret->data;
-    for (i = count - 1; i >= 0; i--) {
-      switch (this->sinkcaps.width) {
-        case 8:
-          if (this->sinkcaps.sign) {
-            CONVERT_TO (cur, src, gint8, this->sinkcaps.sign,
-                this->sinkcaps.endianness, GINT8_IDENTITY, GINT8_IDENTITY);
-          } else {
-            CONVERT_TO (cur, src, guint8, this->sinkcaps.sign,
-                this->sinkcaps.endianness, GUINT8_IDENTITY, GUINT8_IDENTITY);
-          }
-          break;
-        case 16:
-          if (this->sinkcaps.sign) {
-            CONVERT_TO (cur, src, gint16, this->sinkcaps.sign,
-                this->sinkcaps.endianness, GINT16_FROM_LE, GINT16_FROM_BE);
-          } else {
-            CONVERT_TO (cur, src, guint16, this->sinkcaps.sign,
-                this->sinkcaps.endianness, GUINT16_FROM_LE, GUINT16_FROM_BE);
-          }
-          break;
-        case 24:
-        {
-          /* Read 24-bits LE/BE into signed 64 host-endian */
-          if (this->sinkcaps.endianness == G_LITTLE_ENDIAN) {
-            cur = src[0] | (src[1] << 8) | (src[2] << 16);
-          } else {
-            cur = src[2] | (src[1] << 8) | (src[0] << 16);
-          }
-
-          /* Sign extend */
-          if ((this->sinkcaps.sign)
-              && (cur & (1 << (this->sinkcaps.depth - 1))))
-            cur |= ((gint64) (-1)) ^ ((1 << this->sinkcaps.depth) - 1);
-
-          src -= 3;
-        }
-          break;
-        case 32:
-          if (this->sinkcaps.sign) {
-            CONVERT_TO (cur, src, gint32, this->sinkcaps.sign,
-                this->sinkcaps.endianness, GINT32_FROM_LE, GINT32_FROM_BE);
-          } else {
-            CONVERT_TO (cur, src, guint32, this->sinkcaps.sign,
-                this->sinkcaps.endianness, GUINT32_FROM_LE, GUINT32_FROM_BE);
-          }
-          break;
-        default:
-          g_assert_not_reached ();
-      }
-      cur = cur * ((gint64) 1 << (32 - this->sinkcaps.depth));
-      cur = CLAMP (cur, -((gint64) 1 << 32), (gint64) 0x7FFFFFFF);
-      write = cur;
-      memcpy (&dest[i], &write, 4);
-    }
-  } else {
-    /* float2int */
-    gfloat *in;
-    gint32 *out;
-    float temp;
-
-    /* should just give the same buffer, unless it's not writable -- float is
-     * already 32 bits */
-    ret = gst_audio_convert_get_buffer (buf, buf->size);
-    gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
-
-    in = (gfloat *) GST_BUFFER_DATA (buf);
-    out = (gint32 *) GST_BUFFER_DATA (ret);
-    for (i = buf->size / sizeof (float); i > 0; i--) {
-      temp = *in * 2147483647.0f + .5;
-      *out = (gint32) CLAMP ((gint64) temp, -2147483648ll, 2147483647ll);
-      out++;
-      in++;
-    }
-  }
+  GstAudioConvert *this = GST_AUDIO_CONVERT (base);
+  gboolean res;
+  gint insize, outsize;
+  gint samples;
+  gpointer src, dst;
+
+  /* get amount of samples to convert. */
+  samples = GST_BUFFER_SIZE (inbuf) / this->ctx.in.unit_size;
+
+  /* get in/output sizes, to see if the buffers we got are of correct
+   * sizes */
+  if (!(res = audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize)))
+    goto error;
+
+  /* check in and outsize */
+  if (GST_BUFFER_SIZE (inbuf) < insize)
+    goto wrong_size;
+  if (GST_BUFFER_SIZE (outbuf) < outsize)
+    goto wrong_size;
+
+  /* get src and dst data */
+  src = GST_BUFFER_DATA (inbuf);
+  dst = GST_BUFFER_DATA (outbuf);
+
+  /* and convert the samples */
+  if (!(res = audio_convert_convert (&this->ctx, src, dst,
+              samples, gst_buffer_is_writable (inbuf))))
+    goto error;
 
-  gst_buffer_unref (buf);
-  return ret;
-}
+  return GST_FLOW_OK;
 
-#define POPULATE(out, format, be_func, le_func) G_STMT_START {         \
-  format val;                                                          \
-  format* p = (format *) out;                                          \
-  int_value >>= (32 - this->srccaps.depth);                            \
-  if (this->srccaps.sign) {                                            \
-    val = (format) int_value;                                          \
-  } else {                                                             \
-    val = (format) int_value + (1 << (this->srccaps.depth - 1));       \
-  }                                                                    \
-  switch (this->srccaps.endianness) {                                  \
-    case G_LITTLE_ENDIAN:                                               \
-      val = le_func (val);                                              \
-      break;                                                            \
-    case G_BIG_ENDIAN:                                                  \
-      val = be_func (val);                                              \
-      break;                                                            \
-    default:                                                            \
-      g_assert_not_reached ();                                          \
-  };                                                                    \
-  *p = val;                                                             \
-  p ++;                                                                 \
-  out = (guint8 *) p;                                                   \
-}G_STMT_END
-
-static GstBuffer *
-gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
-    GstBuffer * buf)
-{
-  GstBaseTransform *base;
-  GstBuffer *ret;
-  guint count, i;
-  gint32 *src;
-
-  base = GST_BASE_TRANSFORM (this);
-
-  GST_LOG_OBJECT (base, "converting buffer of size %d from default format",
-      GST_BUFFER_SIZE (buf));
-
-  if (this->srccaps.is_int && this->srccaps.width == 32
-      && this->srccaps.depth == 32 && this->srccaps.endianness == G_BYTE_ORDER
-      && this->srccaps.sign == TRUE)
-    return buf;
-
-  if (this->srccaps.is_int) {
-    guint8 *dest;
-
-    count = buf->size / 4;      /* size is undefined after gst_audio_convert_get_buffer! */
-    ret =
-        gst_audio_convert_get_buffer (buf,
-        buf->size * this->srccaps.width / 32);
-    gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
-
-    dest = ret->data;
-    src = (gint32 *) buf->data;
-
-    for (i = 0; i < count; i++) {
-      gint32 int_value = *src;
-
-      src++;
-      switch (this->srccaps.width) {
-        case 8:
-          if (this->srccaps.sign) {
-            POPULATE (dest, gint8, GINT8_IDENTITY, GINT8_IDENTITY);
-          } else {
-            POPULATE (dest, guint8, GUINT8_IDENTITY, GUINT8_IDENTITY);
-          }
-          break;
-        case 16:
-          if (this->srccaps.sign) {
-            POPULATE (dest, gint16, GINT16_TO_BE, GINT16_TO_LE);
-          } else {
-            POPULATE (dest, guint16, GUINT16_TO_BE, GUINT16_TO_LE);
-          }
-          break;
-        case 24:
-        {
-          guint8 tmp[4];
-          guint8 *tmpp = tmp;
-
-          /* Write out big endian array */
-          if (this->srccaps.sign) {
-            POPULATE (tmpp, gint32, GINT32_TO_BE, GINT32_TO_BE);
-          } else {
-            POPULATE (tmpp, guint32, GUINT32_TO_BE, GUINT32_TO_BE);
-          }
-
-          if (this->srccaps.endianness == G_LITTLE_ENDIAN) {
-            dest[2] = tmp[1];
-            dest[1] = tmp[2];
-            dest[0] = tmp[3];
-          } else {
-            memcpy (dest, tmp + 1, 3);
-          }
-          dest += 3;
-        }
-          break;
-        case 32:
-          if (this->srccaps.sign) {
-            POPULATE (dest, gint32, GINT32_TO_BE, GINT32_TO_LE);
-          } else {
-            POPULATE (dest, guint32, GUINT32_TO_BE, GUINT32_TO_LE);
-          }
-          break;
-        default:
-          g_assert_not_reached ();
-      }
-    }
-  } else {
-    gfloat *dest;
-
-    count = buf->size / 4;      /* size is undefined after gst_audio_convert_get_buffer! */
-    ret =
-        gst_audio_convert_get_buffer (buf,
-        buf->size * this->srccaps.width / 32);
-    gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
-
-    dest = (gfloat *) ret->data;
-    src = (gint32 *) buf->data;
-    for (i = 0; i < count; i++) {
-      *dest = INT2FLOAT (*src);
-      dest++;
-      src++;
-    }
+  /* ERRORS */
+error:
+  {
+    return GST_FLOW_ERROR;
+  }
+wrong_size:
+  {
+    return GST_FLOW_ERROR;
   }
-
-  gst_buffer_unref (buf);
-  return ret;
-}
-
-static GstBuffer *
-gst_audio_convert_channels (GstAudioConvert * this, GstBuffer * buf)
-{
-  GstBaseTransform *base = GST_BASE_TRANSFORM (this);
-  GstBuffer *ret;
-  gint units;                   /* one unit is one sample of audio for each channel, combined */
-
-  g_assert (this->matrix != NULL);
-
-  GST_LOG_OBJECT (base, "converting buffer of size %d for different channels",
-      GST_BUFFER_SIZE (buf));
-
-  /* check for passthrough */
-  if (gst_audio_convert_passthrough (this))
-    return buf;
-
-  /* convert */
-  GST_LOG_OBJECT (base, "%d sinkpad channels, %d srcpad channels",
-      this->sinkcaps.channels, this->srccaps.channels);
-  units = GST_BUFFER_SIZE (buf) / 4 / this->sinkcaps.channels;
-  ret = gst_audio_convert_get_buffer (buf, units * 4 * this->srccaps.channels);
-  gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
-  gst_audio_convert_mix (this, (gint32 *) GST_BUFFER_DATA (buf),
-      (gint32 *) GST_BUFFER_DATA (ret), units);
-  gst_buffer_unref (buf);
-
-  return ret;
 }
diff --git a/gst/audioconvert/gstaudioconvert.h b/gst/audioconvert/gstaudioconvert.h
new file mode 100644 (file)
index 0000000..44b7365
--- /dev/null
@@ -0,0 +1,52 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
+ *
+ * gstaudioconvert.h: Convert audio to different audio formats automatically
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_AUDIO_CONVERT_H__
+#define __GST_AUDIO_CONVERT_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/multichannel.h>
+
+#include "audioconvert.h"
+
+#define GST_TYPE_AUDIO_CONVERT          (gst_audio_convert_get_type())
+#define GST_AUDIO_CONVERT(obj)          (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CONVERT,GstAudioConvert))
+#define GST_AUDIO_CONVERT_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_CONVERT,GstAudioConvert))
+#define GST_IS_AUDIO_CONVERT(obj)       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_CONVERT))
+#define GST_IS_AUDIO_CONVERT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_CONVERT))
+
+typedef struct _GstAudioConvert GstAudioConvert;
+typedef struct _GstAudioConvertClass GstAudioConvertClass;
+
+struct _GstAudioConvert
+{
+  GstBaseTransform element;
+
+  AudioConvertCtx ctx;
+};
+
+struct _GstAudioConvertClass
+{
+  GstBaseTransformClass parent_class;
+};
+
+#endif /* __GST_AUDIO_CONVERT_H__ */
index 23bdcbe..570a854 100644 (file)
@@ -43,7 +43,7 @@
  */
 
 void
-gst_audio_convert_unset_matrix (GstAudioConvert * this)
+gst_channel_mix_unset_matrix (AudioConvertCtx * this)
 {
   gint i;
 
@@ -52,7 +52,7 @@ gst_audio_convert_unset_matrix (GstAudioConvert * this)
     return;
 
   /* free */
-  for (i = 0; i < this->sinkcaps.channels; i++)
+  for (i = 0; i < this->in.channels; i++)
     g_free (this->matrix[i]);
   g_free (this->matrix);
 
@@ -66,17 +66,17 @@ gst_audio_convert_unset_matrix (GstAudioConvert * this)
  */
 
 static void
-gst_audio_convert_fill_identical (GstAudioConvert * this)
+gst_channel_mix_fill_identical (AudioConvertCtx * this)
 {
   gint ci, co;
 
   /* Apart from the compatible channel assignments, we can also have
    * same channel assignments. This is much simpler, we simply copy
    * the value from source to dest! */
-  for (co = 0; co < this->srccaps.channels; co++) {
+  for (co = 0; co < this->out.channels; co++) {
     /* find a channel in input with same position */
-    for (ci = 0; ci < this->sinkcaps.channels; ci++) {
-      if (this->sinkcaps.pos[ci] == this->srccaps.pos[co]) {
+    for (ci = 0; ci < this->in.channels; ci++) {
+      if (this->in.pos[ci] == this->out.pos[co]) {
         this->matrix[ci][co] = 1.0;
       }
     }
@@ -90,7 +90,7 @@ gst_audio_convert_fill_identical (GstAudioConvert * this)
  */
 
 static void
-gst_audio_convert_fill_compatible (GstAudioConvert * this)
+gst_channel_mix_fill_compatible (AudioConvertCtx * this)
 {
   /* Conversions from one-channel to compatible two-channel configs */
   struct
@@ -128,14 +128,14 @@ gst_audio_convert_fill_compatible (GstAudioConvert * this)
     gint pos1_0 = -1, pos1_1 = -1, pos2_0 = -1, n;
 
     /* Try to go from the given 2 channels to the given 1 channel */
-    for (n = 0; n < this->sinkcaps.channels; n++) {
-      if (this->sinkcaps.pos[n] == conv[c].pos1[0])
+    for (n = 0; n < this->in.channels; n++) {
+      if (this->in.pos[n] == conv[c].pos1[0])
         pos1_0 = n;
-      else if (this->sinkcaps.pos[n] == conv[c].pos1[1])
+      else if (this->in.pos[n] == conv[c].pos1[1])
         pos1_1 = n;
     }
-    for (n = 0; n < this->srccaps.channels; n++) {
-      if (this->srccaps.pos[n] == conv[c].pos2[0])
+    for (n = 0; n < this->out.channels; n++) {
+      if (this->out.pos[n] == conv[c].pos2[0])
         pos2_0 = n;
     }
 
@@ -149,14 +149,14 @@ gst_audio_convert_fill_compatible (GstAudioConvert * this)
     pos1_1 = -1;
     pos2_0 = -1;
 
-    for (n = 0; n < this->srccaps.channels; n++) {
-      if (this->srccaps.pos[n] == conv[c].pos1[0])
+    for (n = 0; n < this->out.channels; n++) {
+      if (this->out.pos[n] == conv[c].pos1[0])
         pos1_0 = n;
-      else if (this->srccaps.pos[n] == conv[c].pos1[1])
+      else if (this->out.pos[n] == conv[c].pos1[1])
         pos1_1 = n;
     }
-    for (n = 0; n < this->sinkcaps.channels; n++) {
-      if (this->sinkcaps.pos[n] == conv[c].pos2[0])
+    for (n = 0; n < this->in.channels; n++) {
+      if (this->in.pos[n] == conv[c].pos2[0])
         pos2_0 = n;
     }
 
@@ -177,7 +177,7 @@ gst_audio_convert_fill_compatible (GstAudioConvert * this)
  */
 
 static void
-gst_audio_convert_detect_pos (GstAudioConvertCaps * caps,
+gst_channel_mix_detect_pos (AudioConvertFmt * caps,
     gint * f, gboolean * has_f,
     gint * c, gboolean * has_c, gint * r, gboolean * has_r,
     gint * s, gboolean * has_s, gint * b, gboolean * has_b)
@@ -232,12 +232,12 @@ gst_audio_convert_detect_pos (GstAudioConvertCaps * caps,
 }
 
 static void
-gst_audio_convert_fill_one_other (gfloat ** matrix,
-    GstAudioConvertCaps * from_caps, gint * from_idx,
+gst_channel_mix_fill_one_other (gfloat ** matrix,
+    AudioConvertFmt * from_caps, gint * from_idx,
     GstAudioChannelPosition from_pos_l,
     GstAudioChannelPosition from_pos_r,
     GstAudioChannelPosition from_pos_c,
-    GstAudioConvertCaps * to_caps, gint * to_idx,
+    AudioConvertFmt * to_caps, gint * to_idx,
     GstAudioChannelPosition to_pos_l,
     GstAudioChannelPosition to_pos_r,
     GstAudioChannelPosition to_pos_c, gfloat ratio)
@@ -285,7 +285,7 @@ gst_audio_convert_fill_one_other (gfloat ** matrix,
 #define RATIO_CENTER_BASS (1.0 / sqrt (2.0))
 
 static void
-gst_audio_convert_fill_others (GstAudioConvert * this)
+gst_channel_mix_fill_others (AudioConvertCtx * this)
 {
   gboolean in_has_front = FALSE, out_has_front = FALSE,
       in_has_center = FALSE, out_has_center = FALSE,
@@ -305,33 +305,33 @@ gst_audio_convert_fill_others (GstAudioConvert * this)
 
   /* First see where (if at all) the various channels from/to
    * which we want to convert are located in our matrix/array. */
-  gst_audio_convert_detect_pos (&this->sinkcaps,
+  gst_channel_mix_detect_pos (&this->in,
       in_f, &in_has_front,
       in_c, &in_has_center, in_r, &in_has_rear,
       in_s, &in_has_side, in_b, &in_has_bass);
-  gst_audio_convert_detect_pos (&this->srccaps,
+  gst_channel_mix_detect_pos (&this->out,
       out_f, &out_has_front,
       out_c, &out_has_center, out_r, &out_has_rear,
       out_s, &out_has_side, out_b, &out_has_bass);
 
   /* center/front */
   if (!in_has_center && in_has_front && out_has_center) {
-    gst_audio_convert_fill_one_other (this->matrix,
-        &this->sinkcaps, in_f,
+    gst_channel_mix_fill_one_other (this->matrix,
+        &this->in, in_f,
         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
-        &this->srccaps, out_c,
+        &this->out, out_c,
         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, RATIO_FRONT_CENTER);
   } else if (in_has_center && !out_has_center && out_has_front) {
-    gst_audio_convert_fill_one_other (this->matrix,
-        &this->sinkcaps, in_c,
+    gst_channel_mix_fill_one_other (this->matrix,
+        &this->in, in_c,
         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
-        &this->srccaps, out_f,
+        &this->out, out_f,
         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, RATIO_FRONT_CENTER);
@@ -339,22 +339,22 @@ gst_audio_convert_fill_others (GstAudioConvert * this)
 
   /* rear/front */
   if (!in_has_rear && in_has_front && out_has_rear) {
-    gst_audio_convert_fill_one_other (this->matrix,
-        &this->sinkcaps, in_f,
+    gst_channel_mix_fill_one_other (this->matrix,
+        &this->in, in_f,
         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
-        &this->srccaps, out_r,
+        &this->out, out_r,
         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, RATIO_FRONT_REAR);
   } else if (in_has_center && !out_has_center && out_has_front) {
-    gst_audio_convert_fill_one_other (this->matrix,
-        &this->sinkcaps, in_r,
+    gst_channel_mix_fill_one_other (this->matrix,
+        &this->in, in_r,
         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
-        &this->srccaps, out_f,
+        &this->out, out_f,
         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, RATIO_FRONT_REAR);
@@ -363,68 +363,68 @@ gst_audio_convert_fill_others (GstAudioConvert * this)
   /* bass/any */
   if (in_has_bass && !out_has_bass) {
     if (out_has_front) {
-      gst_audio_convert_fill_one_other (this->matrix,
-          &this->sinkcaps, in_b,
+      gst_channel_mix_fill_one_other (this->matrix,
+          &this->in, in_b,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_LFE,
-          &this->srccaps, out_f,
+          &this->out, out_f,
           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
           GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, RATIO_FRONT_BASS);
     }
     if (out_has_center) {
-      gst_audio_convert_fill_one_other (this->matrix,
-          &this->sinkcaps, in_b,
+      gst_channel_mix_fill_one_other (this->matrix,
+          &this->in, in_b,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_LFE,
-          &this->srccaps, out_c,
+          &this->out, out_c,
           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
           GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, RATIO_CENTER_BASS);
     }
     if (out_has_rear) {
-      gst_audio_convert_fill_one_other (this->matrix,
-          &this->sinkcaps, in_b,
+      gst_channel_mix_fill_one_other (this->matrix,
+          &this->in, in_b,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_LFE,
-          &this->srccaps, out_r,
+          &this->out, out_r,
           GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
           GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
           GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, RATIO_REAR_BASS);
     }
   } else if (!in_has_bass && out_has_bass) {
     if (in_has_front) {
-      gst_audio_convert_fill_one_other (this->matrix,
-          &this->sinkcaps, in_f,
+      gst_channel_mix_fill_one_other (this->matrix,
+          &this->in, in_f,
           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
           GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
-          &this->srccaps, out_b,
+          &this->out, out_b,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_LFE, RATIO_FRONT_BASS);
     }
     if (in_has_center) {
-      gst_audio_convert_fill_one_other (this->matrix,
-          &this->sinkcaps, in_c,
+      gst_channel_mix_fill_one_other (this->matrix,
+          &this->in, in_c,
           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
           GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
-          &this->srccaps, out_b,
+          &this->out, out_b,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_LFE, RATIO_CENTER_BASS);
     }
     if (in_has_rear) {
-      gst_audio_convert_fill_one_other (this->matrix,
-          &this->sinkcaps, in_r,
+      gst_channel_mix_fill_one_other (this->matrix,
+          &this->in, in_r,
           GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
           GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
           GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
-          &this->srccaps, out_b,
+          &this->out, out_b,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_INVALID,
           GST_AUDIO_CHANNEL_POSITION_LFE, RATIO_REAR_BASS);
@@ -439,15 +439,15 @@ gst_audio_convert_fill_others (GstAudioConvert * this)
  */
 
 static void
-gst_audio_convert_fill_normalize (GstAudioConvert * this)
+gst_channel_mix_fill_normalize (AudioConvertCtx * this)
 {
   gfloat sum, top = 0;
   gint i, j;
 
-  for (j = 0; j < this->srccaps.channels; j++) {
+  for (j = 0; j < this->out.channels; j++) {
     /* calculate sum */
     sum = 0.0;
-    for (i = 0; i < this->sinkcaps.channels; i++) {
+    for (i = 0; i < this->in.channels; i++) {
       sum += fabs (this->matrix[i][j]);
     }
     if (sum > top) {
@@ -456,8 +456,8 @@ gst_audio_convert_fill_normalize (GstAudioConvert * this)
   }
 
   /* normalize to this */
-  for (j = 0; j < this->srccaps.channels; j++) {
-    for (i = 0; i < this->sinkcaps.channels; i++) {
+  for (j = 0; j < this->out.channels; j++) {
+    for (i = 0; i < this->in.channels; i++) {
       this->matrix[i][j] /= top;
     }
   }
@@ -468,45 +468,45 @@ gst_audio_convert_fill_normalize (GstAudioConvert * this)
  */
 
 static void
-gst_audio_convert_fill_matrix (GstAudioConvert * this)
+gst_channel_mix_fill_matrix (AudioConvertCtx * this)
 {
-  gst_audio_convert_fill_identical (this);
-  gst_audio_convert_fill_compatible (this);
-  gst_audio_convert_fill_others (this);
-  gst_audio_convert_fill_normalize (this);
+  gst_channel_mix_fill_identical (this);
+  gst_channel_mix_fill_compatible (this);
+  gst_channel_mix_fill_others (this);
+  gst_channel_mix_fill_normalize (this);
 }
 
-/* only call after this->srccaps and this->sinkcaps are filled in */
+/* only call after this->out and this->in are filled in */
 void
-gst_audio_convert_setup_matrix (GstAudioConvert * this)
+gst_channel_mix_setup_matrix (AudioConvertCtx * this)
 {
   gint i, j;
   GString *s;
 
   /* don't lose memory */
-  gst_audio_convert_unset_matrix (this);
+  gst_channel_mix_unset_matrix (this);
 
   /* allocate */
-  this->matrix = g_new0 (gfloat *, this->sinkcaps.channels);
-  for (i = 0; i < this->sinkcaps.channels; i++) {
-    this->matrix[i] = g_new (gfloat, this->srccaps.channels);
-    for (j = 0; j < this->srccaps.channels; j++)
+  this->matrix = g_new0 (gfloat *, this->in.channels);
+  for (i = 0; i < this->in.channels; i++) {
+    this->matrix[i] = g_new (gfloat, this->out.channels);
+    for (j = 0; j < this->out.channels; j++)
       this->matrix[i][j] = 0.;
   }
 
   /* setup the matrix' internal values */
-  gst_audio_convert_fill_matrix (this);
+  gst_channel_mix_fill_matrix (this);
 
   /* debug */
   s = g_string_new ("Matrix for");
   g_string_append_printf (s, " %d -> %d: ",
-      this->sinkcaps.channels, this->srccaps.channels);
+      this->in.channels, this->out.channels);
   g_string_append (s, "{");
-  for (i = 0; i < this->sinkcaps.channels; i++) {
+  for (i = 0; i < this->in.channels; i++) {
     if (i != 0)
       g_string_append (s, ",");
     g_string_append (s, " {");
-    for (j = 0; j < this->srccaps.channels; j++) {
+    for (j = 0; j < this->out.channels; j++) {
       if (j != 0)
         g_string_append (s, ",");
       g_string_append_printf (s, " %f", this->matrix[i][j]);
@@ -519,16 +519,16 @@ gst_audio_convert_setup_matrix (GstAudioConvert * this)
 }
 
 gboolean
-gst_audio_convert_passthrough (GstAudioConvert * this)
+gst_channel_mix_passthrough (AudioConvertCtx * this)
 {
   gint i;
 
   /* only NxN matrices can be identities */
-  if (this->sinkcaps.channels != this->srccaps.channels)
+  if (this->in.channels != this->out.channels)
     return FALSE;
 
   /* this assumes a normalized matrix */
-  for (i = 0; i < this->sinkcaps.channels; i++)
+  for (i = 0; i < this->in.channels; i++)
     if (this->matrix[i][i] != 1.)
       return FALSE;
 
@@ -538,23 +538,22 @@ gst_audio_convert_passthrough (GstAudioConvert * this)
 /* IMPORTANT: out_data == in_data is possible, make sure to not overwrite data
  * you might need later on! */
 void
-gst_audio_convert_mix (GstAudioConvert * this,
+gst_channel_mix_mix (AudioConvertCtx * this,
     gint32 * in_data, gint32 * out_data, gint samples)
 {
   gint in, out, n;
   gint64 res;
-  gint32 tmp[this->srccaps.channels];
-  gboolean backwards = this->srccaps.channels > this->sinkcaps.channels;
+  gint32 tmp[this->out.channels];
+  gboolean backwards = this->out.channels > this->in.channels;
 
   /* FIXME: use liboil here? */
   for (n = (backwards ? samples - 1 : 0); n < samples && n >= 0;
       backwards ? n-- : n++) {
-    for (out = 0; out < this->srccaps.channels; out++) {
+    for (out = 0; out < this->out.channels; out++) {
       /* convert */
       res = 0;
-      for (in = 0; in < this->sinkcaps.channels; in++) {
-        res += in_data[n * this->sinkcaps.channels + in] *
-            this->matrix[in][out];
+      for (in = 0; in < this->in.channels; in++) {
+        res += in_data[n * this->in.channels + in] * this->matrix[in][out];
       }
 
       /* clip (shouldn't we use doubles instead as intermediate format?) */
@@ -564,7 +563,7 @@ gst_audio_convert_mix (GstAudioConvert * this,
         res = G_MAXINT32;
       tmp[out] = res;
     }
-    memcpy (&out_data[n * this->srccaps.channels], tmp,
-        sizeof (gint32) * this->srccaps.channels);
+    memcpy (&out_data[n * this->out.channels], tmp,
+        sizeof (gint32) * this->out.channels);
   }
 }
index ae0361e..9aec9ce 100644 (file)
 #define __GST_CHANNEL_MIX_H__
 
 #include <gst/gst.h>
-#include <gst/base/gstbasetransform.h>
-#include <gst/audio/multichannel.h>
-
-#define GST_TYPE_AUDIO_CONVERT          (gst_audio_convert_get_type())
-#define GST_AUDIO_CONVERT(obj)          (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CONVERT,GstAudioConvert))
-#define GST_AUDIO_CONVERT_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_CONVERT,GstAudioConvert))
-#define GST_IS_AUDIO_CONVERT(obj)       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_CONVERT))
-#define GST_IS_AUDIO_CONVERT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_CONVERT))
+#include "audioconvert.h"
 
 GST_DEBUG_CATEGORY_EXTERN (audio_convert_debug);
 #define GST_CAT_DEFAULT (audio_convert_debug)
 
-typedef struct _GstAudioConvert GstAudioConvert;
-typedef struct _GstAudioConvertCaps GstAudioConvertCaps;
-typedef struct _GstAudioConvertClass GstAudioConvertClass;
-
-/* this struct is a handy way of passing around all the caps info ... */
-struct _GstAudioConvertCaps
-{
-  /* general caps */
-  gboolean is_int;
-  gint endianness;
-  gint width;
-  gint rate;
-  gint channels;
-  GstAudioChannelPosition *pos;
-
-  /* int audio caps */
-  gboolean sign;
-  gint depth;
-
-  /* float audio caps */
-  gint buffer_frames;
-};
-
-struct _GstAudioConvert
-{
-  GstBaseTransform element;
-
-  GstAudioConvertCaps srccaps;
-  GstAudioConvertCaps sinkcaps;
-
-  GstCaps *src_prefered;
-  GstCaps *sink_prefered;
-
-  /* channel conversion matrix, m[in_channels][out_channels].
-   * If identity matrix, passthrough applies. */
-  gfloat **matrix;
-
-  /* conversion functions */
-  GstBuffer *(*convert_internal) (GstAudioConvert * this, GstBuffer * buf);
-};
-
-struct _GstAudioConvertClass
-{
-  GstBaseTransformClass parent_class;
-};
-
 /*
  * Delete channel mixer matrix.
  */
-void           gst_audio_convert_unset_matrix  (GstAudioConvert * this);
+void           gst_channel_mix_unset_matrix    (AudioConvertCtx * this);
 
 /*
  * Setup channel mixer matrix.
  */
-void           gst_audio_convert_setup_matrix  (GstAudioConvert * this);
+void           gst_channel_mix_setup_matrix    (AudioConvertCtx * this);
 
 /*
  * Checks for passthrough (= identity matrix).
  */
-gboolean       gst_audio_convert_passthrough   (GstAudioConvert * this);
+gboolean       gst_channel_mix_passthrough     (AudioConvertCtx * this);
 
 /*
  * Do actual mixing.
  */
-void           gst_audio_convert_mix           (GstAudioConvert * this,
+void           gst_channel_mix_mix             (AudioConvertCtx * this,
                                                 gint32          * in_data,
                                                 gint32          * out_data,
                                                 gint              samples);