2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 /* Element-Checklist-Version: 5 */
23 * SECTION:element-audioresample
26 * Audioresample resamples raw audio buffers to different sample rates using
27 * a configurable windowing function to enhance quality.
28 * <title>Example launch line</title>
31 * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw-int, rate=8000 ! alsasink
33 * Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
34 * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
38 * Last reviewed on 2006-03-02 (0.10.4)
48 /*#define DEBUG_ENABLED */
49 #include "gstaudioresample.h"
50 #include <gst/audio/audio.h>
51 #include <gst/base/gstbasetransform.h>
53 GST_DEBUG_CATEGORY (audioresample_debug);
54 #define GST_CAT_DEFAULT audioresample_debug
56 /* elementfactory information */
57 static GstElementDetails gst_audioresample_details =
58 GST_ELEMENT_DETAILS ("Audio scaler",
59 "Filter/Converter/Audio",
61 "David Schleef <ds@schleef.org>");
63 /* GstAudioresample signals and args */
70 #define DEFAULT_FILTERLEN 16
78 #define SUPPORTED_CAPS \
81 "rate = (int) [ 1, MAX ], " \
82 "channels = (int) [ 1, MAX ], " \
83 "endianness = (int) BYTE_ORDER, " \
84 "width = (int) 16, " \
85 "depth = (int) 16, " \
86 "signed = (boolean) true;" \
88 "rate = (int) [ 1, MAX ], " \
89 "channels = (int) [ 1, MAX ], " \
90 "endianness = (int) BYTE_ORDER, " \
91 "width = (int) 32, " \
92 "depth = (int) 32, " \
93 "signed = (boolean) true;" \
94 "audio/x-raw-float, " \
95 "rate = (int) [ 1, MAX ], " \
96 "channels = (int) [ 1, MAX ], " \
97 "endianness = (int) BYTE_ORDER, " \
98 "width = (int) 32; " \
99 "audio/x-raw-float, " \
100 "rate = (int) [ 1, MAX ], " \
101 "channels = (int) [ 1, MAX ], " \
102 "endianness = (int) BYTE_ORDER, " \
106 static GstStaticPadTemplate gst_audioresample_sink_template =
107 GST_STATIC_PAD_TEMPLATE ("sink",
108 GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
110 static GstStaticPadTemplate gst_audioresample_src_template =
111 GST_STATIC_PAD_TEMPLATE ("src",
112 GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
114 static void gst_audioresample_dispose (GObject * object);
116 static void gst_audioresample_set_property (GObject * object,
117 guint prop_id, const GValue * value, GParamSpec * pspec);
118 static void gst_audioresample_get_property (GObject * object,
119 guint prop_id, GValue * value, GParamSpec * pspec);
122 gboolean audioresample_get_unit_size (GstBaseTransform * base,
123 GstCaps * caps, guint * size);
124 GstCaps *audioresample_transform_caps (GstBaseTransform * base,
125 GstPadDirection direction, GstCaps * caps);
126 gboolean audioresample_transform_size (GstBaseTransform * trans,
127 GstPadDirection direction, GstCaps * incaps, guint insize,
128 GstCaps * outcaps, guint * outsize);
129 gboolean audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
131 static GstFlowReturn audioresample_pushthrough (GstAudioresample *
133 static GstFlowReturn audioresample_transform (GstBaseTransform * base,
134 GstBuffer * inbuf, GstBuffer * outbuf);
135 static gboolean audioresample_event (GstBaseTransform * base, GstEvent * event);
137 /*static guint gst_audioresample_signals[LAST_SIGNAL] = { 0 }; */
139 #define DEBUG_INIT(bla) \
140 GST_DEBUG_CATEGORY_INIT (audioresample_debug, "audioresample", 0, "audio resampling element");
142 GST_BOILERPLATE_FULL (GstAudioresample, gst_audioresample, GstBaseTransform,
143 GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
146 gst_audioresample_base_init (gpointer g_class)
148 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
150 gst_element_class_add_pad_template (gstelement_class,
151 gst_static_pad_template_get (&gst_audioresample_src_template));
152 gst_element_class_add_pad_template (gstelement_class,
153 gst_static_pad_template_get (&gst_audioresample_sink_template));
155 gst_element_class_set_details (gstelement_class, &gst_audioresample_details);
159 gst_audioresample_class_init (GstAudioresampleClass * klass)
161 GObjectClass *gobject_class;
163 gobject_class = (GObjectClass *) klass;
165 gobject_class->set_property = gst_audioresample_set_property;
166 gobject_class->get_property = gst_audioresample_get_property;
167 gobject_class->dispose = gst_audioresample_dispose;
169 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTERLEN,
170 g_param_spec_int ("filter_length", "filter_length", "filter_length",
171 0, G_MAXINT, DEFAULT_FILTERLEN,
172 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
174 GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
175 GST_DEBUG_FUNCPTR (audioresample_transform_size);
176 GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
177 GST_DEBUG_FUNCPTR (audioresample_get_unit_size);
178 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
179 GST_DEBUG_FUNCPTR (audioresample_transform_caps);
180 GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
181 GST_DEBUG_FUNCPTR (audioresample_set_caps);
182 GST_BASE_TRANSFORM_CLASS (klass)->transform =
183 GST_DEBUG_FUNCPTR (audioresample_transform);
184 GST_BASE_TRANSFORM_CLASS (klass)->event =
185 GST_DEBUG_FUNCPTR (audioresample_event);
187 GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
191 gst_audioresample_init (GstAudioresample * audioresample,
192 GstAudioresampleClass * klass)
195 GstBaseTransform *trans;
197 trans = GST_BASE_TRANSFORM (audioresample);
199 /* buffer alloc passthrough is too impossible. FIXME, it
200 * is trivial in the passtrough case. */
201 gst_pad_set_bufferalloc_function (trans->sinkpad, NULL);
204 audioresample->resample = r;
205 audioresample->ts_offset = -1;
206 audioresample->offset = -1;
207 audioresample->next_ts = -1;
209 resample_set_filter_length (r, DEFAULT_FILTERLEN);
213 gst_audioresample_dispose (GObject * object)
215 GstAudioresample *audioresample = GST_AUDIORESAMPLE (object);
217 if (audioresample->resample) {
218 resample_free (audioresample->resample);
219 audioresample->resample = NULL;
222 G_OBJECT_CLASS (parent_class)->dispose (object);
227 audioresample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
230 gint width, channels;
231 GstStructure *structure;
234 g_return_val_if_fail (size, FALSE);
236 /* this works for both float and int */
237 structure = gst_caps_get_structure (caps, 0);
238 ret = gst_structure_get_int (structure, "width", &width);
239 ret &= gst_structure_get_int (structure, "channels", &channels);
240 g_return_val_if_fail (ret, FALSE);
242 *size = width * channels / 8;
248 audioresample_transform_caps (GstBaseTransform * base,
249 GstPadDirection direction, GstCaps * caps)
252 GstStructure *structure;
254 /* transform caps gives one single caps so we can just replace
255 * the rate property with our range. */
256 res = gst_caps_copy (caps);
257 structure = gst_caps_get_structure (res, 0);
258 gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
264 resample_set_state_from_caps (ResampleState * state, GstCaps * incaps,
265 GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate)
267 GstStructure *structure;
269 gint myinrate, myoutrate;
272 ResampleFormat format;
274 GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
275 GST_PTR_FORMAT, incaps, outcaps);
277 structure = gst_caps_get_structure (incaps, 0);
280 ret = gst_structure_get_int (structure, "width", &width);
284 /* figure out the format */
285 if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float")) {
287 format = RESAMPLE_FORMAT_F32;
288 else if (width == 64)
289 format = RESAMPLE_FORMAT_F64;
293 /* for int, depth and width must be the same */
294 ret = gst_structure_get_int (structure, "depth", &depth);
295 if (!ret || width != depth)
299 format = RESAMPLE_FORMAT_S16;
300 else if (width == 32)
301 format = RESAMPLE_FORMAT_S32;
305 ret = gst_structure_get_int (structure, "rate", &myinrate);
306 ret &= gst_structure_get_int (structure, "channels", &mychannels);
308 goto no_in_rate_channels;
310 structure = gst_caps_get_structure (outcaps, 0);
311 ret = gst_structure_get_int (structure, "rate", &myoutrate);
316 *channels = mychannels;
320 *outrate = myoutrate;
322 resample_set_format (state, format);
323 resample_set_n_channels (state, mychannels);
324 resample_set_input_rate (state, myinrate);
325 resample_set_output_rate (state, myoutrate);
332 GST_DEBUG ("failed to get width from caps");
337 GST_DEBUG ("width %d and depth %d must be the same", width, depth);
342 GST_DEBUG ("unknown depth %d found", depth);
347 GST_DEBUG ("could not get input rate and channels");
352 GST_DEBUG ("could not get output rate");
358 audioresample_transform_size (GstBaseTransform * base,
359 GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
362 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
363 ResampleState *state;
364 GstCaps *srccaps, *sinkcaps;
365 gboolean use_internal = FALSE; /* whether we use the internal state */
368 GST_DEBUG_OBJECT (base, "asked to transform size %d in direction %s",
369 size, direction == GST_PAD_SINK ? "SINK" : "SRC");
370 if (direction == GST_PAD_SINK) {
374 sinkcaps = othercaps;
378 /* if the caps are the ones that _set_caps got called with; we can use
379 * our own state; otherwise we'll have to create a state */
380 if (gst_caps_is_equal (sinkcaps, audioresample->sinkcaps) &&
381 gst_caps_is_equal (srccaps, audioresample->srccaps)) {
383 state = audioresample->resample;
385 GST_DEBUG_OBJECT (audioresample,
386 "caps are not the set caps, creating state");
387 state = resample_new ();
388 resample_set_filter_length (state, audioresample->filter_length);
389 resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL);
392 if (direction == GST_PAD_SINK) {
393 /* asked to convert size of an incoming buffer */
394 *othersize = resample_get_output_size_for_input (state, size);
396 /* asked to convert size of an outgoing buffer */
397 *othersize = resample_get_input_size_for_output (state, size);
399 g_assert (*othersize % state->sample_size == 0);
401 /* we make room for one extra sample, given that the resampling filter
402 * can output an extra one for non-integral i_rate/o_rate */
403 GST_DEBUG_OBJECT (base, "transformed size %d to %d", size, *othersize);
406 resample_free (state);
413 audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
417 gint inrate, outrate;
419 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
421 GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
422 GST_PTR_FORMAT, incaps, outcaps);
424 ret = resample_set_state_from_caps (audioresample->resample, incaps, outcaps,
425 &channels, &inrate, &outrate);
427 g_return_val_if_fail (ret, FALSE);
429 audioresample->channels = channels;
430 GST_DEBUG_OBJECT (audioresample, "set channels to %d", channels);
431 audioresample->i_rate = inrate;
432 GST_DEBUG_OBJECT (audioresample, "set i_rate to %d", inrate);
433 audioresample->o_rate = outrate;
434 GST_DEBUG_OBJECT (audioresample, "set o_rate to %d", outrate);
436 /* save caps so we can short-circuit in the size_transform if the caps
438 /* FIXME: clean them up in state change ? */
439 gst_caps_ref (incaps);
440 gst_caps_replace (&audioresample->sinkcaps, incaps);
441 gst_caps_ref (outcaps);
442 gst_caps_replace (&audioresample->srccaps, outcaps);
448 audioresample_event (GstBaseTransform * base, GstEvent * event)
450 GstAudioresample *audioresample;
452 audioresample = GST_AUDIORESAMPLE (base);
454 switch (GST_EVENT_TYPE (event)) {
455 case GST_EVENT_FLUSH_START:
457 case GST_EVENT_FLUSH_STOP:
458 resample_input_flush (audioresample->resample);
459 audioresample->ts_offset = -1;
460 audioresample->next_ts = -1;
461 audioresample->offset = -1;
463 case GST_EVENT_NEWSEGMENT:
464 resample_input_pushthrough (audioresample->resample);
465 audioresample_pushthrough (audioresample);
466 audioresample->ts_offset = -1;
467 audioresample->next_ts = -1;
468 audioresample->offset = -1;
471 resample_input_eos (audioresample->resample);
472 audioresample_pushthrough (audioresample);
477 parent_class->event (base, event);
483 audioresample_do_output (GstAudioresample * audioresample, GstBuffer * outbuf)
489 r = audioresample->resample;
491 outsize = resample_get_output_size (r);
492 GST_DEBUG_OBJECT (audioresample, "audioresample can give me %d bytes",
495 /* protect against mem corruption */
496 if (outsize > GST_BUFFER_SIZE (outbuf)) {
497 GST_WARNING_OBJECT (audioresample,
498 "overriding audioresample's outsize %d with outbuffer's size %d",
499 outsize, GST_BUFFER_SIZE (outbuf));
500 outsize = GST_BUFFER_SIZE (outbuf);
502 /* catch possibly wrong size differences */
503 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
504 GST_WARNING_OBJECT (audioresample,
505 "audioresample's outsize %d too far from outbuffer's size %d",
506 outsize, GST_BUFFER_SIZE (outbuf));
509 outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize);
510 outsamples = outsize / r->sample_size;
511 GST_LOG_OBJECT (audioresample, "resample gave me %d bytes or %d samples",
512 outsize, outsamples);
514 GST_BUFFER_OFFSET (outbuf) = audioresample->offset;
515 GST_BUFFER_TIMESTAMP (outbuf) = audioresample->next_ts;
517 if (audioresample->ts_offset != -1) {
518 audioresample->offset += outsamples;
519 audioresample->ts_offset += outsamples;
520 audioresample->next_ts =
521 gst_util_uint64_scale_int (audioresample->ts_offset, GST_SECOND,
522 audioresample->o_rate);
523 GST_BUFFER_OFFSET_END (outbuf) = audioresample->offset;
525 /* we calculate DURATION as the difference between "next" timestamp
526 * and current timestamp so we ensure a contiguous stream, instead of
527 * having rounding errors. */
528 GST_BUFFER_DURATION (outbuf) = audioresample->next_ts -
529 GST_BUFFER_TIMESTAMP (outbuf);
531 /* no valid offset know, we can still sortof calculate the duration though */
532 GST_BUFFER_DURATION (outbuf) =
533 gst_util_uint64_scale_int (outsamples, GST_SECOND,
534 audioresample->o_rate);
537 /* check for possible mem corruption */
538 if (outsize > GST_BUFFER_SIZE (outbuf)) {
539 /* this is an error that when it happens, would need fixing in the
540 * resample library; we told
541 * it we wanted only GST_BUFFER_SIZE (outbuf), and it gave us more ! */
542 GST_WARNING_OBJECT (audioresample,
543 "audioresample, you memory corrupting bastard. "
544 "you gave me outsize %d while my buffer was size %d",
545 outsize, GST_BUFFER_SIZE (outbuf));
546 return GST_FLOW_ERROR;
548 /* catch possibly wrong size differences */
549 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
550 GST_WARNING_OBJECT (audioresample,
551 "audioresample's written outsize %d too far from outbuffer's size %d",
552 outsize, GST_BUFFER_SIZE (outbuf));
554 GST_BUFFER_SIZE (outbuf) = outsize;
560 audioresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
563 GstAudioresample *audioresample;
565 guchar *data, *datacopy;
567 GstClockTime timestamp;
569 audioresample = GST_AUDIORESAMPLE (base);
570 r = audioresample->resample;
572 data = GST_BUFFER_DATA (inbuf);
573 size = GST_BUFFER_SIZE (inbuf);
574 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
576 GST_DEBUG_OBJECT (audioresample, "got buffer of %ld bytes", size);
578 if (audioresample->ts_offset == -1) {
579 /* if we don't know the initial offset yet, calculate it based on the
580 * input timestamp. */
581 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
584 /* offset used to calculate the timestamps. We use the sample offset for this
585 * to make it more accurate. We want the first buffer to have the same timestamp
586 * as the incomming timestamp. */
587 audioresample->next_ts = timestamp;
588 audioresample->ts_offset =
589 gst_util_uint64_scale_int (timestamp, r->o_rate, GST_SECOND);
590 /* offset used to set as the buffer offset, this offset is always relative
591 * to the stream time, note that timestamp is not... */
592 stime = (timestamp - base->segment.start) + base->segment.time;
593 audioresample->offset =
594 gst_util_uint64_scale_int (stime, r->o_rate, GST_SECOND);
598 /* need to memdup, resample takes ownership. */
599 datacopy = g_memdup (data, size);
600 resample_add_input_data (r, datacopy, size, g_free, datacopy);
602 return audioresample_do_output (audioresample, outbuf);
605 /* push remaining data in the buffers out */
607 audioresample_pushthrough (GstAudioresample * audioresample)
612 GstFlowReturn res = GST_FLOW_OK;
613 GstBaseTransform *trans;
615 r = audioresample->resample;
617 outsize = resample_get_output_size (r);
621 outbuf = gst_buffer_new_and_alloc (outsize);
623 res = audioresample_do_output (audioresample, outbuf);
624 if (res != GST_FLOW_OK)
627 trans = GST_BASE_TRANSFORM (audioresample);
629 res = gst_pad_push (trans->srcpad, outbuf);
637 gst_audioresample_set_property (GObject * object, guint prop_id,
638 const GValue * value, GParamSpec * pspec)
640 GstAudioresample *audioresample;
642 g_return_if_fail (GST_IS_AUDIORESAMPLE (object));
643 audioresample = GST_AUDIORESAMPLE (object);
647 audioresample->filter_length = g_value_get_int (value);
648 GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d",
649 audioresample->filter_length);
650 resample_set_filter_length (audioresample->resample,
651 audioresample->filter_length);
654 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
660 gst_audioresample_get_property (GObject * object, guint prop_id,
661 GValue * value, GParamSpec * pspec)
663 GstAudioresample *audioresample;
665 g_return_if_fail (GST_IS_AUDIORESAMPLE (object));
666 audioresample = GST_AUDIORESAMPLE (object);
670 g_value_set_int (value, audioresample->filter_length);
673 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
680 plugin_init (GstPlugin * plugin)
684 if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
685 GST_TYPE_AUDIORESAMPLE)) {
692 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
695 "Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,