2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
26 #include <gst/audio/audio.h>
28 #define GST_TYPE_AUDIO_RATE \
29 (gst_audio_rate_get_type())
30 #define GST_AUDIO_RATE(obj) \
31 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_RATE,GstAudioRate))
32 #define GST_AUDIO_RATE_CLASS(klass) \
33 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_RATE,GstAudioRate))
34 #define GST_IS_AUDIO_RATE(obj) \
35 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_RATE))
36 #define GST_IS_AUDIO_RATE_CLASS(obj) \
37 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_RATE))
39 typedef struct _GstAudioRate GstAudioRate;
40 typedef struct _GstAudioRateClass GstAudioRateClass;
46 GstPad *sinkpad, *srcpad;
48 gint bytes_per_sample;
53 guint64 in, out, add, drop;
57 struct _GstAudioRateClass
59 GstElementClass parent_class;
62 /* elementfactory information */
63 static GstElementDetails audio_rate_details =
64 GST_ELEMENT_DETAILS ("Audio rate adjuster",
65 "Filter/Effect/Audio",
66 "Drops/duplicates/adjusts timestamps on audio samples to make a perfect stream",
67 "Wim Taymans <wim@fluendo.com>");
69 /* GstAudioRate signals and args */
76 #define DEFAULT_SILENT TRUE
89 static GstStaticPadTemplate gst_audio_rate_src_template =
90 GST_STATIC_PAD_TEMPLATE ("src",
93 GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS)
96 static GstStaticPadTemplate gst_audio_rate_sink_template =
97 GST_STATIC_PAD_TEMPLATE ("sink",
100 GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS)
103 static void gst_audio_rate_base_init (gpointer g_class);
104 static void gst_audio_rate_class_init (GstAudioRateClass * klass);
105 static void gst_audio_rate_init (GstAudioRate * audiorate);
106 static GstFlowReturn gst_audio_rate_chain (GstPad * pad, GstBuffer * buf);
108 static void gst_audio_rate_set_property (GObject * object,
109 guint prop_id, const GValue * value, GParamSpec * pspec);
110 static void gst_audio_rate_get_property (GObject * object,
111 guint prop_id, GValue * value, GParamSpec * pspec);
113 static GstStateChangeReturn gst_audio_rate_change_state (GstElement * element,
114 GstStateChange transition);
116 static GstElementClass *parent_class = NULL;
118 /*static guint gst_audio_rate_signals[LAST_SIGNAL] = { 0 }; */
121 gst_audio_rate_get_type (void)
123 static GType audio_rate_type = 0;
125 if (!audio_rate_type) {
126 static const GTypeInfo audio_rate_info = {
127 sizeof (GstAudioRateClass),
128 gst_audio_rate_base_init,
130 (GClassInitFunc) gst_audio_rate_class_init,
133 sizeof (GstAudioRate),
135 (GInstanceInitFunc) gst_audio_rate_init,
138 audio_rate_type = g_type_register_static (GST_TYPE_ELEMENT,
139 "GstAudioRate", &audio_rate_info, 0);
142 return audio_rate_type;
146 gst_audio_rate_base_init (gpointer g_class)
148 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
150 gst_element_class_set_details (element_class, &audio_rate_details);
152 gst_element_class_add_pad_template (element_class,
153 gst_static_pad_template_get (&gst_audio_rate_sink_template));
154 gst_element_class_add_pad_template (element_class,
155 gst_static_pad_template_get (&gst_audio_rate_src_template));
158 gst_audio_rate_class_init (GstAudioRateClass * klass)
160 GObjectClass *object_class = G_OBJECT_CLASS (klass);
161 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
163 parent_class = g_type_class_peek_parent (klass);
165 object_class->set_property = gst_audio_rate_set_property;
166 object_class->get_property = gst_audio_rate_get_property;
168 g_object_class_install_property (object_class, ARG_IN,
169 g_param_spec_uint64 ("in", "In",
170 "Number of input samples", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
171 g_object_class_install_property (object_class, ARG_OUT,
172 g_param_spec_uint64 ("out", "Out",
173 "Number of output samples", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
174 g_object_class_install_property (object_class, ARG_ADD,
175 g_param_spec_uint64 ("add", "Add",
176 "Number of added samples", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
177 g_object_class_install_property (object_class, ARG_DROP,
178 g_param_spec_uint64 ("drop", "Drop",
179 "Number of dropped samples", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
180 g_object_class_install_property (object_class, ARG_SILENT,
181 g_param_spec_boolean ("silent", "silent",
182 "Don't emit notify for dropped and duplicated frames",
183 DEFAULT_SILENT, G_PARAM_READWRITE));
185 element_class->change_state = gst_audio_rate_change_state;
189 gst_audio_rate_setcaps (GstPad * pad, GstCaps * caps)
191 GstAudioRate *audiorate;
192 GstStructure *structure;
194 gint ret, channels, depth;
196 audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));
198 otherpad = (pad == audiorate->srcpad) ? audiorate->sinkpad :
201 if (!gst_pad_set_caps (otherpad, caps))
204 structure = gst_caps_get_structure (caps, 0);
206 ret = gst_structure_get_int (structure, "channels", &channels);
207 ret &= gst_structure_get_int (structure, "depth", &depth);
212 audiorate->bytes_per_sample = channels * (depth / 8);
213 if (audiorate->bytes_per_sample == 0)
214 audiorate->bytes_per_sample = 1;
220 gst_audio_rate_init (GstAudioRate * audiorate)
223 gst_pad_new_from_static_template (&gst_audio_rate_sink_template, "sink");
224 gst_element_add_pad (GST_ELEMENT (audiorate), audiorate->sinkpad);
225 gst_pad_set_chain_function (audiorate->sinkpad, gst_audio_rate_chain);
226 gst_pad_set_setcaps_function (audiorate->sinkpad, gst_audio_rate_setcaps);
227 gst_pad_set_getcaps_function (audiorate->sinkpad, gst_pad_proxy_getcaps);
230 gst_pad_new_from_static_template (&gst_audio_rate_src_template, "src");
231 gst_element_add_pad (GST_ELEMENT (audiorate), audiorate->srcpad);
232 gst_pad_set_setcaps_function (audiorate->srcpad, gst_audio_rate_setcaps);
233 gst_pad_set_getcaps_function (audiorate->srcpad, gst_pad_proxy_getcaps);
235 audiorate->bytes_per_sample = 1;
240 audiorate->silent = DEFAULT_SILENT;
244 gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
246 GstAudioRate *audiorate;
247 GstClockTime in_time, in_duration;
248 guint64 in_offset, in_offset_end;
250 GstFlowReturn ret = GST_FLOW_OK;
252 audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));
256 in_time = GST_BUFFER_TIMESTAMP (buf);
257 in_duration = GST_BUFFER_DURATION (buf);
258 in_size = GST_BUFFER_SIZE (buf);
259 in_offset = GST_BUFFER_OFFSET (buf);
260 in_offset_end = GST_BUFFER_OFFSET_END (buf);
262 if (in_offset == GST_CLOCK_TIME_NONE || in_offset_end == GST_CLOCK_TIME_NONE) {
263 GST_WARNING_OBJECT (audiorate, "audiorate got buffer without offsets");
266 /* do we need to insert samples */
267 if (in_offset > audiorate->next_offset) {
272 fillsamples = in_offset - audiorate->next_offset;
273 fillsize = fillsamples * audiorate->bytes_per_sample;
275 fill = gst_buffer_new_and_alloc (fillsize);
276 memset (GST_BUFFER_DATA (fill), 0, fillsize);
278 GST_LOG_OBJECT (audiorate, "inserting %lld samples", fillsamples);
280 GST_BUFFER_DURATION (fill) = in_duration * fillsize / in_size;
281 GST_BUFFER_TIMESTAMP (fill) = in_time - GST_BUFFER_DURATION (fill);
282 GST_BUFFER_OFFSET (fill) = audiorate->next_offset;
283 GST_BUFFER_OFFSET_END (fill) = in_offset;
285 if ((ret = gst_pad_push (audiorate->srcpad, fill) != GST_FLOW_OK))
288 audiorate->add += fillsamples;
290 if (!audiorate->silent)
291 g_object_notify (G_OBJECT (audiorate), "add");
292 } else if (in_offset < audiorate->next_offset) {
293 /* need to remove samples */
294 if (in_offset_end <= audiorate->next_offset) {
295 guint64 drop = in_size / audiorate->bytes_per_sample;
297 audiorate->drop += drop;
299 GST_LOG_OBJECT (audiorate, "dropping %lld samples", drop);
301 /* we can drop the buffer completely */
302 gst_buffer_unref (buf);
304 if (!audiorate->silent)
305 g_object_notify (G_OBJECT (audiorate), "drop");
309 guint64 truncsamples, truncsize, leftsize;
312 /* truncate buffer */
313 truncsamples = audiorate->next_offset - in_offset;
314 truncsize = truncsamples * audiorate->bytes_per_sample;
315 leftsize = in_size - truncsize;
317 trunc = gst_buffer_create_sub (buf, truncsize, in_size);
318 GST_BUFFER_DURATION (trunc) = in_duration * leftsize / in_size;
319 GST_BUFFER_TIMESTAMP (trunc) =
320 in_time + in_duration - GST_BUFFER_DURATION (trunc);
321 GST_BUFFER_OFFSET (trunc) = audiorate->next_offset;
322 GST_BUFFER_OFFSET_END (trunc) = in_offset_end;
324 GST_LOG_OBJECT (audiorate, "truncating %lld samples", truncsamples);
326 gst_buffer_unref (buf);
329 audiorate->drop += truncsamples;
332 ret = gst_pad_push (audiorate->srcpad, buf);
335 audiorate->next_offset = in_offset_end;
341 gst_audio_rate_set_property (GObject * object,
342 guint prop_id, const GValue * value, GParamSpec * pspec)
344 GstAudioRate *audiorate = GST_AUDIO_RATE (object);
348 audiorate->silent = g_value_get_boolean (value);
351 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
357 gst_audio_rate_get_property (GObject * object,
358 guint prop_id, GValue * value, GParamSpec * pspec)
360 GstAudioRate *audiorate = GST_AUDIO_RATE (object);
364 g_value_set_uint64 (value, audiorate->in);
367 g_value_set_uint64 (value, audiorate->out);
370 g_value_set_uint64 (value, audiorate->add);
373 g_value_set_uint64 (value, audiorate->drop);
376 g_value_set_boolean (value, audiorate->silent);
379 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
384 static GstStateChangeReturn
385 gst_audio_rate_change_state (GstElement * element, GstStateChange transition)
387 GstAudioRate *audiorate = GST_AUDIO_RATE (element);
389 switch (transition) {
390 case GST_STATE_CHANGE_PAUSED_TO_READY:
392 case GST_STATE_CHANGE_READY_TO_PAUSED:
393 audiorate->next_offset = 0;
399 if (parent_class->change_state)
400 return parent_class->change_state (element, transition);
402 return GST_STATE_CHANGE_SUCCESS;
406 plugin_init (GstPlugin * plugin)
408 return gst_element_register (plugin, "audiorate", GST_RANK_NONE,
409 GST_TYPE_AUDIO_RATE);
412 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
415 "Adjusts audio frames",
416 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)