2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
4 * Copyright (C) 2007-2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:element-audioresample
25 * audioresample resamples raw audio buffers to different sample rates using
26 * a configurable windowing function to enhance quality.
29 * <title>Example launch line</title>
31 * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw-int, rate=8000 ! alsasink
32 * ]| Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
33 * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
38 * - Enable SSE/ARM optimizations and select at runtime
48 #include "gstaudioresample.h"
49 #include <gst/gstutils.h>
50 #include <gst/audio/audio.h>
51 #include <gst/base/gstbasetransform.h>
55 #include <orc-test/orctest.h>
56 #include <orc-test/orcprofile.h>
59 GST_DEBUG_CATEGORY (audio_resample_debug);
60 #define GST_CAT_DEFAULT audio_resample_debug
69 #define SUPPORTED_CAPS \
71 "audio/x-raw-float, " \
72 "rate = (int) [ 1, MAX ], " \
73 "channels = (int) [ 1, MAX ], " \
74 "endianness = (int) BYTE_ORDER, " \
75 "width = (int) { 32, 64 }; " \
77 "rate = (int) [ 1, MAX ], " \
78 "channels = (int) [ 1, MAX ], " \
79 "endianness = (int) BYTE_ORDER, " \
80 "width = (int) 32, " \
81 "depth = (int) 32, " \
82 "signed = (boolean) true; " \
84 "rate = (int) [ 1, MAX ], " \
85 "channels = (int) [ 1, MAX ], " \
86 "endianness = (int) BYTE_ORDER, " \
87 "width = (int) 24, " \
88 "depth = (int) 24, " \
89 "signed = (boolean) true; " \
91 "rate = (int) [ 1, MAX ], " \
92 "channels = (int) [ 1, MAX ], " \
93 "endianness = (int) BYTE_ORDER, " \
94 "width = (int) 16, " \
95 "depth = (int) 16, " \
96 "signed = (boolean) true; " \
98 "rate = (int) [ 1, MAX ], " \
99 "channels = (int) [ 1, MAX ], " \
100 "endianness = (int) BYTE_ORDER, " \
101 "width = (int) 8, " \
102 "depth = (int) 8, " \
103 "signed = (boolean) true" \
106 /* If TRUE integer arithmetic resampling is faster and will be used if appropiate */
107 #if defined AUDIORESAMPLE_FORMAT_INT
108 static gboolean gst_audio_resample_use_int = TRUE;
109 #elif defined AUDIORESAMPLE_FORMAT_FLOAT
110 static gboolean gst_audio_resample_use_int = FALSE;
112 static gboolean gst_audio_resample_use_int = FALSE;
115 static GstStaticPadTemplate gst_audio_resample_sink_template =
116 GST_STATIC_PAD_TEMPLATE ("sink",
117 GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
119 static GstStaticPadTemplate gst_audio_resample_src_template =
120 GST_STATIC_PAD_TEMPLATE ("src",
121 GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
123 static void gst_audio_resample_set_property (GObject * object,
124 guint prop_id, const GValue * value, GParamSpec * pspec);
125 static void gst_audio_resample_get_property (GObject * object,
126 guint prop_id, GValue * value, GParamSpec * pspec);
129 static gboolean gst_audio_resample_get_unit_size (GstBaseTransform * base,
130 GstCaps * caps, guint * size);
131 static GstCaps *gst_audio_resample_transform_caps (GstBaseTransform * base,
132 GstPadDirection direction, GstCaps * caps);
133 static void gst_audio_resample_fixate_caps (GstBaseTransform * base,
134 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
135 static gboolean gst_audio_resample_transform_size (GstBaseTransform * trans,
136 GstPadDirection direction, GstCaps * incaps, guint insize,
137 GstCaps * outcaps, guint * outsize);
138 static gboolean gst_audio_resample_set_caps (GstBaseTransform * base,
139 GstCaps * incaps, GstCaps * outcaps);
140 static GstFlowReturn gst_audio_resample_transform (GstBaseTransform * base,
141 GstBuffer * inbuf, GstBuffer * outbuf);
142 static gboolean gst_audio_resample_event (GstBaseTransform * base,
144 static gboolean gst_audio_resample_start (GstBaseTransform * base);
145 static gboolean gst_audio_resample_stop (GstBaseTransform * base);
146 static gboolean gst_audio_resample_query (GstPad * pad, GstQuery * query);
147 static const GstQueryType *gst_audio_resample_query_type (GstPad * pad);
149 GST_BOILERPLATE (GstAudioResample, gst_audio_resample, GstBaseTransform,
150 GST_TYPE_BASE_TRANSFORM);
153 gst_audio_resample_base_init (gpointer g_class)
155 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
157 gst_element_class_add_pad_template (gstelement_class,
158 gst_static_pad_template_get (&gst_audio_resample_src_template));
159 gst_element_class_add_pad_template (gstelement_class,
160 gst_static_pad_template_get (&gst_audio_resample_sink_template));
162 gst_element_class_set_details_simple (gstelement_class, "Audio resampler",
163 "Filter/Converter/Audio", "Resamples audio",
164 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
168 gst_audio_resample_class_init (GstAudioResampleClass * klass)
170 GObjectClass *gobject_class = (GObjectClass *) klass;
172 gobject_class->set_property = gst_audio_resample_set_property;
173 gobject_class->get_property = gst_audio_resample_get_property;
175 g_object_class_install_property (gobject_class, PROP_QUALITY,
176 g_param_spec_int ("quality", "Quality", "Resample quality with 0 being "
177 "the lowest and 10 being the best",
178 SPEEX_RESAMPLER_QUALITY_MIN, SPEEX_RESAMPLER_QUALITY_MAX,
179 SPEEX_RESAMPLER_QUALITY_DEFAULT,
180 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
182 /* FIXME 0.11: Remove this property, it's just for compatibility
183 * with old audioresample
186 * GstAudioResample:filter-length:
188 * Length of the resample filter
190 * Deprectated: Use #GstAudioResample:quality property instead
192 g_object_class_install_property (gobject_class, PROP_FILTER_LENGTH,
193 g_param_spec_int ("filter-length", "Filter length",
194 "Length of the resample filter", 0, G_MAXINT, 64,
195 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
197 GST_BASE_TRANSFORM_CLASS (klass)->start =
198 GST_DEBUG_FUNCPTR (gst_audio_resample_start);
199 GST_BASE_TRANSFORM_CLASS (klass)->stop =
200 GST_DEBUG_FUNCPTR (gst_audio_resample_stop);
201 GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
202 GST_DEBUG_FUNCPTR (gst_audio_resample_transform_size);
203 GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
204 GST_DEBUG_FUNCPTR (gst_audio_resample_get_unit_size);
205 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
206 GST_DEBUG_FUNCPTR (gst_audio_resample_transform_caps);
207 GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
208 GST_DEBUG_FUNCPTR (gst_audio_resample_fixate_caps);
209 GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
210 GST_DEBUG_FUNCPTR (gst_audio_resample_set_caps);
211 GST_BASE_TRANSFORM_CLASS (klass)->transform =
212 GST_DEBUG_FUNCPTR (gst_audio_resample_transform);
213 GST_BASE_TRANSFORM_CLASS (klass)->event =
214 GST_DEBUG_FUNCPTR (gst_audio_resample_event);
216 GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
220 gst_audio_resample_init (GstAudioResample * resample,
221 GstAudioResampleClass * klass)
223 GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
225 resample->quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
227 gst_base_transform_set_gap_aware (trans, TRUE);
228 gst_pad_set_query_function (trans->srcpad, gst_audio_resample_query);
229 gst_pad_set_query_type_function (trans->srcpad,
230 gst_audio_resample_query_type);
235 gst_audio_resample_start (GstBaseTransform * base)
237 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
239 resample->need_discont = TRUE;
241 resample->num_gap_samples = 0;
242 resample->num_nongap_samples = 0;
243 resample->t0 = GST_CLOCK_TIME_NONE;
244 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
245 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
246 resample->samples_in = 0;
247 resample->samples_out = 0;
249 resample->tmp_in = NULL;
250 resample->tmp_in_size = 0;
251 resample->tmp_out = NULL;
252 resample->tmp_out_size = 0;
258 gst_audio_resample_stop (GstBaseTransform * base)
260 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
262 if (resample->state) {
263 resample->funcs->destroy (resample->state);
264 resample->state = NULL;
267 resample->funcs = NULL;
269 g_free (resample->tmp_in);
270 resample->tmp_in = NULL;
271 resample->tmp_in_size = 0;
273 g_free (resample->tmp_out);
274 resample->tmp_out = NULL;
275 resample->tmp_out_size = 0;
277 gst_caps_replace (&resample->sinkcaps, NULL);
278 gst_caps_replace (&resample->srccaps, NULL);
284 gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
287 gint width, channels;
288 GstStructure *structure;
291 g_return_val_if_fail (size != NULL, FALSE);
293 /* this works for both float and int */
294 structure = gst_caps_get_structure (caps, 0);
295 ret = gst_structure_get_int (structure, "width", &width);
296 ret &= gst_structure_get_int (structure, "channels", &channels);
298 if (G_UNLIKELY (!ret))
301 *size = (width / 8) * channels;
307 gst_audio_resample_transform_caps (GstBaseTransform * base,
308 GstPadDirection direction, GstCaps * caps)
314 /* transform single caps into input_caps + input_caps with the rate
315 * field set to our supported range. This ensures that upstream knows
316 * about downstream's prefered rate(s) and can negotiate accordingly. */
317 res = gst_caps_copy (caps);
319 /* first, however, check if the caps contain a range for the rate field, in
320 * which case that side isn't going to care much about the exact sample rate
321 * chosen and we should just assume things will get fixated to something sane
322 * and we may just as well offer our full range instead of the range in the
323 * caps. If the rate is not an int range value, it's likely to express a
324 * real preference or limitation and we should maintain that structure as
325 * preference by putting it first into the transformed caps, and only add
326 * our full rate range as second option */
327 s = gst_caps_get_structure (res, 0);
328 val = gst_structure_get_value (s, "rate");
329 if (val == NULL || GST_VALUE_HOLDS_INT_RANGE (val)) {
330 /* overwrite existing range, or add field if it doesn't exist yet */
331 gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
333 /* append caps with full range to existing caps with non-range rate field */
334 s = gst_structure_copy (s);
335 gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
336 gst_caps_append_structure (res, s);
342 /* Fixate rate to the allowed rate that has the smallest difference */
344 gst_audio_resample_fixate_caps (GstBaseTransform * base,
345 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
350 s = gst_caps_get_structure (caps, 0);
351 if (G_UNLIKELY (!gst_structure_get_int (s, "rate", &rate)))
354 s = gst_caps_get_structure (othercaps, 0);
355 gst_structure_fixate_field_nearest_int (s, "rate", rate);
358 static const SpeexResampleFuncs *
359 gst_audio_resample_get_funcs (gint width, gboolean fp)
361 const SpeexResampleFuncs *funcs = NULL;
363 if (gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
365 else if ((!gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
366 || (width == 32 && fp))
367 funcs = &float_funcs;
368 else if ((width == 64 && fp) || ((width == 32 || width == 24) && !fp))
369 funcs = &double_funcs;
371 g_assert_not_reached ();
376 static SpeexResamplerState *
377 gst_audio_resample_init_state (GstAudioResample * resample, gint width,
378 gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
380 SpeexResamplerState *ret = NULL;
381 gint err = RESAMPLER_ERR_SUCCESS;
382 const SpeexResampleFuncs *funcs = gst_audio_resample_get_funcs (width, fp);
384 ret = funcs->init (channels, inrate, outrate, quality, &err);
386 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
387 GST_ERROR_OBJECT (resample, "Failed to create resampler state: %s",
388 funcs->strerror (err));
392 funcs->skip_zeros (ret);
398 gst_audio_resample_update_state (GstAudioResample * resample, gint width,
399 gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
402 gboolean updated_latency = FALSE;
404 updated_latency = (resample->inrate != inrate
405 || quality != resample->quality) && resample->state != NULL;
407 if (resample->state == NULL) {
409 } else if (resample->channels != channels || fp != resample->fp
410 || width != resample->width) {
411 resample->funcs->destroy (resample->state);
413 gst_audio_resample_init_state (resample, width, channels, inrate,
414 outrate, quality, fp);
416 resample->funcs = gst_audio_resample_get_funcs (width, fp);
417 ret = (resample->state != NULL);
418 } else if (resample->inrate != inrate || resample->outrate != outrate) {
419 gint err = RESAMPLER_ERR_SUCCESS;
421 err = resample->funcs->set_rate (resample->state, inrate, outrate);
423 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
424 GST_ERROR_OBJECT (resample, "Failed to update rate: %s",
425 resample->funcs->strerror (err));
427 ret = (err == RESAMPLER_ERR_SUCCESS);
428 } else if (quality != resample->quality) {
429 gint err = RESAMPLER_ERR_SUCCESS;
431 err = resample->funcs->set_quality (resample->state, quality);
433 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
434 GST_ERROR_OBJECT (resample, "Failed to update quality: %s",
435 resample->funcs->strerror (err));
437 ret = (err == RESAMPLER_ERR_SUCCESS);
440 resample->width = width;
441 resample->channels = channels;
443 resample->quality = quality;
444 resample->inrate = inrate;
445 resample->outrate = outrate;
448 gst_element_post_message (GST_ELEMENT (resample),
449 gst_message_new_latency (GST_OBJECT (resample)));
455 gst_audio_resample_reset_state (GstAudioResample * resample)
458 resample->funcs->reset_mem (resample->state);
462 gst_audio_resample_parse_caps (GstCaps * incaps,
463 GstCaps * outcaps, gint * width, gint * channels, gint * inrate,
464 gint * outrate, gboolean * fp)
466 GstStructure *structure;
468 gint mywidth, myinrate, myoutrate, mychannels;
471 GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
472 GST_PTR_FORMAT, incaps, outcaps);
474 structure = gst_caps_get_structure (incaps, 0);
476 if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float"))
481 ret = gst_structure_get_int (structure, "rate", &myinrate);
482 ret &= gst_structure_get_int (structure, "channels", &mychannels);
483 ret &= gst_structure_get_int (structure, "width", &mywidth);
484 if (G_UNLIKELY (!ret))
485 goto no_in_rate_channels;
487 structure = gst_caps_get_structure (outcaps, 0);
488 ret = gst_structure_get_int (structure, "rate", &myoutrate);
489 if (G_UNLIKELY (!ret))
493 *channels = mychannels;
497 *outrate = myoutrate;
508 GST_DEBUG ("could not get input rate and channels");
513 GST_DEBUG ("could not get output rate");
519 _gcd (gint a, gint b)
532 gst_audio_resample_transform_size (GstBaseTransform * base,
533 GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
537 guint32 ratio_den, ratio_num;
538 gint inrate, outrate, gcd;
539 gint bytes_per_samp, channels;
541 GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
542 size, direction == GST_PAD_SINK ? "SINK" : "SRC");
544 /* Get sample width -> bytes_per_samp, channels, inrate, outrate */
546 gst_audio_resample_parse_caps (caps, othercaps, &bytes_per_samp,
547 &channels, &inrate, &outrate, NULL);
548 if (G_UNLIKELY (!ret)) {
549 GST_ERROR_OBJECT (base, "Wrong caps");
552 /* Number of samples in either buffer is size / (width*channels) ->
553 * calculate the factor */
554 bytes_per_samp = bytes_per_samp * channels / 8;
555 /* Convert source buffer size to samples */
556 size /= bytes_per_samp;
558 /* Simplify the conversion ratio factors */
559 gcd = _gcd (inrate, outrate);
560 ratio_num = inrate / gcd;
561 ratio_den = outrate / gcd;
563 if (direction == GST_PAD_SINK) {
564 /* asked to convert size of an incoming buffer. Round up the output size */
565 *othersize = gst_util_uint64_scale_int_ceil (size, ratio_den, ratio_num);
566 *othersize *= bytes_per_samp;
568 /* asked to convert size of an outgoing buffer. Round down the input size */
569 *othersize = gst_util_uint64_scale_int (size, ratio_num, ratio_den);
570 *othersize *= bytes_per_samp;
573 GST_LOG_OBJECT (base, "transformed size %d to %d", size * bytes_per_samp,
580 gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
584 gint width = 0, inrate = 0, outrate = 0, channels = 0;
586 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
588 GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %"
589 GST_PTR_FORMAT, incaps, outcaps);
591 ret = gst_audio_resample_parse_caps (incaps, outcaps,
592 &width, &channels, &inrate, &outrate, &fp);
594 if (G_UNLIKELY (!ret))
598 gst_audio_resample_update_state (resample, width, channels, inrate,
599 outrate, resample->quality, fp);
601 if (G_UNLIKELY (!ret))
604 /* save caps so we can short-circuit in the size_transform if the caps
606 gst_caps_replace (&resample->sinkcaps, incaps);
607 gst_caps_replace (&resample->srccaps, outcaps);
612 #define GST_MAXINT24 (8388607)
613 #define GST_MININT24 (-8388608)
615 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
616 #define GST_READ_UINT24 GST_READ_UINT24_LE
617 #define GST_WRITE_UINT24 GST_WRITE_UINT24_LE
619 #define GST_READ_UINT24 GST_READ_UINT24_BE
620 #define GST_WRITE_UINT24 GST_WRITE_UINT24_BE
624 gst_audio_resample_convert_buffer (GstAudioResample * resample,
625 const guint8 * in, guint8 * out, guint len, gboolean inverse)
627 len *= resample->channels;
630 if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
631 gint8 *o = (gint8 *) out;
632 gint16 *i = (gint16 *) in;
636 tmp = *i + (G_MAXINT8 >> 1);
637 *o = CLAMP (tmp >> 8, G_MININT8, G_MAXINT8);
642 } else if (!gst_audio_resample_use_int && resample->width == 8
644 gint8 *o = (gint8 *) out;
645 gfloat *i = (gfloat *) in;
650 *o = (gint8) CLAMP (tmp * G_MAXINT8 + 0.5, G_MININT8, G_MAXINT8);
655 } else if (!gst_audio_resample_use_int && resample->width == 16
657 gint16 *o = (gint16 *) out;
658 gfloat *i = (gfloat *) in;
663 *o = (gint16) CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
668 } else if (resample->width == 24 && !resample->fp) {
669 guint8 *o = (guint8 *) out;
670 gdouble *i = (gdouble *) in;
675 GST_WRITE_UINT24 (o, (gint32) CLAMP (tmp * GST_MAXINT24 + 0.5,
676 GST_MININT24, GST_MAXINT24));
681 } else if (resample->width == 32 && !resample->fp) {
682 gint32 *o = (gint32 *) out;
683 gdouble *i = (gdouble *) in;
688 *o = (gint32) CLAMP (tmp * G_MAXINT32 + 0.5, G_MININT32, G_MAXINT32);
694 g_assert_not_reached ();
697 if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
698 gint8 *i = (gint8 *) in;
699 gint16 *o = (gint16 *) out;
709 } else if (!gst_audio_resample_use_int && resample->width == 8
711 gint8 *i = (gint8 *) in;
712 gfloat *o = (gfloat *) out;
717 *o = tmp / G_MAXINT8;
722 } else if (!gst_audio_resample_use_int && resample->width == 16
724 gint16 *i = (gint16 *) in;
725 gfloat *o = (gfloat *) out;
730 *o = tmp / G_MAXINT16;
735 } else if (resample->width == 24 && !resample->fp) {
736 guint8 *i = (guint8 *) in;
737 gdouble *o = (gdouble *) out;
742 tmp2 = GST_READ_UINT24 (i);
743 if (tmp2 & 0x00800000)
746 *o = tmp / GST_MAXINT24;
751 } else if (resample->width == 32 && !resample->fp) {
752 gint32 *i = (gint32 *) in;
753 gdouble *o = (gdouble *) out;
758 *o = tmp / G_MAXINT32;
764 g_assert_not_reached ();
770 gst_audio_resample_workspace_realloc (guint8 ** workspace, guint * size,
774 if (new_size <= *size)
775 /* no need to resize */
777 new = g_realloc (*workspace, new_size);
779 /* failure (re)allocating memeory */
787 /* Push history_len zeros into the filter, but discard the output. */
789 gst_audio_resample_dump_drain (GstAudioResample * resample, guint history_len)
792 guint in_len, in_processed;
793 guint out_len, out_processed;
797 g_assert (resample->state != NULL);
799 resample->funcs->get_ratio (resample->state, &num, &den);
801 in_len = in_processed = history_len;
802 out_processed = out_len =
803 gst_util_uint64_scale_int_ceil (history_len, den, num);
804 outsize = out_len * resample->channels * (resample->funcs->width / 8);
809 buf = g_malloc (outsize);
810 resample->funcs->process (resample->state, NULL, &in_processed, buf,
814 g_assert (in_len == in_processed);
818 gst_audio_resample_push_drain (GstAudioResample * resample, guint history_len)
823 guint in_len, in_processed;
824 guint out_len, out_processed;
828 g_assert (resample->state != NULL);
830 /* Don't drain samples if we were reset. */
831 if (!GST_CLOCK_TIME_IS_VALID (resample->t0))
834 resample->funcs->get_ratio (resample->state, &num, &den);
836 in_len = in_processed = history_len;
837 out_len = out_processed =
838 gst_util_uint64_scale_int_ceil (history_len, den, num);
839 outsize = out_len * resample->channels * (resample->width / 8);
845 gst_pad_alloc_buffer_and_set_caps (GST_BASE_TRANSFORM_SRC_PAD (resample),
846 GST_BUFFER_OFFSET_NONE, outsize,
847 GST_PAD_CAPS (GST_BASE_TRANSFORM_SRC_PAD (resample)), &outbuf);
848 if (G_UNLIKELY (res != GST_FLOW_OK)) {
849 GST_WARNING_OBJECT (resample, "failed allocating buffer of %d bytes",
854 if (resample->funcs->width != resample->width) {
855 /* need to convert data format; allocate workspace */
856 if (!gst_audio_resample_workspace_realloc (&resample->tmp_out,
857 &resample->tmp_out_size, (resample->funcs->width / 8) * out_len *
858 resample->channels)) {
859 GST_ERROR_OBJECT (resample, "failed to allocate workspace");
864 err = resample->funcs->process (resample->state, NULL, &in_processed,
865 resample->tmp_out, &out_processed);
867 /* convert output format */
868 gst_audio_resample_convert_buffer (resample, resample->tmp_out,
869 GST_BUFFER_DATA (outbuf), out_processed, TRUE);
871 /* don't need to convert data format; process */
872 err = resample->funcs->process (resample->state, NULL, &in_processed,
873 GST_BUFFER_DATA (outbuf), &out_processed);
876 /* If we wrote more than allocated something is really wrong now
877 * and we should better abort immediately */
878 g_assert (out_len >= out_processed);
880 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
881 GST_WARNING_OBJECT (resample, "Failed to process drain: %s",
882 resample->funcs->strerror (err));
883 gst_buffer_unref (outbuf);
888 if (GST_CLOCK_TIME_IS_VALID (resample->t0)) {
889 GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 +
890 gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
892 GST_BUFFER_DURATION (outbuf) = resample->t0 +
893 gst_util_uint64_scale_int_round (resample->samples_out + out_processed,
894 GST_SECOND, resample->outrate) - GST_BUFFER_TIMESTAMP (outbuf);
896 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
897 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
900 if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
901 GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out;
902 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_processed;
904 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
905 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
908 resample->samples_out += out_processed;
909 resample->samples_in += history_len;
911 if (G_UNLIKELY (out_processed == 0 && in_len * den > num)) {
912 GST_WARNING_OBJECT (resample, "Failed to get drain, dropping buffer");
913 gst_buffer_unref (outbuf);
917 GST_BUFFER_SIZE (outbuf) =
918 out_processed * resample->channels * (resample->width / 8);
920 GST_LOG_OBJECT (resample,
921 "Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT
922 " duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT " offset_end %"
923 G_GUINT64_FORMAT, GST_BUFFER_SIZE (outbuf),
924 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
925 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
926 GST_BUFFER_OFFSET_END (outbuf));
928 res = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (resample), outbuf);
930 if (G_UNLIKELY (res != GST_FLOW_OK))
931 GST_WARNING_OBJECT (resample, "Failed to push drain: %s",
932 gst_flow_get_name (res));
938 gst_audio_resample_event (GstBaseTransform * base, GstEvent * event)
940 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
942 switch (GST_EVENT_TYPE (event)) {
943 case GST_EVENT_FLUSH_STOP:
944 gst_audio_resample_reset_state (resample);
946 resample->funcs->skip_zeros (resample->state);
947 resample->num_gap_samples = 0;
948 resample->num_nongap_samples = 0;
949 resample->t0 = GST_CLOCK_TIME_NONE;
950 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
951 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
952 resample->samples_in = 0;
953 resample->samples_out = 0;
954 resample->need_discont = TRUE;
956 case GST_EVENT_NEWSEGMENT:
957 if (resample->state) {
958 guint latency = resample->funcs->get_input_latency (resample->state);
959 gst_audio_resample_push_drain (resample, latency);
961 gst_audio_resample_reset_state (resample);
963 resample->funcs->skip_zeros (resample->state);
964 resample->num_gap_samples = 0;
965 resample->num_nongap_samples = 0;
966 resample->t0 = GST_CLOCK_TIME_NONE;
967 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
968 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
969 resample->samples_in = 0;
970 resample->samples_out = 0;
971 resample->need_discont = TRUE;
974 if (resample->state) {
975 guint latency = resample->funcs->get_input_latency (resample->state);
976 gst_audio_resample_push_drain (resample, latency);
978 gst_audio_resample_reset_state (resample);
984 return parent_class->event (base, event);
988 gst_audio_resample_check_discont (GstAudioResample * resample, GstBuffer * buf)
993 /* is the incoming buffer a discontinuity? */
994 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf)))
997 /* no valid timestamps or offsets to compare --> no discontinuity */
998 if (G_UNLIKELY (!(GST_BUFFER_TIMESTAMP_IS_VALID (buf) &&
999 GST_CLOCK_TIME_IS_VALID (resample->t0))))
1002 /* convert the inbound timestamp to an offset. */
1004 gst_util_uint64_scale_int_round (GST_BUFFER_TIMESTAMP (buf) -
1005 resample->t0, resample->inrate, GST_SECOND);
1007 /* many elements generate imperfect streams due to rounding errors, so we
1008 * permit a small error (up to one sample) without triggering a filter
1009 * flush/restart (if triggered incorrectly, this will be audible) */
1010 /* allow even up to more samples, since sink is not so strict anyway,
1011 * so give that one a chance to handle this as configured */
1012 delta = ABS ((gint64) (offset - resample->samples_in));
1013 if (delta <= (resample->inrate >> 5))
1016 GST_WARNING_OBJECT (resample,
1017 "encountered timestamp discontinuity of %" G_GUINT64_FORMAT " samples = %"
1018 GST_TIME_FORMAT, delta,
1019 GST_TIME_ARGS (gst_util_uint64_scale_int_round (delta, GST_SECOND,
1020 resample->inrate)));
1024 static GstFlowReturn
1025 gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
1028 guint32 in_len, in_processed;
1029 guint32 out_len, out_processed;
1030 guint filt_len = resample->funcs->get_filt_len (resample->state);
1032 in_len = GST_BUFFER_SIZE (inbuf) / resample->channels;
1033 out_len = GST_BUFFER_SIZE (outbuf) / resample->channels;
1035 in_len /= (resample->width / 8);
1036 out_len /= (resample->width / 8);
1038 in_processed = in_len;
1039 out_processed = out_len;
1041 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
1042 resample->num_nongap_samples = 0;
1043 if (resample->num_gap_samples < filt_len) {
1044 guint zeros_to_push;
1045 if (in_len >= filt_len - resample->num_gap_samples)
1046 zeros_to_push = filt_len - resample->num_gap_samples;
1048 zeros_to_push = in_len;
1050 gst_audio_resample_push_drain (resample, zeros_to_push);
1051 in_len -= zeros_to_push;
1052 resample->num_gap_samples += zeros_to_push;
1057 resample->funcs->get_ratio (resample->state, &num, &den);
1058 if (resample->samples_in + in_len >= filt_len / 2)
1060 gst_util_uint64_scale_int_ceil (resample->samples_in + in_len -
1061 filt_len / 2, den, num) - resample->samples_out;
1065 memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));
1066 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
1067 resample->num_gap_samples += in_len;
1068 in_processed = in_len;
1070 } else { /* not a gap */
1074 if (resample->num_gap_samples > filt_len) {
1075 /* push in enough zeros to restore the filter to the right offset */
1077 resample->funcs->get_ratio (resample->state, &num, &den);
1078 gst_audio_resample_dump_drain (resample,
1079 (resample->num_gap_samples - filt_len) % num);
1081 resample->num_gap_samples = 0;
1082 if (resample->num_nongap_samples < filt_len) {
1083 resample->num_nongap_samples += in_len;
1084 if (resample->num_nongap_samples > filt_len)
1085 resample->num_nongap_samples = filt_len;
1088 if (resample->funcs->width != resample->width) {
1089 /* need to convert data format for processing; ensure we have enough
1090 * workspace available */
1091 if (!gst_audio_resample_workspace_realloc (&resample->tmp_in,
1092 &resample->tmp_in_size, in_len * resample->channels *
1093 (resample->funcs->width / 8)) ||
1094 !gst_audio_resample_workspace_realloc (&resample->tmp_out,
1095 &resample->tmp_out_size, out_len * resample->channels *
1096 (resample->funcs->width / 8))) {
1097 GST_ERROR_OBJECT (resample, "failed to allocate workspace");
1098 return GST_FLOW_ERROR;
1102 gst_audio_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf),
1103 resample->tmp_in, in_len, FALSE);
1106 err = resample->funcs->process (resample->state,
1107 resample->tmp_in, &in_processed, resample->tmp_out, &out_processed);
1109 /* convert output */
1110 gst_audio_resample_convert_buffer (resample, resample->tmp_out,
1111 GST_BUFFER_DATA (outbuf), out_processed, TRUE);
1113 /* no format conversion required; process */
1114 err = resample->funcs->process (resample->state,
1115 GST_BUFFER_DATA (inbuf), &in_processed,
1116 GST_BUFFER_DATA (outbuf), &out_processed);
1119 if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
1120 GST_ERROR_OBJECT (resample, "Failed to convert data: %s",
1121 resample->funcs->strerror (err));
1122 return GST_FLOW_ERROR;
1126 /* If we wrote more than allocated something is really wrong now and we
1127 * should better abort immediately */
1128 g_assert (out_len >= out_processed);
1130 if (G_UNLIKELY (in_len != in_processed)) {
1131 GST_WARNING_OBJECT (resample, "converted %d of %d input samples",
1132 in_processed, in_len);
1136 if (GST_CLOCK_TIME_IS_VALID (resample->t0)) {
1137 GST_BUFFER_TIMESTAMP (outbuf) = resample->t0 +
1138 gst_util_uint64_scale_int_round (resample->samples_out, GST_SECOND,
1140 GST_BUFFER_DURATION (outbuf) = resample->t0 +
1141 gst_util_uint64_scale_int_round (resample->samples_out + out_processed,
1142 GST_SECOND, resample->outrate) - GST_BUFFER_TIMESTAMP (outbuf);
1144 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
1145 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1148 if (resample->out_offset0 != GST_BUFFER_OFFSET_NONE) {
1149 GST_BUFFER_OFFSET (outbuf) = resample->out_offset0 + resample->samples_out;
1150 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + out_processed;
1152 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
1153 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
1156 resample->samples_out += out_processed;
1157 resample->samples_in += in_len;
1159 GST_BUFFER_SIZE (outbuf) =
1160 out_processed * resample->channels * (resample->width / 8);
1162 GST_LOG_OBJECT (resample,
1163 "Converted to buffer of %" G_GUINT32_FORMAT
1164 " samples (%u bytes) with timestamp %" GST_TIME_FORMAT ", duration %"
1165 GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT ", offset_end %"
1166 G_GUINT64_FORMAT, out_processed, GST_BUFFER_SIZE (outbuf),
1167 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1168 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1169 GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
1171 if (out_processed == 0) {
1172 GST_DEBUG_OBJECT (resample, "buffer dropped");
1173 return GST_BASE_TRANSFORM_FLOW_DROPPED;
1178 static GstFlowReturn
1179 gst_audio_resample_transform (GstBaseTransform * base, GstBuffer * inbuf,
1182 GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
1186 if (resample->state == NULL) {
1187 if (G_UNLIKELY (!(resample->state =
1188 gst_audio_resample_init_state (resample, resample->width,
1189 resample->channels, resample->inrate, resample->outrate,
1190 resample->quality, resample->fp))))
1191 return GST_FLOW_ERROR;
1194 gst_audio_resample_get_funcs (resample->width, resample->fp);
1197 size = GST_BUFFER_SIZE (inbuf);
1199 GST_LOG_OBJECT (resample, "transforming buffer of %ld bytes, ts %"
1200 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
1201 G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
1202 size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
1203 GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
1204 GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
1206 /* check for timestamp discontinuities; flush/reset if needed, and set
1207 * flag to resync timestamp and offset counters and send event
1209 if (G_UNLIKELY (gst_audio_resample_check_discont (resample, inbuf))) {
1210 gst_audio_resample_reset_state (resample);
1211 resample->need_discont = TRUE;
1214 /* handle discontinuity */
1215 if (G_UNLIKELY (resample->need_discont)) {
1216 resample->funcs->skip_zeros (resample->state);
1217 resample->num_gap_samples = 0;
1218 resample->num_nongap_samples = 0;
1220 resample->samples_in = 0;
1221 resample->samples_out = 0;
1222 GST_DEBUG_OBJECT (resample, "found discontinuity; resyncing");
1223 /* resync the timestamp and offset counters if possible */
1224 if (GST_BUFFER_TIMESTAMP_IS_VALID (inbuf)) {
1225 resample->t0 = GST_BUFFER_TIMESTAMP (inbuf);
1227 GST_DEBUG_OBJECT (resample, "... but new timestamp is invalid");
1228 resample->t0 = GST_CLOCK_TIME_NONE;
1230 if (GST_BUFFER_OFFSET_IS_VALID (inbuf)) {
1231 resample->in_offset0 = GST_BUFFER_OFFSET (inbuf);
1232 resample->out_offset0 =
1233 gst_util_uint64_scale_int_round (resample->in_offset0,
1234 resample->outrate, resample->inrate);
1236 GST_DEBUG_OBJECT (resample, "... but new offset is invalid");
1237 resample->in_offset0 = GST_BUFFER_OFFSET_NONE;
1238 resample->out_offset0 = GST_BUFFER_OFFSET_NONE;
1240 /* set DISCONT flag on output buffer */
1241 GST_DEBUG_OBJECT (resample, "marking this buffer with the DISCONT flag");
1242 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1243 resample->need_discont = FALSE;
1246 ret = gst_audio_resample_process (resample, inbuf, outbuf);
1247 if (G_UNLIKELY (ret != GST_FLOW_OK))
1250 GST_DEBUG_OBJECT (resample, "input = samples [%" G_GUINT64_FORMAT ", %"
1251 G_GUINT64_FORMAT ") = [%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT
1252 ") ns; output = samples [%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT
1253 ") = [%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ") ns",
1254 GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf),
1255 GST_BUFFER_TIMESTAMP (inbuf), GST_BUFFER_TIMESTAMP (inbuf) +
1256 GST_BUFFER_DURATION (inbuf), GST_BUFFER_OFFSET (outbuf),
1257 GST_BUFFER_OFFSET_END (outbuf), GST_BUFFER_TIMESTAMP (outbuf),
1258 GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf));
1264 gst_audio_resample_query (GstPad * pad, GstQuery * query)
1266 GstAudioResample *resample = GST_AUDIO_RESAMPLE (gst_pad_get_parent (pad));
1267 GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
1268 gboolean res = TRUE;
1270 switch (GST_QUERY_TYPE (query)) {
1271 case GST_QUERY_LATENCY:
1273 GstClockTime min, max;
1277 gint rate = resample->inrate;
1278 gint resampler_latency;
1280 if (resample->state)
1282 resample->funcs->get_input_latency (resample->state);
1284 resampler_latency = 0;
1286 if (gst_base_transform_is_passthrough (trans))
1287 resampler_latency = 0;
1289 if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM_SINK_PAD (trans)))) {
1290 if ((res = gst_pad_query (peer, query))) {
1291 gst_query_parse_latency (query, &live, &min, &max);
1293 GST_DEBUG_OBJECT (resample, "Peer latency: min %"
1294 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1295 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1297 /* add our own latency */
1298 if (rate != 0 && resampler_latency != 0)
1299 latency = gst_util_uint64_scale_round (resampler_latency,
1304 GST_DEBUG_OBJECT (resample, "Our latency: %" GST_TIME_FORMAT,
1305 GST_TIME_ARGS (latency));
1308 if (GST_CLOCK_TIME_IS_VALID (max))
1311 GST_DEBUG_OBJECT (resample, "Calculated total latency : min %"
1312 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1313 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1315 gst_query_set_latency (query, live, min, max);
1317 gst_object_unref (peer);
1322 res = gst_pad_query_default (pad, query);
1325 gst_object_unref (resample);
1329 static const GstQueryType *
1330 gst_audio_resample_query_type (GstPad * pad)
1332 static const GstQueryType types[] = {
1341 gst_audio_resample_set_property (GObject * object, guint prop_id,
1342 const GValue * value, GParamSpec * pspec)
1344 GstAudioResample *resample;
1346 resample = GST_AUDIO_RESAMPLE (object);
1350 GST_BASE_TRANSFORM_LOCK (resample);
1351 resample->quality = g_value_get_int (value);
1352 GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
1354 gst_audio_resample_update_state (resample, resample->width,
1355 resample->channels, resample->inrate, resample->outrate,
1356 resample->quality, resample->fp);
1357 GST_BASE_TRANSFORM_UNLOCK (resample);
1359 case PROP_FILTER_LENGTH:{
1360 gint filter_length = g_value_get_int (value);
1362 GST_BASE_TRANSFORM_LOCK (resample);
1363 if (filter_length <= 8)
1364 resample->quality = 0;
1365 else if (filter_length <= 16)
1366 resample->quality = 1;
1367 else if (filter_length <= 32)
1368 resample->quality = 2;
1369 else if (filter_length <= 48)
1370 resample->quality = 3;
1371 else if (filter_length <= 64)
1372 resample->quality = 4;
1373 else if (filter_length <= 80)
1374 resample->quality = 5;
1375 else if (filter_length <= 96)
1376 resample->quality = 6;
1377 else if (filter_length <= 128)
1378 resample->quality = 7;
1379 else if (filter_length <= 160)
1380 resample->quality = 8;
1381 else if (filter_length <= 192)
1382 resample->quality = 9;
1384 resample->quality = 10;
1386 GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
1388 gst_audio_resample_update_state (resample, resample->width,
1389 resample->channels, resample->inrate, resample->outrate,
1390 resample->quality, resample->fp);
1391 GST_BASE_TRANSFORM_UNLOCK (resample);
1395 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1401 gst_audio_resample_get_property (GObject * object, guint prop_id,
1402 GValue * value, GParamSpec * pspec)
1404 GstAudioResample *resample;
1406 resample = GST_AUDIO_RESAMPLE (object);
1410 g_value_set_int (value, resample->quality);
1412 case PROP_FILTER_LENGTH:
1413 switch (resample->quality) {
1415 g_value_set_int (value, 8);
1418 g_value_set_int (value, 16);
1421 g_value_set_int (value, 32);
1424 g_value_set_int (value, 48);
1427 g_value_set_int (value, 64);
1430 g_value_set_int (value, 80);
1433 g_value_set_int (value, 96);
1436 g_value_set_int (value, 128);
1439 g_value_set_int (value, 160);
1442 g_value_set_int (value, 192);
1445 g_value_set_int (value, 256);
1450 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1455 /* FIXME: should have a benchmark fallback for the case where orc is disabled */
1456 #if defined(AUDIORESAMPLE_FORMAT_AUTO) && !defined(DISABLE_ORC)
1458 #define BENCHMARK_SIZE 512
1461 _benchmark_int_float (SpeexResamplerState * st)
1463 gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
1464 gfloat in_tmp[BENCHMARK_SIZE], out_tmp[BENCHMARK_SIZE / 2];
1466 guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
1468 for (i = 0; i < BENCHMARK_SIZE; i++) {
1470 in_tmp[i] = tmp / G_MAXINT16;
1473 resample_float_resampler_process_interleaved_float (st,
1474 (const guint8 *) in_tmp, &inlen, (guint8 *) out_tmp, &outlen);
1477 GST_ERROR ("Failed to use float resampler");
1481 for (i = 0; i < outlen; i++) {
1482 gfloat tmp = out_tmp[i];
1483 out[i] = CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
1490 _benchmark_int_int (SpeexResamplerState * st)
1492 gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
1493 guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
1495 resample_int_resampler_process_interleaved_int (st, (const guint8 *) in,
1496 &inlen, (guint8 *) out, &outlen);
1499 GST_ERROR ("Failed to use int resampler");
1507 _benchmark_integer_resampling (void)
1511 SpeexResamplerState *sta, *stb;
1514 orc_profile_init (&a);
1515 orc_profile_init (&b);
1517 sta = resample_float_resampler_init (1, 48000, 24000, 4, NULL);
1519 GST_ERROR ("Failed to create float resampler state");
1523 stb = resample_int_resampler_init (1, 48000, 24000, 4, NULL);
1525 resample_float_resampler_destroy (sta);
1526 GST_ERROR ("Failed to create int resampler state");
1531 for (i = 0; i < 10; i++) {
1532 orc_profile_start (&a);
1533 if (!_benchmark_int_float (sta))
1535 orc_profile_stop (&a);
1539 for (i = 0; i < 10; i++) {
1540 orc_profile_start (&b);
1541 if (!_benchmark_int_int (stb))
1543 orc_profile_stop (&b);
1546 /* Handle results */
1547 orc_profile_get_ave_std (&a, &av, NULL);
1548 orc_profile_get_ave_std (&b, &bv, NULL);
1550 /* Remember benchmark result in global variable */
1551 gst_audio_resample_use_int = (av > bv);
1552 resample_float_resampler_destroy (sta);
1553 resample_int_resampler_destroy (stb);
1556 GST_INFO ("Using integer resampler if appropiate: %lf < %lf", bv, av);
1558 GST_INFO ("Using float resampler for everything: %lf <= %lf", av, bv);
1563 resample_float_resampler_destroy (sta);
1564 resample_int_resampler_destroy (stb);
1568 #endif /* defined(AUDIORESAMPLE_FORMAT_AUTO) && !defined(DISABLE_ORC) */
1571 plugin_init (GstPlugin * plugin)
1573 GST_DEBUG_CATEGORY_INIT (audio_resample_debug, "audioresample", 0,
1574 "audio resampling element");
1576 #if defined(AUDIORESAMPLE_FORMAT_AUTO) && !defined(DISABLE_ORC)
1577 if (!_benchmark_integer_resampling ())
1580 GST_WARNING ("Orc disabled, can't benchmark int vs. float resampler");
1582 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
1583 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
1584 GST_CAT_WARNING (GST_CAT_PERFORMANCE, "orc disabled, no benchmarking done");
1588 if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
1589 GST_TYPE_AUDIO_RESAMPLE)) {
1596 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1599 "Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1600 GST_PACKAGE_ORIGIN);