+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):
libgstaudioconvert_la_SOURCES = \
gstaudioconvert.c \
+ audioconvert.c \
gstchannelmix.c \
bufferframesconvert.c \
plugin.c
$(GST_LIBS)
noinst_HEADERS = \
+ gstaudioconvert.h \
+ audioconvert.h \
gstchannelmix.h \
plugin.h
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
/* 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"
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
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
{
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
/* 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);
/* 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));
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);
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);
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;
}
--- /dev/null
+/* 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__ */
*/
void
-gst_audio_convert_unset_matrix (GstAudioConvert * this)
+gst_channel_mix_unset_matrix (AudioConvertCtx * this)
{
gint i;
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);
*/
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;
}
}
*/
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
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;
}
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;
}
*/
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)
}
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)
#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,
/* 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);
/* 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);
/* 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);
*/
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) {
}
/* 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;
}
}
*/
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]);
}
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;
/* 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?) */
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);
}
}
#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);