diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index cf215169ae..247c2e4794 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -56,25 +56,10 @@ * - (channel mix F64) * - pack from F64 */ -#define DOUBLE_INTERMEDIATE_FORMAT(ctx) \ - (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo) || \ - !GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo) || \ - (ctx->ns != NOISE_SHAPING_NONE)) - -static inline gboolean -check_default (AudioConvertCtx * ctx, const GstAudioFormatInfo * fmt) -{ - if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) { - return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_S32; - } else { - return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_F64; - } -} - gboolean audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, - GstAudioInfo * out, GstAudioConvertDithering dither, - GstAudioConvertNoiseShaping ns) + GstAudioInfo * out, GstAudioDitherMethod dither, + GstAudioNoiseShapingMethod ns) { gint in_depth, out_depth; GstChannelMixFlags flags; @@ -104,19 +89,19 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, * source depth. */ if (out_depth <= 20 && (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo) || in_depth >= out_depth)) { - ctx->dither = dither; - ctx->ns = ns; + dither = dither; + ns = ns; GST_INFO ("using dither %d and noise shaping %d", dither, ns); } else { - ctx->dither = DITHER_NONE; - ctx->ns = NOISE_SHAPING_NONE; + dither = GST_AUDIO_DITHER_NONE; + ns = GST_AUDIO_NOISE_SHAPING_NONE; GST_INFO ("using no dither and noise shaping"); } /* Use simple error feedback when output sample rate is smaller than * 32000 as the other methods might move the noise to audible ranges */ - if (ctx->ns > NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000) - ctx->ns = NOISE_SHAPING_ERROR_FEEDBACK; + if (ns > GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000) + ns = GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK; flags = GST_AUDIO_INFO_IS_UNPOSITIONED (in) ? @@ -128,11 +113,17 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, ctx->mix = gst_channel_mix_new (flags, in->channels, in->position, out->channels, out->position); + if (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo) || + !GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo) || + (ns != GST_AUDIO_NOISE_SHAPING_NONE)) + ctx->mix_format = GST_AUDIO_FORMAT_F64; + else + ctx->mix_format = GST_AUDIO_FORMAT_S32; + /* if one formats is float/double or we use noise shaping use double as * intermediate format and switch mixing */ - if (DOUBLE_INTERMEDIATE_FORMAT (ctx)) { + if (ctx->mix_format == GST_AUDIO_FORMAT_F64) { GST_INFO ("use float mixing"); - ctx->mix_format = GST_AUDIO_FORMAT_F64; if (ctx->in.finfo->unpack_format != GST_AUDIO_FORMAT_F64) { ctx->convert = audio_convert_orc_s32_to_double; GST_INFO ("convert input to F64"); @@ -151,7 +142,6 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, } } else { GST_INFO ("use int mixing"); - ctx->mix_format = GST_AUDIO_FORMAT_S32; /* check if input needs to be unpacked to intermediate format */ ctx->in_default = GST_AUDIO_FORMAT_INFO_FORMAT (in->finfo) == GST_AUDIO_FORMAT_S32; @@ -164,7 +154,8 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, /* check if channel mixer is passthrough */ ctx->mix_passthrough = gst_channel_mix_is_passthrough (ctx->mix); - ctx->quant_default = check_default (ctx, out->finfo); + ctx->quant_default = + GST_AUDIO_FORMAT_INFO_FORMAT (out->finfo) == ctx->mix_format; GST_INFO ("in default %d, mix passthrough %d, out default %d", ctx->in_default, ctx->mix_passthrough, ctx->out_default); @@ -174,7 +165,8 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, GST_INFO ("scale out %d", ctx->out_scale); - gst_audio_quantize_setup (ctx); + ctx->quant = gst_audio_quantize_new (dither, ns, 0, ctx->mix_format, + out->channels, ctx->out_scale); return TRUE; @@ -191,7 +183,8 @@ audio_convert_clean_context (AudioConvertCtx * ctx) { g_return_val_if_fail (ctx != NULL, FALSE); - gst_audio_quantize_free (ctx); + if (ctx->quant) + gst_audio_quantize_free (ctx->quant); if (ctx->mix) gst_channel_mix_free (ctx->mix); ctx->mix = NULL; @@ -244,7 +237,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, out_width = GST_AUDIO_FORMAT_INFO_WIDTH (ctx->out.finfo); /* find biggest temp buffer size */ - size = (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? sizeof (gdouble) + size = (ctx->mix_format == GST_AUDIO_FORMAT_F64) ? sizeof (gdouble) : sizeof (gint32); if (!ctx->in_default) @@ -314,7 +307,9 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, else outbuf = tmpbuf; - ctx->quantize (ctx, src, outbuf, samples); + gst_audio_quantize_samples (ctx->quant, src, samples); + + outbuf = src; } if (!ctx->out_default) { diff --git a/gst/audioconvert/audioconvert.h b/gst/audioconvert/audioconvert.h index 5a0f5403c3..6b5e712baf 100644 --- a/gst/audioconvert/audioconvert.h +++ b/gst/audioconvert/audioconvert.h @@ -26,71 +26,13 @@ #include #include "gstchannelmix.h" +#include "gstaudioquantize.h" GST_DEBUG_CATEGORY_EXTERN (audio_convert_debug); #define GST_CAT_DEFAULT (audio_convert_debug) -/** - * GstAudioConvertDithering: - * @DITHER_NONE: No dithering - * @DITHER_RPDF: Rectangular dithering - * @DITHER_TPDF: Triangular dithering (default) - * @DITHER_TPDF_HF: High frequency triangular dithering - * - * Set of available dithering methods when converting audio. - */ -typedef enum -{ - DITHER_NONE = 0, - DITHER_RPDF, - DITHER_TPDF, - DITHER_TPDF_HF -} GstAudioConvertDithering; - -/** - * GstAudioConvertNoiseShaping: - * @NOISE_SHAPING_NONE: No noise shaping (default) - * @NOISE_SHAPING_ERROR_FEEDBACK: Error feedback - * @NOISE_SHAPING_SIMPLE: Simple 2-pole noise shaping - * @NOISE_SHAPING_MEDIUM: Medium 5-pole noise shaping - * @NOISE_SHAPING_HIGH: High 8-pole noise shaping - * - * Set of available noise shaping methods - */ -typedef enum -{ - NOISE_SHAPING_NONE = 0, - NOISE_SHAPING_ERROR_FEEDBACK, - NOISE_SHAPING_SIMPLE, - NOISE_SHAPING_MEDIUM, - NOISE_SHAPING_HIGH -} GstAudioConvertNoiseShaping; - typedef struct _AudioConvertCtx AudioConvertCtx; -#if 0 -typedef struct _AudioConvertFmt AudioConvertFmt; -struct _AudioConvertFmt -{ - /* general caps */ - gboolean is_int; - gint endianness; - gint width; - gint rate; - gint channels; - GstAudioChannelPosition *pos; - gboolean unpositioned_layout; - - /* int audio caps */ - gboolean sign; - gint depth; - - gint unit_size; -}; -#endif - -typedef void (*AudioConvertQuantize) (AudioConvertCtx * ctx, gpointer src, - gpointer dst, gint count); typedef void (*AudioConvertToF64) (gdouble *dst, const gint32 *src, gint count); struct _AudioConvertCtx @@ -98,7 +40,9 @@ struct _AudioConvertCtx GstAudioInfo in; GstAudioInfo out; + GstAudioFormat mix_format; GstChannelMix *mix; + GstAudioQuantize *quant; gboolean in_default; gboolean mix_passthrough; @@ -109,22 +53,13 @@ struct _AudioConvertCtx gint tmpbufsize; gint out_scale; - GstAudioFormat mix_format; AudioConvertToF64 convert; - AudioConvertQuantize quantize; - - GstAudioConvertDithering dither; - GstAudioConvertNoiseShaping ns; - /* last random number generated per channel for hifreq TPDF dither */ - gpointer last_random; - /* contains the past quantization errors, error[out_channels][count] */ - gdouble *error_buf; }; gboolean audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, GstAudioInfo * out, - GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns); + GstAudioDitherMethod dither, GstAudioNoiseShapingMethod ns); gboolean audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize, gint * dstsize); diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c index 634fd46e13..59c427e580 100644 --- a/gst/audioconvert/gstaudioconvert.c +++ b/gst/audioconvert/gstaudioconvert.c @@ -140,11 +140,12 @@ gst_audio_convert_dithering_get_type (void) if (gtype == 0) { static const GEnumValue values[] = { - {DITHER_NONE, "No dithering", + {GST_AUDIO_DITHER_NONE, "No dithering", "none"}, - {DITHER_RPDF, "Rectangular dithering", "rpdf"}, - {DITHER_TPDF, "Triangular dithering (default)", "tpdf"}, - {DITHER_TPDF_HF, "High frequency triangular dithering", "tpdf-hf"}, + {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} }; @@ -161,12 +162,13 @@ gst_audio_convert_ns_get_type (void) if (gtype == 0) { static const GEnumValue values[] = { - {NOISE_SHAPING_NONE, "No noise shaping (default)", + {GST_AUDIO_NOISE_SHAPING_NONE, "No noise shaping (default)", "none"}, - {NOISE_SHAPING_ERROR_FEEDBACK, "Error feedback", "error-feedback"}, - {NOISE_SHAPING_SIMPLE, "Simple 2-pole noise shaping", "simple"}, - {NOISE_SHAPING_MEDIUM, "Medium 5-pole noise shaping", "medium"}, - {NOISE_SHAPING_HIGH, "High 8-pole noise shaping", "high"}, + {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} }; @@ -191,13 +193,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, DITHER_TPDF, + GST_TYPE_AUDIO_CONVERT_DITHERING, 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, NOISE_SHAPING_NONE, + GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, GST_AUDIO_NOISE_SHAPING_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_element_class_add_pad_template (element_class, @@ -227,8 +229,8 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass) static void gst_audio_convert_init (GstAudioConvert * this) { - this->dither = DITHER_TPDF; - this->ns = NOISE_SHAPING_NONE; + 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); diff --git a/gst/audioconvert/gstaudioconvert.h b/gst/audioconvert/gstaudioconvert.h index 6ff4374325..f52845fbf9 100644 --- a/gst/audioconvert/gstaudioconvert.h +++ b/gst/audioconvert/gstaudioconvert.h @@ -48,8 +48,8 @@ struct _GstAudioConvert AudioConvertCtx ctx; - GstAudioConvertDithering dither; - GstAudioConvertNoiseShaping ns; + GstAudioDitherMethod dither; + GstAudioNoiseShapingMethod ns; }; struct _GstAudioConvertClass diff --git a/gst/audioconvert/gstaudioquantize.c b/gst/audioconvert/gstaudioquantize.c index 1759250028..8f7d1ec07f 100644 --- a/gst/audioconvert/gstaudioquantize.c +++ b/gst/audioconvert/gstaudioquantize.c @@ -34,12 +34,31 @@ #include #include #include -#include "audioconvert.h" #include "gstaudioconvertorc.h" #include "gstaudioquantize.h" #include "gstfastrandom.h" +typedef void (*QuantizeFunc) (GstAudioQuantize * quant, gpointer src, + gpointer dst, gint count); + +struct _GstAudioQuantize +{ + GstAudioDitherMethod dither; + GstAudioNoiseShapingMethod ns; + GstAudioQuantizeFlags flags; + GstAudioFormat format; + guint channels; + guint quantizer; + + /* last random number generated per channel for hifreq TPDF dither */ + gpointer last_random; + /* contains the past quantization errors, error[out_channels][count] */ + gdouble *error_buf; + + QuantizeFunc quantize; +}; + #define MAKE_QUANTIZE_FUNC_NAME(name) \ gst_audio_quantize_quantize_##name @@ -48,11 +67,11 @@ gst_audio_quantize_quantize_##name #define MAKE_QUANTIZE_FUNC_I(name, DITHER_INIT_FUNC, ADD_DITHER_FUNC, \ ROUND_FUNC) \ static void \ -MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \ +MAKE_QUANTIZE_FUNC_NAME (name) (GstAudioQuantize *quant, gint32 *src, \ gint32 *dst, gint count) \ { \ - gint scale = ctx->out_scale; \ - gint channels = ctx->out.channels; \ + gint scale = quant->quantizer; \ + gint channels = quant->channels; \ gint chan_pos; \ \ if (scale > 0) { \ @@ -83,11 +102,11 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \ ADD_NS_FUNC, ADD_DITHER_FUNC, \ UPDATE_ERROR_FUNC) \ static void \ -MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ +MAKE_QUANTIZE_FUNC_NAME (name) (GstAudioQuantize *quant, gdouble *src, \ gint32 *dst, gint count) \ { \ - gint scale = ctx->out_scale; \ - gint channels = ctx->out.channels; \ + gint scale = quant->quantizer; \ + gint channels = quant->channels; \ gint chan_pos; \ gdouble tmp, d, factor = (1U<<(32-scale-1)); \ \ @@ -180,7 +199,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ #define INIT_DITHER_TPDF_HF_I() \ gint32 rand; \ gint32 dither = (1<<(scale-1)); \ - gint32 *last_random = (gint32 *) ctx->last_random, tmp_rand; + gint32 *last_random = (gint32 *) quant->last_random, tmp_rand; #define ADD_DITHER_TPDF_HF_I() \ tmp_rand = RANDOM_INT_DITHER(dither); \ @@ -199,7 +218,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ #define INIT_DITHER_TPDF_HF_F() \ gdouble rand; \ gdouble dither = 1.0/(1U<<(32 - scale)); \ - gdouble *last_random = (gdouble *) ctx->last_random, tmp_rand; + gdouble *last_random = (gdouble *) quant->last_random, tmp_rand; #define ADD_DITHER_TPDF_HF_F() \ tmp_rand = gst_fast_random_double_range (- dither, dither); \ @@ -216,7 +235,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ #define INIT_NS_ERROR_FEEDBACK() \ gdouble orig; \ - gdouble *errors = ctx->error_buf; + gdouble *errors = quant->error_buf; #define ADD_NS_ERROR_FEEDBACK() \ orig = tmp; \ @@ -230,7 +249,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ #define INIT_NS_SIMPLE() \ gdouble orig; \ - gdouble *errors = ctx->error_buf, cur_error; + gdouble *errors = quant->error_buf, cur_error; #define ADD_NS_SIMPLE() \ cur_error = errors[chan_pos*2] - 0.5 * errors[chan_pos*2 + 1]; \ @@ -256,7 +275,7 @@ static const gdouble ns_medium_coeffs[] = { #define INIT_NS_MEDIUM() \ gdouble orig; \ - gdouble *errors = ctx->error_buf, cur_error; \ + gdouble *errors = quant->error_buf, cur_error; \ int j; #define ADD_NS_MEDIUM() \ @@ -280,7 +299,7 @@ static const gdouble ns_high_coeffs[] = { #define INIT_NS_HIGH() \ gdouble orig; \ - gdouble *errors = ctx->error_buf, cur_error; \ + gdouble *errors = quant->error_buf, cur_error; \ int j; #define ADD_NS_HIGH() \ @@ -352,142 +371,149 @@ MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_medium, INIT_DITHER_TPDF_HF_F, MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_high, INIT_DITHER_TPDF_HF_F, INIT_NS_HIGH, ADD_NS_HIGH, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_HIGH); -static const AudioConvertQuantize quantize_funcs[] = { - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_none_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_rpdf_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_hf_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_error_feedback), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_simple), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_medium), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_high), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_error_feedback), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_simple), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_medium), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_high), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_error_feedback), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_simple), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_medium), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_high), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_none), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_error_feedback), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_simple), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_medium), - (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_high) +static const QuantizeFunc quantize_funcs[] = { + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_none_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_rpdf_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_hf_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_error_feedback), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_simple), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_medium), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_high), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_error_feedback), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_simple), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_medium), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_high), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_error_feedback), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_simple), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_medium), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_high), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_none), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_error_feedback), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_simple), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_medium), + (QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_high) }; static void -gst_audio_quantize_setup_noise_shaping (AudioConvertCtx * ctx) +gst_audio_quantize_setup_noise_shaping (GstAudioQuantize * quant) { - switch (ctx->ns) { - case NOISE_SHAPING_HIGH:{ - ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 8); + switch (quant->ns) { + case GST_AUDIO_NOISE_SHAPING_HIGH:{ + quant->error_buf = g_new0 (gdouble, quant->channels * 8); break; } - case NOISE_SHAPING_MEDIUM:{ - ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 5); + case GST_AUDIO_NOISE_SHAPING_MEDIUM:{ + quant->error_buf = g_new0 (gdouble, quant->channels * 5); break; } - case NOISE_SHAPING_SIMPLE:{ - ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 2); + case GST_AUDIO_NOISE_SHAPING_SIMPLE:{ + quant->error_buf = g_new0 (gdouble, quant->channels * 2); break; } - case NOISE_SHAPING_ERROR_FEEDBACK: - ctx->error_buf = g_new0 (gdouble, ctx->out.channels); + case GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK: + quant->error_buf = g_new0 (gdouble, quant->channels); break; - case NOISE_SHAPING_NONE: + case GST_AUDIO_NOISE_SHAPING_NONE: default: - ctx->error_buf = NULL; + quant->error_buf = NULL; break; } return; } static void -gst_audio_quantize_free_noise_shaping (AudioConvertCtx * ctx) +gst_audio_quantize_setup_dither (GstAudioQuantize * quant) { - switch (ctx->ns) { - case NOISE_SHAPING_HIGH: - case NOISE_SHAPING_MEDIUM: - case NOISE_SHAPING_SIMPLE: - case NOISE_SHAPING_ERROR_FEEDBACK: - case NOISE_SHAPING_NONE: + switch (quant->dither) { + case GST_AUDIO_DITHER_TPDF_HF: + quant->last_random = g_new0 (gdouble, quant->channels); + break; + case GST_AUDIO_DITHER_RPDF: + case GST_AUDIO_DITHER_TPDF: + quant->last_random = NULL; + break; + case GST_AUDIO_DITHER_NONE: default: - break; - } - - g_free (ctx->error_buf); - ctx->error_buf = NULL; - return; -} - -static void -gst_audio_quantize_setup_dither (AudioConvertCtx * ctx) -{ - switch (ctx->dither) { - case DITHER_TPDF_HF: - if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo)) - ctx->last_random = g_new0 (gint32, ctx->out.channels); - else - ctx->last_random = g_new0 (gdouble, ctx->out.channels); - break; - case DITHER_RPDF: - case DITHER_TPDF: - ctx->last_random = NULL; - break; - case DITHER_NONE: - default: - ctx->last_random = NULL; + quant->last_random = NULL; break; } return; } static void -gst_audio_quantize_free_dither (AudioConvertCtx * ctx) -{ - g_free (ctx->last_random); - - return; -} - -static void -gst_audio_quantize_setup_quantize_func (AudioConvertCtx * ctx) +gst_audio_quantize_setup_quantize_func (GstAudioQuantize * quant) { gint index = 0; - if (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo)) { - ctx->quantize = NULL; - return; - } - - if (ctx->ns == NOISE_SHAPING_NONE - && GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo)) { - index += ctx->dither; + if (quant->ns == GST_AUDIO_NOISE_SHAPING_NONE + && quant->format == GST_AUDIO_FORMAT_S32) { + index += quant->dither; } else { - index += 4 + (5 * ctx->dither); - index += ctx->ns; - } + g_assert (quant->format == GST_AUDIO_FORMAT_F64); - ctx->quantize = quantize_funcs[index]; + index += 4 + (5 * quant->dither); + index += quant->ns; + } + quant->quantize = quantize_funcs[index]; } -gboolean -gst_audio_quantize_setup (AudioConvertCtx * ctx) +/** + * gst_audio_quantize_new: + * @dither: a #GstAudioDitherMethod + * @ns: a #GstAudioNoiseShapingMethod + * @flags: #GstAudioQuantizeFlags + * @format: the #GstAudioFormat of the samples + * @channels: the amount of channels in the samples + * @quantizer: the quantizer to use + * + * Create a new quantizer object with the given parameters. + * + * Returns: a new #GstAudioQuantize. Free with gst_audio_quantize_free(). + */ +GstAudioQuantize * +gst_audio_quantize_new (GstAudioDitherMethod dither, + GstAudioNoiseShapingMethod ns, GstAudioQuantizeFlags flags, + GstAudioFormat format, guint channels, guint quantizer) { - gst_audio_quantize_setup_dither (ctx); - gst_audio_quantize_setup_noise_shaping (ctx); - gst_audio_quantize_setup_quantize_func (ctx); + GstAudioQuantize *quant; - return TRUE; + quant = g_slice_new0 (GstAudioQuantize); + quant->dither = dither; + quant->ns = ns; + quant->flags = flags; + quant->format = format; + quant->channels = channels; + quant->quantizer = quantizer; + + gst_audio_quantize_setup_dither (quant); + gst_audio_quantize_setup_noise_shaping (quant); + gst_audio_quantize_setup_quantize_func (quant); + + return quant; +} + +/** + * gst_audio_quantize_free: + * @quant: a #GstAudioQuantize + * + * Free a #GstAudioQuantize. + */ +void +gst_audio_quantize_free (GstAudioQuantize * quant) +{ + g_free (quant->error_buf); + g_free (quant->last_random); + + g_slice_free (GstAudioQuantize, quant); } void -gst_audio_quantize_free (AudioConvertCtx * ctx) +gst_audio_quantize_samples (GstAudioQuantize * quant, + gpointer data, guint samples) { - gst_audio_quantize_free_dither (ctx); - gst_audio_quantize_free_noise_shaping (ctx); + quant->quantize (quant, data, data, samples); } diff --git a/gst/audioconvert/gstaudioquantize.h b/gst/audioconvert/gstaudioquantize.h index e5d07081cb..bb5ccf477f 100644 --- a/gst/audioconvert/gstaudioquantize.h +++ b/gst/audioconvert/gstaudioquantize.h @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) 2007 Sebastian Dröge + * (C) 2015 Wim Taymans * * gstaudioquantize.h: quantizes audio to the target format and optionally * applies dithering and noise shaping. @@ -21,14 +22,68 @@ */ #include -#include "audioconvert.h" + +#include + #ifndef __GST_AUDIO_QUANTIZE_H__ #define __GST_AUDIO_QUANTIZE_H__ -gboolean gst_audio_quantize_setup (AudioConvertCtx * ctx); -void gst_audio_quantize_reset (AudioConvertCtx * ctx); -void gst_audio_quantize_free (AudioConvertCtx * ctx); +/** + * GstAudioDitherMethod: + * @GST_AUDIO_DITHER_NONE: No dithering + * @GST_AUDIO_DITHER_RPDF: Rectangular dithering + * @GST_AUDIO_DITHER_TPDF: Triangular dithering (default) + * @GST_AUDIO_DITHER_TPDF_HF: High frequency triangular dithering + * + * Set of available dithering methods. + */ +typedef enum +{ + GST_AUDIO_DITHER_NONE = 0, + GST_AUDIO_DITHER_RPDF, + GST_AUDIO_DITHER_TPDF, + GST_AUDIO_DITHER_TPDF_HF +} GstAudioDitherMethod; +/** + * GstAudioNoiseShapingMethod: + * @GST_AUDIO_NOISE_SHAPING_NONE: No noise shaping (default) + * @GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK: Error feedback + * @GST_AUDIO_NOISE_SHAPING_SIMPLE: Simple 2-pole noise shaping + * @GST_AUDIO_NOISE_SHAPING_MEDIUM: Medium 5-pole noise shaping + * @GST_AUDIO_NOISE_SHAPING_HIGH: High 8-pole noise shaping + * + * Set of available noise shaping methods + */ +typedef enum +{ + GST_AUDIO_NOISE_SHAPING_NONE = 0, + GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK, + GST_AUDIO_NOISE_SHAPING_SIMPLE, + GST_AUDIO_NOISE_SHAPING_MEDIUM, + GST_AUDIO_NOISE_SHAPING_HIGH +} GstAudioNoiseShapingMethod; + + +typedef enum +{ + GST_AUDIO_QUANTIZE_FLAG_NONE = 0 +} GstAudioQuantizeFlags; + + +typedef struct _GstAudioQuantize GstAudioQuantize; + +GstAudioQuantize * gst_audio_quantize_new (GstAudioDitherMethod dither, + GstAudioNoiseShapingMethod ns, + GstAudioQuantizeFlags flags, + GstAudioFormat format, + guint channels, + guint quantizer); + +void gst_audio_quantize_free (GstAudioQuantize * quant); + +void gst_audio_quantize_samples (GstAudioQuantize * quant, + gpointer data, guint samples); #endif /* __GST_AUDIO_QUANTIZE_H__ */