From c36ac3ce45cbf1720de35202c60d8d85bfabed0a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 6 Nov 2015 12:10:48 +0100 Subject: [PATCH] audioconvert: move audio quantize code to libs Move the audio quantize code from audioconvert to the audio library. work on making an audio converter helper function similar to the video converter. Fold fastrandom directly into the quantizer, add some ORC code to optimize this later. --- gst-libs/gst/audio/Makefile.am | 3 + .../gst/audio/audio-quantize.c | 25 +- .../gst/audio/audio-quantize.h | 0 gst-libs/gst/audio/audio.h | 1 + gst-libs/gst/audio/gstaudiopack.orc | 28 ++ gst/audioconvert/Makefile.am | 3 - gst/audioconvert/audioconvert.c | 290 +++++++++++++----- gst/audioconvert/audioconvert.h | 91 +++--- gst/audioconvert/gstaudioconvert.c | 93 ++---- gst/audioconvert/gstaudioconvert.h | 7 +- gst/audioconvert/gstfastrandom.h | 70 ----- 11 files changed, 353 insertions(+), 258 deletions(-) rename gst/audioconvert/gstaudioquantize.c => gst-libs/gst/audio/audio-quantize.c (95%) rename gst/audioconvert/gstaudioquantize.h => gst-libs/gst/audio/audio-quantize.h (100%) delete mode 100644 gst/audioconvert/gstfastrandom.h diff --git a/gst-libs/gst/audio/Makefile.am b/gst-libs/gst/audio/Makefile.am index 275d22227c..dee4e364a7 100644 --- a/gst-libs/gst/audio/Makefile.am +++ b/gst-libs/gst/audio/Makefile.am @@ -7,6 +7,7 @@ glib_enum_headers= \ audio-format.h \ audio-channels.h \ audio-info.h \ + audio-quantize.h \ gstaudioringbuffer.h glib_enum_define = GST_AUDIO @@ -27,6 +28,7 @@ libgstaudio_@GST_API_VERSION@_la_SOURCES = \ audio-format.c \ audio-channels.c \ audio-info.c \ + audio-quantize.c \ gstaudioringbuffer.c \ gstaudioclock.c \ gstaudiocdsrc.c \ @@ -50,6 +52,7 @@ libgstaudio_@GST_API_VERSION@include_HEADERS = \ audio-format.h \ audio-channels.h \ audio-info.h \ + audio-quantize.h \ gstaudioringbuffer.h \ gstaudioclock.h \ gstaudiofilter.h \ diff --git a/gst/audioconvert/gstaudioquantize.c b/gst-libs/gst/audio/audio-quantize.c similarity index 95% rename from gst/audioconvert/gstaudioquantize.c rename to gst-libs/gst/audio/audio-quantize.c index 33e27803ef..7bedd2c0e6 100644 --- a/gst/audioconvert/gstaudioquantize.c +++ b/gst-libs/gst/audio/audio-quantize.c @@ -29,10 +29,9 @@ #include #include #include -#include "gstaudioconvertorc.h" -#include "gstaudioquantize.h" -#include "gstfastrandom.h" +#include "gstaudiopack.h" +#include "audio-quantize.h" typedef void (*QuantizeFunc) (GstAudioQuantize * quant, const gpointer src, gpointer dst, gint count); @@ -85,10 +84,26 @@ static void gst_audio_quantize_quantize_int_none_none (GstAudioQuantize * quant, const gpointer src, gpointer dst, gint samples) { - audio_convert_orc_int_bias (dst, src, quant->bias, ~quant->mask, + audio_orc_int_bias (dst, src, quant->bias, ~quant->mask, samples * quant->channels); } +/* This is the base function, implementing a linear congruential generator + * and returning a pseudo random number between 0 and 2^32 - 1. + */ +static inline guint32 +gst_fast_random_uint32 (void) +{ + static guint32 state = 0xdeadbeef; + return (state = state * 1103515245 + 12345); +} + +static inline gint32 +gst_fast_random_int32 (void) +{ + return (gint32) gst_fast_random_uint32 (); +} + /* Assuming dither == 2^n, * returns one of 2^(n+1) possible random values: * -dither <= retval < dither */ @@ -155,7 +170,7 @@ gst_audio_quantize_quantize_int_dither_none (GstAudioQuantize * quant, { setup_dither_buf (quant, samples); - audio_convert_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask, + audio_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask, samples * quant->channels); } diff --git a/gst/audioconvert/gstaudioquantize.h b/gst-libs/gst/audio/audio-quantize.h similarity index 100% rename from gst/audioconvert/gstaudioquantize.h rename to gst-libs/gst/audio/audio-quantize.h diff --git a/gst-libs/gst/audio/audio.h b/gst-libs/gst/audio/audio.h index 07a997bc5a..277c2e9eb7 100644 --- a/gst-libs/gst/audio/audio.h +++ b/gst-libs/gst/audio/audio.h @@ -27,6 +27,7 @@ #include #include #include +#include G_BEGIN_DECLS diff --git a/gst-libs/gst/audio/gstaudiopack.orc b/gst-libs/gst/audio/gstaudiopack.orc index 160c165494..57484744d9 100644 --- a/gst-libs/gst/audio/gstaudiopack.orc +++ b/gst-libs/gst/audio/gstaudiopack.orc @@ -380,3 +380,31 @@ copyl d1, p1 copyq d1, p1 +.function audio_orc_int_bias +.dest 4 d1 gint32 +.source 4 s1 gint32 +.param 4 bias gint32 +.param 4 mask gint32 +.temp 4 t1 + +addssl t1, s1, bias +andl d1, t1, mask + +.function audio_orc_int_dither +.dest 4 d1 gint32 +.source 4 s1 gint32 +.source 4 dither gint32 +.param 4 mask gint32 +.temp 4 t1 + +addssl t1, s1, dither +andl d1, t1, mask + +.function audio_orc_update_rand +.dest 4 r guint32 +.temp 4 t + +mulll t, r, 1103515245 +addl r, t, 12345 + + diff --git a/gst/audioconvert/Makefile.am b/gst/audioconvert/Makefile.am index 1e2672b61d..d29c6bbef2 100644 --- a/gst/audioconvert/Makefile.am +++ b/gst/audioconvert/Makefile.am @@ -7,7 +7,6 @@ libgstaudioconvert_la_SOURCES = \ gstaudioconvert.c \ audioconvert.c \ gstchannelmix.c \ - gstaudioquantize.c \ plugin.c nodist_libgstaudioconvert_la_SOURCES = $(ORC_NODIST_SOURCES) @@ -22,6 +21,4 @@ noinst_HEADERS = \ gstaudioconvert.h \ audioconvert.h \ gstchannelmix.h \ - gstaudioquantize.h \ - gstfastrandom.h \ plugin.h diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index 5ca86d5f23..d7807036fe 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -27,10 +27,11 @@ #include #include "gstchannelmix.h" -#include "gstaudioquantize.h" #include "audioconvert.h" #include "gstaudioconvertorc.h" +typedef void (*AudioConvertFunc) (gpointer dst, const gpointer src, gint count); + /** * int/int int/float float/int float/float * @@ -41,29 +42,160 @@ * quantize S32 S32 * pack S32 F64 S32 F64 */ -gboolean -audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, - GstAudioInfo * out, GstAudioDitherMethod dither, - GstAudioNoiseShapingMethod ns) +struct _GstAudioConverter { + GstAudioInfo in; + GstAudioInfo out; + + GstStructure *config; + + gboolean in_default; + + AudioConvertFunc convert_in; + + GstAudioFormat mix_format; + gboolean mix_passthrough; + GstChannelMix *mix; + + AudioConvertFunc convert_out; + + GstAudioQuantize *quant; + + gboolean out_default; + + gboolean passthrough; + + gpointer tmpbuf; + gpointer tmpbuf2; + gint tmpbufsize; +}; + +/* +static guint +get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def) +{ + guint res; + if (!gst_structure_get_uint (convert->config, opt, &res)) + res = def; + return res; +} +*/ + +static gint +get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type, + gint def) +{ + gint res; + if (!gst_structure_get_enum (convert->config, opt, type, &res)) + res = def; + return res; +} + +#define DEFAULT_OPT_DITHER_METHOD GST_AUDIO_DITHER_NONE +#define DEFAULT_OPT_NOISE_SHAPING_METHOD GST_AUDIO_NOISE_SHAPING_NONE +#define DEFAULT_OPT_QUANTIZATION 1 + +#define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \ + GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, \ + DEFAULT_OPT_DITHER_METHOD) +#define GET_OPT_NOISE_SHAPING_METHOD(c) get_opt_enum(c, \ + GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, \ + DEFAULT_OPT_NOISE_SHAPING_METHOD) +#define GET_OPT_QUANTIZATION(c) get_opt_uint(c, \ + GST_AUDIO_CONVERTER_OPT_QUANTIZATION, DEFAULT_OPT_QUANTIZATION) + +static gboolean +copy_config (GQuark field_id, const GValue * value, gpointer user_data) +{ + GstAudioConverter *convert = user_data; + + gst_structure_id_set_value (convert->config, field_id, value); + + return TRUE; +} + +/** + * gst_audio_converter_set_config: + * @convert: a #GstAudioConverter + * @config: (transfer full): a #GstStructure + * + * Set @config as extra configuraion for @convert. + * + * If the parameters in @config can not be set exactly, this function returns + * %FALSE and will try to update as much state as possible. The new state can + * then be retrieved and refined with gst_audio_converter_get_config(). + * + * Look at the #GST_AUDIO_CONVERTER_OPT_* fields to check valid configuration + * option and values. + * + * Returns: %TRUE when @config could be set. + */ +gboolean +gst_audio_converter_set_config (GstAudioConverter * convert, + GstStructure * config) +{ + g_return_val_if_fail (convert != NULL, FALSE); + g_return_val_if_fail (config != NULL, FALSE); + + gst_structure_foreach (config, copy_config, convert); + gst_structure_free (config); + + return TRUE; +} + +/** + * gst_audio_converter_get_config: + * @convert: a #GstAudioConverter + * + * Get the current configuration of @convert. + * + * Returns: a #GstStructure that remains valid for as long as @convert is valid + * or until gst_audio_converter_set_config() is called. + */ +const GstStructure * +gst_audio_converter_get_config (GstAudioConverter * convert) +{ + g_return_val_if_fail (convert != NULL, NULL); + + return convert->config; +} + + +/** + * + */ +GstAudioConverter * +gst_audio_converter_new (GstAudioInfo * in, GstAudioInfo * out, + GstStructure * config) +{ + GstAudioConverter *convert; gint in_depth, out_depth; GstChannelMixFlags flags; gboolean in_int, out_int; GstAudioFormat format; + GstAudioDitherMethod dither; + GstAudioNoiseShapingMethod ns; - 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); if ((GST_AUDIO_INFO_CHANNELS (in) != GST_AUDIO_INFO_CHANNELS (out)) && (GST_AUDIO_INFO_IS_UNPOSITIONED (in) || GST_AUDIO_INFO_IS_UNPOSITIONED (out))) goto unpositioned; - ctx->in = *in; - ctx->out = *out; + convert = g_slice_new0 (GstAudioConverter); + + convert->in = *in; + convert->out = *out; + + /* default config */ + convert->config = gst_structure_new_empty ("GstAudioConverter"); + if (config) + gst_audio_converter_set_config (convert, config); + + dither = GET_OPT_DITHER_METHOD (convert); + ns = GET_OPT_NOISE_SHAPING_METHOD (convert); GST_INFO ("unitsizes: %d -> %d", in->bpf, out->bpf); @@ -85,7 +217,7 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, /* step 1, unpack */ format = in->finfo->unpack_format; - ctx->in_default = in->finfo->unpack_format == in->finfo->format; + convert->in_default = in->finfo->unpack_format == in->finfo->format; GST_INFO ("unpack format %s to %s", gst_audio_format_to_string (in->finfo->format), gst_audio_format_to_string (format)); @@ -93,23 +225,23 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, /* step 2, optional convert from S32 to F64 for channel mix */ if (in_int && !out_int) { GST_INFO ("convert S32 to F64"); - ctx->convert_in = (AudioConvertFunc) audio_convert_orc_s32_to_double; + convert->convert_in = (AudioConvertFunc) audio_convert_orc_s32_to_double; format = GST_AUDIO_FORMAT_F64; } /* step 3, channel mix */ - ctx->mix_format = format; - ctx->mix = gst_channel_mix_new (flags, in->channels, in->position, + convert->mix_format = format; + convert->mix = gst_channel_mix_new (flags, in->channels, in->position, out->channels, out->position); - ctx->mix_passthrough = gst_channel_mix_is_passthrough (ctx->mix); + convert->mix_passthrough = gst_channel_mix_is_passthrough (convert->mix); GST_INFO ("mix format %s, passthrough %d, in_channels %d, out_channels %d", - gst_audio_format_to_string (format), ctx->mix_passthrough, + gst_audio_format_to_string (format), convert->mix_passthrough, in->channels, out->channels); /* step 4, optional convert for quantize */ if (!in_int && out_int) { GST_INFO ("convert F64 to S32"); - ctx->convert_out = (AudioConvertFunc) audio_convert_orc_double_to_s32; + convert->convert_out = (AudioConvertFunc) audio_convert_orc_double_to_s32; format = GST_AUDIO_FORMAT_S32; } /* step 5, optional quantize */ @@ -132,78 +264,72 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, * the rounding correct */ if (out_int && out_depth < 32) { GST_INFO ("quantize to %d bits, dither %d, ns %d", out_depth, dither, ns); - ctx->quant = gst_audio_quantize_new (dither, ns, 0, format, + convert->quant = gst_audio_quantize_new (dither, ns, 0, format, out->channels, 1U << (32 - out_depth)); } /* step 6, pack */ g_assert (out->finfo->unpack_format == format); - ctx->out_default = format == out->finfo->format; + convert->out_default = format == out->finfo->format; GST_INFO ("pack format %s to %s", gst_audio_format_to_string (format), gst_audio_format_to_string (out->finfo->format)); /* optimize */ - if (out->finfo->format == in->finfo->format && ctx->mix_passthrough) { + if (out->finfo->format == in->finfo->format && convert->mix_passthrough) { GST_INFO ("same formats and passthrough mixing -> passthrough"); - ctx->passthrough = TRUE; + convert->passthrough = TRUE; } - return TRUE; + return convert; /* ERRORS */ unpositioned: { GST_WARNING ("unpositioned channels"); - return FALSE; + return NULL; } } -gboolean -audio_convert_clean_context (AudioConvertCtx * ctx) +void +gst_audio_converter_free (GstAudioConverter * convert) { - g_return_val_if_fail (ctx != NULL, FALSE); + g_return_if_fail (convert != NULL); - if (ctx->quant) - gst_audio_quantize_free (ctx->quant); - ctx->quant = NULL; - if (ctx->mix) - gst_channel_mix_free (ctx->mix); - ctx->mix = NULL; - gst_audio_info_init (&ctx->in); - gst_audio_info_init (&ctx->out); - ctx->convert_in = NULL; - ctx->convert_out = NULL; + if (convert->quant) + gst_audio_quantize_free (convert->quant); + if (convert->mix) + gst_channel_mix_free (convert->mix); + gst_audio_info_init (&convert->in); + gst_audio_info_init (&convert->out); - g_free (ctx->tmpbuf); - g_free (ctx->tmpbuf2); - ctx->tmpbuf = NULL; - ctx->tmpbuf2 = NULL; - ctx->tmpbufsize = 0; + g_free (convert->tmpbuf); + g_free (convert->tmpbuf2); + gst_structure_free (convert->config); - return TRUE; + g_slice_free (GstAudioConverter, convert); } gboolean -audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize, - gint * dstsize) +gst_audio_converter_get_sizes (GstAudioConverter * convert, gint samples, + gint * srcsize, gint * dstsize) { - g_return_val_if_fail (ctx != NULL, FALSE); + g_return_val_if_fail (convert != NULL, FALSE); if (srcsize) - *srcsize = samples * ctx->in.bpf; + *srcsize = samples * convert->in.bpf; if (dstsize) - *dstsize = samples * ctx->out.bpf; + *dstsize = samples * convert->out.bpf; return TRUE; } gboolean -audio_convert_convert (AudioConvertCtx * ctx, gpointer src, - gpointer dst, gint samples, gboolean src_writable) +gst_audio_converter_samples (GstAudioConverter * convert, + GstAudioConverterFlags flags, gpointer src, gpointer dst, gint samples) { guint size; gpointer outbuf, tmpbuf, tmpbuf2; - g_return_val_if_fail (ctx != NULL, FALSE); + g_return_val_if_fail (convert != 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); @@ -211,86 +337,88 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, if (samples == 0) return TRUE; - if (ctx->passthrough) { - memcpy (dst, src, samples * ctx->in.bpf); + if (convert->passthrough) { + memcpy (dst, src, samples * convert->in.bpf); return TRUE; } - size = sizeof (gdouble) * samples * MAX (ctx->in.channels, ctx->out.channels); + size = + sizeof (gdouble) * samples * MAX (convert->in.channels, + convert->out.channels); - if (size > ctx->tmpbufsize) { - ctx->tmpbuf = g_realloc (ctx->tmpbuf, size); - ctx->tmpbuf2 = g_realloc (ctx->tmpbuf2, size); - ctx->tmpbufsize = size; + if (size > convert->tmpbufsize) { + convert->tmpbuf = g_realloc (convert->tmpbuf, size); + convert->tmpbuf2 = g_realloc (convert->tmpbuf2, size); + convert->tmpbufsize = size; } - tmpbuf = ctx->tmpbuf; - tmpbuf2 = ctx->tmpbuf2; + tmpbuf = convert->tmpbuf; + tmpbuf2 = convert->tmpbuf2; /* 1. unpack */ - if (!ctx->in_default) { - if (!ctx->convert_in && ctx->mix_passthrough && !ctx->convert_out - && !ctx->quant && ctx->out_default) + if (!convert->in_default) { + if (!convert->convert_in && convert->mix_passthrough + && !convert->convert_out && !convert->quant && convert->out_default) outbuf = dst; else outbuf = tmpbuf; - ctx->in.finfo->unpack_func (ctx->in.finfo, + convert->in.finfo->unpack_func (convert->in.finfo, GST_AUDIO_PACK_FLAG_TRUNCATE_RANGE, outbuf, src, - samples * ctx->in.channels); + samples * convert->in.channels); src = outbuf; } /* 2. optionally convert for mixing */ - if (ctx->convert_in) { - if (ctx->mix_passthrough && !ctx->convert_out && !ctx->quant - && ctx->out_default) + if (convert->convert_in) { + if (convert->mix_passthrough && !convert->convert_out && !convert->quant + && convert->out_default) outbuf = dst; else if (src == tmpbuf) outbuf = tmpbuf2; else outbuf = tmpbuf; - ctx->convert_in (outbuf, src, samples * ctx->in.channels); + convert->convert_in (outbuf, src, samples * convert->in.channels); src = outbuf; } /* step 3, channel mix if not passthrough */ - if (!ctx->mix_passthrough) { - if (!ctx->convert_out && !ctx->quant && ctx->out_default) + if (!convert->mix_passthrough) { + if (!convert->convert_out && !convert->quant && convert->out_default) outbuf = dst; else outbuf = tmpbuf; - gst_channel_mix_mix (ctx->mix, ctx->mix_format, ctx->in.layout, src, outbuf, - samples); + gst_channel_mix_mix (convert->mix, convert->mix_format, convert->in.layout, + src, outbuf, samples); src = outbuf; } /* step 4, optional convert F64 -> S32 for quantize */ - if (ctx->convert_out) { - if (!ctx->quant && ctx->out_default) + if (convert->convert_out) { + if (!convert->quant && convert->out_default) outbuf = dst; else outbuf = tmpbuf; - ctx->convert_out (outbuf, src, samples * ctx->out.channels); + convert->convert_out (outbuf, src, samples * convert->out.channels); src = outbuf; } /* step 5, optional quantize */ - if (ctx->quant) { - if (ctx->out_default) + if (convert->quant) { + if (convert->out_default) outbuf = dst; else outbuf = tmpbuf; - gst_audio_quantize_samples (ctx->quant, outbuf, src, samples); + gst_audio_quantize_samples (convert->quant, outbuf, src, samples); src = outbuf; } /* step 6, pack */ - if (!ctx->out_default) { - ctx->out.finfo->pack_func (ctx->out.finfo, 0, src, dst, - samples * ctx->out.channels); + if (!convert->out_default) { + convert->out.finfo->pack_func (convert->out.finfo, 0, src, dst, + samples * convert->out.channels); } return TRUE; diff --git a/gst/audioconvert/audioconvert.h b/gst/audioconvert/audioconvert.h index c34e2aa8e0..8c3f778c28 100644 --- a/gst/audioconvert/audioconvert.h +++ b/gst/audioconvert/audioconvert.h @@ -1,7 +1,8 @@ /* GStreamer * Copyright (C) 2004 Ronald Bultje + * (C) 2015 Wim Taymans * - * audioconvert.h: audio format conversion library + * audioconverter.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 @@ -19,57 +20,73 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __AUDIO_CONVERT_H__ -#define __AUDIO_CONVERT_H__ +#ifndef __GST_AUDIO_CONVERTER_H__ +#define __GST_AUDIO_CONVERTER_H__ #include #include #include "gstchannelmix.h" -#include "gstaudioquantize.h" -GST_DEBUG_CATEGORY_EXTERN (audio_convert_debug); -#define GST_CAT_DEFAULT (audio_convert_debug) +typedef struct _GstAudioConverter GstAudioConverter; -typedef struct _AudioConvertCtx AudioConvertCtx; +/** + * GST_AUDIO_CONVERTER_OPT_DITHER_METHOD: + * + * #GST_TYPE_AUDIO_DITHER_METHOD, The dither method to use when + * changing bit depth. + * Default is #GST_AUDIO_DITHER_NONE. + */ +#define GST_AUDIO_CONVERTER_OPT_DITHER_METHOD "GstAudioConverter.dither-method" -typedef void (*AudioConvertFunc) (gpointer dst, const gpointer src, gint count); +/** + * GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD: + * + * #GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, The noise shaping method to use + * to mask noise from quantization errors. + * Default is #GST_AUDIO_NOISE_SHAPING_NONE. + */ +#define GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD "GstAudioConverter.noise-shaping-method" -struct _AudioConvertCtx -{ - GstAudioInfo in; - GstAudioInfo out; +/** + * GST_AUDIO_CONVERTER_OPT_QUANTIZATION: + * + * #G_TYPE_UINT, The quantization amount. Components will be + * quantized to multiples of this value. + * Default is 1 + */ +#define GST_AUDIO_CONVERTER_OPT_QUANTIZATION "GstAudioConverter.quantization" - gboolean in_default; - AudioConvertFunc convert_in; +/** + * @GST_AUDIO_CONVERTER_FLAG_NONE: no flag + * @GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE: the source is writable and can be + * used as temporary storage during conversion. + * + * Extra flags passed to gst_audio_converter_samples(). + */ +typedef enum { + GST_AUDIO_CONVERTER_FLAG_NONE = 0, + GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE = (1 << 0) +} GstAudioConverterFlags; - GstAudioFormat mix_format; - gboolean mix_passthrough; - GstChannelMix *mix; +GstAudioConverter * gst_audio_converter_new (GstAudioInfo *in_info, + GstAudioInfo *out_info, + GstStructure *config); - AudioConvertFunc convert_out; +void gst_audio_converter_free (GstAudioConverter * convert); - GstAudioQuantize *quant; +gboolean gst_audio_converter_set_config (GstAudioConverter * convert, GstStructure *config); +const GstStructure * gst_audio_converter_get_config (GstAudioConverter * convert); - gboolean out_default; - gboolean passthrough; +gboolean gst_audio_converter_get_sizes (GstAudioConverter * convert, + gint samples, + gint * srcsize, gint * dstsize); - gpointer tmpbuf; - gpointer tmpbuf2; - gint tmpbufsize; -}; +gboolean gst_audio_converter_samples (GstAudioConverter * convert, + GstAudioConverterFlags flags, + gpointer src, gpointer dst, + gint samples); -gboolean audio_convert_prepare_context (AudioConvertCtx * ctx, - GstAudioInfo * in, GstAudioInfo * out, - GstAudioDitherMethod dither, GstAudioNoiseShapingMethod ns); -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__ */ +#endif /* __GST_AUDIO_CONVERTER_H__ */ diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c index f3fbe93ee1..29cab90e6d 100644 --- a/gst/audioconvert/gstaudioconvert.c +++ b/gst/audioconvert/gstaudioconvert.c @@ -64,7 +64,6 @@ #include "gstaudioconvert.h" #include "gstchannelmix.h" -#include "gstaudioquantize.h" #include "plugin.h" GST_DEBUG_CATEGORY (audio_convert_debug); @@ -134,51 +133,6 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, STATIC_CAPS); -#define GST_TYPE_AUDIO_CONVERT_DITHERING (gst_audio_convert_dithering_get_type ()) -static GType -gst_audio_convert_dithering_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {GST_AUDIO_DITHER_NONE, "No dithering", - "none"}, - {GST_AUDIO_DITHER_RPDF, "Rectangular dithering", "rpdf"}, - {GST_AUDIO_DITHER_TPDF, "Triangular dithering (default)", "tpdf"}, - {GST_AUDIO_DITHER_TPDF_HF, "High frequency triangular dithering", - "tpdf-hf"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioConvertDithering", values); - } - return gtype; -} - -#define GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING (gst_audio_convert_ns_get_type ()) -static GType -gst_audio_convert_ns_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {GST_AUDIO_NOISE_SHAPING_NONE, "No noise shaping (default)", - "none"}, - {GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK, "Error feedback", - "error-feedback"}, - {GST_AUDIO_NOISE_SHAPING_SIMPLE, "Simple 2-pole noise shaping", "simple"}, - {GST_AUDIO_NOISE_SHAPING_MEDIUM, "Medium 5-pole noise shaping", "medium"}, - {GST_AUDIO_NOISE_SHAPING_HIGH, "High 8-pole noise shaping", "high"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioConvertNoiseShaping", values); - } - return gtype; -} - /*** TYPE FUNCTIONS ***********************************************************/ static void @@ -195,13 +149,13 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass) g_object_class_install_property (gobject_class, PROP_DITHERING, g_param_spec_enum ("dithering", "Dithering", "Selects between different dithering methods.", - GST_TYPE_AUDIO_CONVERT_DITHERING, GST_AUDIO_DITHER_TPDF, + GST_TYPE_AUDIO_DITHER_METHOD, GST_AUDIO_DITHER_TPDF, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_NOISE_SHAPING, g_param_spec_enum ("noise-shaping", "Noise shaping", "Selects between different noise shaping methods.", - GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, GST_AUDIO_NOISE_SHAPING_NONE, + GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, GST_AUDIO_NOISE_SHAPING_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_element_class_add_pad_template (element_class, @@ -235,7 +189,6 @@ gst_audio_convert_init (GstAudioConvert * this) { this->dither = GST_AUDIO_DITHER_TPDF; this->ns = GST_AUDIO_NOISE_SHAPING_NONE; - memset (&this->ctx, 0, sizeof (AudioConvertCtx)); gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (this), TRUE); } @@ -245,7 +198,7 @@ gst_audio_convert_dispose (GObject * obj) { GstAudioConvert *this = GST_AUDIO_CONVERT (obj); - audio_convert_clean_context (&this->ctx); + gst_audio_converter_free (this->convert); G_OBJECT_CLASS (parent_class)->dispose (obj); } @@ -694,15 +647,29 @@ gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps, GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %" GST_PTR_FORMAT, incaps, outcaps); + if (this->convert) { + gst_audio_converter_free (this->convert); + this->convert = NULL; + } + if (!gst_audio_info_from_caps (&in_info, incaps)) goto invalid_in; if (!gst_audio_info_from_caps (&out_info, outcaps)) goto invalid_out; - if (!audio_convert_prepare_context (&this->ctx, &in_info, &out_info, - this->dither, this->ns)) + this->convert = gst_audio_converter_new (&in_info, &out_info, + gst_structure_new ("GstAudioConverterConfig", + GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, + this->dither, + GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, + GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, this->ns, NULL)); + + if (this->convert == NULL) goto no_converter; + this->in_info = in_info; + this->out_info = out_info; + return TRUE; /* ERRORS */ @@ -718,7 +685,7 @@ invalid_out: } no_converter: { - GST_ERROR_OBJECT (base, "could not find converter"); + GST_ERROR_OBJECT (base, "could not make converter"); return FALSE; } } @@ -732,15 +699,17 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf, GstMapInfo srcmap, dstmap; gint insize, outsize; gboolean inbuf_writable; + GstAudioConverterFlags flags; gint samples; /* get amount of samples to convert. */ - samples = gst_buffer_get_size (inbuf) / this->ctx.in.bpf; + samples = gst_buffer_get_size (inbuf) / this->in_info.bpf; /* get in/output sizes, to see if the buffers we got are of correct * sizes */ - if (!audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize)) + if (!gst_audio_converter_get_sizes (this->convert, samples, &insize, + &outsize)) goto error; if (insize == 0 || outsize == 0) @@ -762,13 +731,17 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf, goto wrong_size; /* and convert the samples */ + flags = 0; + if (inbuf_writable) + flags |= GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE; + if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) { - if (!audio_convert_convert (&this->ctx, srcmap.data, dstmap.data, - samples, inbuf_writable)) + if (!gst_audio_converter_samples (this->convert, flags, srcmap.data, + dstmap.data, samples)) goto convert_error; } else { /* Create silence buffer */ - gst_audio_format_fill_silence (this->ctx.out.finfo, dstmap.data, outsize); + gst_audio_format_fill_silence (this->out_info.finfo, dstmap.data, outsize); } ret = GST_FLOW_OK; @@ -829,8 +802,8 @@ gst_audio_convert_submit_input_buffer (GstBaseTransform * base, if (base->segment.format == GST_FORMAT_TIME) { input = - gst_audio_buffer_clip (input, &base->segment, this->ctx.in.rate, - this->ctx.in.bpf); + gst_audio_buffer_clip (input, &base->segment, this->in_info.rate, + this->in_info.bpf); if (!input) return GST_FLOW_OK; diff --git a/gst/audioconvert/gstaudioconvert.h b/gst/audioconvert/gstaudioconvert.h index f52845fbf9..86cec91d6c 100644 --- a/gst/audioconvert/gstaudioconvert.h +++ b/gst/audioconvert/gstaudioconvert.h @@ -46,10 +46,13 @@ struct _GstAudioConvert { GstBaseTransform element; - AudioConvertCtx ctx; - + /* properties */ GstAudioDitherMethod dither; GstAudioNoiseShapingMethod ns; + + GstAudioInfo in_info; + GstAudioInfo out_info; + GstAudioConverter *convert; }; struct _GstAudioConvertClass diff --git a/gst/audioconvert/gstfastrandom.h b/gst/audioconvert/gstfastrandom.h deleted file mode 100644 index deaa1291fd..0000000000 --- a/gst/audioconvert/gstfastrandom.h +++ /dev/null @@ -1,70 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 Sebastian Dröge - * - * gstfastrandom.h: Fast, bad PNRG - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include - -#ifndef __GST_FAST_RANDOM__ -#define __GST_FAST_RANDOM__ - -/* transform [0..2^32] -> [0..1] */ -#define GST_RAND_DOUBLE_TRANSFORM 2.3283064365386962890625e-10 - -/* This is the base function, implementing a linear congruential generator - * and returning a pseudo random number between 0 and 2^32 - 1. - */ -static inline guint32 -gst_fast_random_uint32 (void) -{ - static guint32 state = 0xdeadbeef; - - return (state = state * 1103515245 + 12345); -} - -static inline gint32 -gst_fast_random_int32 (void) -{ - return (gint32) gst_fast_random_uint32 (); -} - -static inline gdouble -gst_fast_random_double (void) -{ - gdouble ret; - - ret = gst_fast_random_uint32 () * GST_RAND_DOUBLE_TRANSFORM; - ret = (ret + gst_fast_random_uint32 ()) * GST_RAND_DOUBLE_TRANSFORM; - - if (ret >= 1.0) - return gst_fast_random_double (); - - return ret; -} - -static inline gdouble -gst_fast_random_double_range (gdouble start, gdouble end) -{ - return gst_fast_random_double () * (end - start) + start; -} - -#undef GST_RAND_DOUBLE_TRANSFORM - -#endif /* __GST_FAST_RANDOM__ */ -