diff --git a/ChangeLog b/ChangeLog index f3a6cc9d5d..d10d0fc17c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-02-28 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/gstaudioconvert.c: + (gst_audio_convert_class_init), (gst_audio_convert_get_unit_size), + (gst_audio_convert_transform_caps): + * tests/check/elements/audioconvert.c: (GST_START_TEST), + (audioconvert_suite): + Don't run inplace if that overwrites source data as we go. Add more + tests. Fixes #339837 even more. + 2007-02-27 Julien MOUTTE * tests/examples/seek/seek.c: (do_seek), (set_update_scale), diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index 049e101b20..d06f6ac485 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -43,13 +43,12 @@ audio_convert_unpack_##name #define MAKE_UNPACK_FUNC(name, stride, sign, READ_FUNC) \ static void \ -MAKE_UNPACK_FUNC_NAME (name) (gpointer src, gint32 *dst, \ +MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \ gint scale, gint count) \ { \ - guint8* p = (guint8 *) src; \ for (;count; count--) { \ - *dst++ = (((gint32) READ_FUNC (p)) << scale) ^ (sign); \ - p+=stride; \ + *dst++ = (((gint32) READ_FUNC (src)) << scale) ^ (sign); \ + src+=stride; \ } \ } @@ -83,16 +82,14 @@ MAKE_UNPACK_FUNC_NAME (float_hq) (gfloat * src, gdouble * dst, gint s, gint count) { for (; count; count--) - *dst++ = (gdouble) * src++; + *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++; + memcpy (dst, src, count * sizeof (gdouble)); } #define READ8(p) GST_READ_UINT8(p) @@ -150,8 +147,9 @@ static void MAKE_PACK_FUNC_NAME (double) (gint32 * src, gdouble * dst, gint scale, gint count) { - for (; count; count--) + for (; count; count--) { *dst++ = INT2DOUBLE (*src++); + } } static void @@ -165,9 +163,7 @@ static void MAKE_PACK_FUNC_NAME (double_hq) (gdouble * src, gdouble * dst, gint s, gint count) { - /* FIXME: memcpy */ - for (; count; count--) - *dst++ = *src++; + memcpy (dst, src, count * sizeof (gdouble)); } #define WRITE8(p, v) GST_WRITE_UINT8 (p, v) @@ -303,16 +299,17 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, /* 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"); + GST_INFO ("use int mixing"); ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_int; } else { - GST_DEBUG ("use float mixing"); + GST_INFO ("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; } + GST_INFO ("unitsizes: %d -> %d", in->unit_size, out->unit_size); /* check if input is in default format */ ctx->in_default = check_default (in); @@ -321,8 +318,11 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, /* check if output is in default format */ ctx->out_default = check_default (out); - ctx->in_scale = 32 - in->depth; - ctx->out_scale = 32 - out->depth; + GST_INFO ("in default %d, mix passthrough %d, out default %d", + ctx->in_default, ctx->mix_passthrough, ctx->out_default); + + ctx->in_scale = (in->is_int) ? (32 - in->depth) : 0; + ctx->out_scale = (out->is_int) ? (32 - out->depth) : 0; return TRUE; @@ -369,7 +369,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, { gint insize, outsize, size; gpointer outbuf, tmpbuf; - gint biggest = 0; + gint intemp = 0, outtemp = 0, biggest; g_return_val_if_fail (ctx != NULL, FALSE); g_return_val_if_fail (src != NULL, FALSE); @@ -383,16 +383,19 @@ 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; + size = (ctx->in.is_int || ctx->out.is_int) ? + sizeof (gint32) : sizeof (gdouble); + if (!ctx->in_default) - biggest = insize * size / ctx->in.width; + intemp = insize * size * 8 / ctx->in.width; if (!ctx->mix_passthrough) - biggest = MAX (biggest, outsize * size / ctx->out.width); + outtemp = outsize * size * 8 / ctx->out.width; + biggest = MAX (intemp, outtemp); /* see if one of the buffers can be used as temp */ - if (outsize >= biggest) + if ((outsize >= biggest) && (ctx->out.unit_size <= size)) tmpbuf = dst; - else if (insize >= biggest && src_writable) + else if ((insize >= biggest) && src_writable && (ctx->in.unit_size >= size)) tmpbuf = src; else { if (biggest > ctx->tmpbufsize) { diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c index 6eff1d653c..c18529bc92 100644 --- a/gst/audioconvert/gstaudioconvert.c +++ b/gst/audioconvert/gstaudioconvert.c @@ -197,6 +197,7 @@ static void gst_audio_convert_class_init (GstAudioConvertClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass); gint i; gobject_class->dispose = gst_audio_convert_dispose; @@ -206,20 +207,20 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass) for (i = 0; i < GST_AUDIO_CHANNEL_POSITION_NUM; i++) supported_positions[i] = i; - GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = + basetransform_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_audio_convert_get_unit_size); - GST_BASE_TRANSFORM_CLASS (klass)->transform_caps = + basetransform_class->transform_caps = GST_DEBUG_FUNCPTR (gst_audio_convert_transform_caps); - GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps = + basetransform_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_audio_convert_fixate_caps); - GST_BASE_TRANSFORM_CLASS (klass)->set_caps = + basetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_convert_set_caps); - GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = + basetransform_class->transform_ip = GST_DEBUG_FUNCPTR (gst_audio_convert_transform_ip); - GST_BASE_TRANSFORM_CLASS (klass)->transform = + basetransform_class->transform = GST_DEBUG_FUNCPTR (gst_audio_convert_transform); - GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE; + basetransform_class->passthrough_on_same_caps = TRUE; } static void @@ -315,6 +316,7 @@ gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps, if (!gst_audio_convert_parse_caps (caps, &fmt)) goto parse_error; + GST_INFO_OBJECT (base, "unit_size = %u", fmt.unit_size); *size = fmt.unit_size; audio_convert_clean_fmt (&fmt); @@ -323,6 +325,7 @@ gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps, parse_error: { + GST_INFO_OBJECT (base, "failed to parse caps to get unit_size"); return FALSE; } } @@ -525,14 +528,9 @@ gst_audio_convert_transform_caps (GstBaseTransform * base, * done the equivalent above. */ if (!gst_structure_get_int (structure, "width", &width) || width > 16) { if (isfloat) { - /* These are invalid widths/depths for float, but we don't actually use - * them - we just pass it to append_with_other_format, which makes them - * valid - */ GstStructure *s2 = gst_structure_copy (s); - set_structure_widths (s2, 16, 32); - gst_structure_set (s2, "depth", GST_TYPE_INT_RANGE, 16, 32, NULL); + set_structure_widths_32_and_64 (s2); append_with_other_format (ret, s2, TRUE); gst_structure_free (s2); } else { diff --git a/tests/check/elements/audioconvert.c b/tests/check/elements/audioconvert.c index deb2cc2d0f..3517b825b9 100644 --- a/tests/check/elements/audioconvert.c +++ b/tests/check/elements/audioconvert.c @@ -348,6 +348,7 @@ verify_convert (const gchar * which, void *in, int inlength, verify_convert (which, inarray, sizeof (inarray), \ in_get_caps, outarray, sizeof (outarray), out_get_caps) + GST_START_TEST (test_int16) { /* stereo to mono */ @@ -384,6 +385,32 @@ GST_START_TEST (test_int16) GST_END_TEST; + +GST_START_TEST (test_float32) +{ + /* stereo to mono */ + { + gfloat in[] = { 0.6, -0.0078125, 0.03125, 0.03125 }; + gfloat out[] = { 0.29609375, 0.03125 }; + + RUN_CONVERSION ("float32 stereo to mono", + in, get_float_caps (2, "BYTE_ORDER", 32), + out, get_float_caps (1, "BYTE_ORDER", 32)); + } + /* mono to stereo */ + { + gfloat in[] = { 0.015625, 0.03125 }; + gfloat out[] = { 0.015625, 0.015625, 0.03125, 0.03125 }; + + RUN_CONVERSION ("float32 mono to stereo", + in, get_float_caps (1, "BYTE_ORDER", 32), + out, get_float_caps (2, "BYTE_ORDER", 32)); + } +} + +GST_END_TEST; + + GST_START_TEST (test_int_conversion) { /* 8 <-> 16 signed */ @@ -448,6 +475,7 @@ GST_START_TEST (test_int_conversion) GST_END_TEST; + GST_START_TEST (test_float_conversion) { /* 32 float <-> 16 signed */ @@ -459,9 +487,55 @@ GST_START_TEST (test_float_conversion) /* only one direction conversion, the other direction does * not produce exactly the same as the input due to floating * point rounding errors etc. */ - RUN_CONVERSION ("32 float to 16 signed", in, get_float_caps (1, - "BYTE_ORDER", 32), out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE) - ); + RUN_CONVERSION ("32 float to 16 signed", + in, get_float_caps (1, "BYTE_ORDER", 32), + out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE)); + } + { + gint16 in[] = { 0, -32768, 16384, -16384 }; + gfloat out[] = { 0.0, -1.0, 0.5, -0.5 }; + + RUN_CONVERSION ("16 signed to 32 float", + in, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE), + out, get_float_caps (1, "BYTE_ORDER", 32)); + } + + /* 64 float <-> 16 signed */ + /* NOTE: if audioconvert was doing dithering we'd have a problem */ + { + gdouble in[] = { 0.0, 1.0, -1.0, 0.5, -0.5, 1.1, -1.1 }; + gint16 out[] = { 0, 32767, -32768, 16384, -16384, 32767, -32768 }; + + /* only one direction conversion, the other direction does + * not produce exactly the same as the input due to floating + * point rounding errors etc. */ + RUN_CONVERSION ("64 float to 16 signed", + in, get_float_caps (1, "BYTE_ORDER", 64), + out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE)); + } + { + gint16 in[] = { 0, -32768, 16384, -16384 }; + gdouble out[] = { 0.0, + 4.6566128752457969e-10 * (gdouble) (-32768L << 16), /* ~ -1.0 */ + 4.6566128752457969e-10 * (gdouble) (16384L << 16), /* ~ 0.5 */ + 4.6566128752457969e-10 * (gdouble) (-16384L << 16), /* ~ -0.5 */ + }; + + RUN_CONVERSION ("16 signed to 64 float", + in, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE), + out, get_float_caps (1, "BYTE_ORDER", 64)); + } + { + gint32 in[] = { 0, (-1L << 31), (1L << 30), (-1L << 30) }; + gdouble out[] = { 0.0, + 4.6566128752457969e-10 * (gdouble) (-1L << 31), /* ~ -1.0 */ + 4.6566128752457969e-10 * (gdouble) (1L << 30), /* ~ 0.5 */ + 4.6566128752457969e-10 * (gdouble) (-1L << 30), /* ~ -0.5 */ + }; + + RUN_CONVERSION ("32 signed to 64 float", + in, get_int_caps (1, "BYTE_ORDER", 32, 32, TRUE), + out, get_float_caps (1, "BYTE_ORDER", 64)); } /* 64-bit float <-> 32-bit float */ @@ -481,6 +555,7 @@ GST_START_TEST (test_float_conversion) GST_END_TEST; + GST_START_TEST (test_multichannel_conversion) { { @@ -501,6 +576,7 @@ GST_START_TEST (test_multichannel_conversion) GST_END_TEST; + GST_START_TEST (test_channel_remapping) { /* float */ @@ -606,6 +682,7 @@ audioconvert_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_int16); + tcase_add_test (tc_chain, test_float32); tcase_add_test (tc_chain, test_int_conversion); tcase_add_test (tc_chain, test_float_conversion); tcase_add_test (tc_chain, test_multichannel_conversion);