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
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.
36 * Last reviewed on 2006-03-02 (0.10.4)
46 /*#define DEBUG_ENABLED */
47 #include "gstaudioresample.h"
48 #include <gst/audio/audio.h>
49 #include <gst/base/gstbasetransform.h>
51 GST_DEBUG_CATEGORY_STATIC (audioresample_debug);
52 #define GST_CAT_DEFAULT audioresample_debug
54 /* elementfactory information */
55 static const GstElementDetails gst_audioresample_details =
56 GST_ELEMENT_DETAILS ("Audio scaler",
57 "Filter/Converter/Audio",
59 "David Schleef <ds@schleef.org>");
61 #define DEFAULT_FILTERLEN 16
69 #define SUPPORTED_CAPS \
72 "rate = (int) [ 1, MAX ], " \
73 "channels = (int) [ 1, MAX ], " \
74 "endianness = (int) BYTE_ORDER, " \
75 "width = (int) 16, " \
76 "depth = (int) 16, " \
77 "signed = (boolean) true;" \
79 "rate = (int) [ 1, MAX ], " \
80 "channels = (int) [ 1, MAX ], " \
81 "endianness = (int) BYTE_ORDER, " \
82 "width = (int) 32, " \
83 "depth = (int) 32, " \
84 "signed = (boolean) true;" \
85 "audio/x-raw-float, " \
86 "rate = (int) [ 1, MAX ], " \
87 "channels = (int) [ 1, MAX ], " \
88 "endianness = (int) BYTE_ORDER, " \
89 "width = (int) 32; " \
90 "audio/x-raw-float, " \
91 "rate = (int) [ 1, MAX ], " \
92 "channels = (int) [ 1, MAX ], " \
93 "endianness = (int) BYTE_ORDER, " \
97 static GstStaticPadTemplate gst_audioresample_sink_template =
98 GST_STATIC_PAD_TEMPLATE ("sink",
99 GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
101 static GstStaticPadTemplate gst_audioresample_src_template =
102 GST_STATIC_PAD_TEMPLATE ("src",
103 GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
105 static void gst_audioresample_set_property (GObject * object,
106 guint prop_id, const GValue * value, GParamSpec * pspec);
107 static void gst_audioresample_get_property (GObject * object,
108 guint prop_id, GValue * value, GParamSpec * pspec);
111 static gboolean audioresample_get_unit_size (GstBaseTransform * base,
112 GstCaps * caps, guint * size);
113 static GstCaps *audioresample_transform_caps (GstBaseTransform * base,
114 GstPadDirection direction, GstCaps * caps);
115 static gboolean audioresample_transform_size (GstBaseTransform * trans,
116 GstPadDirection direction, GstCaps * incaps, guint insize,
117 GstCaps * outcaps, guint * outsize);
118 static gboolean audioresample_set_caps (GstBaseTransform * base,
119 GstCaps * incaps, GstCaps * outcaps);
120 static GstFlowReturn audioresample_pushthrough (GstAudioresample *
122 static GstFlowReturn audioresample_transform (GstBaseTransform * base,
123 GstBuffer * inbuf, GstBuffer * outbuf);
124 static gboolean audioresample_event (GstBaseTransform * base, GstEvent * event);
125 static gboolean audioresample_start (GstBaseTransform * base);
126 static gboolean audioresample_stop (GstBaseTransform * base);
128 static gboolean audioresample_query (GstPad * pad, GstQuery * query);
129 static const GstQueryType *audioresample_query_type (GstPad * pad);
131 #define DEBUG_INIT(bla) \
132 GST_DEBUG_CATEGORY_INIT (audioresample_debug, "audioresample", 0, "audio resampling element");
134 GST_BOILERPLATE_FULL (GstAudioresample, gst_audioresample, GstBaseTransform,
135 GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
138 gst_audioresample_base_init (gpointer g_class)
140 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
142 gst_element_class_add_pad_template (gstelement_class,
143 gst_static_pad_template_get (&gst_audioresample_src_template));
144 gst_element_class_add_pad_template (gstelement_class,
145 gst_static_pad_template_get (&gst_audioresample_sink_template));
147 gst_element_class_set_details (gstelement_class, &gst_audioresample_details);
151 gst_audioresample_class_init (GstAudioresampleClass * klass)
153 GObjectClass *gobject_class;
155 gobject_class = (GObjectClass *) klass;
157 gobject_class->set_property = gst_audioresample_set_property;
158 gobject_class->get_property = gst_audioresample_get_property;
160 g_object_class_install_property (gobject_class, PROP_FILTERLEN,
161 g_param_spec_int ("filter-length", "filter length",
162 "Length of the resample filter", 0, G_MAXINT, DEFAULT_FILTERLEN,
163 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
165 GST_BASE_TRANSFORM_CLASS (klass)->start =
166 GST_DEBUG_FUNCPTR (audioresample_start);
167 GST_BASE_TRANSFORM_CLASS (klass)->stop =
168 GST_DEBUG_FUNCPTR (audioresample_stop);
169 GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
170 GST_DEBUG_FUNCPTR (audioresample_transform_size);
171 GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
172 GST_DEBUG_FUNCPTR (audioresample_get_unit_size);
173 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
174 GST_DEBUG_FUNCPTR (audioresample_transform_caps);
175 GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
176 GST_DEBUG_FUNCPTR (audioresample_set_caps);
177 GST_BASE_TRANSFORM_CLASS (klass)->transform =
178 GST_DEBUG_FUNCPTR (audioresample_transform);
179 GST_BASE_TRANSFORM_CLASS (klass)->event =
180 GST_DEBUG_FUNCPTR (audioresample_event);
182 GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
186 gst_audioresample_init (GstAudioresample * audioresample,
187 GstAudioresampleClass * klass)
189 GstBaseTransform *trans;
191 trans = GST_BASE_TRANSFORM (audioresample);
193 /* buffer alloc passthrough is too impossible. FIXME, it
194 * is trivial in the passthrough case. */
195 gst_pad_set_bufferalloc_function (trans->sinkpad, NULL);
197 audioresample->filter_length = DEFAULT_FILTERLEN;
199 audioresample->need_discont = FALSE;
201 gst_pad_set_query_function (trans->srcpad, audioresample_query);
202 gst_pad_set_query_type_function (trans->srcpad, audioresample_query_type);
207 audioresample_start (GstBaseTransform * base)
209 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
211 audioresample->resample = resample_new ();
212 audioresample->ts_offset = -1;
213 audioresample->offset = -1;
214 audioresample->next_ts = -1;
216 resample_set_filter_length (audioresample->resample,
217 audioresample->filter_length);
223 audioresample_stop (GstBaseTransform * base)
225 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
227 if (audioresample->resample) {
228 resample_free (audioresample->resample);
229 audioresample->resample = NULL;
232 gst_caps_replace (&audioresample->sinkcaps, NULL);
233 gst_caps_replace (&audioresample->srccaps, NULL);
239 audioresample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
242 gint width, channels;
243 GstStructure *structure;
248 /* this works for both float and int */
249 structure = gst_caps_get_structure (caps, 0);
250 ret = gst_structure_get_int (structure, "width", &width);
251 ret &= gst_structure_get_int (structure, "channels", &channels);
252 g_return_val_if_fail (ret, FALSE);
254 *size = width * channels / 8;
260 audioresample_transform_caps (GstBaseTransform * base,
261 GstPadDirection direction, GstCaps * caps)
264 GstStructure *structure;
266 /* transform caps gives one single caps so we can just replace
267 * the rate property with our range. */
268 res = gst_caps_copy (caps);
269 structure = gst_caps_get_structure (res, 0);
270 gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
276 resample_set_state_from_caps (ResampleState * state, GstCaps * incaps,
277 GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate)
279 GstStructure *structure;
281 gint myinrate, myoutrate;
284 ResampleFormat format;
286 GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
287 GST_PTR_FORMAT, incaps, outcaps);
289 structure = gst_caps_get_structure (incaps, 0);
292 ret = gst_structure_get_int (structure, "width", &width);
296 /* figure out the format */
297 if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float")) {
299 format = RESAMPLE_FORMAT_F32;
300 else if (width == 64)
301 format = RESAMPLE_FORMAT_F64;
305 /* for int, depth and width must be the same */
306 ret = gst_structure_get_int (structure, "depth", &depth);
307 if (!ret || width != depth)
311 format = RESAMPLE_FORMAT_S16;
312 else if (width == 32)
313 format = RESAMPLE_FORMAT_S32;
317 ret = gst_structure_get_int (structure, "rate", &myinrate);
318 ret &= gst_structure_get_int (structure, "channels", &mychannels);
320 goto no_in_rate_channels;
322 structure = gst_caps_get_structure (outcaps, 0);
323 ret = gst_structure_get_int (structure, "rate", &myoutrate);
328 *channels = mychannels;
332 *outrate = myoutrate;
334 resample_set_format (state, format);
335 resample_set_n_channels (state, mychannels);
336 resample_set_input_rate (state, myinrate);
337 resample_set_output_rate (state, myoutrate);
344 GST_DEBUG ("failed to get width from caps");
349 GST_DEBUG ("width %d and depth %d must be the same", width, depth);
354 GST_DEBUG ("unknown depth %d found", depth);
359 GST_DEBUG ("could not get input rate and channels");
364 GST_DEBUG ("could not get output rate");
370 audioresample_transform_size (GstBaseTransform * base,
371 GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
374 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
375 ResampleState *state;
376 GstCaps *srccaps, *sinkcaps;
377 gboolean use_internal = FALSE; /* whether we use the internal state */
380 GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
381 size, direction == GST_PAD_SINK ? "SINK" : "SRC");
382 if (direction == GST_PAD_SINK) {
386 sinkcaps = othercaps;
390 /* if the caps are the ones that _set_caps got called with; we can use
391 * our own state; otherwise we'll have to create a state */
392 if (gst_caps_is_equal (sinkcaps, audioresample->sinkcaps) &&
393 gst_caps_is_equal (srccaps, audioresample->srccaps)) {
395 state = audioresample->resample;
397 GST_DEBUG_OBJECT (audioresample,
398 "caps are not the set caps, creating state");
399 state = resample_new ();
400 resample_set_filter_length (state, audioresample->filter_length);
401 resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL);
404 if (direction == GST_PAD_SINK) {
405 /* asked to convert size of an incoming buffer */
406 *othersize = resample_get_output_size_for_input (state, size);
408 /* asked to convert size of an outgoing buffer */
409 *othersize = resample_get_input_size_for_output (state, size);
411 g_assert (*othersize % state->sample_size == 0);
413 /* we make room for one extra sample, given that the resampling filter
414 * can output an extra one for non-integral i_rate/o_rate */
415 GST_LOG_OBJECT (base, "transformed size %d to %d", size, *othersize);
418 resample_free (state);
425 audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
429 gint inrate, outrate;
431 GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
433 GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
434 GST_PTR_FORMAT, incaps, outcaps);
436 ret = resample_set_state_from_caps (audioresample->resample, incaps, outcaps,
437 &channels, &inrate, &outrate);
439 g_return_val_if_fail (ret, FALSE);
441 audioresample->channels = channels;
442 GST_DEBUG_OBJECT (audioresample, "set channels to %d", channels);
443 audioresample->i_rate = inrate;
444 GST_DEBUG_OBJECT (audioresample, "set i_rate to %d", inrate);
445 audioresample->o_rate = outrate;
446 GST_DEBUG_OBJECT (audioresample, "set o_rate to %d", outrate);
448 /* save caps so we can short-circuit in the size_transform if the caps
450 gst_caps_replace (&audioresample->sinkcaps, incaps);
451 gst_caps_replace (&audioresample->srccaps, outcaps);
457 audioresample_event (GstBaseTransform * base, GstEvent * event)
459 GstAudioresample *audioresample;
461 audioresample = GST_AUDIORESAMPLE (base);
463 switch (GST_EVENT_TYPE (event)) {
464 case GST_EVENT_FLUSH_START:
466 case GST_EVENT_FLUSH_STOP:
467 resample_input_flush (audioresample->resample);
468 audioresample->ts_offset = -1;
469 audioresample->next_ts = -1;
470 audioresample->offset = -1;
472 case GST_EVENT_NEWSEGMENT:
473 resample_input_pushthrough (audioresample->resample);
474 audioresample_pushthrough (audioresample);
475 audioresample->ts_offset = -1;
476 audioresample->next_ts = -1;
477 audioresample->offset = -1;
480 resample_input_eos (audioresample->resample);
481 audioresample_pushthrough (audioresample);
486 parent_class->event (base, event);
492 audioresample_do_output (GstAudioresample * audioresample, GstBuffer * outbuf)
498 r = audioresample->resample;
500 outsize = resample_get_output_size (r);
501 GST_LOG_OBJECT (audioresample, "audioresample can give me %d bytes", outsize);
503 /* protect against mem corruption */
504 if (outsize > GST_BUFFER_SIZE (outbuf)) {
505 GST_WARNING_OBJECT (audioresample,
506 "overriding audioresample's outsize %d with outbuffer's size %d",
507 outsize, GST_BUFFER_SIZE (outbuf));
508 outsize = GST_BUFFER_SIZE (outbuf);
510 /* catch possibly wrong size differences */
511 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
512 GST_WARNING_OBJECT (audioresample,
513 "audioresample's outsize %d too far from outbuffer's size %d",
514 outsize, GST_BUFFER_SIZE (outbuf));
517 outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize);
518 outsamples = outsize / r->sample_size;
519 GST_LOG_OBJECT (audioresample, "resample gave me %d bytes or %d samples",
520 outsize, outsamples);
522 GST_BUFFER_OFFSET (outbuf) = audioresample->offset;
523 GST_BUFFER_TIMESTAMP (outbuf) = audioresample->next_ts;
525 if (audioresample->ts_offset != -1) {
526 audioresample->offset += outsamples;
527 audioresample->ts_offset += outsamples;
528 audioresample->next_ts =
529 gst_util_uint64_scale_int (audioresample->ts_offset, GST_SECOND,
530 audioresample->o_rate);
531 GST_BUFFER_OFFSET_END (outbuf) = audioresample->offset;
533 /* we calculate DURATION as the difference between "next" timestamp
534 * and current timestamp so we ensure a contiguous stream, instead of
535 * having rounding errors. */
536 GST_BUFFER_DURATION (outbuf) = audioresample->next_ts -
537 GST_BUFFER_TIMESTAMP (outbuf);
539 /* no valid offset know, we can still sortof calculate the duration though */
540 GST_BUFFER_DURATION (outbuf) =
541 gst_util_uint64_scale_int (outsamples, GST_SECOND,
542 audioresample->o_rate);
545 /* check for possible mem corruption */
546 if (outsize > GST_BUFFER_SIZE (outbuf)) {
547 /* this is an error that when it happens, would need fixing in the
548 * resample library; we told it we wanted only GST_BUFFER_SIZE (outbuf),
549 * and it gave us more ! */
550 GST_WARNING_OBJECT (audioresample,
551 "audioresample, you memory corrupting bastard. "
552 "you gave me outsize %d while my buffer was size %d",
553 outsize, GST_BUFFER_SIZE (outbuf));
554 return GST_FLOW_ERROR;
556 /* catch possibly wrong size differences */
557 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
558 GST_WARNING_OBJECT (audioresample,
559 "audioresample's written outsize %d too far from outbuffer's size %d",
560 outsize, GST_BUFFER_SIZE (outbuf));
562 GST_BUFFER_SIZE (outbuf) = outsize;
564 if (G_UNLIKELY (audioresample->need_discont)) {
565 GST_DEBUG_OBJECT (audioresample,
566 "marking this buffer with the DISCONT flag");
567 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
568 audioresample->need_discont = FALSE;
571 GST_LOG_OBJECT (audioresample, "transformed to buffer of %d bytes, ts %"
572 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
573 G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
574 outsize, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
575 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
576 GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
583 audioresample_check_discont (GstAudioresample * audioresample,
584 GstClockTime timestamp)
586 if (timestamp != GST_CLOCK_TIME_NONE &&
587 audioresample->prev_ts != GST_CLOCK_TIME_NONE &&
588 audioresample->prev_duration != GST_CLOCK_TIME_NONE &&
589 timestamp != audioresample->prev_ts + audioresample->prev_duration) {
590 /* Potentially a discontinuous buffer. However, it turns out that many
591 * elements generate imperfect streams due to rounding errors, so we permit
592 * a small error (up to one sample) without triggering a filter
593 * flush/restart (if triggered incorrectly, this will be audible) */
594 GstClockTimeDiff diff = timestamp -
595 (audioresample->prev_ts + audioresample->prev_duration);
597 if (ABS (diff) > GST_SECOND / audioresample->i_rate) {
598 GST_WARNING_OBJECT (audioresample,
599 "encountered timestamp discontinuity of %" G_GINT64_FORMAT, diff);
608 audioresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
611 GstAudioresample *audioresample;
613 guchar *data, *datacopy;
615 GstClockTime timestamp;
617 audioresample = GST_AUDIORESAMPLE (base);
618 r = audioresample->resample;
620 data = GST_BUFFER_DATA (inbuf);
621 size = GST_BUFFER_SIZE (inbuf);
622 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
624 GST_LOG_OBJECT (audioresample, "transforming buffer of %ld bytes, ts %"
625 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
626 G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
627 size, GST_TIME_ARGS (timestamp),
628 GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
629 GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
631 /* check for timestamp discontinuities and flush/reset if needed */
632 if (G_UNLIKELY (audioresample_check_discont (audioresample, timestamp))) {
633 /* Flush internal samples */
634 audioresample_pushthrough (audioresample);
635 /* Inform downstream element about discontinuity */
636 audioresample->need_discont = TRUE;
637 /* We want to recalculate the offset */
638 audioresample->ts_offset = -1;
641 if (audioresample->ts_offset == -1) {
642 /* if we don't know the initial offset yet, calculate it based on the
643 * input timestamp. */
644 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
647 /* offset used to calculate the timestamps. We use the sample offset for
648 * this to make it more accurate. We want the first buffer to have the
649 * same timestamp as the incoming timestamp. */
650 audioresample->next_ts = timestamp;
651 audioresample->ts_offset =
652 gst_util_uint64_scale_int (timestamp, r->o_rate, GST_SECOND);
653 /* offset used to set as the buffer offset, this offset is always
654 * relative to the stream time, note that timestamp is not... */
655 stime = (timestamp - base->segment.start) + base->segment.time;
656 audioresample->offset =
657 gst_util_uint64_scale_int (stime, r->o_rate, GST_SECOND);
660 audioresample->prev_ts = timestamp;
661 audioresample->prev_duration = GST_BUFFER_DURATION (inbuf);
663 /* need to memdup, resample takes ownership. */
664 datacopy = g_memdup (data, size);
665 resample_add_input_data (r, datacopy, size, g_free, datacopy);
667 return audioresample_do_output (audioresample, outbuf);
670 /* push remaining data in the buffers out */
672 audioresample_pushthrough (GstAudioresample * audioresample)
677 GstFlowReturn res = GST_FLOW_OK;
678 GstBaseTransform *trans;
680 r = audioresample->resample;
682 outsize = resample_get_output_size (r);
684 GST_DEBUG_OBJECT (audioresample, "no internal buffers needing flush");
688 trans = GST_BASE_TRANSFORM (audioresample);
690 res = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET_NONE, outsize,
691 GST_PAD_CAPS (trans->srcpad), &outbuf);
692 if (G_UNLIKELY (res != GST_FLOW_OK)) {
693 GST_WARNING_OBJECT (audioresample, "failed allocating buffer of %d bytes",
698 res = audioresample_do_output (audioresample, outbuf);
699 if (G_UNLIKELY (res != GST_FLOW_OK))
702 res = gst_pad_push (trans->srcpad, outbuf);
709 audioresample_query (GstPad * pad, GstQuery * query)
711 GstAudioresample *audioresample =
712 GST_AUDIORESAMPLE (gst_pad_get_parent (pad));
713 GstBaseTransform *trans = GST_BASE_TRANSFORM (audioresample);
716 switch (GST_QUERY_TYPE (query)) {
717 case GST_QUERY_LATENCY:
719 GstClockTime min, max;
723 gint rate = audioresample->i_rate;
724 gint resampler_latency = audioresample->filter_length / 2;
726 if (gst_base_transform_is_passthrough (trans))
727 resampler_latency = 0;
729 if ((peer = gst_pad_get_peer (trans->sinkpad))) {
730 if ((res = gst_pad_query (peer, query))) {
731 gst_query_parse_latency (query, &live, &min, &max);
733 GST_DEBUG ("Peer latency: min %"
734 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
735 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
737 /* add our own latency */
738 if (rate != 0 && resampler_latency != 0)
740 gst_util_uint64_scale (resampler_latency, GST_SECOND, rate);
744 GST_DEBUG ("Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
747 if (max != GST_CLOCK_TIME_NONE)
750 GST_DEBUG ("Calculated total latency : min %"
751 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
752 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
754 gst_query_set_latency (query, live, min, max);
756 gst_object_unref (peer);
761 res = gst_pad_query_default (pad, query);
764 gst_object_unref (audioresample);
768 static const GstQueryType *
769 audioresample_query_type (GstPad * pad)
771 static const GstQueryType types[] = {
780 gst_audioresample_set_property (GObject * object, guint prop_id,
781 const GValue * value, GParamSpec * pspec)
783 GstAudioresample *audioresample;
785 audioresample = GST_AUDIORESAMPLE (object);
789 audioresample->filter_length = g_value_get_int (value);
790 GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d",
791 audioresample->filter_length);
792 if (audioresample->resample) {
793 resample_set_filter_length (audioresample->resample,
794 audioresample->filter_length);
795 gst_element_post_message (GST_ELEMENT (audioresample),
796 gst_message_new_latency (GST_OBJECT (audioresample)));
800 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
806 gst_audioresample_get_property (GObject * object, guint prop_id,
807 GValue * value, GParamSpec * pspec)
809 GstAudioresample *audioresample;
811 audioresample = GST_AUDIORESAMPLE (object);
815 g_value_set_int (value, audioresample->filter_length);
818 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
825 plugin_init (GstPlugin * plugin)
829 if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
830 GST_TYPE_AUDIORESAMPLE)) {
837 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
840 "Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,