From 00d7c52de83255b922657a26430914a844a84f62 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 22 Feb 2007 09:04:37 +0000 Subject: [PATCH] Add float as an intermediate format, as well as float mixing. Enable test that was failing before. Fixes #339837 Original commit message from CVS: * gst/audioconvert/audioconvert.c: (float), (double), (float_hq), (double_hq), (audio_convert_get_func_index), (audio_convert_prepare_context), (audio_convert_convert): * gst/audioconvert/audioconvert.h: * gst/audioconvert/gstchannelmix.c: (gst_channel_mix_setup_matrix), (gst_channel_mix_mix_int), (gst_channel_mix_mix_float): * gst/audioconvert/gstchannelmix.h: * tests/check/elements/audioconvert.c: (GST_START_TEST): Add float as an intermediate format, as well as float mixing. Enable test that was failing before. Fixes #339837 --- ChangeLog | 13 +++ gst/audioconvert/audioconvert.c | 171 +++++++++++++++++----------- gst/audioconvert/audioconvert.h | 10 +- gst/audioconvert/gstchannelmix.c | 50 +++++++- gst/audioconvert/gstchannelmix.h | 7 +- tests/check/elements/audioconvert.c | 3 - 6 files changed, 180 insertions(+), 74 deletions(-) diff --git a/ChangeLog b/ChangeLog index a0cec585b2..e14724d0e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-02-22 Stefan Kost + + * gst/audioconvert/audioconvert.c: (float), (double), (float_hq), + (double_hq), (audio_convert_get_func_index), + (audio_convert_prepare_context), (audio_convert_convert): + * gst/audioconvert/audioconvert.h: + * gst/audioconvert/gstchannelmix.c: (gst_channel_mix_setup_matrix), + (gst_channel_mix_mix_int), (gst_channel_mix_mix_float): + * gst/audioconvert/gstchannelmix.h: + * tests/check/elements/audioconvert.c: (GST_START_TEST): + Add float as an intermediate format, as well as float mixing. Enable + test that was failing before. Fixes #339837 + 2007-02-21 Jan Schmidt * tests/examples/seek/seek.c: (do_seek): diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index d14a99171c..049e101b20 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -55,33 +55,46 @@ MAKE_UNPACK_FUNC_NAME (name) (gpointer src, gint32 *dst, \ /* special unpack code for float/double */ static void -MAKE_UNPACK_FUNC_NAME (float) (gpointer src, gint32 * dst, - gint scale, gint count) +MAKE_UNPACK_FUNC_NAME (float) (gfloat * src, gint32 * dst, gint s, gint count) { - gfloat *p = (gfloat *) src; gdouble temp; for (; count; count--) { /* blow up to 32 bit */ - temp = (*p++ * 2147483647.0) + 0.5; + temp = (*src++ * 2147483647.0) + 0.5; *dst++ = (gint32) CLAMP (temp, G_MININT32, G_MAXINT32); } } static void -MAKE_UNPACK_FUNC_NAME (double) (gpointer src, gint32 * dst, - gint scale, gint count) +MAKE_UNPACK_FUNC_NAME (double) (gdouble * src, gint32 * dst, gint s, gint count) { - gdouble *p = (gdouble *) src; gdouble temp; for (; count; count--) { /* blow up to 32 bit */ - temp = (*p++ * 2147483647.0) + 0.5; + temp = (*src++ * 2147483647.0) + 0.5; *dst++ = (gint32) CLAMP (temp, G_MININT32, G_MAXINT32); } } +static void +MAKE_UNPACK_FUNC_NAME (float_hq) (gfloat * src, gdouble * dst, gint s, + gint count) +{ + for (; count; count--) + *dst++ = (gdouble) * src++; +} + +static void +MAKE_UNPACK_FUNC_NAME (double_hq) (gdouble * src, gdouble * dst, gint s, + gint count) +{ + /* FIXME: memcpy */ + for (; count; count--) + *dst++ = *src++; +} + #define READ8(p) GST_READ_UINT8(p) #define READ16_FROM_LE(p) GST_READ_UINT16_LE (p) #define READ16_FROM_BE(p) GST_READ_UINT16_BE (p) @@ -127,24 +140,34 @@ MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst, \ /* special pack code for float/double */ static void -MAKE_PACK_FUNC_NAME (float) (gint32 * src, gpointer dst, gint scale, gint count) +MAKE_PACK_FUNC_NAME (float) (gint32 * src, gfloat * dst, gint scale, gint count) { - gfloat *p = (gfloat *) dst; - - for (; count; count--) { - *p++ = INT2FLOAT (*src++); - } + for (; count; count--) + *dst++ = INT2FLOAT (*src++); } static void -MAKE_PACK_FUNC_NAME (double) (gint32 * src, gpointer dst, gint scale, +MAKE_PACK_FUNC_NAME (double) (gint32 * src, gdouble * dst, gint scale, gint count) { - gdouble *p = (gdouble *) dst; + for (; count; count--) + *dst++ = INT2DOUBLE (*src++); +} - for (; count; count--) { - *p++ = INT2DOUBLE (*src++); - } +static void +MAKE_PACK_FUNC_NAME (float_hq) (gdouble * src, gfloat * dst, gint s, gint count) +{ + for (; count; count--) + *dst++ = (gfloat) (*src++); +} + +static void +MAKE_PACK_FUNC_NAME (double_hq) (gdouble * src, gdouble * dst, gint s, + gint count) +{ + /* FIXME: memcpy */ + for (; count; count--) + *dst++ = *src++; } #define WRITE8(p, v) GST_WRITE_UINT8 (p, v) @@ -171,45 +194,49 @@ MAKE_PACK_FUNC (u32_be, 4, SIGNED, WRITE32_TO_BE); MAKE_PACK_FUNC (s32_be, 4, 0, WRITE32_TO_BE); 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), - MAKE_UNPACK_FUNC_NAME (u24_le), - MAKE_UNPACK_FUNC_NAME (s24_le), - MAKE_UNPACK_FUNC_NAME (u24_be), - MAKE_UNPACK_FUNC_NAME (s24_be), - 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), - MAKE_UNPACK_FUNC_NAME (double), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s8), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s8), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u16_le), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s16_le), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u16_be), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s16_be), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u24_le), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s24_le), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u24_be), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s24_be), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_le), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_le), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_be), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_be), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_hq), + (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_hq), }; 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), - MAKE_PACK_FUNC_NAME (u24_le), - MAKE_PACK_FUNC_NAME (s24_le), - MAKE_PACK_FUNC_NAME (u24_be), - MAKE_PACK_FUNC_NAME (s24_be), - 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), - MAKE_PACK_FUNC_NAME (double), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u8), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s8), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u8), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s8), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u16_le), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s16_le), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u16_be), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s16_be), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u24_le), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s24_le), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u24_be), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s24_be), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_le), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_le), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_be), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_be), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (float), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (double), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (float_hq), + (AudioConvertPack) MAKE_PACK_FUNC_NAME (double_hq), }; static gint @@ -251,7 +278,7 @@ gboolean audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, AudioConvertFmt * out) { - gint idx; + gint idx_in, idx_out; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (in != NULL, FALSE); @@ -265,14 +292,28 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, gst_channel_mix_setup_matrix (ctx); - idx = audio_convert_get_func_index (in); - if (!(ctx->unpack = unpack_funcs[idx])) + idx_in = audio_convert_get_func_index (in); + if (!(ctx->unpack = unpack_funcs[idx_in])) goto not_supported; - idx = audio_convert_get_func_index (out); - if (!(ctx->pack = pack_funcs[idx])) + idx_out = audio_convert_get_func_index (out); + if (!(ctx->pack = pack_funcs[idx_out])) goto not_supported; + /* if both formats are float/double use double as intermediate format and + * and switch mixing */ + if (in->is_int || out->is_int) { + GST_DEBUG ("use int mixing"); + ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_int; + } else { + GST_DEBUG ("use float mixing"); + ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float; + if (!(ctx->unpack = unpack_funcs[idx_in + 2])) + goto not_supported; + if (!(ctx->pack = pack_funcs[idx_out + 2])) + goto not_supported; + } + /* check if input is in default format */ ctx->in_default = check_default (in); /* check if channel mixer is passthrough */ @@ -287,6 +328,7 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, not_supported: { + GST_INFO ("missing pack/unpack function"); return FALSE; } } @@ -325,7 +367,7 @@ gboolean audio_convert_convert (AudioConvertCtx * ctx, gpointer src, gpointer dst, gint samples, gboolean src_writable) { - gint insize, outsize; + gint insize, outsize, size; gpointer outbuf, tmpbuf; gint biggest = 0; @@ -341,10 +383,11 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, outsize = ctx->out.unit_size * samples; /* find biggest temp buffer size */ + size = (ctx->in.is_int || ctx->out.is_int) ? 32 : 64; if (!ctx->in_default) - biggest = insize * 32 / ctx->in.width; + biggest = insize * size / ctx->in.width; if (!ctx->mix_passthrough) - biggest = MAX (biggest, outsize * 32 / ctx->out.width); + biggest = MAX (biggest, outsize * size / ctx->out.width); /* see if one of the buffers can be used as temp */ if (outsize >= biggest) @@ -381,7 +424,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, outbuf = dst; /* convert channels */ - gst_channel_mix_mix (ctx, src, outbuf, samples); + ctx->channel_mix (ctx, src, outbuf, samples); src = outbuf; } diff --git a/gst/audioconvert/audioconvert.h b/gst/audioconvert/audioconvert.h index 3c90624ccd..34e90329d7 100644 --- a/gst/audioconvert/audioconvert.h +++ b/gst/audioconvert/audioconvert.h @@ -45,8 +45,10 @@ struct _AudioConvertFmt gint unit_size; }; -typedef void (*AudioConvertUnpack) (gpointer src, gint32 *dst, gint scale, gint count); -typedef void (*AudioConvertPack) (gint32 *src, gpointer dst, gint scale, gint count); +typedef void (*AudioConvertUnpack) (gpointer src, gpointer dst, gint scale, gint count); +typedef void (*AudioConvertPack) (gpointer src, gpointer dst, gint scale, gint count); + +typedef void (*AudioConvertMix) (AudioConvertCtx *, gpointer, gpointer, gint); struct _AudioConvertCtx { @@ -60,7 +62,7 @@ struct _AudioConvertCtx * If identity matrix, passthrough applies. */ gfloat **matrix; /* temp storage for channelmix */ - gint32 *tmp; + gpointer tmp; gboolean in_default; gboolean mix_passthrough; @@ -71,6 +73,8 @@ struct _AudioConvertCtx gint in_scale; gint out_scale; + + AudioConvertMix channel_mix; }; gboolean audio_convert_clean_fmt (AudioConvertFmt *fmt); diff --git a/gst/audioconvert/gstchannelmix.c b/gst/audioconvert/gstchannelmix.c index f4f6e6f13f..94023d99fc 100644 --- a/gst/audioconvert/gstchannelmix.c +++ b/gst/audioconvert/gstchannelmix.c @@ -480,7 +480,11 @@ gst_channel_mix_setup_matrix (AudioConvertCtx * this) gst_channel_mix_unset_matrix (this); /* temp storage */ - this->tmp = g_new (gint32, this->out.channels); + if (this->in.is_int || this->out.is_int) { + this->tmp = (gpointer) g_new (gint32, this->out.channels); + } else { + this->tmp = (gpointer) g_new (gdouble, this->out.channels); + } /* allocate */ this->matrix = g_new0 (gfloat *, this->in.channels); @@ -534,13 +538,14 @@ gst_channel_mix_passthrough (AudioConvertCtx * this) /* IMPORTANT: out_data == in_data is possible, make sure to not overwrite data * you might need later on! */ void -gst_channel_mix_mix (AudioConvertCtx * this, +gst_channel_mix_mix_int (AudioConvertCtx * this, gint32 * in_data, gint32 * out_data, gint samples) { gint in, out, n; gint64 res; gboolean backwards; gint inchannels, outchannels; + gint32 *tmp = (gint32 *) this->tmp; g_return_if_fail (this->matrix != NULL); g_return_if_fail (this->tmp != NULL); @@ -564,9 +569,48 @@ gst_channel_mix_mix (AudioConvertCtx * this, res = G_MININT32; else if (res > G_MAXINT32) res = G_MAXINT32; - this->tmp[out] = res; + tmp[out] = res; } memcpy (&out_data[n * outchannels], this->tmp, sizeof (gint32) * outchannels); } } + +void +gst_channel_mix_mix_float (AudioConvertCtx * this, + gdouble * in_data, gdouble * out_data, gint samples) +{ + gint in, out, n; + gdouble res; + gboolean backwards; + gint inchannels, outchannels; + gdouble *tmp = (gdouble *) this->tmp; + + g_return_if_fail (this->matrix != NULL); + g_return_if_fail (this->tmp != NULL); + + inchannels = this->in.channels; + outchannels = this->out.channels; + backwards = outchannels > inchannels; + + /* FIXME: use liboil here? */ + for (n = (backwards ? samples - 1 : 0); n < samples && n >= 0; + backwards ? n-- : n++) { + for (out = 0; out < outchannels; out++) { + /* convert */ + res = 0.0; + for (in = 0; in < inchannels; in++) { + res += in_data[n * inchannels + in] * this->matrix[in][out]; + } + + /* clip (shouldn't we use doubles instead as intermediate format?) */ + if (res < -1.0) + res = -1.0; + else if (res > 1.0) + res = 1.0; + tmp[out] = res; + } + memcpy (&out_data[n * outchannels], this->tmp, + sizeof (gdouble) * outchannels); + } +} diff --git a/gst/audioconvert/gstchannelmix.h b/gst/audioconvert/gstchannelmix.h index 866f34a924..d0462109a5 100644 --- a/gst/audioconvert/gstchannelmix.h +++ b/gst/audioconvert/gstchannelmix.h @@ -46,9 +46,14 @@ gboolean gst_channel_mix_passthrough (AudioConvertCtx * this); /* * Do actual mixing. */ -void gst_channel_mix_mix (AudioConvertCtx * this, +void gst_channel_mix_mix_int (AudioConvertCtx * this, gint32 * in_data, gint32 * out_data, gint samples); +void gst_channel_mix_mix_float (AudioConvertCtx * this, + gdouble * in_data, + gdouble * out_data, + gint samples); + #endif /* __GST_CHANNEL_MIX_H__ */ diff --git a/tests/check/elements/audioconvert.c b/tests/check/elements/audioconvert.c index f8ea130473..deb2cc2d0f 100644 --- a/tests/check/elements/audioconvert.c +++ b/tests/check/elements/audioconvert.c @@ -473,12 +473,9 @@ GST_START_TEST (test_float_conversion) in, get_float_caps (1, "BYTE_ORDER", 64), out, get_float_caps (1, "BYTE_ORDER", 32)); - /* FIXME: this fails */ -#if 0 RUN_CONVERSION ("32 float to 64 float", out, get_float_caps (1, "BYTE_ORDER", 32), in, get_float_caps (1, "BYTE_ORDER", 64)); -#endif } }