gst/adder/gstadder.c (gst_adder_src_event, gst_adder_collected, gst_adder_change_stat...
[platform/upstream/gstreamer.git] / gst / adder / gstadder.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2001 Thomas <thomas@apestaart.org>
4  *               2005,2006 Wim Taymans <wim@fluendo.com>
5  *
6  * adder.c: Adder element, N in, one out, samples are added
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23 /**
24  * SECTION:element-adder
25  *
26  * <refsect2>
27  * <para>
28  * The Adder allows to mix several streams into one by adding the data.
29  * Mixed data is clamped to the min/max values of the data format.
30  * </para>
31  * <title>Example launch line</title>
32  * <para>
33  * <programlisting>
34  * gst-launch audiotestsrc freq=100 ! adder name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
35  * </programlisting>
36  * This pipeline produces two sine waves mixed together.
37  * </para>
38  * <para>
39  * The Adder currently mixes all data received on the sinkpads as soon as possible
40  * without trying to synchronize the streams.
41  * </para>
42  * </refsect2>
43  *
44  * Last reviewed on 2006-05-09 (0.10.7)
45  */
46 /* Element-Checklist-Version: 5 */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51 #include "gstadder.h"
52 #include <gst/audio/audio.h>
53 #include <string.h>             /* strcmp */
54
55 /* highest positive/lowest negative x-bit value we can use for clamping */
56 #define MAX_INT_32  ((gint32) (0x7fffffff))
57 #define MAX_INT_16  ((gint16) (0x7fff))
58 #define MAX_INT_8   ((gint8)  (0x7f))
59 #define MAX_UINT_32 ((guint32)(0xffffffff))
60 #define MAX_UINT_16 ((guint16)(0xffff))
61 #define MAX_UINT_8  ((guint8) (0xff))
62
63 #define MIN_INT_32  ((gint32) (0x80000000))
64 #define MIN_INT_16  ((gint16) (0x8000))
65 #define MIN_INT_8   ((gint8)  (0x80))
66 #define MIN_UINT_32 ((guint32)(0x00000000))
67 #define MIN_UINT_16 ((guint16)(0x0000))
68 #define MIN_UINT_8  ((guint8) (0x00))
69
70 #define GST_CAT_DEFAULT gst_adder_debug
71 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
72
73 /* elementfactory information */
74 static const GstElementDetails adder_details = GST_ELEMENT_DETAILS ("Adder",
75     "Generic/Audio",
76     "Add N audio channels together",
77     "Thomas <thomas@apestaart.org>");
78
79 static GstStaticPadTemplate gst_adder_src_template =
80     GST_STATIC_PAD_TEMPLATE ("src",
81     GST_PAD_SRC,
82     GST_PAD_ALWAYS,
83     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
84         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
85     );
86
87 static GstStaticPadTemplate gst_adder_sink_template =
88     GST_STATIC_PAD_TEMPLATE ("sink%d",
89     GST_PAD_SINK,
90     GST_PAD_REQUEST,
91     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
92         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
93     );
94
95 static void gst_adder_class_init (GstAdderClass * klass);
96 static void gst_adder_init (GstAdder * adder);
97 static void gst_adder_finalize (GObject * object);
98
99 static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
100 static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
101 static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
102 static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
103
104 static GstPad *gst_adder_request_new_pad (GstElement * element,
105     GstPadTemplate * temp, const gchar * unused);
106 static void gst_adder_release_pad (GstElement * element, GstPad * pad);
107
108 static GstStateChangeReturn gst_adder_change_state (GstElement * element,
109     GstStateChange transition);
110
111 static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
112     gpointer user_data);
113
114 static GstElementClass *parent_class = NULL;
115
116 GType
117 gst_adder_get_type (void)
118 {
119   static GType adder_type = 0;
120
121   if (G_UNLIKELY (adder_type == 0)) {
122     static const GTypeInfo adder_info = {
123       sizeof (GstAdderClass), NULL, NULL,
124       (GClassInitFunc) gst_adder_class_init, NULL, NULL,
125       sizeof (GstAdder), 0,
126       (GInstanceInitFunc) gst_adder_init,
127     };
128
129     adder_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAdder",
130         &adder_info, 0);
131     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "adder", 0,
132         "audio channel mixing element");
133   }
134   return adder_type;
135 }
136
137 /* clipping versions */
138 #define MAKE_FUNC(name,type,ttype,min,max)                      \
139 static void name (type *out, type *in, gint bytes) {            \
140   gint i;                                                       \
141   for (i = 0; i < bytes / sizeof (type); i++)                   \
142     out[i] = CLAMP ((ttype)out[i] + (ttype)in[i], min, max);    \
143 }
144
145 /* non-clipping versions (for float) */
146 #define MAKE_FUNC_NC(name,type,ttype)                           \
147 static void name (type *out, type *in, gint bytes) {            \
148   gint i;                                                       \
149   for (i = 0; i < bytes / sizeof (type); i++)                   \
150     out[i] = (ttype)out[i] + (ttype)in[i];                      \
151 }
152
153 /* *INDENT-OFF* */
154 MAKE_FUNC (add_int32, gint32, gint64, MIN_INT_32, MAX_INT_32)
155 MAKE_FUNC (add_int16, gint16, gint32, MIN_INT_16, MAX_INT_16)
156 MAKE_FUNC (add_int8, gint8, gint16, MIN_INT_8, MAX_INT_8)
157 MAKE_FUNC (add_uint32, guint32, guint64, MIN_UINT_32, MAX_UINT_32)
158 MAKE_FUNC (add_uint16, guint16, guint32, MIN_UINT_16, MAX_UINT_16)
159 MAKE_FUNC (add_uint8, guint8, guint16, MIN_UINT_8, MAX_UINT_8)
160 MAKE_FUNC_NC (add_float64, gdouble, gdouble)
161 MAKE_FUNC_NC (add_float32, gfloat, gfloat)
162 /* *INDENT-ON* */
163
164 static gboolean
165 gst_adder_setcaps (GstPad * pad, GstCaps * caps)
166 {
167   GstAdder *adder;
168   GList *pads;
169   GstStructure *structure;
170   const char *media_type;
171
172   adder = GST_ADDER (GST_PAD_PARENT (pad));
173
174   GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
175       GST_PAD_NAME (pad), caps);
176
177   /* FIXME, see if the other pads can accept the format. Also lock the
178    * format on the other pads to this new format. */
179   GST_OBJECT_LOCK (adder);
180   pads = GST_ELEMENT (adder)->pads;
181   while (pads) {
182     GstPad *otherpad = GST_PAD (pads->data);
183
184     if (otherpad != pad) {
185       gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
186     }
187     pads = g_list_next (pads);
188   }
189   GST_OBJECT_UNLOCK (adder);
190
191   /* parse caps now */
192   structure = gst_caps_get_structure (caps, 0);
193   media_type = gst_structure_get_name (structure);
194   if (strcmp (media_type, "audio/x-raw-int") == 0) {
195     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format int");
196     adder->format = GST_ADDER_FORMAT_INT;
197     gst_structure_get_int (structure, "width", &adder->width);
198     gst_structure_get_int (structure, "depth", &adder->depth);
199     gst_structure_get_int (structure, "endianness", &adder->endianness);
200     gst_structure_get_boolean (structure, "signed", &adder->is_signed);
201
202     if (adder->endianness != G_BYTE_ORDER)
203       goto not_supported;
204
205     switch (adder->width) {
206       case 8:
207         adder->func = (adder->is_signed ?
208             (GstAdderFunction) add_int8 : (GstAdderFunction) add_uint8);
209         break;
210       case 16:
211         adder->func = (adder->is_signed ?
212             (GstAdderFunction) add_int16 : (GstAdderFunction) add_uint16);
213         break;
214       case 32:
215         adder->func = (adder->is_signed ?
216             (GstAdderFunction) add_int32 : (GstAdderFunction) add_uint32);
217         break;
218       default:
219         goto not_supported;
220     }
221   } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
222     GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format float");
223     adder->format = GST_ADDER_FORMAT_FLOAT;
224     gst_structure_get_int (structure, "width", &adder->width);
225
226     switch (adder->width) {
227       case 32:
228         adder->func = (GstAdderFunction) add_float32;
229         break;
230       case 64:
231         adder->func = (GstAdderFunction) add_float64;
232         break;
233       default:
234         goto not_supported;
235     }
236   } else {
237     goto not_supported;
238   }
239
240   gst_structure_get_int (structure, "channels", &adder->channels);
241   gst_structure_get_int (structure, "rate", &adder->rate);
242   /* precalc bps */
243   adder->bps = (adder->width / 8) * adder->channels;
244
245   return TRUE;
246
247   /* ERRORS */
248 not_supported:
249   {
250     GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
251     return FALSE;
252   }
253 }
254
255 /* FIXME, the duration query should reflect how long you will produce
256  * data, that is the amount of stream time until you will emit EOS.
257  *
258  * For synchronized mixing this is always the max of all the durations
259  * of upstream since we emit EOS when all of them finished.
260  *
261  * We don't do synchronized mixing so this really depends on where the
262  * streams where punched in and what their relative offsets are against
263  * eachother which we can get from the first timestamps we see.
264  *
265  * When we add a new stream (or remove a stream) the duration might
266  * also become invalid again and we need to post a new DURATION
267  * message to notify this fact to the parent.
268  * For now we take the max of all the upstream elements so the simple
269  * cases work at least somewhat.
270  */
271 static gboolean
272 gst_adder_query_duration (GstAdder * adder, GstQuery * query)
273 {
274   gint64 max;
275   gboolean res;
276   GstFormat format;
277   GstIterator *it;
278   gboolean done;
279
280   /* parse format */
281   gst_query_parse_duration (query, &format, NULL);
282
283   max = -1;
284   res = TRUE;
285   done = FALSE;
286
287   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
288   while (!done) {
289     GstIteratorResult ires;
290     gpointer item;
291
292     ires = gst_iterator_next (it, &item);
293     switch (ires) {
294       case GST_ITERATOR_DONE:
295         done = TRUE;
296         break;
297       case GST_ITERATOR_OK:
298       {
299         GstPad *pad = GST_PAD_CAST (item);
300         gint64 duration;
301
302         /* ask sink peer for duration */
303         res &= gst_pad_query_peer_duration (pad, &format, &duration);
304         /* take max from all valid return values */
305         if (res) {
306           /* valid unknown length, stop searching */
307           if (duration == -1) {
308             max = duration;
309             done = TRUE;
310           }
311           /* else see if bigger than current max */
312           else if (duration > max)
313             max = duration;
314         }
315         break;
316       }
317       case GST_ITERATOR_RESYNC:
318         max = -1;
319         res = TRUE;
320         break;
321       default:
322         res = FALSE;
323         done = TRUE;
324         break;
325     }
326   }
327   gst_iterator_free (it);
328
329   if (res) {
330     /* and store the max */
331     gst_query_set_duration (query, format, max);
332   }
333
334   return res;
335 }
336
337 static gboolean
338 gst_adder_query (GstPad * pad, GstQuery * query)
339 {
340   GstAdder *adder = GST_ADDER (gst_pad_get_parent (pad));
341   gboolean res = FALSE;
342
343   switch (GST_QUERY_TYPE (query)) {
344     case GST_QUERY_POSITION:
345     {
346       GstFormat format;
347
348       gst_query_parse_position (query, &format, NULL);
349
350       switch (format) {
351         case GST_FORMAT_TIME:
352           /* FIXME, bring to stream time, might be tricky */
353           gst_query_set_position (query, format, adder->timestamp);
354           res = TRUE;
355           break;
356         case GST_FORMAT_DEFAULT:
357           gst_query_set_position (query, format, adder->offset);
358           res = TRUE;
359           break;
360         default:
361           break;
362       }
363       break;
364     }
365     case GST_QUERY_DURATION:
366       res = gst_adder_query_duration (adder, query);
367       break;
368     default:
369       /* FIXME, needs a custom query handler because we have multiple
370        * sinkpads */
371       res = gst_pad_query_default (pad, query);
372       break;
373   }
374
375   gst_object_unref (adder);
376   return res;
377 }
378
379 static gboolean
380 forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
381 {
382   gst_event_ref (event);
383   GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
384   if (!gst_pad_push_event (pad, event)) {
385     g_value_set_boolean (ret, FALSE);
386     GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
387         event, GST_EVENT_TYPE_NAME (event));
388   } else {
389     GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
390         event, GST_EVENT_TYPE_NAME (event));
391   }
392   gst_object_unref (pad);
393   return TRUE;
394 }
395
396 /* forwards the event to all sinkpads, takes ownership of the
397  * event
398  *
399  * Returns: TRUE if the event could be forwarded on all
400  * sinkpads.
401  */
402 static gboolean
403 forward_event (GstAdder * adder, GstEvent * event)
404 {
405   gboolean ret;
406   GstIterator *it;
407   GValue vret = { 0 };
408
409   GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
410       GST_EVENT_TYPE_NAME (event));
411
412   ret = TRUE;
413
414   g_value_init (&vret, G_TYPE_BOOLEAN);
415   g_value_set_boolean (&vret, TRUE);
416   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
417   gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
418       event);
419   gst_iterator_free (it);
420   gst_event_unref (event);
421
422   ret = g_value_get_boolean (&vret);
423
424   return ret;
425 }
426
427 static gboolean
428 gst_adder_src_event (GstPad * pad, GstEvent * event)
429 {
430   GstAdder *adder;
431   gboolean result;
432
433   adder = GST_ADDER (gst_pad_get_parent (pad));
434
435   switch (GST_EVENT_TYPE (event)) {
436     case GST_EVENT_QOS:
437       /* QoS might be tricky */
438       result = FALSE;
439       break;
440     case GST_EVENT_SEEK:
441     {
442       GstSeekFlags flags;
443       GstSeekType curtype;
444       gint64 cur;
445
446       /* parse the seek parameters */
447       gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
448           &cur, NULL, NULL);
449
450       /* check if we are flushing */
451       if (flags & GST_SEEK_FLAG_FLUSH) {
452         /* make sure we accept nothing anymore and return WRONG_STATE */
453         gst_collect_pads_set_flushing (adder->collect, TRUE);
454
455         /* flushing seek, start flush downstream, the flush will be done
456          * when all pads received a FLUSH_STOP. */
457         gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
458       }
459
460       /* now wait for the collected to be finished and mark a new
461        * segment */
462       GST_OBJECT_LOCK (adder->collect);
463       if (curtype == GST_SEEK_TYPE_SET)
464         adder->segment_position = cur;
465       else
466         adder->segment_position = 0;
467       adder->segment_pending = TRUE;
468       GST_OBJECT_UNLOCK (adder->collect);
469
470       result = forward_event (adder, event);
471       break;
472     }
473     case GST_EVENT_NAVIGATION:
474       /* navigation is rather pointless. */
475       result = FALSE;
476       break;
477     default:
478       /* just forward the rest for now */
479       result = forward_event (adder, event);
480       break;
481   }
482   gst_object_unref (adder);
483
484   return result;
485 }
486
487 static gboolean
488 gst_adder_sink_event (GstPad * pad, GstEvent * event)
489 {
490   GstAdder *adder;
491   gboolean ret;
492
493   adder = GST_ADDER (gst_pad_get_parent (pad));
494
495   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
496       GST_DEBUG_PAD_NAME (pad));
497
498   switch (GST_EVENT_TYPE (event)) {
499     case GST_EVENT_FLUSH_STOP:
500       /* mark a pending new segment. This event is synchronized
501        * with the streaming thread so we can safely update the
502        * variable without races. It's somewhat weird because we
503        * assume the collectpads forwarded the FLUSH_STOP past us
504        * and downstream (using our source pad, the bastard!).
505        */
506       adder->segment_pending = TRUE;
507       break;
508     default:
509       break;
510   }
511
512   /* now GstCollectPads can take care of the rest, e.g. EOS */
513   ret = adder->collect_event (pad, event);
514
515   gst_object_unref (adder);
516   return ret;
517 }
518
519 static void
520 gst_adder_class_init (GstAdderClass * klass)
521 {
522   GObjectClass *gobject_class;
523   GstElementClass *gstelement_class;
524
525   gobject_class = (GObjectClass *) klass;
526
527   gobject_class->finalize = gst_adder_finalize;
528
529   gstelement_class = (GstElementClass *) klass;
530
531   gst_element_class_add_pad_template (gstelement_class,
532       gst_static_pad_template_get (&gst_adder_src_template));
533   gst_element_class_add_pad_template (gstelement_class,
534       gst_static_pad_template_get (&gst_adder_sink_template));
535   gst_element_class_set_details (gstelement_class, &adder_details);
536
537   parent_class = g_type_class_peek_parent (klass);
538
539   gstelement_class->request_new_pad = gst_adder_request_new_pad;
540   gstelement_class->release_pad = gst_adder_release_pad;
541   gstelement_class->change_state = gst_adder_change_state;
542 }
543
544 static void
545 gst_adder_init (GstAdder * adder)
546 {
547   GstPadTemplate *template;
548
549   template = gst_static_pad_template_get (&gst_adder_src_template);
550   adder->srcpad = gst_pad_new_from_template (template, "src");
551   gst_object_unref (template);
552   gst_pad_set_getcaps_function (adder->srcpad,
553       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
554   gst_pad_set_setcaps_function (adder->srcpad,
555       GST_DEBUG_FUNCPTR (gst_adder_setcaps));
556   gst_pad_set_query_function (adder->srcpad,
557       GST_DEBUG_FUNCPTR (gst_adder_query));
558   gst_pad_set_event_function (adder->srcpad,
559       GST_DEBUG_FUNCPTR (gst_adder_src_event));
560   gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
561
562   adder->format = GST_ADDER_FORMAT_UNSET;
563   adder->padcount = 0;
564   adder->func = NULL;
565
566   /* keep track of the sinkpads requested */
567   adder->collect = gst_collect_pads_new ();
568   gst_collect_pads_set_function (adder->collect,
569       GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
570 }
571
572 static void
573 gst_adder_finalize (GObject * object)
574 {
575   GstAdder *adder = GST_ADDER (object);
576
577   gst_object_unref (adder->collect);
578   adder->collect = NULL;
579
580   G_OBJECT_CLASS (parent_class)->finalize (object);
581 }
582
583 static GstPad *
584 gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
585     const gchar * unused)
586 {
587   gchar *name;
588   GstAdder *adder;
589   GstPad *newpad;
590   gint padcount;
591
592   if (templ->direction != GST_PAD_SINK)
593     goto not_sink;
594
595   adder = GST_ADDER (element);
596
597   /* increment pad counter */
598   padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
599
600   name = g_strdup_printf ("sink%d", padcount);
601   newpad = gst_pad_new_from_template (templ, name);
602   GST_DEBUG_OBJECT (adder, "request new pad %s", name);
603   g_free (name);
604
605   gst_pad_set_getcaps_function (newpad,
606       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
607   gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_setcaps));
608   gst_collect_pads_add_pad (adder->collect, newpad, sizeof (GstCollectData));
609
610   /* FIXME: hacked way to override/extend the event function of
611    * GstCollectPads; because it sets its own event function giving the
612    * element no access to events */
613   adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
614   gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event));
615
616   /* takes ownership of the pad */
617   if (!gst_element_add_pad (GST_ELEMENT (adder), newpad))
618     goto could_not_add;
619
620   return newpad;
621
622   /* errors */
623 not_sink:
624   {
625     g_warning ("gstadder: request new pad that is not a SINK pad\n");
626     return NULL;
627   }
628 could_not_add:
629   {
630     GST_DEBUG_OBJECT (adder, "could not add pad");
631     gst_collect_pads_remove_pad (adder->collect, newpad);
632     gst_object_unref (newpad);
633     return NULL;
634   }
635 }
636
637 static void
638 gst_adder_release_pad (GstElement * element, GstPad * pad)
639 {
640   GstAdder *adder;
641
642   adder = GST_ADDER (element);
643
644   GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
645
646   gst_collect_pads_remove_pad (adder->collect, pad);
647   gst_element_remove_pad (element, pad);
648 }
649
650 static GstFlowReturn
651 gst_adder_collected (GstCollectPads * pads, gpointer user_data)
652 {
653   /*
654    * combine channels by adding sample values
655    * basic algorithm :
656    * - this function is called when all pads have a buffer
657    * - get available bytes on all pads.
658    * - repeat for each input pad :
659    *   - read available bytes, copy or add to target buffer
660    *   - if there's an EOS event, remove the input channel
661    * - push out the output buffer
662    */
663   GstAdder *adder;
664   guint size;
665   GSList *collected;
666   GstBuffer *outbuf;
667   GstFlowReturn ret;
668   gpointer outbytes;
669
670   adder = GST_ADDER (user_data);
671
672   /* this is fatal */
673   if (G_UNLIKELY (adder->func == NULL))
674     goto not_negotiated;
675
676   /* get available bytes for reading, this can be 0 which could mean
677    * empty buffers or EOS, which we will catch when we loop over the
678    * pads. */
679   size = gst_collect_pads_available (pads);
680
681   GST_LOG_OBJECT (adder,
682       "starting to cycle through channels, %d bytes available (bps = %d)", size,
683       adder->bps);
684
685   outbuf = NULL;
686   outbytes = NULL;
687
688   for (collected = pads->data; collected; collected = g_slist_next (collected)) {
689     GstCollectData *data;
690     guint8 *bytes;
691     guint len;
692
693     data = (GstCollectData *) collected->data;
694
695     /* get pointer to copy size bytes */
696     len = gst_collect_pads_read (pads, data, &bytes, size);
697     /* length 0 means EOS or an empty buffer so we still need to flush in
698      * case of an empty buffer. */
699     if (len == 0) {
700       GST_LOG_OBJECT (adder, "channel %p: no bytes available", data);
701       goto next;
702     }
703
704     if (outbuf == NULL) {
705       GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes",
706           data, size);
707
708       /* first buffer, alloc size bytes. FIXME, we can easily subbuffer
709        * and _make_writable. */
710       outbuf = gst_buffer_new_and_alloc (size);
711       outbytes = GST_BUFFER_DATA (outbuf);
712       gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
713
714       /* clear if we are only going to fill a partial buffer */
715       if (G_UNLIKELY (size > len))
716         memset (outbytes, 0, size);
717
718       GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p",
719           data, len, bytes);
720
721       /* and copy the data into it */
722       memcpy (outbytes, bytes, len);
723     } else {
724       GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
725           data, len, bytes);
726       /* other buffers, need to add them */
727       adder->func ((gpointer) outbytes, (gpointer) bytes, len);
728     }
729   next:
730     gst_collect_pads_flush (pads, data, len);
731   }
732
733   /* can only happen when no pads to collect or all EOS */
734   if (outbuf == NULL)
735     goto eos;
736
737   /* our timestamping is very simple, just an ever incrementing
738    * counter, the new segment time will take care of their respective
739    * stream time. */
740   if (adder->segment_pending) {
741     GstEvent *event;
742
743     /* FIXME, use rate/applied_rate as set on all sinkpads.
744      * - currently we just set rate as received from last seek-event
745      * We could potentially figure out the duration as well using
746      * the current segment positions and the stated stop positions.
747      * Also we just start from stream time 0 which is rather
748      * weird. For non-synchronized mixing, the time should be
749      * the min of the stream times of all received segments,
750      * rationale being that the duration is at least going to
751      * be as long as the earliest stream we start mixing. This
752      * would also be correct for synchronized mixing but then
753      * the later streams would be delayed until the stream times
754      * match.
755      */
756     event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
757         1.0, GST_FORMAT_TIME, adder->timestamp, -1, adder->segment_position);
758
759     gst_pad_push_event (adder->srcpad, event);
760     adder->segment_pending = FALSE;
761     adder->segment_position = 0;
762   }
763
764   /* set timestamps on the output buffer */
765   GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
766   GST_BUFFER_OFFSET (outbuf) = adder->offset;
767
768   /* for the next timestamp, use the sample counter, which will
769    * never accumulate rounding errors */
770   adder->offset += size / adder->bps;
771   adder->timestamp = gst_util_uint64_scale_int (adder->offset,
772       GST_SECOND, adder->rate);
773
774   /* now we can set the duration of the buffer */
775   GST_BUFFER_DURATION (outbuf) = adder->timestamp -
776       GST_BUFFER_TIMESTAMP (outbuf);
777
778   /* send it out */
779   GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
780       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
781   ret = gst_pad_push (adder->srcpad, outbuf);
782
783   return ret;
784
785   /* ERRORS */
786 not_negotiated:
787   {
788     GST_ELEMENT_ERROR (adder, STREAM, FORMAT, (NULL),
789         ("Unknown data received, not negotiated"));
790     return GST_FLOW_NOT_NEGOTIATED;
791   }
792 eos:
793   {
794     GST_DEBUG_OBJECT (adder, "no data available, must be EOS");
795     gst_pad_push_event (adder->srcpad, gst_event_new_eos ());
796     return GST_FLOW_UNEXPECTED;
797   }
798 }
799
800 static GstStateChangeReturn
801 gst_adder_change_state (GstElement * element, GstStateChange transition)
802 {
803   GstAdder *adder;
804   GstStateChangeReturn ret;
805
806   adder = GST_ADDER (element);
807
808   switch (transition) {
809     case GST_STATE_CHANGE_NULL_TO_READY:
810       break;
811     case GST_STATE_CHANGE_READY_TO_PAUSED:
812       adder->timestamp = 0;
813       adder->offset = 0;
814       adder->segment_pending = TRUE;
815       adder->segment_position = 0;
816       adder->segment_rate = 1.0;
817       gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
818       gst_collect_pads_start (adder->collect);
819       break;
820     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
821       break;
822     case GST_STATE_CHANGE_PAUSED_TO_READY:
823       /* need to unblock the collectpads before calling the
824        * parent change_state so that streaming can finish */
825       gst_collect_pads_stop (adder->collect);
826       break;
827     default:
828       break;
829   }
830
831   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
832
833   switch (transition) {
834     default:
835       break;
836   }
837
838   return ret;
839 }
840
841
842 static gboolean
843 plugin_init (GstPlugin * plugin)
844 {
845   if (!gst_element_register (plugin, "adder", GST_RANK_NONE, GST_TYPE_ADDER)) {
846     return FALSE;
847   }
848
849   return TRUE;
850 }
851
852 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
853     GST_VERSION_MINOR,
854     "adder",
855     "Adds multiple streams",
856     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)