blob: cbcd6fddc2becdddc2b613ebaf9de7ccdb4f6ccc [file] [log] [blame]
David Schleefbde8ec92005-08-23 19:29:38 +00001/* GStreamer
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +00002 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
David Schleefbde8ec92005-08-23 19:29:38 +00003 * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
4 *
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.
9 *
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.
14 *
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.
19 */
20/* Element-Checklist-Version: 5 */
21
Wim Taymans46369002006-03-02 18:23:55 +000022/**
Sebastian Dröge6ff76892008-11-28 09:49:56 +000023 * SECTION:element-legacyresample
Wim Taymans46369002006-03-02 18:23:55 +000024 *
Sebastian Dröge6ff76892008-11-28 09:49:56 +000025 * legacyresample resamples raw audio buffers to different sample rates using
Wim Taymans46369002006-03-02 18:23:55 +000026 * a configurable windowing function to enhance quality.
Stefan Kost9549b4e2008-07-10 21:06:03 +000027 *
28 * <refsect2>
Wim Taymans46369002006-03-02 18:23:55 +000029 * <title>Example launch line</title>
Stefan Kost9549b4e2008-07-10 21:06:03 +000030 * |[
Sebastian Dröge6ff76892008-11-28 09:49:56 +000031 * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! legacyresample ! audio/x-raw-int, rate=8000 ! alsasink
Stefan Kost9549b4e2008-07-10 21:06:03 +000032 * ]| Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
Wim Taymans46369002006-03-02 18:23:55 +000033 * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
Wim Taymans46369002006-03-02 18:23:55 +000034 * </refsect2>
35 *
36 * Last reviewed on 2006-03-02 (0.10.4)
37 */
38
David Schleefbde8ec92005-08-23 19:29:38 +000039#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +000042
David Schleefbde8ec92005-08-23 19:29:38 +000043#include <string.h>
44#include <math.h>
45
46/*#define DEBUG_ENABLED */
Sebastian Drögee4e3b442009-01-23 12:46:28 +010047#include "gstlegacyresample.h"
David Schleefbde8ec92005-08-23 19:29:38 +000048#include <gst/audio/audio.h>
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +000049#include <gst/base/gstbasetransform.h>
David Schleefbde8ec92005-08-23 19:29:38 +000050
Sebastian Drögee4e3b442009-01-23 12:46:28 +010051GST_DEBUG_CATEGORY_STATIC (legacyresample_debug);
52#define GST_CAT_DEFAULT legacyresample_debug
David Schleefbde8ec92005-08-23 19:29:38 +000053
54/* elementfactory information */
Sebastian Drögee4e3b442009-01-23 12:46:28 +010055static const GstElementDetails gst_legacyresample_details =
David Schleefbde8ec92005-08-23 19:29:38 +000056GST_ELEMENT_DETAILS ("Audio scaler",
57 "Filter/Converter/Audio",
58 "Resample audio",
59 "David Schleef <ds@schleef.org>");
60
Thomas Vander Stichelecefa8382005-12-06 19:42:02 +000061#define DEFAULT_FILTERLEN 16
Wim Taymansc962e652005-12-02 11:34:50 +000062
David Schleefbde8ec92005-08-23 19:29:38 +000063enum
64{
Wim Taymans46369002006-03-02 18:23:55 +000065 PROP_0,
66 PROP_FILTERLEN
David Schleefbde8ec92005-08-23 19:29:38 +000067};
68
69#define SUPPORTED_CAPS \
Thomas Vander Stichele0daade22005-08-25 12:31:31 +000070GST_STATIC_CAPS ( \
David Schleefbde8ec92005-08-23 19:29:38 +000071 "audio/x-raw-int, " \
72 "rate = (int) [ 1, MAX ], " \
73 "channels = (int) [ 1, MAX ], " \
74 "endianness = (int) BYTE_ORDER, " \
75 "width = (int) 16, " \
76 "depth = (int) 16, " \
Wim Taymansc19601e2006-04-28 14:17:00 +000077 "signed = (boolean) true;" \
78 "audio/x-raw-int, " \
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, " \
94 "width = (int) 64" \
Thomas Vander Stichele0daade22005-08-25 12:31:31 +000095)
David Schleefbde8ec92005-08-23 19:29:38 +000096
Sebastian Drögee4e3b442009-01-23 12:46:28 +010097static GstStaticPadTemplate gst_legacyresample_sink_template =
Wim Taymans46369002006-03-02 18:23:55 +000098GST_STATIC_PAD_TEMPLATE ("sink",
99 GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
David Schleefbde8ec92005-08-23 19:29:38 +0000100
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100101static GstStaticPadTemplate gst_legacyresample_src_template =
Wim Taymans46369002006-03-02 18:23:55 +0000102GST_STATIC_PAD_TEMPLATE ("src",
103 GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
David Schleefbde8ec92005-08-23 19:29:38 +0000104
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100105static void gst_legacyresample_set_property (GObject * object,
Wim Taymans46369002006-03-02 18:23:55 +0000106 guint prop_id, const GValue * value, GParamSpec * pspec);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100107static void gst_legacyresample_get_property (GObject * object,
Wim Taymans46369002006-03-02 18:23:55 +0000108 guint prop_id, GValue * value, GParamSpec * pspec);
David Schleefbde8ec92005-08-23 19:29:38 +0000109
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000110/* vmethods */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100111static gboolean legacyresample_get_unit_size (GstBaseTransform * base,
Wim Taymans46369002006-03-02 18:23:55 +0000112 GstCaps * caps, guint * size);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100113static GstCaps *legacyresample_transform_caps (GstBaseTransform * base,
Wim Taymans46369002006-03-02 18:23:55 +0000114 GstPadDirection direction, GstCaps * caps);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100115static void legacyresample_fixate_caps (GstBaseTransform * base,
Sebastian Drögee4493882008-10-28 16:25:00 +0000116 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100117static gboolean legacyresample_transform_size (GstBaseTransform * trans,
Wim Taymans46369002006-03-02 18:23:55 +0000118 GstPadDirection direction, GstCaps * incaps, guint insize,
119 GstCaps * outcaps, guint * outsize);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100120static gboolean legacyresample_set_caps (GstBaseTransform * base,
Tim-Philipp Müller86d6bc02007-04-21 14:14:24 +0000121 GstCaps * incaps, GstCaps * outcaps);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100122static GstFlowReturn legacyresample_pushthrough (GstLegacyresample *
123 legacyresample);
124static GstFlowReturn legacyresample_transform (GstBaseTransform * base,
Wim Taymans46369002006-03-02 18:23:55 +0000125 GstBuffer * inbuf, GstBuffer * outbuf);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100126static gboolean legacyresample_event (GstBaseTransform * base,
127 GstEvent * event);
128static gboolean legacyresample_start (GstBaseTransform * base);
129static gboolean legacyresample_stop (GstBaseTransform * base);
David Schleefbde8ec92005-08-23 19:29:38 +0000130
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100131static gboolean legacyresample_query (GstPad * pad, GstQuery * query);
132static const GstQueryType *legacyresample_query_type (GstPad * pad);
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000133
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000134#define DEBUG_INIT(bla) \
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100135 GST_DEBUG_CATEGORY_INIT (legacyresample_debug, "legacyresample", 0, "audio resampling element");
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000136
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100137GST_BOILERPLATE_FULL (GstLegacyresample, gst_legacyresample, GstBaseTransform,
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000138 GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
139
Wim Taymans46369002006-03-02 18:23:55 +0000140static void
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100141gst_legacyresample_base_init (gpointer g_class)
Wim Taymans46369002006-03-02 18:23:55 +0000142{
143 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
David Schleefbde8ec92005-08-23 19:29:38 +0000144
Wim Taymans46369002006-03-02 18:23:55 +0000145 gst_element_class_add_pad_template (gstelement_class,
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100146 gst_static_pad_template_get (&gst_legacyresample_src_template));
Wim Taymans46369002006-03-02 18:23:55 +0000147 gst_element_class_add_pad_template (gstelement_class,
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100148 gst_static_pad_template_get (&gst_legacyresample_sink_template));
David Schleefbde8ec92005-08-23 19:29:38 +0000149
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100150 gst_element_class_set_details (gstelement_class, &gst_legacyresample_details);
Wim Taymans46369002006-03-02 18:23:55 +0000151}
David Schleefbde8ec92005-08-23 19:29:38 +0000152
Wim Taymans46369002006-03-02 18:23:55 +0000153static void
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100154gst_legacyresample_class_init (GstLegacyresampleClass * klass)
David Schleefbde8ec92005-08-23 19:29:38 +0000155{
156 GObjectClass *gobject_class;
David Schleefbde8ec92005-08-23 19:29:38 +0000157
158 gobject_class = (GObjectClass *) klass;
David Schleefbde8ec92005-08-23 19:29:38 +0000159
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100160 gobject_class->set_property = gst_legacyresample_set_property;
161 gobject_class->get_property = gst_legacyresample_get_property;
David Schleefbde8ec92005-08-23 19:29:38 +0000162
Cody Russellea0de112006-06-22 10:10:51 +0000163 g_object_class_install_property (gobject_class, PROP_FILTERLEN,
Sebastian Dröge180aee52008-03-22 15:00:47 +0000164 g_param_spec_int ("filter-length", "filter length",
165 "Length of the resample filter", 0, G_MAXINT, DEFAULT_FILTERLEN,
166 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
David Schleefbde8ec92005-08-23 19:29:38 +0000167
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000168 GST_BASE_TRANSFORM_CLASS (klass)->start =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100169 GST_DEBUG_FUNCPTR (legacyresample_start);
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000170 GST_BASE_TRANSFORM_CLASS (klass)->stop =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100171 GST_DEBUG_FUNCPTR (legacyresample_stop);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000172 GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100173 GST_DEBUG_FUNCPTR (legacyresample_transform_size);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000174 GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100175 GST_DEBUG_FUNCPTR (legacyresample_get_unit_size);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000176 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100177 GST_DEBUG_FUNCPTR (legacyresample_transform_caps);
Sebastian Drögee4493882008-10-28 16:25:00 +0000178 GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100179 GST_DEBUG_FUNCPTR (legacyresample_fixate_caps);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000180 GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100181 GST_DEBUG_FUNCPTR (legacyresample_set_caps);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000182 GST_BASE_TRANSFORM_CLASS (klass)->transform =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100183 GST_DEBUG_FUNCPTR (legacyresample_transform);
Wim Taymansc962e652005-12-02 11:34:50 +0000184 GST_BASE_TRANSFORM_CLASS (klass)->event =
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100185 GST_DEBUG_FUNCPTR (legacyresample_event);
Jan Schmidt37fb8d02005-09-09 17:53:47 +0000186
187 GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
David Schleefbde8ec92005-08-23 19:29:38 +0000188}
189
Wim Taymansc962e652005-12-02 11:34:50 +0000190static void
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100191gst_legacyresample_init (GstLegacyresample * legacyresample,
192 GstLegacyresampleClass * klass)
David Schleefbde8ec92005-08-23 19:29:38 +0000193{
Wim Taymansc962e652005-12-02 11:34:50 +0000194 GstBaseTransform *trans;
195
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100196 trans = GST_BASE_TRANSFORM (legacyresample);
Wim Taymansc962e652005-12-02 11:34:50 +0000197
Tim-Philipp Müller8ed88a32008-05-14 13:57:41 +0000198 /* buffer alloc passthrough is too impossible. FIXME, it
199 * is trivial in the passthrough case. */
200 gst_pad_set_bufferalloc_function (trans->sinkpad, NULL);
201
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100202 legacyresample->filter_length = DEFAULT_FILTERLEN;
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000203
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100204 legacyresample->need_discont = FALSE;
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000205
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100206 gst_pad_set_query_function (trans->srcpad, legacyresample_query);
207 gst_pad_set_query_type_function (trans->srcpad, legacyresample_query_type);
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000208}
209
210/* vmethods */
211static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100212legacyresample_start (GstBaseTransform * base)
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000213{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100214 GstLegacyresample *legacyresample = GST_LEGACYRESAMPLE (base);
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000215
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100216 legacyresample->resample = resample_new ();
217 legacyresample->ts_offset = -1;
218 legacyresample->offset = -1;
219 legacyresample->next_ts = -1;
David Schleefbde8ec92005-08-23 19:29:38 +0000220
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100221 resample_set_filter_length (legacyresample->resample,
222 legacyresample->filter_length);
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000223
224 return TRUE;
David Schleefbde8ec92005-08-23 19:29:38 +0000225}
226
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000227static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100228legacyresample_stop (GstBaseTransform * base)
David Schleefbde8ec92005-08-23 19:29:38 +0000229{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100230 GstLegacyresample *legacyresample = GST_LEGACYRESAMPLE (base);
David Schleefbde8ec92005-08-23 19:29:38 +0000231
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100232 if (legacyresample->resample) {
233 resample_free (legacyresample->resample);
234 legacyresample->resample = NULL;
David Schleefbde8ec92005-08-23 19:29:38 +0000235 }
236
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100237 gst_caps_replace (&legacyresample->sinkcaps, NULL);
238 gst_caps_replace (&legacyresample->srccaps, NULL);
Jan Schmidtec5ed042006-07-28 17:17:24 +0000239
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000240 return TRUE;
David Schleefbde8ec92005-08-23 19:29:38 +0000241}
242
Tim-Philipp Müller86d6bc02007-04-21 14:14:24 +0000243static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100244legacyresample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
Wim Taymans46369002006-03-02 18:23:55 +0000245 guint * size)
246{
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000247 gint width, channels;
248 GstStructure *structure;
249 gboolean ret;
250
Stefan Kostf59ca212006-08-20 13:05:43 +0000251 g_assert (size);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000252
253 /* this works for both float and int */
254 structure = gst_caps_get_structure (caps, 0);
255 ret = gst_structure_get_int (structure, "width", &width);
256 ret &= gst_structure_get_int (structure, "channels", &channels);
257 g_return_val_if_fail (ret, FALSE);
258
259 *size = width * channels / 8;
260
261 return TRUE;
262}
263
Tim-Philipp Müller86d6bc02007-04-21 14:14:24 +0000264static GstCaps *
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100265legacyresample_transform_caps (GstBaseTransform * base,
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000266 GstPadDirection direction, GstCaps * caps)
David Schleefbde8ec92005-08-23 19:29:38 +0000267{
Tim-Philipp Müllerfffc3ba2009-04-01 15:45:22 +0100268 const GValue *val;
269 GstStructure *s;
Wim Taymansc962e652005-12-02 11:34:50 +0000270 GstCaps *res;
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000271
Tim-Philipp Müllerfffc3ba2009-04-01 15:45:22 +0100272 /* transform single caps into input_caps + input_caps with the rate
273 * field set to our supported range. This ensures that upstream knows
274 * about downstream's prefered rate(s) and can negotiate accordingly. */
Wim Taymansc962e652005-12-02 11:34:50 +0000275 res = gst_caps_copy (caps);
Tim-Philipp Müllerfffc3ba2009-04-01 15:45:22 +0100276
277 /* first, however, check if the caps contain a range for the rate field, in
278 * which case that side isn't going to care much about the exact sample rate
279 * chosen and we should just assume things will get fixated to something sane
280 * and we may just as well offer our full range instead of the range in the
281 * caps. If the rate is not an int range value, it's likely to express a
282 * real preference or limitation and we should maintain that structure as
283 * preference by putting it first into the transformed caps, and only add
284 * our full rate range as second option */
285 s = gst_caps_get_structure (res, 0);
286 val = gst_structure_get_value (s, "rate");
287 if (val == NULL || GST_VALUE_HOLDS_INT_RANGE (val)) {
288 /* overwrite existing range, or add field if it doesn't exist yet */
289 gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
290 } else {
291 /* append caps with full range to existing caps with non-range rate field */
292 s = gst_structure_copy (s);
293 gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
294 gst_caps_append_structure (res, s);
295 }
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000296
297 return res;
298}
299
Sebastian Drögee4493882008-10-28 16:25:00 +0000300/* Fixate rate to the allowed rate that has the smallest difference */
301static void
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100302legacyresample_fixate_caps (GstBaseTransform * base,
Sebastian Drögee4493882008-10-28 16:25:00 +0000303 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
304{
305 GstStructure *s;
306 gint rate;
307
308 s = gst_caps_get_structure (caps, 0);
309 if (!gst_structure_get_int (s, "rate", &rate))
310 return;
311
312 s = gst_caps_get_structure (othercaps, 0);
313 gst_structure_fixate_field_nearest_int (s, "rate", rate);
314}
315
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000316static gboolean
Wim Taymans46369002006-03-02 18:23:55 +0000317resample_set_state_from_caps (ResampleState * state, GstCaps * incaps,
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000318 GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate)
319{
320 GstStructure *structure;
321 gboolean ret;
322 gint myinrate, myoutrate;
323 int mychannels;
Wim Taymansc19601e2006-04-28 14:17:00 +0000324 gint width, depth;
325 ResampleFormat format;
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000326
327 GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
328 GST_PTR_FORMAT, incaps, outcaps);
329
330 structure = gst_caps_get_structure (incaps, 0);
331
Wim Taymansc19601e2006-04-28 14:17:00 +0000332 /* get width */
333 ret = gst_structure_get_int (structure, "width", &width);
334 if (!ret)
335 goto no_width;
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000336
Wim Taymansc19601e2006-04-28 14:17:00 +0000337 /* figure out the format */
338 if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float")) {
339 if (width == 32)
340 format = RESAMPLE_FORMAT_F32;
341 else if (width == 64)
342 format = RESAMPLE_FORMAT_F64;
343 else
344 goto wrong_depth;
345 } else {
346 /* for int, depth and width must be the same */
347 ret = gst_structure_get_int (structure, "depth", &depth);
348 if (!ret || width != depth)
349 goto not_equal;
350
351 if (width == 16)
352 format = RESAMPLE_FORMAT_S16;
353 else if (width == 32)
354 format = RESAMPLE_FORMAT_S32;
355 else
356 goto wrong_depth;
357 }
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000358 ret = gst_structure_get_int (structure, "rate", &myinrate);
359 ret &= gst_structure_get_int (structure, "channels", &mychannels);
Wim Taymansc19601e2006-04-28 14:17:00 +0000360 if (!ret)
361 goto no_in_rate_channels;
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000362
363 structure = gst_caps_get_structure (outcaps, 0);
364 ret = gst_structure_get_int (structure, "rate", &myoutrate);
Wim Taymansc19601e2006-04-28 14:17:00 +0000365 if (!ret)
366 goto no_out_rate;
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000367
368 if (channels)
369 *channels = mychannels;
370 if (inrate)
371 *inrate = myinrate;
372 if (outrate)
373 *outrate = myoutrate;
374
Wim Taymansc19601e2006-04-28 14:17:00 +0000375 resample_set_format (state, format);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000376 resample_set_n_channels (state, mychannels);
377 resample_set_input_rate (state, myinrate);
378 resample_set_output_rate (state, myoutrate);
379
380 return TRUE;
Wim Taymansc19601e2006-04-28 14:17:00 +0000381
382 /* ERRORS */
383no_width:
384 {
385 GST_DEBUG ("failed to get width from caps");
386 return FALSE;
387 }
388not_equal:
389 {
390 GST_DEBUG ("width %d and depth %d must be the same", width, depth);
391 return FALSE;
392 }
393wrong_depth:
394 {
395 GST_DEBUG ("unknown depth %d found", depth);
396 return FALSE;
397 }
398no_in_rate_channels:
399 {
400 GST_DEBUG ("could not get input rate and channels");
401 return FALSE;
402 }
403no_out_rate:
404 {
405 GST_DEBUG ("could not get output rate");
406 return FALSE;
407 }
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000408}
409
Tim-Philipp Müller86d6bc02007-04-21 14:14:24 +0000410static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100411legacyresample_transform_size (GstBaseTransform * base,
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000412 GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
Wim Taymans46369002006-03-02 18:23:55 +0000413 guint * othersize)
414{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100415 GstLegacyresample *legacyresample = GST_LEGACYRESAMPLE (base);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000416 ResampleState *state;
417 GstCaps *srccaps, *sinkcaps;
418 gboolean use_internal = FALSE; /* whether we use the internal state */
419 gboolean ret = TRUE;
420
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000421 GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000422 size, direction == GST_PAD_SINK ? "SINK" : "SRC");
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000423 if (direction == GST_PAD_SINK) {
424 sinkcaps = caps;
425 srccaps = othercaps;
426 } else {
427 sinkcaps = othercaps;
428 srccaps = caps;
429 }
430
431 /* if the caps are the ones that _set_caps got called with; we can use
432 * our own state; otherwise we'll have to create a state */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100433 if (gst_caps_is_equal (sinkcaps, legacyresample->sinkcaps) &&
434 gst_caps_is_equal (srccaps, legacyresample->srccaps)) {
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000435 use_internal = TRUE;
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100436 state = legacyresample->resample;
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000437 } else {
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100438 GST_DEBUG_OBJECT (legacyresample,
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000439 "caps are not the set caps, creating state");
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000440 state = resample_new ();
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100441 resample_set_filter_length (state, legacyresample->filter_length);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000442 resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL);
443 }
444
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000445 if (direction == GST_PAD_SINK) {
446 /* asked to convert size of an incoming buffer */
447 *othersize = resample_get_output_size_for_input (state, size);
448 } else {
Wim Taymansc962e652005-12-02 11:34:50 +0000449 /* asked to convert size of an outgoing buffer */
450 *othersize = resample_get_input_size_for_output (state, size);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000451 }
Thomas Vander Stichelefb397492005-08-26 17:35:28 +0000452 g_assert (*othersize % state->sample_size == 0);
453
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000454 /* we make room for one extra sample, given that the resampling filter
455 * can output an extra one for non-integral i_rate/o_rate */
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000456 GST_LOG_OBJECT (base, "transformed size %d to %d", size, *othersize);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000457
458 if (!use_internal) {
459 resample_free (state);
460 }
461
462 return ret;
463}
464
Tim-Philipp Müller86d6bc02007-04-21 14:14:24 +0000465static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100466legacyresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
Wim Taymans46369002006-03-02 18:23:55 +0000467 GstCaps * outcaps)
468{
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000469 gboolean ret;
470 gint inrate, outrate;
471 int channels;
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100472 GstLegacyresample *legacyresample = GST_LEGACYRESAMPLE (base);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000473
474 GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
475 GST_PTR_FORMAT, incaps, outcaps);
476
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100477 ret = resample_set_state_from_caps (legacyresample->resample, incaps, outcaps,
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000478 &channels, &inrate, &outrate);
479
480 g_return_val_if_fail (ret, FALSE);
481
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100482 legacyresample->channels = channels;
483 GST_DEBUG_OBJECT (legacyresample, "set channels to %d", channels);
484 legacyresample->i_rate = inrate;
485 GST_DEBUG_OBJECT (legacyresample, "set i_rate to %d", inrate);
486 legacyresample->o_rate = outrate;
487 GST_DEBUG_OBJECT (legacyresample, "set o_rate to %d", outrate);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000488
489 /* save caps so we can short-circuit in the size_transform if the caps
490 * are the same */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100491 gst_caps_replace (&legacyresample->sinkcaps, incaps);
492 gst_caps_replace (&legacyresample->srccaps, outcaps);
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000493
494 return TRUE;
495}
496
Wim Taymans46369002006-03-02 18:23:55 +0000497static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100498legacyresample_event (GstBaseTransform * base, GstEvent * event)
Wim Taymansc962e652005-12-02 11:34:50 +0000499{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100500 GstLegacyresample *legacyresample;
Wim Taymansc962e652005-12-02 11:34:50 +0000501
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100502 legacyresample = GST_LEGACYRESAMPLE (base);
Wim Taymansc962e652005-12-02 11:34:50 +0000503
504 switch (GST_EVENT_TYPE (event)) {
505 case GST_EVENT_FLUSH_START:
506 break;
507 case GST_EVENT_FLUSH_STOP:
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100508 if (legacyresample->resample)
509 resample_input_flush (legacyresample->resample);
510 legacyresample->ts_offset = -1;
511 legacyresample->next_ts = -1;
512 legacyresample->offset = -1;
Wim Taymansc962e652005-12-02 11:34:50 +0000513 break;
514 case GST_EVENT_NEWSEGMENT:
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100515 resample_input_pushthrough (legacyresample->resample);
516 legacyresample_pushthrough (legacyresample);
517 legacyresample->ts_offset = -1;
518 legacyresample->next_ts = -1;
519 legacyresample->offset = -1;
Wim Taymansc962e652005-12-02 11:34:50 +0000520 break;
521 case GST_EVENT_EOS:
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100522 resample_input_eos (legacyresample->resample);
523 legacyresample_pushthrough (legacyresample);
Wim Taymansc962e652005-12-02 11:34:50 +0000524 break;
525 default:
526 break;
527 }
Stefan Kost896ef6c2008-10-30 11:43:12 +0000528 return parent_class->event (base, event);
Wim Taymansc962e652005-12-02 11:34:50 +0000529}
530
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000531static GstFlowReturn
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100532legacyresample_do_output (GstLegacyresample * legacyresample,
533 GstBuffer * outbuf)
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000534{
David Schleefbde8ec92005-08-23 19:29:38 +0000535 int outsize;
Thomas Vander Stichele3d95afd2005-08-25 15:44:58 +0000536 int outsamples;
Wim Taymansc962e652005-12-02 11:34:50 +0000537 ResampleState *r;
David Schleefbde8ec92005-08-23 19:29:38 +0000538
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100539 r = legacyresample->resample;
David Schleefbde8ec92005-08-23 19:29:38 +0000540
David Schleefbde8ec92005-08-23 19:29:38 +0000541 outsize = resample_get_output_size (r);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100542 GST_LOG_OBJECT (legacyresample, "legacyresample can give me %d bytes",
543 outsize);
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000544
545 /* protect against mem corruption */
546 if (outsize > GST_BUFFER_SIZE (outbuf)) {
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100547 GST_WARNING_OBJECT (legacyresample,
548 "overriding legacyresample's outsize %d with outbuffer's size %d",
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000549 outsize, GST_BUFFER_SIZE (outbuf));
550 outsize = GST_BUFFER_SIZE (outbuf);
David Schleefbde8ec92005-08-23 19:29:38 +0000551 }
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000552 /* catch possibly wrong size differences */
553 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100554 GST_WARNING_OBJECT (legacyresample,
555 "legacyresample's outsize %d too far from outbuffer's size %d",
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000556 outsize, GST_BUFFER_SIZE (outbuf));
557 }
David Schleefbde8ec92005-08-23 19:29:38 +0000558
559 outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize);
Thomas Vander Stichele3d95afd2005-08-25 15:44:58 +0000560 outsamples = outsize / r->sample_size;
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100561 GST_LOG_OBJECT (legacyresample, "resample gave me %d bytes or %d samples",
Thomas Vander Stichele3d95afd2005-08-25 15:44:58 +0000562 outsize, outsamples);
563
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100564 GST_BUFFER_OFFSET (outbuf) = legacyresample->offset;
565 GST_BUFFER_TIMESTAMP (outbuf) = legacyresample->next_ts;
Thomas Vander Stichele7d1ce172005-08-25 17:20:02 +0000566
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100567 if (legacyresample->ts_offset != -1) {
568 legacyresample->offset += outsamples;
569 legacyresample->ts_offset += outsamples;
570 legacyresample->next_ts =
571 gst_util_uint64_scale_int (legacyresample->ts_offset, GST_SECOND,
572 legacyresample->o_rate);
573 GST_BUFFER_OFFSET_END (outbuf) = legacyresample->offset;
David Schleefbde8ec92005-08-23 19:29:38 +0000574
Wim Taymansc962e652005-12-02 11:34:50 +0000575 /* we calculate DURATION as the difference between "next" timestamp
576 * and current timestamp so we ensure a contiguous stream, instead of
577 * having rounding errors. */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100578 GST_BUFFER_DURATION (outbuf) = legacyresample->next_ts -
Wim Taymansc962e652005-12-02 11:34:50 +0000579 GST_BUFFER_TIMESTAMP (outbuf);
580 } else {
581 /* no valid offset know, we can still sortof calculate the duration though */
582 GST_BUFFER_DURATION (outbuf) =
583 gst_util_uint64_scale_int (outsamples, GST_SECOND,
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100584 legacyresample->o_rate);
Wim Taymansc962e652005-12-02 11:34:50 +0000585 }
Thomas Vander Stichele7d1ce172005-08-25 17:20:02 +0000586
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000587 /* check for possible mem corruption */
588 if (outsize > GST_BUFFER_SIZE (outbuf)) {
589 /* this is an error that when it happens, would need fixing in the
Thomas Vander Stichele0dcd5d32007-03-14 14:09:21 +0000590 * resample library; we told it we wanted only GST_BUFFER_SIZE (outbuf),
591 * and it gave us more ! */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100592 GST_WARNING_OBJECT (legacyresample,
593 "legacyresample, you memory corrupting bastard. "
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000594 "you gave me outsize %d while my buffer was size %d",
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000595 outsize, GST_BUFFER_SIZE (outbuf));
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000596 return GST_FLOW_ERROR;
597 }
598 /* catch possibly wrong size differences */
599 if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100600 GST_WARNING_OBJECT (legacyresample,
601 "legacyresample's written outsize %d too far from outbuffer's size %d",
Thomas Vander Stichele0daade22005-08-25 12:31:31 +0000602 outsize, GST_BUFFER_SIZE (outbuf));
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000603 }
Wim Taymansc962e652005-12-02 11:34:50 +0000604 GST_BUFFER_SIZE (outbuf) = outsize;
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000605
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100606 if (G_UNLIKELY (legacyresample->need_discont)) {
607 GST_DEBUG_OBJECT (legacyresample,
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000608 "marking this buffer with the DISCONT flag");
609 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100610 legacyresample->need_discont = FALSE;
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000611 }
612
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100613 GST_LOG_OBJECT (legacyresample, "transformed to buffer of %d bytes, ts %"
Thomas Vander Stichele0dcd5d32007-03-14 14:09:21 +0000614 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
615 G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
616 outsize, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
617 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
618 GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
619
620
Thomas Vander Stichelec4763db2005-08-24 14:08:58 +0000621 return GST_FLOW_OK;
David Schleefbde8ec92005-08-23 19:29:38 +0000622}
623
Michael Smith03ab5302007-03-15 10:52:21 +0000624static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100625legacyresample_check_discont (GstLegacyresample * legacyresample,
Michael Smith03ab5302007-03-15 10:52:21 +0000626 GstClockTime timestamp)
627{
628 if (timestamp != GST_CLOCK_TIME_NONE &&
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100629 legacyresample->prev_ts != GST_CLOCK_TIME_NONE &&
630 legacyresample->prev_duration != GST_CLOCK_TIME_NONE &&
631 timestamp != legacyresample->prev_ts + legacyresample->prev_duration) {
Michael Smith03ab5302007-03-15 10:52:21 +0000632 /* Potentially a discontinuous buffer. However, it turns out that many
633 * elements generate imperfect streams due to rounding errors, so we permit
634 * a small error (up to one sample) without triggering a filter
635 * flush/restart (if triggered incorrectly, this will be audible) */
636 GstClockTimeDiff diff = timestamp -
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100637 (legacyresample->prev_ts + legacyresample->prev_duration);
Michael Smith03ab5302007-03-15 10:52:21 +0000638
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100639 if (ABS (diff) > GST_SECOND / legacyresample->i_rate) {
640 GST_WARNING_OBJECT (legacyresample,
Michael Smith03ab5302007-03-15 10:52:21 +0000641 "encountered timestamp discontinuity of %" G_GINT64_FORMAT, diff);
642 return TRUE;
643 }
644 }
645
646 return FALSE;
647}
648
Wim Taymansc962e652005-12-02 11:34:50 +0000649static GstFlowReturn
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100650legacyresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
Wim Taymansc962e652005-12-02 11:34:50 +0000651 GstBuffer * outbuf)
652{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100653 GstLegacyresample *legacyresample;
Wim Taymansc962e652005-12-02 11:34:50 +0000654 ResampleState *r;
Michael Smithe1eae402005-12-15 10:30:14 +0000655 guchar *data, *datacopy;
Wim Taymansc962e652005-12-02 11:34:50 +0000656 gulong size;
657 GstClockTime timestamp;
658
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100659 legacyresample = GST_LEGACYRESAMPLE (base);
660 r = legacyresample->resample;
Wim Taymansc962e652005-12-02 11:34:50 +0000661
662 data = GST_BUFFER_DATA (inbuf);
663 size = GST_BUFFER_SIZE (inbuf);
664 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
665
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100666 GST_LOG_OBJECT (legacyresample, "transforming buffer of %ld bytes, ts %"
Thomas Vander Stichele0dcd5d32007-03-14 14:09:21 +0000667 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
668 G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
669 size, GST_TIME_ARGS (timestamp),
670 GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
671 GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
Wim Taymansc962e652005-12-02 11:34:50 +0000672
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000673 /* check for timestamp discontinuities and flush/reset if needed */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100674 if (G_UNLIKELY (legacyresample_check_discont (legacyresample, timestamp))) {
Michael Smith03ab5302007-03-15 10:52:21 +0000675 /* Flush internal samples */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100676 legacyresample_pushthrough (legacyresample);
Michael Smith03ab5302007-03-15 10:52:21 +0000677 /* Inform downstream element about discontinuity */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100678 legacyresample->need_discont = TRUE;
Michael Smith03ab5302007-03-15 10:52:21 +0000679 /* We want to recalculate the offset */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100680 legacyresample->ts_offset = -1;
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000681 }
682
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100683 if (legacyresample->ts_offset == -1) {
Wim Taymansc962e652005-12-02 11:34:50 +0000684 /* if we don't know the initial offset yet, calculate it based on the
685 * input timestamp. */
686 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
687 GstClockTime stime;
688
Thomas Vander Stichele0dcd5d32007-03-14 14:09:21 +0000689 /* offset used to calculate the timestamps. We use the sample offset for
690 * this to make it more accurate. We want the first buffer to have the
691 * same timestamp as the incoming timestamp. */
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100692 legacyresample->next_ts = timestamp;
693 legacyresample->ts_offset =
Wim Taymansc962e652005-12-02 11:34:50 +0000694 gst_util_uint64_scale_int (timestamp, r->o_rate, GST_SECOND);
Thomas Vander Stichele0dcd5d32007-03-14 14:09:21 +0000695 /* offset used to set as the buffer offset, this offset is always
696 * relative to the stream time, note that timestamp is not... */
Wim Taymansc962e652005-12-02 11:34:50 +0000697 stime = (timestamp - base->segment.start) + base->segment.time;
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100698 legacyresample->offset =
Wim Taymansc962e652005-12-02 11:34:50 +0000699 gst_util_uint64_scale_int (stime, r->o_rate, GST_SECOND);
700 }
701 }
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100702 legacyresample->prev_ts = timestamp;
703 legacyresample->prev_duration = GST_BUFFER_DURATION (inbuf);
Wim Taymansc962e652005-12-02 11:34:50 +0000704
705 /* need to memdup, resample takes ownership. */
Michael Smithe1eae402005-12-15 10:30:14 +0000706 datacopy = g_memdup (data, size);
707 resample_add_input_data (r, datacopy, size, g_free, datacopy);
Wim Taymansc962e652005-12-02 11:34:50 +0000708
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100709 return legacyresample_do_output (legacyresample, outbuf);
Wim Taymansc962e652005-12-02 11:34:50 +0000710}
711
712/* push remaining data in the buffers out */
713static GstFlowReturn
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100714legacyresample_pushthrough (GstLegacyresample * legacyresample)
Wim Taymansc962e652005-12-02 11:34:50 +0000715{
716 int outsize;
717 ResampleState *r;
718 GstBuffer *outbuf;
719 GstFlowReturn res = GST_FLOW_OK;
720 GstBaseTransform *trans;
721
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100722 r = legacyresample->resample;
Wim Taymansc962e652005-12-02 11:34:50 +0000723
724 outsize = resample_get_output_size (r);
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000725 if (outsize == 0) {
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100726 GST_DEBUG_OBJECT (legacyresample, "no internal buffers needing flush");
Wim Taymansc962e652005-12-02 11:34:50 +0000727 goto done;
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000728 }
Wim Taymansc962e652005-12-02 11:34:50 +0000729
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100730 trans = GST_BASE_TRANSFORM (legacyresample);
Wim Taymansc962e652005-12-02 11:34:50 +0000731
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000732 res = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET_NONE, outsize,
733 GST_PAD_CAPS (trans->srcpad), &outbuf);
734 if (G_UNLIKELY (res != GST_FLOW_OK)) {
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100735 GST_WARNING_OBJECT (legacyresample, "failed allocating buffer of %d bytes",
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000736 outsize);
737 goto done;
738 }
739
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100740 res = legacyresample_do_output (legacyresample, outbuf);
Julien Mouttee3ef9cd2007-03-14 17:16:30 +0000741 if (G_UNLIKELY (res != GST_FLOW_OK))
742 goto done;
743
Wim Taymansc962e652005-12-02 11:34:50 +0000744 res = gst_pad_push (trans->srcpad, outbuf);
745
746done:
747 return res;
748}
749
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000750static gboolean
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100751legacyresample_query (GstPad * pad, GstQuery * query)
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000752{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100753 GstLegacyresample *legacyresample =
754 GST_LEGACYRESAMPLE (gst_pad_get_parent (pad));
755 GstBaseTransform *trans = GST_BASE_TRANSFORM (legacyresample);
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000756 gboolean res = TRUE;
757
758 switch (GST_QUERY_TYPE (query)) {
759 case GST_QUERY_LATENCY:
760 {
761 GstClockTime min, max;
762 gboolean live;
763 guint64 latency;
764 GstPad *peer;
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100765 gint rate = legacyresample->i_rate;
766 gint resampler_latency = legacyresample->filter_length / 2;
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000767
768 if (gst_base_transform_is_passthrough (trans))
769 resampler_latency = 0;
770
771 if ((peer = gst_pad_get_peer (trans->sinkpad))) {
772 if ((res = gst_pad_query (peer, query))) {
773 gst_query_parse_latency (query, &live, &min, &max);
774
775 GST_DEBUG ("Peer latency: min %"
776 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
777 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
778
779 /* add our own latency */
780 if (rate != 0 && resampler_latency != 0)
781 latency =
782 gst_util_uint64_scale (resampler_latency, GST_SECOND, rate);
783 else
784 latency = 0;
785
786 GST_DEBUG ("Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
787
788 min += latency;
789 if (max != GST_CLOCK_TIME_NONE)
790 max += latency;
791
792 GST_DEBUG ("Calculated total latency : min %"
793 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
794 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
795
796 gst_query_set_latency (query, live, min, max);
797 }
798 gst_object_unref (peer);
799 }
800 break;
801 }
802 default:
803 res = gst_pad_query_default (pad, query);
804 break;
805 }
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100806 gst_object_unref (legacyresample);
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000807 return res;
808}
809
810static const GstQueryType *
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100811legacyresample_query_type (GstPad * pad)
Sebastian Drögec7cc3862007-11-23 10:21:11 +0000812{
813 static const GstQueryType types[] = {
814 GST_QUERY_LATENCY,
815 0
816 };
817
818 return types;
819}
Wim Taymansc962e652005-12-02 11:34:50 +0000820
David Schleefbde8ec92005-08-23 19:29:38 +0000821static void
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100822gst_legacyresample_set_property (GObject * object, guint prop_id,
David Schleefbde8ec92005-08-23 19:29:38 +0000823 const GValue * value, GParamSpec * pspec)
824{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100825 GstLegacyresample *legacyresample;
David Schleefbde8ec92005-08-23 19:29:38 +0000826
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100827 legacyresample = GST_LEGACYRESAMPLE (object);
David Schleefbde8ec92005-08-23 19:29:38 +0000828
829 switch (prop_id) {
Wim Taymans46369002006-03-02 18:23:55 +0000830 case PROP_FILTERLEN:
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100831 legacyresample->filter_length = g_value_get_int (value);
832 GST_DEBUG_OBJECT (GST_ELEMENT (legacyresample), "new filter length %d",
833 legacyresample->filter_length);
834 if (legacyresample->resample) {
835 resample_set_filter_length (legacyresample->resample,
836 legacyresample->filter_length);
837 gst_element_post_message (GST_ELEMENT (legacyresample),
838 gst_message_new_latency (GST_OBJECT (legacyresample)));
Tim-Philipp Müllerab841282006-06-16 15:17:44 +0000839 }
David Schleefbde8ec92005-08-23 19:29:38 +0000840 break;
Wim Taymans46369002006-03-02 18:23:55 +0000841 default:
842 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
David Schleefbde8ec92005-08-23 19:29:38 +0000843 break;
844 }
845}
846
847static void
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100848gst_legacyresample_get_property (GObject * object, guint prop_id,
David Schleefbde8ec92005-08-23 19:29:38 +0000849 GValue * value, GParamSpec * pspec)
850{
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100851 GstLegacyresample *legacyresample;
David Schleefbde8ec92005-08-23 19:29:38 +0000852
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100853 legacyresample = GST_LEGACYRESAMPLE (object);
David Schleefbde8ec92005-08-23 19:29:38 +0000854
855 switch (prop_id) {
Wim Taymans46369002006-03-02 18:23:55 +0000856 case PROP_FILTERLEN:
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100857 g_value_set_int (value, legacyresample->filter_length);
David Schleefbde8ec92005-08-23 19:29:38 +0000858 break;
859 default:
860 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
861 break;
862 }
863}
864
865
Wim Taymans46369002006-03-02 18:23:55 +0000866static gboolean
867plugin_init (GstPlugin * plugin)
David Schleefbde8ec92005-08-23 19:29:38 +0000868{
869 resample_init ();
870
Sebastian Dröge5da03602008-11-27 16:58:31 +0000871 if (!gst_element_register (plugin, "legacyresample", GST_RANK_MARGINAL,
Sebastian Drögee4e3b442009-01-23 12:46:28 +0100872 GST_TYPE_LEGACYRESAMPLE)) {
David Schleefbde8ec92005-08-23 19:29:38 +0000873 return FALSE;
874 }
875
876 return TRUE;
877}
878
879GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
880 GST_VERSION_MINOR,
Sebastian Dröge5da03602008-11-27 16:58:31 +0000881 "legacyresample",
Thomas Vander Stichelee575d002005-10-16 13:54:38 +0000882 "Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
883 GST_PACKAGE_ORIGIN);