Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / gst / audiorate / gstaudiorate.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /**
21  * SECTION:element-audiorate
22  * @see_also: #GstVideoRate
23  *
24  * This element takes an incoming stream of timestamped raw audio frames and
25  * produces a perfect stream by inserting or dropping samples as needed.
26  *
27  * This operation may be of use to link to elements that require or otherwise
28  * implicitly assume a perfect stream as they do not store timestamps,
29  * but derive this by some means (e.g. bitrate for some AVI cases).
30  *
31  * The properties #GstAudioRate:in, #GstAudioRate:out, #GstAudioRate:add
32  * and #GstAudioRate:drop can be read to obtain information about number of
33  * input samples, output samples, dropped samples (i.e. the number of unused
34  * input samples) and inserted samples (i.e. the number of samples added to
35  * stream).
36  *
37  * When the #GstAudioRate:silent property is set to FALSE, a GObject property
38  * notification will be emitted whenever one of the #GstAudioRate:add or
39  * #GstAudioRate:drop values changes.
40  * This can potentially cause performance degradation.
41  * Note that property notification will happen from the streaming thread, so
42  * applications should be prepared for this.
43  *
44  * If the #GstAudioRate:tolerance property is non-zero, and an incoming buffer's
45  * timestamp deviates less than the property indicates from what would make a
46  * 'perfect time', then no samples will be added or dropped.
47  * Note that the output is still guaranteed to be a perfect stream, which means
48  * that the incoming data is then simply shifted (by less than the indicated
49  * tolerance) to a perfect time.
50  *
51  * <refsect2>
52  * <title>Example pipelines</title>
53  * |[
54  * gst-launch -v alsasrc ! audiorate ! wavenc ! filesink location=alsa.wav
55  * ]| Capture audio from an ALSA device, and turn it into a perfect stream
56  * for saving in a raw audio file.
57  * </refsect2>
58  */
59
60 #ifdef HAVE_CONFIG_H
61 #include "config.h"
62 #endif
63
64 #include <string.h>
65 #include <stdlib.h>
66
67 #include "gstaudiorate.h"
68
69 #define GST_CAT_DEFAULT audio_rate_debug
70 GST_DEBUG_CATEGORY_STATIC (audio_rate_debug);
71
72 /* GstAudioRate signals and args */
73 enum
74 {
75   /* FILL ME */
76   LAST_SIGNAL
77 };
78
79 #define DEFAULT_SILENT     TRUE
80 #define DEFAULT_TOLERANCE  0
81 #define DEFAULT_SKIP_TO_FIRST FALSE
82
83 enum
84 {
85   ARG_0,
86   ARG_IN,
87   ARG_OUT,
88   ARG_ADD,
89   ARG_DROP,
90   ARG_SILENT,
91   ARG_TOLERANCE,
92   ARG_SKIP_TO_FIRST
93 };
94
95 static GstStaticPadTemplate gst_audio_rate_src_template =
96     GST_STATIC_PAD_TEMPLATE ("src",
97     GST_PAD_SRC,
98     GST_PAD_ALWAYS,
99     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS ";"
100         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
101     );
102
103 static GstStaticPadTemplate gst_audio_rate_sink_template =
104     GST_STATIC_PAD_TEMPLATE ("sink",
105     GST_PAD_SINK,
106     GST_PAD_ALWAYS,
107     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS ";"
108         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
109     );
110
111 static void gst_audio_rate_base_init (gpointer g_class);
112 static void gst_audio_rate_class_init (GstAudioRateClass * klass);
113 static void gst_audio_rate_init (GstAudioRate * audiorate);
114 static gboolean gst_audio_rate_sink_event (GstPad * pad, GstEvent * event);
115 static gboolean gst_audio_rate_src_event (GstPad * pad, GstEvent * event);
116 static GstFlowReturn gst_audio_rate_chain (GstPad * pad, GstBuffer * buf);
117
118 static void gst_audio_rate_set_property (GObject * object,
119     guint prop_id, const GValue * value, GParamSpec * pspec);
120 static void gst_audio_rate_get_property (GObject * object,
121     guint prop_id, GValue * value, GParamSpec * pspec);
122
123 static GstStateChangeReturn gst_audio_rate_change_state (GstElement * element,
124     GstStateChange transition);
125
126 static GstElementClass *parent_class = NULL;
127
128 /*static guint gst_audio_rate_signals[LAST_SIGNAL] = { 0 }; */
129
130 static GParamSpec *pspec_drop = NULL;
131 static GParamSpec *pspec_add = NULL;
132
133 static GType
134 gst_audio_rate_get_type (void)
135 {
136   static GType audio_rate_type = 0;
137
138   if (!audio_rate_type) {
139     static const GTypeInfo audio_rate_info = {
140       sizeof (GstAudioRateClass),
141       gst_audio_rate_base_init,
142       NULL,
143       (GClassInitFunc) gst_audio_rate_class_init,
144       NULL,
145       NULL,
146       sizeof (GstAudioRate),
147       0,
148       (GInstanceInitFunc) gst_audio_rate_init,
149     };
150
151     audio_rate_type = g_type_register_static (GST_TYPE_ELEMENT,
152         "GstAudioRate", &audio_rate_info, 0);
153   }
154
155   return audio_rate_type;
156 }
157
158 static void
159 gst_audio_rate_base_init (gpointer g_class)
160 {
161   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
162
163   gst_element_class_set_details_simple (element_class,
164       "Audio rate adjuster", "Filter/Effect/Audio",
165       "Drops/duplicates/adjusts timestamps on audio samples to make a perfect stream",
166       "Wim Taymans <wim@fluendo.com>");
167
168   gst_element_class_add_pad_template (element_class,
169       gst_static_pad_template_get (&gst_audio_rate_sink_template));
170   gst_element_class_add_pad_template (element_class,
171       gst_static_pad_template_get (&gst_audio_rate_src_template));
172 }
173
174 static void
175 gst_audio_rate_class_init (GstAudioRateClass * klass)
176 {
177   GObjectClass *object_class = G_OBJECT_CLASS (klass);
178   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
179
180   parent_class = g_type_class_peek_parent (klass);
181
182   object_class->set_property = gst_audio_rate_set_property;
183   object_class->get_property = gst_audio_rate_get_property;
184
185   g_object_class_install_property (object_class, ARG_IN,
186       g_param_spec_uint64 ("in", "In",
187           "Number of input samples", 0, G_MAXUINT64, 0,
188           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
189   g_object_class_install_property (object_class, ARG_OUT,
190       g_param_spec_uint64 ("out", "Out", "Number of output samples", 0,
191           G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
192   pspec_add = g_param_spec_uint64 ("add", "Add", "Number of added samples",
193       0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
194   g_object_class_install_property (object_class, ARG_ADD, pspec_add);
195   pspec_drop = g_param_spec_uint64 ("drop", "Drop", "Number of dropped samples",
196       0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
197   g_object_class_install_property (object_class, ARG_DROP, pspec_drop);
198   g_object_class_install_property (object_class, ARG_SILENT,
199       g_param_spec_boolean ("silent", "silent",
200           "Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT,
201           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202   /**
203    * GstAudioRate:tolerance
204    *
205    * The difference between incoming timestamp and next timestamp must exceed
206    * the given value for audiorate to add or drop samples.
207    *
208    * Since: 0.10.26
209    **/
210   g_object_class_install_property (object_class, ARG_TOLERANCE,
211       g_param_spec_uint64 ("tolerance", "tolerance",
212           "Only act if timestamp jitter/imperfection exceeds indicated tolerance (ns)",
213           0, G_MAXUINT64, DEFAULT_TOLERANCE,
214           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
215
216   /**
217    * GstAudioRate:skip-to-first:
218    *
219    * Don't produce buffers before the first one we receive.
220    *
221    * Since: 0.10.33
222    **/
223   g_object_class_install_property (object_class, ARG_SKIP_TO_FIRST,
224       g_param_spec_boolean ("skip-to-first", "Skip to first buffer",
225           "Don't produce buffers before the first one we receive",
226           DEFAULT_SKIP_TO_FIRST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
227
228   element_class->change_state = gst_audio_rate_change_state;
229 }
230
231 static void
232 gst_audio_rate_reset (GstAudioRate * audiorate)
233 {
234   audiorate->next_offset = -1;
235   audiorate->next_ts = -1;
236   audiorate->discont = TRUE;
237   gst_segment_init (&audiorate->sink_segment, GST_FORMAT_UNDEFINED);
238   gst_segment_init (&audiorate->src_segment, GST_FORMAT_TIME);
239
240   GST_DEBUG_OBJECT (audiorate, "handle reset");
241 }
242
243 static gboolean
244 gst_audio_rate_setcaps (GstPad * pad, GstCaps * caps)
245 {
246   GstAudioRate *audiorate;
247   GstStructure *structure;
248   GstPad *otherpad;
249   gboolean ret = FALSE;
250   gint channels, width, rate;
251
252   audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));
253
254   structure = gst_caps_get_structure (caps, 0);
255
256   if (!gst_structure_get_int (structure, "channels", &channels))
257     goto wrong_caps;
258   if (!gst_structure_get_int (structure, "width", &width))
259     goto wrong_caps;
260   if (!gst_structure_get_int (structure, "rate", &rate))
261     goto wrong_caps;
262
263   audiorate->bytes_per_sample = channels * (width / 8);
264   if (audiorate->bytes_per_sample == 0)
265     goto wrong_format;
266
267   audiorate->rate = rate;
268
269   /* the format is correct, configure caps on other pad */
270   otherpad = (pad == audiorate->srcpad) ? audiorate->sinkpad :
271       audiorate->srcpad;
272
273   ret = gst_pad_set_caps (otherpad, caps);
274
275 done:
276   gst_object_unref (audiorate);
277   return ret;
278
279   /* ERRORS */
280 wrong_caps:
281   {
282     GST_DEBUG_OBJECT (audiorate, "could not get channels/width from caps");
283     goto done;
284   }
285 wrong_format:
286   {
287     GST_DEBUG_OBJECT (audiorate, "bytes_per_samples gave 0");
288     goto done;
289   }
290 }
291
292 static void
293 gst_audio_rate_init (GstAudioRate * audiorate)
294 {
295   audiorate->sinkpad =
296       gst_pad_new_from_static_template (&gst_audio_rate_sink_template, "sink");
297   gst_pad_set_event_function (audiorate->sinkpad, gst_audio_rate_sink_event);
298   gst_pad_set_chain_function (audiorate->sinkpad, gst_audio_rate_chain);
299   gst_pad_set_setcaps_function (audiorate->sinkpad, gst_audio_rate_setcaps);
300   gst_pad_set_getcaps_function (audiorate->sinkpad, gst_pad_proxy_getcaps);
301   gst_element_add_pad (GST_ELEMENT (audiorate), audiorate->sinkpad);
302
303   audiorate->srcpad =
304       gst_pad_new_from_static_template (&gst_audio_rate_src_template, "src");
305   gst_pad_set_event_function (audiorate->srcpad, gst_audio_rate_src_event);
306   gst_pad_set_setcaps_function (audiorate->srcpad, gst_audio_rate_setcaps);
307   gst_pad_set_getcaps_function (audiorate->srcpad, gst_pad_proxy_getcaps);
308   gst_element_add_pad (GST_ELEMENT (audiorate), audiorate->srcpad);
309
310   audiorate->in = 0;
311   audiorate->out = 0;
312   audiorate->drop = 0;
313   audiorate->add = 0;
314   audiorate->silent = DEFAULT_SILENT;
315   audiorate->tolerance = DEFAULT_TOLERANCE;
316 }
317
318 static void
319 gst_audio_rate_fill_to_time (GstAudioRate * audiorate, GstClockTime time)
320 {
321   GstBuffer *buf;
322
323   GST_DEBUG_OBJECT (audiorate, "next_ts: %" GST_TIME_FORMAT
324       ", filling to %" GST_TIME_FORMAT, GST_TIME_ARGS (audiorate->next_ts),
325       GST_TIME_ARGS (time));
326
327   if (!GST_CLOCK_TIME_IS_VALID (time) ||
328       !GST_CLOCK_TIME_IS_VALID (audiorate->next_ts))
329     return;
330
331   /* feed an empty buffer to chain with the given timestamp,
332    * it will take care of filling */
333   buf = gst_buffer_new ();
334   GST_BUFFER_TIMESTAMP (buf) = time;
335   gst_audio_rate_chain (audiorate->sinkpad, buf);
336 }
337
338 static gboolean
339 gst_audio_rate_sink_event (GstPad * pad, GstEvent * event)
340 {
341   gboolean res;
342   GstAudioRate *audiorate;
343
344   audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));
345
346   switch (GST_EVENT_TYPE (event)) {
347     case GST_EVENT_FLUSH_STOP:
348       GST_DEBUG_OBJECT (audiorate, "handling FLUSH_STOP");
349       gst_audio_rate_reset (audiorate);
350       res = gst_pad_push_event (audiorate->srcpad, event);
351       break;
352     case GST_EVENT_NEWSEGMENT:
353     {
354       GstFormat format;
355       gdouble rate, arate;
356       gint64 start, stop, time;
357       gboolean update;
358
359       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
360           &start, &stop, &time);
361
362       GST_DEBUG_OBJECT (audiorate, "handle NEWSEGMENT");
363       /* FIXME: bad things will likely happen if rate < 0 ... */
364       if (!update) {
365         /* a new segment starts. We need to figure out what will be the next
366          * sample offset. We mark the offsets as invalid so that the _chain
367          * function will perform this calculation. */
368         gst_audio_rate_fill_to_time (audiorate, audiorate->src_segment.stop);
369         audiorate->next_offset = -1;
370         audiorate->next_ts = -1;
371       } else {
372         gst_audio_rate_fill_to_time (audiorate, audiorate->src_segment.start);
373       }
374
375       /* we accept all formats */
376       gst_segment_set_newsegment_full (&audiorate->sink_segment, update, rate,
377           arate, format, start, stop, time);
378
379       GST_DEBUG_OBJECT (audiorate, "updated segment: %" GST_SEGMENT_FORMAT,
380           &audiorate->sink_segment);
381
382       if (format == GST_FORMAT_TIME) {
383         /* TIME formats can be copied to src and forwarded */
384         res = gst_pad_push_event (audiorate->srcpad, event);
385         memcpy (&audiorate->src_segment, &audiorate->sink_segment,
386             sizeof (GstSegment));
387       } else {
388         /* other formats will be handled in the _chain function */
389         gst_event_unref (event);
390         res = TRUE;
391       }
392       break;
393     }
394     case GST_EVENT_EOS:
395       /* Fill segment until the end */
396       if (GST_CLOCK_TIME_IS_VALID (audiorate->src_segment.stop))
397         gst_audio_rate_fill_to_time (audiorate, audiorate->src_segment.stop);
398       res = gst_pad_push_event (audiorate->srcpad, event);
399       break;
400     default:
401       res = gst_pad_push_event (audiorate->srcpad, event);
402       break;
403   }
404
405   gst_object_unref (audiorate);
406
407   return res;
408 }
409
410 static gboolean
411 gst_audio_rate_src_event (GstPad * pad, GstEvent * event)
412 {
413   gboolean res;
414   GstAudioRate *audiorate;
415
416   audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));
417
418   switch (GST_EVENT_TYPE (event)) {
419     default:
420       res = gst_pad_push_event (audiorate->sinkpad, event);
421       break;
422   }
423
424   gst_object_unref (audiorate);
425
426   return res;
427 }
428
429 static gboolean
430 gst_audio_rate_convert (GstAudioRate * audiorate,
431     GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
432 {
433   if (src_fmt == dest_fmt) {
434     *dest_val = src_val;
435     return TRUE;
436   }
437
438   switch (src_fmt) {
439     case GST_FORMAT_DEFAULT:
440       switch (dest_fmt) {
441         case GST_FORMAT_BYTES:
442           *dest_val = src_val * audiorate->bytes_per_sample;
443           break;
444         case GST_FORMAT_TIME:
445           *dest_val =
446               gst_util_uint64_scale_int (src_val, GST_SECOND, audiorate->rate);
447           break;
448         default:
449           return FALSE;;
450       }
451       break;
452     case GST_FORMAT_BYTES:
453       switch (dest_fmt) {
454         case GST_FORMAT_DEFAULT:
455           *dest_val = src_val / audiorate->bytes_per_sample;
456           break;
457         case GST_FORMAT_TIME:
458           *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND,
459               audiorate->rate * audiorate->bytes_per_sample);
460           break;
461         default:
462           return FALSE;;
463       }
464       break;
465     case GST_FORMAT_TIME:
466       switch (dest_fmt) {
467         case GST_FORMAT_BYTES:
468           *dest_val = gst_util_uint64_scale_int (src_val,
469               audiorate->rate * audiorate->bytes_per_sample, GST_SECOND);
470           break;
471         case GST_FORMAT_DEFAULT:
472           *dest_val =
473               gst_util_uint64_scale_int (src_val, audiorate->rate, GST_SECOND);
474           break;
475         default:
476           return FALSE;;
477       }
478       break;
479     default:
480       return FALSE;
481   }
482   return TRUE;
483 }
484
485
486 static gboolean
487 gst_audio_rate_convert_segments (GstAudioRate * audiorate)
488 {
489   GstFormat src_fmt, dst_fmt;
490
491   src_fmt = audiorate->sink_segment.format;
492   dst_fmt = audiorate->src_segment.format;
493
494 #define CONVERT_VAL(field) gst_audio_rate_convert (audiorate, \
495                 src_fmt, audiorate->sink_segment.field,       \
496                 dst_fmt, &audiorate->src_segment.field);
497
498   audiorate->sink_segment.rate = audiorate->src_segment.rate;
499   audiorate->sink_segment.abs_rate = audiorate->src_segment.abs_rate;
500   audiorate->sink_segment.flags = audiorate->src_segment.flags;
501   audiorate->sink_segment.applied_rate = audiorate->src_segment.applied_rate;
502   CONVERT_VAL (start);
503   CONVERT_VAL (stop);
504   CONVERT_VAL (time);
505   CONVERT_VAL (accum);
506   CONVERT_VAL (last_stop);
507 #undef CONVERT_VAL
508
509   return TRUE;
510 }
511
512 static void
513 gst_audio_rate_notify_drop (GstAudioRate * audiorate)
514 {
515 #if !GLIB_CHECK_VERSION(2,26,0)
516   g_object_notify ((GObject *) audiorate, "drop");
517 #else
518   g_object_notify_by_pspec ((GObject *) audiorate, pspec_drop);
519 #endif
520 }
521
522 static void
523 gst_audio_rate_notify_add (GstAudioRate * audiorate)
524 {
525 #if !GLIB_CHECK_VERSION(2,26,0)
526   g_object_notify ((GObject *) audiorate, "add");
527 #else
528   g_object_notify_by_pspec ((GObject *) audiorate, pspec_add);
529 #endif
530 }
531
532 static GstFlowReturn
533 gst_audio_rate_chain (GstPad * pad, GstBuffer * buf)
534 {
535   GstAudioRate *audiorate;
536   GstClockTime in_time;
537   guint64 in_offset, in_offset_end, in_samples;
538   guint in_size;
539   GstFlowReturn ret = GST_FLOW_OK;
540   GstClockTimeDiff diff;
541
542   audiorate = GST_AUDIO_RATE (gst_pad_get_parent (pad));
543
544   /* need to be negotiated now */
545   if (audiorate->bytes_per_sample == 0)
546     goto not_negotiated;
547
548   /* we have a new pending segment */
549   if (audiorate->next_offset == -1) {
550     gint64 pos;
551
552     /* update the TIME segment */
553     gst_audio_rate_convert_segments (audiorate);
554
555     /* first buffer, we are negotiated and we have a segment, calculate the
556      * current expected offsets based on the segment.start, which is the first
557      * media time of the segment and should match the media time of the first
558      * buffer in that segment, which is the offset expressed in DEFAULT units.
559      */
560     /* convert first timestamp of segment to sample position */
561     pos = gst_util_uint64_scale_int (audiorate->src_segment.start,
562         audiorate->rate, GST_SECOND);
563
564     GST_DEBUG_OBJECT (audiorate, "resync to offset %" G_GINT64_FORMAT, pos);
565
566     /* resyncing is a discont */
567     audiorate->discont = TRUE;
568
569     audiorate->next_offset = pos;
570     audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset,
571         GST_SECOND, audiorate->rate);
572
573     if (audiorate->skip_to_first && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
574       GST_DEBUG_OBJECT (audiorate, "but skipping to first buffer instead");
575       pos = gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf),
576           audiorate->rate, GST_SECOND);
577       GST_DEBUG_OBJECT (audiorate, "so resync to offset %" G_GINT64_FORMAT,
578           pos);
579       audiorate->next_offset = pos;
580       audiorate->next_ts = GST_BUFFER_TIMESTAMP (buf);
581     }
582   }
583
584   audiorate->in++;
585
586   in_time = GST_BUFFER_TIMESTAMP (buf);
587   if (in_time == GST_CLOCK_TIME_NONE) {
588     GST_DEBUG_OBJECT (audiorate, "no timestamp, using expected next time");
589     in_time = audiorate->next_ts;
590   }
591
592   in_size = GST_BUFFER_SIZE (buf);
593   in_samples = in_size / audiorate->bytes_per_sample;
594
595   /* calculate the buffer offset */
596   in_offset = gst_util_uint64_scale_int_round (in_time, audiorate->rate,
597       GST_SECOND);
598   in_offset_end = in_offset + in_samples;
599
600   GST_LOG_OBJECT (audiorate,
601       "in_time:%" GST_TIME_FORMAT ", in_duration:%" GST_TIME_FORMAT
602       ", in_size:%u, in_offset:%" G_GUINT64_FORMAT ", in_offset_end:%"
603       G_GUINT64_FORMAT ", ->next_offset:%" G_GUINT64_FORMAT ", ->next_ts:%"
604       GST_TIME_FORMAT, GST_TIME_ARGS (in_time),
605       GST_TIME_ARGS (GST_FRAMES_TO_CLOCK_TIME (in_samples, audiorate->rate)),
606       in_size, in_offset, in_offset_end, audiorate->next_offset,
607       GST_TIME_ARGS (audiorate->next_ts));
608
609   diff = in_time - audiorate->next_ts;
610   if (diff <= (GstClockTimeDiff) audiorate->tolerance &&
611       diff >= (GstClockTimeDiff) - audiorate->tolerance) {
612     /* buffer time close enough to expected time,
613      * so produce a perfect stream by simply 'shifting'
614      * it to next ts and offset and sending */
615     GST_LOG_OBJECT (audiorate, "within tolerance %" GST_TIME_FORMAT,
616         GST_TIME_ARGS (audiorate->tolerance));
617     /* The outgoing buffer's offset will be set to ->next_offset, we also
618      * need to adjust the offset_end value accordingly */
619     in_offset_end = audiorate->next_offset + in_samples;
620     goto send;
621   }
622
623   /* do we need to insert samples */
624   if (in_offset > audiorate->next_offset) {
625     GstBuffer *fill;
626     gint fillsize;
627     guint64 fillsamples;
628
629     /* We don't want to allocate a single unreasonably huge buffer - it might
630        be hundreds of megabytes. So, limit each output buffer to one second of
631        audio */
632     fillsamples = in_offset - audiorate->next_offset;
633
634     while (fillsamples > 0) {
635       guint64 cursamples = MIN (fillsamples, audiorate->rate);
636
637       fillsamples -= cursamples;
638       fillsize = cursamples * audiorate->bytes_per_sample;
639
640       fill = gst_buffer_new_and_alloc (fillsize);
641       /* FIXME, 0 might not be the silence byte for the negotiated format. */
642       memset (GST_BUFFER_DATA (fill), 0, fillsize);
643
644       GST_DEBUG_OBJECT (audiorate, "inserting %" G_GUINT64_FORMAT " samples",
645           cursamples);
646
647       GST_BUFFER_OFFSET (fill) = audiorate->next_offset;
648       audiorate->next_offset += cursamples;
649       GST_BUFFER_OFFSET_END (fill) = audiorate->next_offset;
650
651       /* Use next timestamp, then calculate following timestamp based on 
652        * offset to get duration. Neccesary complexity to get 'perfect' 
653        * streams */
654       GST_BUFFER_TIMESTAMP (fill) = audiorate->next_ts;
655       audiorate->next_ts = gst_util_uint64_scale_int (audiorate->next_offset,
656           GST_SECOND, audiorate->rate);
657       GST_BUFFER_DURATION (fill) = audiorate->next_ts -
658           GST_BUFFER_TIMESTAMP (fill);
659
660       /* we created this buffer to fill a gap */
661       GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_GAP);
662       /* set discont if it's pending, this is mostly done for the first buffer 
663        * and after a flushing seek */
664       if (audiorate->discont) {
665         GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_DISCONT);
666         audiorate->discont = FALSE;
667       }
668       gst_buffer_set_caps (fill, GST_PAD_CAPS (audiorate->srcpad));
669
670       ret = gst_pad_push (audiorate->srcpad, fill);
671       if (ret != GST_FLOW_OK)
672         goto beach;
673       audiorate->out++;
674       audiorate->add += cursamples;
675
676       if (!audiorate->silent)
677         gst_audio_rate_notify_add (audiorate);
678     }
679
680   } else if (in_offset < audiorate->next_offset) {
681     /* need to remove samples */
682     if (in_offset_end <= audiorate->next_offset) {
683       guint64 drop = in_size / audiorate->bytes_per_sample;
684
685       audiorate->drop += drop;
686
687       GST_DEBUG_OBJECT (audiorate, "dropping %" G_GUINT64_FORMAT " samples",
688           drop);
689
690       /* we can drop the buffer completely */
691       gst_buffer_unref (buf);
692       buf = NULL;
693
694       if (!audiorate->silent)
695         gst_audio_rate_notify_drop (audiorate);
696
697       goto beach;
698     } else {
699       guint64 truncsamples;
700       guint truncsize, leftsize;
701       GstBuffer *trunc;
702
703       /* truncate buffer */
704       truncsamples = audiorate->next_offset - in_offset;
705       truncsize = truncsamples * audiorate->bytes_per_sample;
706       leftsize = in_size - truncsize;
707
708       trunc = gst_buffer_create_sub (buf, truncsize, leftsize);
709
710       gst_buffer_unref (buf);
711       buf = trunc;
712
713       gst_buffer_set_caps (buf, GST_PAD_CAPS (audiorate->srcpad));
714
715       audiorate->drop += truncsamples;
716       GST_DEBUG_OBJECT (audiorate, "truncating %" G_GUINT64_FORMAT " samples",
717           truncsamples);
718
719       if (!audiorate->silent)
720         gst_audio_rate_notify_drop (audiorate);
721     }
722   }
723
724 send:
725   if (GST_BUFFER_SIZE (buf) == 0)
726     goto beach;
727
728   /* Now calculate parameters for whichever buffer (either the original
729    * or truncated one) we're pushing. */
730   GST_BUFFER_OFFSET (buf) = audiorate->next_offset;
731   GST_BUFFER_OFFSET_END (buf) = in_offset_end;
732
733   GST_BUFFER_TIMESTAMP (buf) = audiorate->next_ts;
734   audiorate->next_ts = gst_util_uint64_scale_int (in_offset_end,
735       GST_SECOND, audiorate->rate);
736   GST_BUFFER_DURATION (buf) = audiorate->next_ts - GST_BUFFER_TIMESTAMP (buf);
737
738   if (audiorate->discont) {
739     /* we need to output a discont buffer, do so now */
740     GST_DEBUG_OBJECT (audiorate, "marking DISCONT on output buffer");
741     buf = gst_buffer_make_metadata_writable (buf);
742     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
743     audiorate->discont = FALSE;
744   } else if (GST_BUFFER_IS_DISCONT (buf)) {
745     /* else we make everything continuous so we can safely remove the DISCONT
746      * flag from the buffer if there was one */
747     GST_DEBUG_OBJECT (audiorate, "removing DISCONT from buffer");
748     buf = gst_buffer_make_metadata_writable (buf);
749     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
750   }
751
752   /* set last_stop on segment */
753   gst_segment_set_last_stop (&audiorate->src_segment, GST_FORMAT_TIME,
754       GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf));
755
756   ret = gst_pad_push (audiorate->srcpad, buf);
757   buf = NULL;
758   audiorate->out++;
759
760   audiorate->next_offset = in_offset_end;
761 beach:
762
763   if (buf)
764     gst_buffer_unref (buf);
765
766   gst_object_unref (audiorate);
767
768   return ret;
769
770   /* ERRORS */
771 not_negotiated:
772   {
773     gst_buffer_unref (buf);
774
775     GST_ELEMENT_ERROR (audiorate, STREAM, FORMAT,
776         (NULL), ("pipeline error, format was not negotiated"));
777     return GST_FLOW_NOT_NEGOTIATED;
778   }
779 }
780
781 static void
782 gst_audio_rate_set_property (GObject * object,
783     guint prop_id, const GValue * value, GParamSpec * pspec)
784 {
785   GstAudioRate *audiorate = GST_AUDIO_RATE (object);
786
787   switch (prop_id) {
788     case ARG_SILENT:
789       audiorate->silent = g_value_get_boolean (value);
790       break;
791     case ARG_TOLERANCE:
792       audiorate->tolerance = g_value_get_uint64 (value);
793       break;
794     case ARG_SKIP_TO_FIRST:
795       audiorate->skip_to_first = g_value_get_boolean (value);
796       break;
797     default:
798       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
799       break;
800   }
801 }
802
803 static void
804 gst_audio_rate_get_property (GObject * object,
805     guint prop_id, GValue * value, GParamSpec * pspec)
806 {
807   GstAudioRate *audiorate = GST_AUDIO_RATE (object);
808
809   switch (prop_id) {
810     case ARG_IN:
811       g_value_set_uint64 (value, audiorate->in);
812       break;
813     case ARG_OUT:
814       g_value_set_uint64 (value, audiorate->out);
815       break;
816     case ARG_ADD:
817       g_value_set_uint64 (value, audiorate->add);
818       break;
819     case ARG_DROP:
820       g_value_set_uint64 (value, audiorate->drop);
821       break;
822     case ARG_SILENT:
823       g_value_set_boolean (value, audiorate->silent);
824       break;
825     case ARG_TOLERANCE:
826       g_value_set_uint64 (value, audiorate->tolerance);
827       break;
828     case ARG_SKIP_TO_FIRST:
829       g_value_set_boolean (value, audiorate->skip_to_first);
830       break;
831     default:
832       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
833       break;
834   }
835 }
836
837 static GstStateChangeReturn
838 gst_audio_rate_change_state (GstElement * element, GstStateChange transition)
839 {
840   GstAudioRate *audiorate = GST_AUDIO_RATE (element);
841
842   switch (transition) {
843     case GST_STATE_CHANGE_PAUSED_TO_READY:
844       break;
845     case GST_STATE_CHANGE_READY_TO_PAUSED:
846       audiorate->in = 0;
847       audiorate->out = 0;
848       audiorate->drop = 0;
849       audiorate->bytes_per_sample = 0;
850       audiorate->add = 0;
851       gst_audio_rate_reset (audiorate);
852       break;
853     default:
854       break;
855   }
856
857   if (parent_class->change_state)
858     return parent_class->change_state (element, transition);
859
860   return GST_STATE_CHANGE_SUCCESS;
861 }
862
863 static gboolean
864 plugin_init (GstPlugin * plugin)
865 {
866   GST_DEBUG_CATEGORY_INIT (audio_rate_debug, "audiorate", 0,
867       "AudioRate stream fixer");
868
869   return gst_element_register (plugin, "audiorate", GST_RANK_NONE,
870       GST_TYPE_AUDIO_RATE);
871 }
872
873 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
874     GST_VERSION_MINOR,
875     "audiorate",
876     "Adjusts audio frames",
877     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)