diff options
Diffstat (limited to 'gst/speexresample/gstspeexresample.c')
-rw-r--r-- | gst/speexresample/gstspeexresample.c | 1023 |
1 files changed, 305 insertions, 718 deletions
diff --git a/gst/speexresample/gstspeexresample.c b/gst/speexresample/gstspeexresample.c index 4c6dbffe..096c6b93 100644 --- a/gst/speexresample/gstspeexresample.c +++ b/gst/speexresample/gstspeexresample.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org> - * Copyright (C) 2007-2008 Sebastian Dröge <sebastian.droege@collabora.co.uk> + * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -34,10 +34,6 @@ * </refsect2> */ -/* TODO: - * - Enable SSE/ARM optimizations and select at runtime - */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -49,18 +45,13 @@ #include <gst/audio/audio.h> #include <gst/base/gstbasetransform.h> -#define OIL_ENABLE_UNSTABLE_API -#include <liboil/liboilprofile.h> -#include <liboil/liboil.h> - GST_DEBUG_CATEGORY (speex_resample_debug); #define GST_CAT_DEFAULT speex_resample_debug enum { PROP_0, - PROP_QUALITY, - PROP_FILTER_LENGTH + PROP_QUALITY }; #define SUPPORTED_CAPS \ @@ -69,40 +60,16 @@ GST_STATIC_CAPS ( \ "rate = (int) [ 1, MAX ], " \ "channels = (int) [ 1, MAX ], " \ "endianness = (int) BYTE_ORDER, " \ - "width = (int) { 32, 64 }; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 32, " \ - "depth = (int) 32, " \ - "signed = (boolean) true; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 24, " \ - "depth = (int) 24, " \ - "signed = (boolean) true; " \ + "width = (int) 32; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ "channels = (int) [ 1, MAX ], " \ "endianness = (int) BYTE_ORDER, " \ "width = (int) 16, " \ "depth = (int) 16, " \ - "signed = (boolean) true; " \ - "audio/x-raw-int, " \ - "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, MAX ], " \ - "endianness = (int) BYTE_ORDER, " \ - "width = (int) 8, " \ - "depth = (int) 8, " \ "signed = (boolean) true" \ ) -/* If TRUE integer arithmetic resampling is faster and will be used if appropiate */ -static gboolean gst_speex_resample_use_int = FALSE; - static GstStaticPadTemplate gst_speex_resample_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS); @@ -121,8 +88,6 @@ static gboolean gst_speex_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps, guint * size); static GstCaps *gst_speex_resample_transform_caps (GstBaseTransform * base, GstPadDirection direction, GstCaps * caps); -static void gst_speex_resample_fixate_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); static gboolean gst_speex_resample_transform_size (GstBaseTransform * trans, GstPadDirection direction, GstCaps * incaps, guint insize, GstCaps * outcaps, guint * outsize); @@ -137,8 +102,11 @@ static gboolean gst_speex_resample_stop (GstBaseTransform * base); static gboolean gst_speex_resample_query (GstPad * pad, GstQuery * query); static const GstQueryType *gst_speex_resample_query_type (GstPad * pad); -GST_BOILERPLATE (GstSpeexResample, gst_speex_resample, GstBaseTransform, - GST_TYPE_BASE_TRANSFORM); +#define DEBUG_INIT(bla) \ + GST_DEBUG_CATEGORY_INIT (speex_resample_debug, "speex_resample", 0, "audio resampling element"); + +GST_BOILERPLATE_FULL (GstSpeexResample, gst_speex_resample, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM, DEBUG_INIT); static void gst_speex_resample_base_init (gpointer g_class) @@ -152,7 +120,7 @@ gst_speex_resample_base_init (gpointer g_class) gst_element_class_set_details_simple (gstelement_class, "Audio resampler", "Filter/Converter/Audio", "Resamples audio", - "Sebastian Dröge <sebastian.droege@collabora.co.uk>"); + "Sebastian Dröge <slomo@circular-chaos.org>"); } static void @@ -170,14 +138,6 @@ gst_speex_resample_class_init (GstSpeexResampleClass * klass) SPEEX_RESAMPLER_QUALITY_DEFAULT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - /* FIXME 0.11: Remove this property, it's just for compatibility - * with old audioresample - */ - g_object_class_install_property (gobject_class, PROP_FILTER_LENGTH, - g_param_spec_int ("filter-length", "Filter length", - "DEPRECATED, DON'T USE THIS! " "Length of the resample filter", 0, - G_MAXINT, 64, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - GST_BASE_TRANSFORM_CLASS (klass)->start = GST_DEBUG_FUNCPTR (gst_speex_resample_start); GST_BASE_TRANSFORM_CLASS (klass)->stop = @@ -188,8 +148,6 @@ gst_speex_resample_class_init (GstSpeexResampleClass * klass) GST_DEBUG_FUNCPTR (gst_speex_resample_get_unit_size); GST_BASE_TRANSFORM_CLASS (klass)->transform_caps = GST_DEBUG_FUNCPTR (gst_speex_resample_transform_caps); - GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps = - GST_DEBUG_FUNCPTR (gst_speex_resample_fixate_caps); GST_BASE_TRANSFORM_CLASS (klass)->set_caps = GST_DEBUG_FUNCPTR (gst_speex_resample_set_caps); GST_BASE_TRANSFORM_CLASS (klass)->transform = @@ -221,9 +179,9 @@ gst_speex_resample_start (GstBaseTransform * base) { GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base); - resample->next_offset = -1; + resample->ts_offset = -1; + resample->offset = -1; resample->next_ts = -1; - resample->next_upstream_ts = -1; return TRUE; } @@ -234,20 +192,10 @@ gst_speex_resample_stop (GstBaseTransform * base) GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base); if (resample->state) { - resample->funcs->destroy (resample->state); + resample_resampler_destroy (resample->state); resample->state = NULL; } - resample->funcs = NULL; - - g_free (resample->tmp_in); - resample->tmp_in = NULL; - resample->tmp_in_size = 0; - - g_free (resample->tmp_out); - resample->tmp_out = NULL; - resample->tmp_out_size = 0; - gst_caps_replace (&resample->sinkcaps, NULL); gst_caps_replace (&resample->srccaps, NULL); @@ -268,11 +216,9 @@ gst_speex_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps, structure = gst_caps_get_structure (caps, 0); ret = gst_structure_get_int (structure, "width", &width); ret &= gst_structure_get_int (structure, "channels", &channels); + g_return_val_if_fail (ret, FALSE); - if (G_UNLIKELY (!ret)) - return FALSE; - - *size = (width / 8) * channels; + *size = width * channels / 8; return TRUE; } @@ -293,64 +239,38 @@ gst_speex_resample_transform_caps (GstBaseTransform * base, return res; } -/* Fixate rate to the allowed rate that has the smallest difference */ -static void -gst_speex_resample_fixate_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) -{ - GstStructure *s; - gint rate; - - s = gst_caps_get_structure (caps, 0); - if (G_UNLIKELY (!gst_structure_get_int (s, "rate", &rate))) - return; - - s = gst_caps_get_structure (othercaps, 0); - gst_structure_fixate_field_nearest_int (s, "rate", rate); -} - -static const SpeexResampleFuncs * -gst_speex_resample_get_funcs (gint width, gboolean fp) -{ - const SpeexResampleFuncs *funcs = NULL; - - if (gst_speex_resample_use_int && (width == 8 || width == 16) && !fp) - funcs = &int_funcs; - else if ((!gst_speex_resample_use_int && (width == 8 || width == 16) && !fp) - || (width == 32 && fp)) - funcs = &float_funcs; - else if ((width == 64 && fp) || ((width == 32 || width == 24) && !fp)) - funcs = &double_funcs; - else - g_assert_not_reached (); - - return funcs; -} - static SpeexResamplerState * -gst_speex_resample_init_state (GstSpeexResample * resample, gint width, - gint channels, gint inrate, gint outrate, gint quality, gboolean fp) +gst_speex_resample_init_state (guint channels, guint inrate, guint outrate, + guint quality, gboolean fp) { SpeexResamplerState *ret = NULL; gint err = RESAMPLER_ERR_SUCCESS; - const SpeexResampleFuncs *funcs = gst_speex_resample_get_funcs (width, fp); - ret = funcs->init (channels, inrate, outrate, quality, &err); + if (fp) + ret = + resample_float_resampler_init (channels, inrate, outrate, quality, + &err); + else + ret = + resample_int_resampler_init (channels, inrate, outrate, quality, &err); - if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) { - GST_ERROR_OBJECT (resample, "Failed to create resampler state: %s", - funcs->strerror (err)); + if (err != RESAMPLER_ERR_SUCCESS) { + GST_ERROR ("Failed to create resampler state: %s", + resample_resampler_strerror (err)); return NULL; } - funcs->skip_zeros (ret); + if (fp) + resample_float_resampler_skip_zeros (ret); + else + resample_int_resampler_skip_zeros (ret); return ret; } static gboolean -gst_speex_resample_update_state (GstSpeexResample * resample, gint width, - gint channels, gint inrate, gint outrate, gint quality, gboolean fp) +gst_speex_resample_update_state (GstSpeexResample * resample, gint channels, + gint inrate, gint outrate, gint quality, gboolean fp) { gboolean ret = TRUE; gboolean updated_latency = FALSE; @@ -360,38 +280,41 @@ gst_speex_resample_update_state (GstSpeexResample * resample, gint width, if (resample->state == NULL) { ret = TRUE; - } else if (resample->channels != channels || fp != resample->fp - || width != resample->width) { - resample->funcs->destroy (resample->state); + } else if (resample->channels != channels || fp != resample->fp) { + resample_resampler_destroy (resample->state); resample->state = - gst_speex_resample_init_state (resample, width, channels, inrate, - outrate, quality, fp); + gst_speex_resample_init_state (channels, inrate, outrate, quality, fp); - resample->funcs = gst_speex_resample_get_funcs (width, fp); ret = (resample->state != NULL); } else if (resample->inrate != inrate || resample->outrate != outrate) { gint err = RESAMPLER_ERR_SUCCESS; - err = resample->funcs->set_rate (resample->state, inrate, outrate); + if (fp) + err = + resample_float_resampler_set_rate (resample->state, inrate, outrate); + else + err = resample_int_resampler_set_rate (resample->state, inrate, outrate); - if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) - GST_ERROR_OBJECT (resample, "Failed to update rate: %s", - resample->funcs->strerror (err)); + if (err != RESAMPLER_ERR_SUCCESS) + GST_ERROR ("Failed to update rate: %s", + resample_resampler_strerror (err)); ret = (err == RESAMPLER_ERR_SUCCESS); } else if (quality != resample->quality) { gint err = RESAMPLER_ERR_SUCCESS; - err = resample->funcs->set_quality (resample->state, quality); + if (fp) + err = resample_float_resampler_set_quality (resample->state, quality); + else + err = resample_int_resampler_set_quality (resample->state, quality); - if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) - GST_ERROR_OBJECT (resample, "Failed to update quality: %s", - resample->funcs->strerror (err)); + if (err != RESAMPLER_ERR_SUCCESS) + GST_ERROR ("Failed to update quality: %s", + resample_resampler_strerror (err)); ret = (err == RESAMPLER_ERR_SUCCESS); } - resample->width = width; resample->channels = channels; resample->fp = fp; resample->quality = quality; @@ -408,18 +331,20 @@ gst_speex_resample_update_state (GstSpeexResample * resample, gint width, static void gst_speex_resample_reset_state (GstSpeexResample * resample) { - if (resample->state) - resample->funcs->reset_mem (resample->state); + if (resample->state && resample->fp) + resample_float_resampler_reset_mem (resample->state); + else if (resample->state && !resample->fp) + resample_int_resampler_reset_mem (resample->state); } static gboolean gst_speex_resample_parse_caps (GstCaps * incaps, - GstCaps * outcaps, gint * width, gint * channels, gint * inrate, - gint * outrate, gboolean * fp) + GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate, + gboolean * fp) { GstStructure *structure; gboolean ret; - gint mywidth, myinrate, myoutrate, mychannels; + gint myinrate, myoutrate, mychannels; gboolean myfp; GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %" @@ -434,13 +359,12 @@ gst_speex_resample_parse_caps (GstCaps * incaps, ret = gst_structure_get_int (structure, "rate", &myinrate); ret &= gst_structure_get_int (structure, "channels", &mychannels); - ret &= gst_structure_get_int (structure, "width", &mywidth); - if (G_UNLIKELY (!ret)) + if (!ret) goto no_in_rate_channels; structure = gst_caps_get_structure (outcaps, 0); ret = gst_structure_get_int (structure, "rate", &myoutrate); - if (G_UNLIKELY (!ret)) + if (!ret) goto no_out_rate; if (channels) @@ -449,8 +373,7 @@ gst_speex_resample_parse_caps (GstCaps * incaps, *inrate = myinrate; if (outrate) *outrate = myoutrate; - if (width) - *width = mywidth; + if (fp) *fp = myfp; @@ -469,32 +392,20 @@ no_out_rate: } } -static gint -_gcd (gint a, gint b) -{ - while (b != 0) { - int temp = a; - - a = b; - b = temp % b; - } - - return ABS (a); -} - static gboolean gst_speex_resample_transform_size (GstBaseTransform * base, GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, guint * othersize) { GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base); + SpeexResamplerState *state; GstCaps *srccaps, *sinkcaps; + gboolean use_internal = FALSE; /* whether we use the internal state */ gboolean ret = TRUE; guint32 ratio_den, ratio_num; - gint inrate, outrate, gcd; - gint width; + gboolean fp; - GST_LOG_OBJECT (resample, "asked to transform size %d in direction %s", + GST_LOG ("asked to transform size %d in direction %s", size, direction == GST_PAD_SINK ? "SINK" : "SRC"); if (direction == GST_PAD_SINK) { sinkcaps = caps; @@ -504,37 +415,59 @@ gst_speex_resample_transform_size (GstBaseTransform * base, srccaps = caps; } - ret = - gst_speex_resample_parse_caps (caps, othercaps, &width, NULL, &inrate, - &outrate, NULL); - if (G_UNLIKELY (!ret)) { - GST_ERROR_OBJECT (resample, "Wrong caps"); - return FALSE; + /* if the caps are the ones that _set_caps got called with; we can use + * our own state; otherwise we'll have to create a state */ + if (resample->state && gst_caps_is_equal (sinkcaps, resample->sinkcaps) && + gst_caps_is_equal (srccaps, resample->srccaps)) { + use_internal = TRUE; + state = resample->state; + fp = resample->fp; + } else { + gint inrate, outrate, channels; + + GST_DEBUG ("Can't use internal state, creating state"); + + ret = + gst_speex_resample_parse_caps (caps, othercaps, &channels, &inrate, + &outrate, &fp); + + if (!ret) { + GST_ERROR ("Wrong caps"); + return FALSE; + } + + state = gst_speex_resample_init_state (channels, inrate, outrate, 0, TRUE); + if (!state) + return FALSE; } - gcd = _gcd (inrate, outrate); - ratio_num = inrate / gcd; - ratio_den = outrate / gcd; + if (resample->fp || use_internal) + resample_float_resampler_get_ratio (state, &ratio_num, &ratio_den); + else + resample_int_resampler_get_ratio (state, &ratio_num, &ratio_den); if (direction == GST_PAD_SINK) { - gint fac = width / 8; + gint fac = (fp) ? 4 : 2; /* asked to convert size of an incoming buffer */ size /= fac; - *othersize = (size * ratio_den + ratio_num - 1) / ratio_num; + *othersize = (size * ratio_den + (ratio_num >> 1)) / ratio_num; *othersize *= fac; size *= fac; } else { - gint fac = width / 8; + gint fac = (fp) ? 4 : 2; /* asked to convert size of an outgoing buffer */ size /= fac; - *othersize = (size * ratio_num + ratio_den - 1) / ratio_den; + *othersize = (size * ratio_num + (ratio_den >> 1)) / ratio_den; *othersize *= fac; size *= fac; } - GST_LOG_OBJECT (resample, "transformed size %d to %d", size, *othersize); + GST_LOG ("transformed size %d to %d", size, *othersize); + + if (!use_internal) + resample_resampler_destroy (state); return ret; } @@ -544,25 +477,23 @@ gst_speex_resample_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) { gboolean ret; - gint width = 0, inrate = 0, outrate = 0, channels = 0; - gboolean fp; + gint inrate = 0, outrate = 0, channels = 0; + gboolean fp = FALSE; GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base); GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %" GST_PTR_FORMAT, incaps, outcaps); ret = gst_speex_resample_parse_caps (incaps, outcaps, - &width, &channels, &inrate, &outrate, &fp); + &channels, &inrate, &outrate, &fp); - if (G_UNLIKELY (!ret)) - return FALSE; + g_return_val_if_fail (ret, FALSE); ret = - gst_speex_resample_update_state (resample, width, channels, inrate, - outrate, resample->quality, fp); + gst_speex_resample_update_state (resample, channels, inrate, outrate, + resample->quality, fp); - if (G_UNLIKELY (!ret)) - return FALSE; + g_return_val_if_fail (ret, FALSE); /* save caps so we can short-circuit in the size_transform if the caps * are the same */ @@ -572,163 +503,6 @@ gst_speex_resample_set_caps (GstBaseTransform * base, GstCaps * incaps, return TRUE; } -#define GST_MAXINT24 (8388607) -#define GST_MININT24 (-8388608) - -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) -#define GST_READ_UINT24 GST_READ_UINT24_LE -#define GST_WRITE_UINT24 GST_WRITE_UINT24_LE -#else -#define GST_READ_UINT24 GST_READ_UINT24_BE -#define GST_WRITE_UINT24 GST_WRITE_UINT24_BE -#endif - -static void -gst_speex_resample_convert_buffer (GstSpeexResample * resample, - const guint8 * in, guint8 * out, guint len, gboolean inverse) -{ - len *= resample->channels; - - if (inverse) { - if (gst_speex_resample_use_int && resample->width == 8 && !resample->fp) { - gint8 *o = (gint8 *) out; - gint16 *i = (gint16 *) in; - gint32 tmp; - - while (len) { - tmp = *i + (G_MAXINT8 >> 1); - *o = CLAMP (tmp >> 8, G_MININT8, G_MAXINT8); - o++; - i++; - len--; - } - } else if (!gst_speex_resample_use_int && resample->width == 8 - && !resample->fp) { - gint8 *o = (gint8 *) out; - gfloat *i = (gfloat *) in; - gfloat tmp; - - while (len) { - tmp = *i; - *o = (gint8) CLAMP (tmp * G_MAXINT8 + 0.5, G_MININT8, G_MAXINT8); - o++; - i++; - len--; - } - } else if (!gst_speex_resample_use_int && resample->width == 16 - && !resample->fp) { - gint16 *o = (gint16 *) out; - gfloat *i = (gfloat *) in; - gfloat tmp; - - while (len) { - tmp = *i; - *o = (gint16) CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16); - o++; - i++; - len--; - } - } else if (resample->width == 24 && !resample->fp) { - guint8 *o = (guint8 *) out; - gdouble *i = (gdouble *) in; - gdouble tmp; - - while (len) { - tmp = *i; - GST_WRITE_UINT24 (o, (gint32) CLAMP (tmp * GST_MAXINT24 + 0.5, - GST_MININT24, GST_MAXINT24)); - o += 3; - i++; - len--; - } - } else if (resample->width == 32 && !resample->fp) { - gint32 *o = (gint32 *) out; - gdouble *i = (gdouble *) in; - gdouble tmp; - - while (len) { - tmp = *i; - *o = (gint32) CLAMP (tmp * G_MAXINT32 + 0.5, G_MININT32, G_MAXINT32); - o++; - i++; - len--; - } - } else { - g_assert_not_reached (); - } - } else { - if (gst_speex_resample_use_int && resample->width == 8 && !resample->fp) { - gint8 *i = (gint8 *) in; - gint16 *o = (gint16 *) out; - gint32 tmp; - - while (len) { - tmp = *i; - *o = tmp << 8; - o++; - i++; - len--; - } - } else if (!gst_speex_resample_use_int && resample->width == 8 - && !resample->fp) { - gint8 *i = (gint8 *) in; - gfloat *o = (gfloat *) out; - gfloat tmp; - - while (len) { - tmp = *i; - *o = tmp / G_MAXINT8; - o++; - i++; - len--; - } - } else if (!gst_speex_resample_use_int && resample->width == 16 - && !resample->fp) { - gint16 *i = (gint16 *) in; - gfloat *o = (gfloat *) out; - gfloat tmp; - - while (len) { - tmp = *i; - *o = tmp / G_MAXINT16; - o++; - i++; - len--; - } - } else if (resample->width == 24 && !resample->fp) { - guint8 *i = (guint8 *) in; - gdouble *o = (gdouble *) out; - gdouble tmp; - guint32 tmp2; - - while (len) { - tmp2 = GST_READ_UINT24 (i); - if (tmp2 & 0x00800000) - tmp2 |= 0xff000000; - tmp = (gint32) tmp2; - *o = tmp / GST_MAXINT24; - o++; - i += 3; - len--; - } - } else if (resample->width == 32 && !resample->fp) { - gint32 *i = (gint32 *) in; - gdouble *o = (gdouble *) out; - gdouble tmp; - - while (len) { - tmp = *i; - *o = tmp / G_MAXINT32; - o++; - i++; - len--; - } - } else { - g_assert_not_reached (); - } - } -} - static void gst_speex_resample_push_drain (GstSpeexResample * resample) { @@ -738,97 +512,97 @@ gst_speex_resample_push_drain (GstSpeexResample * resample) gint outsize; guint out_len, out_processed; gint err; - guint num, den, len; - guint8 *outtmp = NULL; - gboolean need_convert = FALSE; if (!resample->state) return; - need_convert = (resample->funcs->width != resample->width); + if (resample->fp) { + guint num, den; + + resample_float_resampler_get_ratio (resample->state, &num, &den); - resample->funcs->get_ratio (resample->state, &num, &den); + out_len = resample_float_resampler_get_input_latency (resample->state); + out_len = out_processed = (out_len * den + (num >> 1)) / num; + outsize = 4 * out_len * resample->channels; + } else { + guint num, den; - out_len = resample->funcs->get_input_latency (resample->state); - out_len = out_processed = (out_len * den + num - 1) / num; - outsize = (resample->width / 8) * out_len * resample->channels; + resample_int_resampler_get_ratio (resample->state, &num, &den); - if (need_convert) { - guint outsize_tmp = - (resample->funcs->width / 8) * out_len * resample->channels; - if (outsize_tmp <= resample->tmp_out_size) { - outtmp = resample->tmp_out; - } else { - resample->tmp_out_size = outsize_tmp; - resample->tmp_out = outtmp = g_realloc (resample->tmp_out, outsize_tmp); - } + out_len = resample_int_resampler_get_input_latency (resample->state); + out_len = out_processed = (out_len * den + (num >> 1)) / num; + outsize = 2 * out_len * resample->channels; } - res = - gst_pad_alloc_buffer_and_set_caps (trans->srcpad, GST_BUFFER_OFFSET_NONE, - outsize, GST_PAD_CAPS (trans->srcpad), &buf); + res = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET_NONE, outsize, + GST_PAD_CAPS (trans->srcpad), &buf); if (G_UNLIKELY (res != GST_FLOW_OK)) { - GST_WARNING_OBJECT (resample, "failed allocating buffer of %d bytes", - outsize); + GST_WARNING ("failed allocating buffer of %d bytes", outsize); return; } - len = resample->funcs->get_input_latency (resample->state); + if (resample->fp) { + guint len = resample_float_resampler_get_input_latency (resample->state); - err = - resample->funcs->process (resample->state, - NULL, &len, (need_convert) ? outtmp : GST_BUFFER_DATA (buf), - &out_processed); + err = + resample_float_resampler_process_interleaved_float (resample->state, + NULL, &len, (gfloat *) GST_BUFFER_DATA (buf), &out_processed); + } else { + guint len = resample_int_resampler_get_input_latency (resample->state); + + err = + resample_int_resampler_process_interleaved_int (resample->state, NULL, + &len, (gint16 *) GST_BUFFER_DATA (buf), &out_processed); + } - if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) { - GST_WARNING_OBJECT (resample, "Failed to process drain: %s", - resample->funcs->strerror (err)); + if (err != RESAMPLER_ERR_SUCCESS) { + GST_WARNING ("Failed to process drain: %s", + resample_resampler_strerror (err)); gst_buffer_unref (buf); return; } - if (G_UNLIKELY (out_processed == 0)) { - GST_WARNING_OBJECT (resample, "Failed to get drain, dropping buffer"); + if (out_processed == 0) { + GST_WARNING ("Failed to get drain, dropping buffer"); gst_buffer_unref (buf); return; } - /* If we wrote more than allocated something is really wrong now - * and we should better abort immediately */ - g_assert (out_len >= out_processed); - - if (need_convert) - gst_speex_resample_convert_buffer (resample, outtmp, GST_BUFFER_DATA (buf), - out_processed, TRUE); - - GST_BUFFER_DURATION (buf) = - GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate); + GST_BUFFER_OFFSET (buf) = resample->offset; + GST_BUFFER_TIMESTAMP (buf) = resample->next_ts; GST_BUFFER_SIZE (buf) = - out_processed * resample->channels * (resample->width / 8); - - if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) { - GST_BUFFER_OFFSET (buf) = resample->next_offset; - GST_BUFFER_OFFSET_END (buf) = resample->next_offset + out_processed; - GST_BUFFER_TIMESTAMP (buf) = resample->next_ts; - - resample->next_ts += GST_BUFFER_DURATION (buf); - resample->next_offset += out_processed; + out_processed * resample->channels * ((resample->fp) ? 4 : 2); + + if (resample->ts_offset != -1) { + resample->offset += out_processed; + resample->ts_offset += out_processed; + resample->next_ts = + GST_FRAMES_TO_CLOCK_TIME (resample->ts_offset, resample->outrate); + GST_BUFFER_OFFSET_END (buf) = resample->offset; + + /* we calculate DURATION as the difference between "next" timestamp + * and current timestamp so we ensure a contiguous stream, instead of + * having rounding errors. */ + GST_BUFFER_DURATION (buf) = resample->next_ts - GST_BUFFER_TIMESTAMP (buf); + } else { + /* no valid offset know, we can still sortof calculate the duration though */ + GST_BUFFER_DURATION (buf) = + GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate); } - GST_LOG_OBJECT (resample, - "Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT - " duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT " offset_end %" - G_GUINT64_FORMAT, GST_BUFFER_SIZE (buf), + GST_LOG ("Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT + " duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT + " offset_end %" G_GUINT64_FORMAT, + GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), - GST_BUFFER_OFFSET_END (buf)); + GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), + GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf)); res = gst_pad_push (trans->srcpad, buf); - if (G_UNLIKELY (res != GST_FLOW_OK)) - GST_WARNING_OBJECT (resample, "Failed to push drain: %s", - gst_flow_get_name (res)); + if (res != GST_FLOW_OK) + GST_WARNING ("Failed to push drain"); return; } @@ -843,15 +617,15 @@ gst_speex_resample_event (GstBaseTransform * base, GstEvent * event) break; case GST_EVENT_FLUSH_STOP: gst_speex_resample_reset_state (resample); - resample->next_offset = -1; + resample->ts_offset = -1; resample->next_ts = -1; - resample->next_upstream_ts = -1; + resample->offset = -1; case GST_EVENT_NEWSEGMENT: gst_speex_resample_push_drain (resample); gst_speex_resample_reset_state (resample); - resample->next_offset = -1; + resample->ts_offset = -1; resample->next_ts = -1; - resample->next_upstream_ts = -1; + resample->offset = -1; break; case GST_EVENT_EOS:{ gst_speex_resample_push_drain (resample); @@ -861,8 +635,9 @@ gst_speex_resample_event (GstBaseTransform * base, GstEvent * event) default: break; } + parent_class->event (base, event); - return parent_class->event (base, event); + return TRUE; } static gboolean @@ -870,18 +645,19 @@ gst_speex_resample_check_discont (GstSpeexResample * resample, GstClockTime timestamp) { if (timestamp != GST_CLOCK_TIME_NONE && - resample->next_upstream_ts != GST_CLOCK_TIME_NONE && - timestamp != resample->next_upstream_ts) { + resample->prev_ts != GST_CLOCK_TIME_NONE && + resample->prev_duration != GST_CLOCK_TIME_NONE && + timestamp != resample->prev_ts + resample->prev_duration) { /* Potentially a discontinuous buffer. However, it turns out that many * elements generate imperfect streams due to rounding errors, so we permit * a small error (up to one sample) without triggering a filter * flush/restart (if triggered incorrectly, this will be audible) */ - GstClockTimeDiff diff = timestamp - resample->next_upstream_ts; + GstClockTimeDiff diff = timestamp - + (resample->prev_ts + resample->prev_duration); - if (ABS (diff) > (GST_SECOND + resample->inrate - 1) / resample->inrate) { - GST_WARNING_OBJECT (resample, - "encountered timestamp discontinuity of %s%" GST_TIME_FORMAT, - (diff < 0) ? "-" : "", GST_TIME_ARGS ((GstClockTime) ABS (diff))); + if (ABS (diff) > GST_SECOND / resample->inrate) { + GST_WARNING ("encountered timestamp discontinuity of %" G_GINT64_FORMAT, + diff); return TRUE; } } @@ -889,6 +665,27 @@ gst_speex_resample_check_discont (GstSpeexResample * resample, return FALSE; } +static void +gst_speex_fix_output_buffer (GstSpeexResample * resample, GstBuffer * outbuf, + guint diff) +{ + GstClockTime timediff = GST_FRAMES_TO_CLOCK_TIME (diff, resample->outrate); + + GST_LOG ("Adjusting buffer by %d samples", diff); + + GST_BUFFER_DURATION (outbuf) -= timediff; + GST_BUFFER_SIZE (outbuf) -= + diff * ((resample->fp) ? 4 : 2) * resample->channels; + + if (resample->ts_offset != -1) { + GST_BUFFER_OFFSET_END (outbuf) -= diff; + resample->offset -= diff; + resample->ts_offset -= diff; + resample->next_ts = + GST_FRAMES_TO_CLOCK_TIME (resample->ts_offset, resample->outrate); + } +} + static GstFlowReturn gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf, GstBuffer * outbuf) @@ -896,99 +693,70 @@ gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf, guint32 in_len, in_processed; guint32 out_len, out_processed; gint err = RESAMPLER_ERR_SUCCESS; - guint8 *in_tmp = NULL, *out_tmp = NULL; - gboolean need_convert = (resample->funcs->width != resample->width); in_len = GST_BUFFER_SIZE (inbuf) / resample->channels; out_len = GST_BUFFER_SIZE (outbuf) / resample->channels; - in_len /= (resample->width / 8); - out_len /= (resample->width / 8); + if (resample->fp) { + in_len /= 4; + out_len /= 4; + } else { + in_len /= 2; + out_len /= 2; + } in_processed = in_len; out_processed = out_len; - if (need_convert) { - guint in_size_tmp = - in_len * resample->channels * (resample->funcs->width / 8); - guint out_size_tmp = - out_len * resample->channels * (resample->funcs->width / 8); - - if (in_size_tmp <= resample->tmp_in_size) { - in_tmp = resample->tmp_in; - } else { - resample->tmp_in = in_tmp = g_realloc (resample->tmp_in, in_size_tmp); - resample->tmp_in_size = in_size_tmp; - } - - gst_speex_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf), - in_tmp, in_len, FALSE); - - if (out_size_tmp <= resample->tmp_out_size) { - out_tmp = resample->tmp_out; - } else { - resample->tmp_out = out_tmp = g_realloc (resample->tmp_out, out_size_tmp); - resample->tmp_out_size = out_size_tmp; - } - } - - if (need_convert) { - err = resample->funcs->process (resample->state, - in_tmp, &in_processed, out_tmp, &out_processed); - } else { - err = resample->funcs->process (resample->state, - (const guint8 *) GST_BUFFER_DATA (inbuf), &in_processed, - (guint8 *) GST_BUFFER_DATA (outbuf), &out_processed); - } + if (resample->fp) + err = resample_float_resampler_process_interleaved_float (resample->state, + (const gfloat *) GST_BUFFER_DATA (inbuf), &in_processed, + (gfloat *) GST_BUFFER_DATA (outbuf), &out_processed); + else + err = resample_int_resampler_process_interleaved_int (resample->state, + (const gint16 *) GST_BUFFER_DATA (inbuf), &in_processed, + (gint16 *) GST_BUFFER_DATA (outbuf), &out_processed); - if (G_UNLIKELY (in_len != in_processed)) - GST_WARNING_OBJECT (resample, "Converted %d of %d input samples", - in_processed, in_len); + if (in_len != in_processed) + GST_WARNING ("Converted %d of %d input samples", in_processed, in_len); if (out_len != out_processed) { + /* One sample difference is allowed as this will happen + * because of rounding errors */ if (out_processed == 0) { - GST_DEBUG_OBJECT (resample, "Converted to 0 samples, buffer dropped"); + GST_DEBUG ("Converted to 0 samples, buffer dropped"); + + if (resample->ts_offset != -1) { + GST_BUFFER_OFFSET_END (outbuf) -= out_len; + resample->offset -= out_len; + resample->ts_offset -= out_len; + resample->next_ts = + GST_FRAMES_TO_CLOCK_TIME (resample->ts_offset, resample->outrate); + } return GST_BASE_TRANSFORM_FLOW_DROPPED; + } else if (out_len - out_processed != 1) + GST_WARNING ("Converted to %d instead of %d output samples", + out_processed, out_len); + if (out_len > out_processed) { + gst_speex_fix_output_buffer (resample, outbuf, out_len - out_processed); + } else { + GST_ERROR ("Wrote more output than allocated!"); + return GST_FLOW_ERROR; } - - /* If we wrote more than allocated something is really wrong now - * and we should better abort immediately */ - g_assert (out_len >= out_processed); } - if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) { - GST_ERROR_OBJECT (resample, "Failed to convert data: %s", - resample->funcs->strerror (err)); + if (err != RESAMPLER_ERR_SUCCESS) { + GST_ERROR ("Failed to convert data: %s", resample_resampler_strerror (err)); return GST_FLOW_ERROR; } else { - - if (need_convert) - gst_speex_resample_convert_buffer (resample, out_tmp, - GST_BUFFER_DATA (outbuf), out_processed, TRUE); - - GST_BUFFER_DURATION (outbuf) = - GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate); - GST_BUFFER_SIZE (outbuf) = - out_processed * resample->channels * (resample->width / 8); - - if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) { - GST_BUFFER_TIMESTAMP (outbuf) = resample->next_ts; - GST_BUFFER_OFFSET (outbuf) = resample->next_offset; - GST_BUFFER_OFFSET_END (outbuf) = resample->next_offset + out_processed; - - resample->next_ts += GST_BUFFER_DURATION (outbuf); - resample->next_offset += out_processed; - } - - GST_LOG_OBJECT (resample, - "Converted to buffer of %u bytes with timestamp %" GST_TIME_FORMAT + GST_LOG ("Converted to buffer of %u bytes with timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT - ", offset_end %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (outbuf), + ", offset_end %" G_GUINT64_FORMAT, + GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf)); - return GST_FLOW_OK; } } @@ -1001,25 +769,19 @@ gst_speex_resample_transform (GstBaseTransform * base, GstBuffer * inbuf, guint8 *data; gulong size; GstClockTime timestamp; - guint outsamples, insamples; - GstFlowReturn ret; + gint outsamples; - if (resample->state == NULL) { - if (G_UNLIKELY (!(resample->state = - gst_speex_resample_init_state (resample, resample->width, - resample->channels, resample->inrate, resample->outrate, - resample->quality, resample->fp)))) + if (resample->state == NULL) + if (!(resample->state = gst_speex_resample_init_state (resample->channels, + resample->inrate, resample->outrate, resample->quality, + resample->fp))) return GST_FLOW_ERROR; - resample->funcs = - gst_speex_resample_get_funcs (resample->width, resample->fp); - } - data = GST_BUFFER_DATA (inbuf); size = GST_BUFFER_SIZE (inbuf); timestamp = GST_BUFFER_TIMESTAMP (inbuf); - GST_LOG_OBJECT (resample, "transforming buffer of %ld bytes, ts %" + GST_LOG ("transforming buffer of %ld bytes, ts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT, size, GST_TIME_ARGS (timestamp), @@ -1033,44 +795,62 @@ gst_speex_resample_transform (GstBaseTransform * base, GstBuffer * inbuf, gst_speex_resample_reset_state (resample); /* Inform downstream element about discontinuity */ resample->need_discont = TRUE; - /* We want to recalculate the timestamps */ - resample->next_ts = -1; - resample->next_upstream_ts = -1; - resample->next_offset = -1; + /* We want to recalculate the offset */ + resample->ts_offset = -1; } - insamples = GST_BUFFER_SIZE (inbuf) / resample->channels; - insamples /= (resample->width / 8); - outsamples = GST_BUFFER_SIZE (outbuf) / resample->channels; - outsamples /= (resample->width / 8); + outsamples /= (resample->fp) ? 4 : 2; + + if (resample->ts_offset == -1) { + /* if we don't know the initial offset yet, calculate it based on the + * input timestamp. */ + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + GstClockTime stime; + + /* offset used to calculate the timestamps. We use the sample offset for + * this to make it more accurate. We want the first buffer to have the + * same timestamp as the incoming timestamp. */ + resample->next_ts = timestamp; + resample->ts_offset = + GST_CLOCK_TIME_TO_FRAMES (timestamp, resample->outrate); + /* offset used to set as the buffer offset, this offset is always + * relative to the stream time, note that timestamp is not... */ + stime = (timestamp - base->segment.start) + base->segment.time; + resample->offset = GST_CLOCK_TIME_TO_FRAMES (stime, resample->outrate); + } + } + resample->prev_ts = timestamp; + resample->prev_duration = GST_BUFFER_DURATION (inbuf); + + GST_BUFFER_OFFSET (outbuf) = resample->offset; + GST_BUFFER_TIMESTAMP (outbuf) = resample->next_ts; + + if (resample->ts_offset != -1) { + resample->offset += outsamples; + resample->ts_offset += outsamples; + resample->next_ts = + GST_FRAMES_TO_CLOCK_TIME (resample->ts_offset, resample->outrate); + GST_BUFFER_OFFSET_END (outbuf) = resample->offset; - if (GST_CLOCK_TIME_IS_VALID (timestamp) - && !GST_CLOCK_TIME_IS_VALID (resample->next_ts)) { - resample->next_ts = timestamp; - resample->next_offset = - GST_CLOCK_TIME_TO_FRAMES (timestamp, resample->outrate); + /* we calculate DURATION as the difference between "next" timestamp + * and current timestamp so we ensure a contiguous stream, instead of + * having rounding errors. */ + GST_BUFFER_DURATION (outbuf) = resample->next_ts - + GST_BUFFER_TIMESTAMP (outbuf); + } else { + /* no valid offset know, we can still sortof calculate the duration though */ + GST_BUFFER_DURATION (outbuf) = + GST_FRAMES_TO_CLOCK_TIME (outsamples, resample->outrate); } if (G_UNLIKELY (resample->need_discont)) { - GST_DEBUG_OBJECT (resample, "marking this buffer with the DISCONT flag"); + GST_DEBUG ("marking this buffer with the DISCONT flag"); GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); resample->need_discont = FALSE; } - ret = gst_speex_resample_process (resample, inbuf, outbuf); - if (G_UNLIKELY (ret != GST_FLOW_OK)) - return ret; - - if (GST_CLOCK_TIME_IS_VALID (timestamp) - && !GST_CLOCK_TIME_IS_VALID (resample->next_upstream_ts)) - resample->next_upstream_ts = timestamp; - - if (GST_CLOCK_TIME_IS_VALID (resample->next_upstream_ts)) - resample->next_upstream_ts += - GST_FRAMES_TO_CLOCK_TIME (insamples, resample->inrate); - - return GST_FLOW_OK; + return gst_speex_resample_process (resample, inbuf, outbuf); } static gboolean @@ -1090,9 +870,12 @@ gst_speex_resample_query (GstPad * pad, GstQuery * query) gint rate = resample->inrate; gint resampler_latency; - if (resample->state) + if (resample->state && resample->fp) + resampler_latency = + resample_float_resampler_get_input_latency (resample->state); + else if (resample->state && !resample->fp) resampler_latency = - resample->funcs->get_input_latency (resample->state); + resample_int_resampler_get_input_latency (resample->state); else resampler_latency = 0; @@ -1103,7 +886,7 @@ gst_speex_resample_query (GstPad * pad, GstQuery * query) if ((res = gst_pad_query (peer, query))) { gst_query_parse_latency (query, &live, &min, &max); - GST_DEBUG_OBJECT (resample, "Peer latency: min %" + GST_DEBUG ("Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); @@ -1114,14 +897,13 @@ gst_speex_resample_query (GstPad * pad, GstQuery * query) else latency = 0; - GST_DEBUG_OBJECT (resample, "Our latency: %" GST_TIME_FORMAT, - GST_TIME_ARGS (latency)); + GST_DEBUG ("Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); min += latency; if (max != GST_CLOCK_TIME_NONE) max += latency; - GST_DEBUG_OBJECT (resample, "Calculated total latency : min %" + GST_DEBUG ("Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); @@ -1161,45 +943,11 @@ gst_speex_resample_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_QUALITY: resample->quality = g_value_get_int (value); - GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality); + GST_DEBUG ("new quality %d", resample->quality); - gst_speex_resample_update_state (resample, resample->width, - resample->channels, resample->inrate, resample->outrate, - resample->quality, resample->fp); + gst_speex_resample_update_state (resample, resample->channels, + resample->inrate, resample->outrate, resample->quality, resample->fp); break; - case PROP_FILTER_LENGTH:{ - gint filter_length = g_value_get_int (value); - - if (filter_length <= 8) - resample->quality = 0; - else if (filter_length <= 16) - resample->quality = 1; - else if (filter_length <= 32) - resample->quality = 2; - else if (filter_length <= 48) - resample->quality = 3; - else if (filter_length <= 64) - resample->quality = 4; - else if (filter_length <= 80) - resample->quality = 5; - else if (filter_length <= 96) - resample->quality = 6; - else if (filter_length <= 128) - resample->quality = 7; - else if (filter_length <= 160) - resample->quality = 8; - else if (filter_length <= 192) - resample->quality = 9; - else - resample->quality = 10; - - GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality); - - gst_speex_resample_update_state (resample, resample->width, - resample->channels, resample->inrate, resample->outrate, - resample->quality, resample->fp); - break; - } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1218,177 +966,16 @@ gst_speex_resample_get_property (GObject * object, guint prop_id, case PROP_QUALITY: g_value_set_int (value, resample->quality); break; - case PROP_FILTER_LENGTH: - switch (resample->quality) { - case 0: - g_value_set_int (value, 8); - break; - case 1: - g_value_set_int (value, 16); - break; - case 2: - g_value_set_int (value, 32); - break; - case 3: - g_value_set_int (value, 48); - break; - case 4: - g_value_set_int (value, 64); - break; - case 5: - g_value_set_int (value, 80); - break; - case 6: - g_value_set_int (value, 96); - break; - case 7: - g_value_set_int (value, 128); - break; - case 8: - g_value_set_int (value, 160); - break; - case 9: - g_value_set_int (value, 192); - break; - case 10: - g_value_set_int (value, 256); - break; - } - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -#define BENCHMARK_SIZE 512 - -static gboolean -_benchmark_int_float (SpeexResamplerState * st) -{ - gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2]; - gfloat in_tmp[BENCHMARK_SIZE], out_tmp[BENCHMARK_SIZE / 2]; - gint i; - guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2; - - for (i = 0; i < BENCHMARK_SIZE; i++) { - gfloat tmp = in[i]; - in_tmp[i] = tmp / G_MAXINT16; - } - - resample_float_resampler_process_interleaved_float (st, - (const guint8 *) in_tmp, &inlen, (guint8 *) out_tmp, &outlen); - - if (outlen == 0) { - GST_ERROR ("Failed to use float resampler"); - return FALSE; - } - - for (i = 0; i < outlen; i++) { - gfloat tmp = out_tmp[i]; - out[i] = CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16); - } - - return TRUE; -} - -static gboolean -_benchmark_int_int (SpeexResamplerState * st) -{ - gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2]; - guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2; - - resample_int_resampler_process_interleaved_int (st, (const guint8 *) in, - &inlen, (guint8 *) out, &outlen); - - if (outlen == 0) { - GST_ERROR ("Failed to use int resampler"); - return FALSE; - } - - return TRUE; -} - -static gboolean -_benchmark_integer_resampling (void) -{ - OilProfile a, b; - gdouble av, bv; - SpeexResamplerState *sta, *stb; - - oil_profile_init (&a); - oil_profile_init (&b); - - sta = resample_float_resampler_init (1, 48000, 24000, 4, NULL); - if (sta == NULL) { - GST_ERROR ("Failed to create float resampler state"); - return FALSE; - } - - stb = resample_int_resampler_init (1, 48000, 24000, 4, NULL); - if (stb == NULL) { - resample_float_resampler_destroy (sta); - GST_ERROR ("Failed to create int resampler state"); - return FALSE; - } - - /* Warm up cache */ - if (!_benchmark_int_float (sta)) - goto error; - if (!_benchmark_int_float (sta)) - goto error; - - /* Benchmark */ - oil_profile_start (&a); - if (!_benchmark_int_float (sta)) - goto error; - oil_profile_stop (&a); - - /* Warm up cache */ - if (!_benchmark_int_int (stb)) - goto error; - if (!_benchmark_int_int (stb)) - goto error; - - /* Benchmark */ - oil_profile_start (&b); - if (!_benchmark_int_int (stb)) - goto error; - oil_profile_stop (&b); - - /* Handle results */ - oil_profile_get_ave_std (&a, &av, NULL); - oil_profile_get_ave_std (&b, &bv, NULL); - - gst_speex_resample_use_int = (av > bv); - resample_float_resampler_destroy (sta); - resample_float_resampler_destroy (stb); - - if (av > bv) - GST_DEBUG ("Using integer resampler if appropiate: %lf < %lf", bv, av); - else - GST_DEBUG ("Using float resampler for everything: %lf <= %lf", av, bv); - - return TRUE; - -error: - resample_float_resampler_destroy (sta); - resample_float_resampler_destroy (stb); - - return FALSE; -} static gboolean plugin_init (GstPlugin * plugin) { - GST_DEBUG_CATEGORY_INIT (speex_resample_debug, "speex_resample", 0, - "audio resampling element"); - - oil_init (); - - if (!_benchmark_integer_resampling ()) - return FALSE; - if (!gst_element_register (plugin, "speexresample", GST_RANK_NONE, GST_TYPE_SPEEX_RESAMPLE)) { return FALSE; |