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 */
29 /*#define DEBUG_ENABLED */
30 #include "gstaudioresample.h"
31 #include <gst/audio/audio.h>
32 #include <gst/base/gstbasetransform.h>
34 GST_DEBUG_CATEGORY_STATIC (audioresample_debug);
35 #define GST_CAT_DEFAULT audioresample_debug
37 /* elementfactory information */
38 static GstElementDetails gst_audioresample_details =
39 GST_ELEMENT_DETAILS ("Audio scaler",
40 "Filter/Converter/Audio",
42 "David Schleef <ds@schleef.org>");
44 /* GstAudioresample signals and args */
57 #define SUPPORTED_CAPS \
60 "rate = (int) [ 1, MAX ], " \
61 "channels = (int) [ 1, MAX ], " \
62 "endianness = (int) BYTE_ORDER, " \
63 "width = (int) 16, " \
64 "depth = (int) 16, " \
65 "signed = (boolean) true " \
69 /* disabled because it segfaults */
71 "rate = (int) [ 1, MAX ], "
72 "channels = (int) [ 1, MAX ], "
73 "endianness = (int) BYTE_ORDER, " "width = (int) 32")
75 static GstStaticPadTemplate gst_audioresample_sink_template =
76 GST_STATIC_PAD_TEMPLATE ("sink",
77 GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
79 static GstStaticPadTemplate gst_audioresample_src_template =
80 GST_STATIC_PAD_TEMPLATE ("src",
81 GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
83 static void gst_audioresample_base_init (gpointer g_class);
84 static void gst_audioresample_class_init (GstAudioresampleClass * klass);
85 static void gst_audioresample_init (GstAudioresample * audioresample);
86 static void gst_audioresample_dispose (GObject * object);
88 static void gst_audioresample_set_property (GObject * object,
89 guint prop_id, const GValue * value, GParamSpec * pspec);
90 static void gst_audioresample_get_property (GObject * object,
91 guint prop_id, GValue * value, GParamSpec * pspec);
94 gboolean audioresample_get_unit_size (GstBaseTransform * base,
95 GstCaps * caps, guint * size);
96 GstCaps *audioresample_transform_caps (GstBaseTransform * base,
97 GstPadDirection direction, GstCaps * caps);
98 gboolean audioresample_transform_size (GstBaseTransform * trans,
99 GstPadDirection direction, GstCaps * incaps, guint insize,
100 GstCaps * outcaps, guint * outsize);
101 gboolean audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
103 static GstFlowReturn audioresample_transform (GstBaseTransform * base,
104 GstBuffer * inbuf, GstBuffer * outbuf);
106 /*static guint gst_audioresample_signals[LAST_SIGNAL] = { 0 }; */
108 #define DEBUG_INIT(bla) \
109 GST_DEBUG_CATEGORY_INIT (audioresample_debug, "audioresample", 0, "audio resampling element");
111 GST_BOILERPLATE_FULL (GstAudioresample, gst_audioresample, GstBaseTransform,
112 GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
114 static void gst_audioresample_base_init (gpointer g_class)
116 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
118 gst_element_class_add_pad_template (gstelement_class,
119 gst_static_pad_template_get (&gst_audioresample_src_template));
120 gst_element_class_add_pad_template (gstelement_class,
121 gst_static_pad_template_get (&gst_audioresample_sink_template));
123 gst_element_class_set_details (gstelement_class,
124 &gst_audioresample_details);
127 static void gst_audioresample_class_init (GstAudioresampleClass * klass)
129 GObjectClass *gobject_class;
131 gobject_class = (GObjectClass *) klass;
133 gobject_class->set_property = gst_audioresample_set_property;
134 gobject_class->get_property = gst_audioresample_get_property;
135 gobject_class->dispose = gst_audioresample_dispose;
137 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILTERLEN,
138 g_param_spec_int ("filter_length", "filter_length", "filter_length",
139 0, G_MAXINT, 16, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
141 GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
142 GST_DEBUG_FUNCPTR (audioresample_transform_size);
143 GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
144 GST_DEBUG_FUNCPTR (audioresample_get_unit_size);
145 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
146 GST_DEBUG_FUNCPTR (audioresample_transform_caps);
147 GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
148 GST_DEBUG_FUNCPTR (audioresample_set_caps);
149 GST_BASE_TRANSFORM_CLASS (klass)->transform =
150 GST_DEBUG_FUNCPTR (audioresample_transform);
153 static void gst_audioresample_init (GstAudioresample * audioresample)
158 audioresample->resample = r;
160 resample_set_filter_length (r, 64);
161 resample_set_format (r, RESAMPLE_FORMAT_S16);
164 static void gst_audioresample_dispose (GObject * object)
166 GstAudioresample *audioresample = GST_AUDIORESAMPLE (object);
168 if (audioresample->resample) {
169 resample_free (audioresample->resample);
170 audioresample->resample = NULL;
173 G_OBJECT_CLASS (parent_class)->dispose (object);
178 audioresample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
180 gint width, channels;
181 GstStructure *structure;
184 g_return_val_if_fail (size, FALSE);
186 /* this works for both float and int */
187 structure = gst_caps_get_structure (caps, 0);
188 ret = gst_structure_get_int (structure, "width", &width);
189 ret &= gst_structure_get_int (structure, "channels", &channels);
190 g_return_val_if_fail (ret, FALSE);
192 *size = width * channels / 8;
197 GstCaps *audioresample_transform_caps (GstBaseTransform * base,
198 GstPadDirection direction, GstCaps * caps)
201 const GstCaps *templcaps;
202 GstStructure *structure;
204 temp = gst_caps_copy (caps);
205 structure = gst_caps_get_structure (temp, 0);
206 gst_structure_remove_field (structure, "rate");
207 templcaps = gst_pad_get_pad_template_caps (base->srcpad);
208 res = gst_caps_intersect (templcaps, temp);
209 gst_caps_unref (temp);
215 resample_set_state_from_caps (ResampleState * state, GstCaps * incaps,
216 GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate)
218 GstStructure *structure;
220 gint myinrate, myoutrate;
223 GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
224 GST_PTR_FORMAT, incaps, outcaps);
226 structure = gst_caps_get_structure (incaps, 0);
228 /* FIXME: once it does float, set the correct format */
230 if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float")) {
231 r->format = GST_RESAMPLE_FLOAT;
233 r->format = GST_RESAMPLE_S16;
237 ret = gst_structure_get_int (structure, "rate", &myinrate);
238 ret &= gst_structure_get_int (structure, "channels", &mychannels);
239 g_return_val_if_fail (ret, FALSE);
241 structure = gst_caps_get_structure (outcaps, 0);
242 ret = gst_structure_get_int (structure, "rate", &myoutrate);
243 g_return_val_if_fail (ret, FALSE);
246 *channels = mychannels;
250 *outrate = myoutrate;
252 resample_set_n_channels (state, mychannels);
253 resample_set_input_rate (state, myinrate);
254 resample_set_output_rate (state, myoutrate);
260 audioresample_transform_size (GstBaseTransform * base,
261 GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
263 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
264 ResampleState *state;
265 GstCaps *srccaps, *sinkcaps;
266 gboolean use_internal = FALSE; /* whether we use the internal state */
269 GST_DEBUG_OBJECT (base, "asked to transform size %d in direction %s",
270 size, direction == GST_PAD_SINK ? "SINK" : "SRC");
271 if (direction == GST_PAD_SINK) {
275 sinkcaps = othercaps;
279 /* if the caps are the ones that _set_caps got called with; we can use
280 * our own state; otherwise we'll have to create a state */
281 if (gst_caps_is_equal (sinkcaps, audioresample->sinkcaps) &&
282 gst_caps_is_equal (srccaps, audioresample->srccaps)) {
284 state = audioresample->resample;
286 GST_DEBUG_OBJECT (audioresample,
287 "caps are not the set caps, creating state");
288 state = resample_new ();
289 resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL);
292 if (direction == GST_PAD_SINK) {
293 /* asked to convert size of an incoming buffer */
294 *othersize = resample_get_output_size_for_input (state, size);
296 /* take a best guess, this is called cheating */
297 *othersize = floor (size * state->i_rate / state->o_rate);
298 *othersize -= *othersize % state->sample_size;
300 *othersize += state->sample_size;
302 g_assert (*othersize % state->sample_size == 0);
304 /* we make room for one extra sample, given that the resampling filter
305 * can output an extra one for non-integral i_rate/o_rate */
306 GST_DEBUG_OBJECT (base, "transformed size %d to %d", size, *othersize);
309 resample_free (state);
316 audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
319 gint inrate, outrate;
321 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
323 GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
324 GST_PTR_FORMAT, incaps, outcaps);
326 ret = resample_set_state_from_caps (audioresample->resample, incaps, outcaps,
327 &channels, &inrate, &outrate);
329 g_return_val_if_fail (ret, FALSE);
331 audioresample->channels = channels;
332 GST_DEBUG_OBJECT (audioresample, "set channels to %d", channels);
333 audioresample->i_rate = inrate;
334 GST_DEBUG_OBJECT (audioresample, "set i_rate to %d", inrate);
335 audioresample->o_rate = outrate;
336 GST_DEBUG_OBJECT (audioresample, "set o_rate to %d", outrate);
338 /* save caps so we can short-circuit in the size_transform if the caps
340 /* FIXME: clean them up in state change ? */
341 gst_caps_ref (incaps);
342 gst_caps_replace (&audioresample->sinkcaps, incaps);
343 gst_caps_ref (outcaps);
344 gst_caps_replace (&audioresample->srccaps, outcaps);
350 audioresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
354 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
361 /* FIXME: move to _inplace */
363 if (audioresample->passthru) {
364 gst_pad_push (audioresample->srcpad, GST_DATA (buf));
369 r = audioresample->resample;
371 data = GST_BUFFER_DATA (inbuf);
372 size = GST_BUFFER_SIZE (inbuf);
374 GST_DEBUG_OBJECT (audioresample, "got buffer of %ld bytes", size);
376 resample_add_input_data (r, data, size, NULL, NULL);
378 outsize = resample_get_output_size (r);
379 GST_DEBUG_OBJECT (audioresample, "audioresample can give me %d bytes",
382 /* protect against mem corruption */
383 if (outsize > GST_BUFFER_SIZE (outbuf)) {
384 GST_WARNING_OBJECT (audioresample,
385 "overriding audioresample's outsize %d with outbuffer's size %d",
386 outsize, GST_BUFFER_SIZE (outbuf));
387 outsize = GST_BUFFER_SIZE (outbuf);
389 /* catch possibly wrong size differences */
390 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
391 GST_WARNING_OBJECT (audioresample,
392 "audioresample's outsize %d too far from outbuffer's size %d",
393 outsize, GST_BUFFER_SIZE (outbuf));
396 outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize);
397 outsamples = outsize / r->sample_size;
398 GST_LOG_OBJECT (audioresample, "resample gave me %d bytes or %d samples",
399 outsize, outsamples);
401 GST_BUFFER_OFFSET (outbuf) = audioresample->offset;
402 GST_BUFFER_TIMESTAMP (outbuf) = base->segment_start +
403 audioresample->offset * GST_SECOND / audioresample->o_rate;
405 audioresample->offset += outsamples;
406 GST_BUFFER_OFFSET_END (outbuf) = audioresample->offset;
408 /* we calculate DURATION as the difference between "next" timestamp
409 * and current timestamp so we ensure a contiguous stream, instead of
410 * having rounding errors. */
411 GST_BUFFER_DURATION (outbuf) = base->segment_start +
412 audioresample->offset * GST_SECOND / audioresample->o_rate -
413 GST_BUFFER_TIMESTAMP (outbuf);
415 /* check for possible mem corruption */
416 if (outsize > GST_BUFFER_SIZE (outbuf)) {
417 /* this is an error that when it happens, would need fixing in the
418 * resample library; we told
419 * it we wanted only GST_BUFFER_SIZE (outbuf), and it gave us more ! */
420 GST_WARNING_OBJECT (audioresample,
421 "audioresample, you memory corrupting bastard. "
422 "you gave me outsize %d while my buffer was size %d",
423 outsize, GST_BUFFER_SIZE (outbuf));
424 return GST_FLOW_ERROR;
426 /* catch possibly wrong size differences */
427 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
428 GST_WARNING_OBJECT (audioresample,
429 "audioresample's written outsize %d too far from outbuffer's size %d",
430 outsize, GST_BUFFER_SIZE (outbuf));
437 gst_audioresample_set_property (GObject * object, guint prop_id,
438 const GValue * value, GParamSpec * pspec)
440 GstAudioresample *audioresample;
442 g_return_if_fail (GST_IS_AUDIORESAMPLE (object));
443 audioresample = GST_AUDIORESAMPLE (object);
447 audioresample->filter_length = g_value_get_int (value);
448 GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d",
449 audioresample->filter_length);
450 resample_set_filter_length (audioresample->resample,
451 audioresample->filter_length);
453 default:G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
459 gst_audioresample_get_property (GObject * object, guint prop_id,
460 GValue * value, GParamSpec * pspec)
462 GstAudioresample *audioresample;
464 g_return_if_fail (GST_IS_AUDIORESAMPLE (object));
465 audioresample = GST_AUDIORESAMPLE (object);
469 g_value_set_int (value, audioresample->filter_length);
472 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
478 static gboolean plugin_init (GstPlugin * plugin)
482 if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
483 GST_TYPE_AUDIORESAMPLE)) {
490 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
493 "Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN);