gst/adder/: Cleanup variable names to make the adder-loop easier to understand.
[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  * The adder allows to mix several streams into one by adding the data.
27  * Mixed data is clamped to the min/max values of the data format.
28  *
29  * The adder currently mixes all data received on the sinkpads as soon as
30  * possible without trying to synchronize the streams.
31  *
32  * <refsect2>
33  * <title>Example launch line</title>
34  * |[
35  * gst-launch audiotestsrc freq=100 ! adder name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
36  * ]| This pipeline produces two sine waves mixed together.
37  * </refsect2>
38  *
39  * Last reviewed on 2006-05-09 (0.10.7)
40  */
41 /* Element-Checklist-Version: 5 */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 #include "gstadder.h"
47 #include <gst/audio/audio.h>
48 #include <string.h>             /* strcmp */
49 /*#include <liboil/liboil.h>*/
50
51 /* highest positive/lowest negative x-bit value we can use for clamping */
52 #define MAX_INT_32  ((gint32) (0x7fffffff))
53 #define MAX_INT_16  ((gint16) (0x7fff))
54 #define MAX_INT_8   ((gint8)  (0x7f))
55 #define MAX_UINT_32 ((guint32)(0xffffffff))
56 #define MAX_UINT_16 ((guint16)(0xffff))
57 #define MAX_UINT_8  ((guint8) (0xff))
58
59 #define MIN_INT_32  ((gint32) (0x80000000))
60 #define MIN_INT_16  ((gint16) (0x8000))
61 #define MIN_INT_8   ((gint8)  (0x80))
62 #define MIN_UINT_32 ((guint32)(0x00000000))
63 #define MIN_UINT_16 ((guint16)(0x0000))
64 #define MIN_UINT_8  ((guint8) (0x00))
65
66 #define GST_CAT_DEFAULT gst_adder_debug
67 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
68
69 /* elementfactory information */
70
71 #define CAPS \
72   "audio/x-raw-int, " \
73   "rate = (int) [ 1, MAX ], " \
74   "channels = (int) [ 1, MAX ], " \
75   "endianness = (int) BYTE_ORDER, " \
76   "width = (int) 32, " \
77   "depth = (int) 32, " \
78   "signed = (boolean) { true, false } ;" \
79   "audio/x-raw-int, " \
80   "rate = (int) [ 1, MAX ], " \
81   "channels = (int) [ 1, MAX ], " \
82   "endianness = (int) BYTE_ORDER, " \
83   "width = (int) 16, " \
84   "depth = (int) 16, " \
85   "signed = (boolean) { true, false } ;" \
86   "audio/x-raw-int, " \
87   "rate = (int) [ 1, MAX ], " \
88   "channels = (int) [ 1, MAX ], " \
89   "endianness = (int) BYTE_ORDER, " \
90   "width = (int) 8, " \
91   "depth = (int) 8, " \
92   "signed = (boolean) { true, false } ;" \
93   "audio/x-raw-float, " \
94   "rate = (int) [ 1, MAX ], " \
95   "channels = (int) [ 1, MAX ], " \
96   "endianness = (int) BYTE_ORDER, " \
97   "width = (int) { 32, 64 }"
98
99 static GstStaticPadTemplate gst_adder_src_template =
100 GST_STATIC_PAD_TEMPLATE ("src",
101     GST_PAD_SRC,
102     GST_PAD_ALWAYS,
103     GST_STATIC_CAPS (CAPS)
104     );
105
106 static GstStaticPadTemplate gst_adder_sink_template =
107 GST_STATIC_PAD_TEMPLATE ("sink%d",
108     GST_PAD_SINK,
109     GST_PAD_REQUEST,
110     GST_STATIC_CAPS (CAPS)
111     );
112
113 static void gst_adder_class_init (GstAdderClass * klass);
114 static void gst_adder_init (GstAdder * adder);
115 static void gst_adder_finalize (GObject * object);
116
117 static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
118 static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
119 static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
120 static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
121
122 static GstPad *gst_adder_request_new_pad (GstElement * element,
123     GstPadTemplate * temp, const gchar * unused);
124 static void gst_adder_release_pad (GstElement * element, GstPad * pad);
125
126 static GstStateChangeReturn gst_adder_change_state (GstElement * element,
127     GstStateChange transition);
128
129 static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
130     gpointer user_data);
131
132 static GstElementClass *parent_class = NULL;
133
134 GType
135 gst_adder_get_type (void)
136 {
137   static GType adder_type = 0;
138
139   if (G_UNLIKELY (adder_type == 0)) {
140     static const GTypeInfo adder_info = {
141       sizeof (GstAdderClass), NULL, NULL,
142       (GClassInitFunc) gst_adder_class_init, NULL, NULL,
143       sizeof (GstAdder), 0,
144       (GInstanceInitFunc) gst_adder_init,
145     };
146
147     adder_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAdder",
148         &adder_info, 0);
149     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "adder", 0,
150         "audio channel mixing element");
151   }
152   return adder_type;
153 }
154
155 /* clipping versions
156  * FIXME: what about: oil_add_s16 (out, out, in, bytes / sizeof (type))
157  */
158 #define MAKE_FUNC(name,type,ttype,min,max)                      \
159 static void name (type *out, type *in, gint bytes) {            \
160   gint i;                                                       \
161   for (i = 0; i < bytes / sizeof (type); i++)                   \
162     out[i] = CLAMP ((ttype)out[i] + (ttype)in[i], min, max);    \
163 }
164
165 /* non-clipping versions (for float) */
166 #define MAKE_FUNC_NC(name,type)                                 \
167 static void name (type *out, type *in, gint bytes) {            \
168   gint i;                                                       \
169   for (i = 0; i < bytes / sizeof (type); i++)                   \
170     out[i] += in[i];                                            \
171 }
172
173 #if 0
174 /* right now, the liboil function don't seems to be faster
175  * time gst-launch audiotestsrc num-buffers=50000 ! audio/x-raw-float ! adder name=m ! fakesink audiotestsrc num-buffers=50000 ! audio/x-raw-float ! m.
176  * time gst-launch audiotestsrc num-buffers=50000 ! audio/x-raw-float,width=32 ! adder name=m ! fakesink audiotestsrc num-buffers=50000 ! audio/x-raw-float,width=32 ! m.
177  */
178 static void
179 add_float32 (gfloat * out, gfloat * in, gint bytes)
180 {
181   oil_add_f32 (out, out, in, bytes / sizeof (gfloat));
182 }
183
184 static void
185 add_float64 (gdouble * out, gdouble * in, gint bytes)
186 {
187   oil_add_f64 (out, out, in, bytes / sizeof (gdouble));
188 }
189 #endif
190
191 /* *INDENT-OFF* */
192 MAKE_FUNC (add_int32, gint32, gint64, MIN_INT_32, MAX_INT_32)
193 MAKE_FUNC (add_int16, gint16, gint32, MIN_INT_16, MAX_INT_16)
194 MAKE_FUNC (add_int8, gint8, gint16, MIN_INT_8, MAX_INT_8)
195 MAKE_FUNC (add_uint32, guint32, guint64, MIN_UINT_32, MAX_UINT_32)
196 MAKE_FUNC (add_uint16, guint16, guint32, MIN_UINT_16, MAX_UINT_16)
197 MAKE_FUNC (add_uint8, guint8, guint16, MIN_UINT_8, MAX_UINT_8)
198 MAKE_FUNC_NC (add_float64, gdouble)
199 MAKE_FUNC_NC (add_float32, gfloat)
200 /* *INDENT-ON* */
201
202 /* we can only accept caps that we and downstream can handle. */
203 static GstCaps *
204 gst_adder_sink_getcaps (GstPad * pad)
205 {
206   GstAdder *adder;
207   GstCaps *result, *peercaps, *sinkcaps;
208
209   adder = GST_ADDER (GST_PAD_PARENT (pad));
210
211   GST_OBJECT_LOCK (adder);
212   /* get the downstream possible caps */
213   peercaps = gst_pad_peer_get_caps (adder->srcpad);
214   /* get the allowed caps on this sinkpad, we use the fixed caps function so
215    * that it does not call recursively in this function. */
216   sinkcaps = gst_pad_get_fixed_caps_func (pad);
217   if (peercaps) {
218     /* if the peer has caps, intersect */
219     GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
220     result = gst_caps_intersect (peercaps, sinkcaps);
221     gst_caps_unref (peercaps);
222     gst_caps_unref (sinkcaps);
223   } else {
224     /* the peer has no caps (or there is no peer), just use the allowed caps
225      * of this sinkpad. */
226     GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
227     result = sinkcaps;
228   }
229   GST_OBJECT_UNLOCK (adder);
230
231   return result;
232 }
233
234 /* the first caps we receive on any of the sinkpads will define the caps for all
235  * the other sinkpads because we can only mix streams with the same caps.
236  * */
237 static gboolean
238 gst_adder_setcaps (GstPad * pad, GstCaps * caps)
239 {
240   GstAdder *adder;
241   GList *pads;
242   GstStructure *structure;
243   const char *media_type;
244
245   adder = GST_ADDER (GST_PAD_PARENT (pad));
246
247   GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
248       GST_PAD_NAME (pad), caps);
249
250   /* FIXME, see if the other pads can accept the format. Also lock the
251    * format on the other pads to this new format. */
252   GST_OBJECT_LOCK (adder);
253   pads = GST_ELEMENT (adder)->pads;
254   while (pads) {
255     GstPad *otherpad = GST_PAD (pads->data);
256
257     if (otherpad != pad) {
258       gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
259     }
260     pads = g_list_next (pads);
261   }
262   GST_OBJECT_UNLOCK (adder);
263
264   /* parse caps now */
265   structure = gst_caps_get_structure (caps, 0);
266   media_type = gst_structure_get_name (structure);
267   if (strcmp (media_type, "audio/x-raw-int") == 0) {
268     adder->format = GST_ADDER_FORMAT_INT;
269     gst_structure_get_int (structure, "width", &adder->width);
270     gst_structure_get_int (structure, "depth", &adder->depth);
271     gst_structure_get_int (structure, "endianness", &adder->endianness);
272     gst_structure_get_boolean (structure, "signed", &adder->is_signed);
273
274     GST_INFO_OBJECT (adder, "parse_caps sets adder to format int, %d bit",
275         adder->width);
276
277     if (adder->endianness != G_BYTE_ORDER)
278       goto not_supported;
279
280     switch (adder->width) {
281       case 8:
282         adder->func = (adder->is_signed ?
283             (GstAdderFunction) add_int8 : (GstAdderFunction) add_uint8);
284         break;
285       case 16:
286         adder->func = (adder->is_signed ?
287             (GstAdderFunction) add_int16 : (GstAdderFunction) add_uint16);
288         break;
289       case 32:
290         adder->func = (adder->is_signed ?
291             (GstAdderFunction) add_int32 : (GstAdderFunction) add_uint32);
292         break;
293       default:
294         goto not_supported;
295     }
296   } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
297     adder->format = GST_ADDER_FORMAT_FLOAT;
298     gst_structure_get_int (structure, "width", &adder->width);
299     gst_structure_get_int (structure, "endianness", &adder->endianness);
300
301     GST_INFO_OBJECT (adder, "parse_caps sets adder to format float, %d bit",
302         adder->width);
303
304     if (adder->endianness != G_BYTE_ORDER)
305       goto not_supported;
306
307     switch (adder->width) {
308       case 32:
309         adder->func = (GstAdderFunction) add_float32;
310         break;
311       case 64:
312         adder->func = (GstAdderFunction) add_float64;
313         break;
314       default:
315         goto not_supported;
316     }
317   } else {
318     goto not_supported;
319   }
320
321   gst_structure_get_int (structure, "channels", &adder->channels);
322   gst_structure_get_int (structure, "rate", &adder->rate);
323   /* precalc bps */
324   adder->bps = (adder->width / 8) * adder->channels;
325
326   return TRUE;
327
328   /* ERRORS */
329 not_supported:
330   {
331     GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
332     return FALSE;
333   }
334 }
335
336 /* FIXME, the duration query should reflect how long you will produce
337  * data, that is the amount of stream time until you will emit EOS.
338  *
339  * For synchronized mixing this is always the max of all the durations
340  * of upstream since we emit EOS when all of them finished.
341  *
342  * We don't do synchronized mixing so this really depends on where the
343  * streams where punched in and what their relative offsets are against
344  * eachother which we can get from the first timestamps we see.
345  *
346  * When we add a new stream (or remove a stream) the duration might
347  * also become invalid again and we need to post a new DURATION
348  * message to notify this fact to the parent.
349  * For now we take the max of all the upstream elements so the simple
350  * cases work at least somewhat.
351  */
352 static gboolean
353 gst_adder_query_duration (GstAdder * adder, GstQuery * query)
354 {
355   gint64 max;
356   gboolean res;
357   GstFormat format;
358   GstIterator *it;
359   gboolean done;
360
361   /* parse format */
362   gst_query_parse_duration (query, &format, NULL);
363
364   max = -1;
365   res = TRUE;
366   done = FALSE;
367
368   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
369   while (!done) {
370     GstIteratorResult ires;
371
372     gpointer item;
373
374     ires = gst_iterator_next (it, &item);
375     switch (ires) {
376       case GST_ITERATOR_DONE:
377         done = TRUE;
378         break;
379       case GST_ITERATOR_OK:
380       {
381         GstPad *pad = GST_PAD_CAST (item);
382
383         gint64 duration;
384
385         /* ask sink peer for duration */
386         res &= gst_pad_query_peer_duration (pad, &format, &duration);
387         /* take max from all valid return values */
388         if (res) {
389           /* valid unknown length, stop searching */
390           if (duration == -1) {
391             max = duration;
392             done = TRUE;
393           }
394           /* else see if bigger than current max */
395           else if (duration > max)
396             max = duration;
397         }
398         gst_object_unref (pad);
399         break;
400       }
401       case GST_ITERATOR_RESYNC:
402         max = -1;
403         res = TRUE;
404         gst_iterator_resync (it);
405         break;
406       default:
407         res = FALSE;
408         done = TRUE;
409         break;
410     }
411   }
412   gst_iterator_free (it);
413
414   if (res) {
415     /* and store the max */
416     GST_DEBUG_OBJECT (adder, "Total duration in format %s: %"
417         GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
418     gst_query_set_duration (query, format, max);
419   }
420
421   return res;
422 }
423
424 static gboolean
425 gst_adder_query_latency (GstAdder * adder, GstQuery * query)
426 {
427   GstClockTime min, max;
428   gboolean live;
429   gboolean res;
430   GstIterator *it;
431   gboolean done;
432
433   res = TRUE;
434   done = FALSE;
435
436   live = FALSE;
437   min = 0;
438   max = GST_CLOCK_TIME_NONE;
439
440   /* Take maximum of all latency values */
441   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
442   while (!done) {
443     GstIteratorResult ires;
444
445     gpointer item;
446
447     ires = gst_iterator_next (it, &item);
448     switch (ires) {
449       case GST_ITERATOR_DONE:
450         done = TRUE;
451         break;
452       case GST_ITERATOR_OK:
453       {
454         GstPad *pad = GST_PAD_CAST (item);
455         GstQuery *peerquery;
456         GstClockTime min_cur, max_cur;
457         gboolean live_cur;
458
459         peerquery = gst_query_new_latency ();
460
461         /* Ask peer for latency */
462         res &= gst_pad_peer_query (pad, peerquery);
463
464         /* take max from all valid return values */
465         if (res) {
466           gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
467
468           if (min_cur > min)
469             min = min_cur;
470
471           if (max_cur != GST_CLOCK_TIME_NONE &&
472               ((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
473                   (max == GST_CLOCK_TIME_NONE)))
474             max = max_cur;
475
476           live = live || live_cur;
477         }
478
479         gst_query_unref (peerquery);
480         gst_object_unref (pad);
481         break;
482       }
483       case GST_ITERATOR_RESYNC:
484         live = FALSE;
485         min = 0;
486         max = GST_CLOCK_TIME_NONE;
487         res = TRUE;
488         gst_iterator_resync (it);
489         break;
490       default:
491         res = FALSE;
492         done = TRUE;
493         break;
494     }
495   }
496   gst_iterator_free (it);
497
498   if (res) {
499     /* store the results */
500     GST_DEBUG_OBJECT (adder, "Calculated total latency: live %s, min %"
501         GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
502         (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
503     gst_query_set_latency (query, live, min, max);
504   }
505
506   return res;
507 }
508
509 static gboolean
510 gst_adder_query (GstPad * pad, GstQuery * query)
511 {
512   GstAdder *adder = GST_ADDER (gst_pad_get_parent (pad));
513   gboolean res = FALSE;
514
515   switch (GST_QUERY_TYPE (query)) {
516     case GST_QUERY_POSITION:
517     {
518       GstFormat format;
519
520       gst_query_parse_position (query, &format, NULL);
521
522       switch (format) {
523         case GST_FORMAT_TIME:
524           /* FIXME, bring to stream time, might be tricky */
525           gst_query_set_position (query, format, adder->timestamp);
526           res = TRUE;
527           break;
528         case GST_FORMAT_DEFAULT:
529           gst_query_set_position (query, format, adder->offset);
530           res = TRUE;
531           break;
532         default:
533           break;
534       }
535       break;
536     }
537     case GST_QUERY_DURATION:
538       res = gst_adder_query_duration (adder, query);
539       break;
540     case GST_QUERY_LATENCY:
541       res = gst_adder_query_latency (adder, query);
542       break;
543     default:
544       /* FIXME, needs a custom query handler because we have multiple
545        * sinkpads */
546       res = gst_pad_query_default (pad, query);
547       break;
548   }
549
550   gst_object_unref (adder);
551   return res;
552 }
553
554 static gboolean
555 forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
556 {
557   gst_event_ref (event);
558   GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
559   if (!gst_pad_push_event (pad, event)) {
560     g_value_set_boolean (ret, FALSE);
561     GST_WARNING_OBJECT (pad, "Sending event  %p (%s) failed.",
562         event, GST_EVENT_TYPE_NAME (event));
563   } else {
564     GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
565         event, GST_EVENT_TYPE_NAME (event));
566   }
567   gst_object_unref (pad);
568   return TRUE;
569 }
570
571 /* forwards the event to all sinkpads, takes ownership of the
572  * event
573  *
574  * Returns: TRUE if the event could be forwarded on all
575  * sinkpads.
576  */
577 static gboolean
578 forward_event (GstAdder * adder, GstEvent * event)
579 {
580   gboolean ret;
581   GstIterator *it;
582   GValue vret = { 0 };
583
584   GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
585       GST_EVENT_TYPE_NAME (event));
586
587   ret = TRUE;
588
589   g_value_init (&vret, G_TYPE_BOOLEAN);
590   g_value_set_boolean (&vret, TRUE);
591   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
592   gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
593       event);
594   gst_iterator_free (it);
595   gst_event_unref (event);
596
597   ret = g_value_get_boolean (&vret);
598
599   return ret;
600 }
601
602 static gboolean
603 gst_adder_src_event (GstPad * pad, GstEvent * event)
604 {
605   GstAdder *adder;
606   gboolean result;
607
608   adder = GST_ADDER (gst_pad_get_parent (pad));
609
610   switch (GST_EVENT_TYPE (event)) {
611     case GST_EVENT_QOS:
612       /* QoS might be tricky */
613       result = FALSE;
614       break;
615     case GST_EVENT_SEEK:
616     {
617       GstSeekFlags flags;
618       GstSeekType curtype;
619       gint64 cur;
620
621       /* parse the seek parameters */
622       gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
623           &cur, NULL, NULL);
624
625       /* check if we are flushing */
626       if (flags & GST_SEEK_FLAG_FLUSH) {
627         /* make sure we accept nothing anymore and return WRONG_STATE */
628         gst_collect_pads_set_flushing (adder->collect, TRUE);
629
630         /* flushing seek, start flush downstream, the flush will be done
631          * when all pads received a FLUSH_STOP. */
632         gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
633       }
634       /* now wait for the collected to be finished and mark a new
635        * segment */
636       GST_OBJECT_LOCK (adder->collect);
637       if (curtype == GST_SEEK_TYPE_SET)
638         adder->segment_position = cur;
639       else
640         adder->segment_position = 0;
641       adder->segment_pending = TRUE;
642       GST_OBJECT_UNLOCK (adder->collect);
643
644       result = forward_event (adder, event);
645       break;
646     }
647     case GST_EVENT_NAVIGATION:
648       /* navigation is rather pointless. */
649       result = FALSE;
650       break;
651     default:
652       /* just forward the rest for now */
653       result = forward_event (adder, event);
654       break;
655   }
656   gst_object_unref (adder);
657
658   return result;
659 }
660
661 static gboolean
662 gst_adder_sink_event (GstPad * pad, GstEvent * event)
663 {
664   GstAdder *adder;
665   gboolean ret;
666
667   adder = GST_ADDER (gst_pad_get_parent (pad));
668
669   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
670       GST_DEBUG_PAD_NAME (pad));
671
672   switch (GST_EVENT_TYPE (event)) {
673     case GST_EVENT_FLUSH_STOP:
674       /* mark a pending new segment. This event is synchronized
675        * with the streaming thread so we can safely update the
676        * variable without races. It's somewhat weird because we
677        * assume the collectpads forwarded the FLUSH_STOP past us
678        * and downstream (using our source pad, the bastard!).
679        */
680       adder->segment_pending = TRUE;
681       break;
682     default:
683       break;
684   }
685
686   /* now GstCollectPads can take care of the rest, e.g. EOS */
687   ret = adder->collect_event (pad, event);
688
689   gst_object_unref (adder);
690   return ret;
691 }
692
693 static void
694 gst_adder_class_init (GstAdderClass * klass)
695 {
696   GObjectClass *gobject_class = (GObjectClass *) klass;
697   GstElementClass *gstelement_class = (GstElementClass *) klass;
698
699   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_adder_finalize);
700
701   gst_element_class_add_pad_template (gstelement_class,
702       gst_static_pad_template_get (&gst_adder_src_template));
703   gst_element_class_add_pad_template (gstelement_class,
704       gst_static_pad_template_get (&gst_adder_sink_template));
705   gst_element_class_set_details_simple (gstelement_class, "Adder",
706       "Generic/Audio",
707       "Add N audio channels together",
708       "Thomas Vander Stichele <thomas at apestaart dot org>");
709
710   parent_class = g_type_class_peek_parent (klass);
711
712   gstelement_class->request_new_pad =
713       GST_DEBUG_FUNCPTR (gst_adder_request_new_pad);
714   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_adder_release_pad);
715   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_adder_change_state);
716 }
717
718 static void
719 gst_adder_init (GstAdder * adder)
720 {
721   GstPadTemplate *template;
722
723   template = gst_static_pad_template_get (&gst_adder_src_template);
724   adder->srcpad = gst_pad_new_from_template (template, "src");
725   gst_object_unref (template);
726
727   gst_pad_set_getcaps_function (adder->srcpad,
728       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
729   gst_pad_set_setcaps_function (adder->srcpad,
730       GST_DEBUG_FUNCPTR (gst_adder_setcaps));
731   gst_pad_set_query_function (adder->srcpad,
732       GST_DEBUG_FUNCPTR (gst_adder_query));
733   gst_pad_set_event_function (adder->srcpad,
734       GST_DEBUG_FUNCPTR (gst_adder_src_event));
735   gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
736
737   adder->format = GST_ADDER_FORMAT_UNSET;
738   adder->padcount = 0;
739   adder->func = NULL;
740
741   /* keep track of the sinkpads requested */
742   adder->collect = gst_collect_pads_new ();
743   gst_collect_pads_set_function (adder->collect,
744       GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
745 }
746
747 static void
748 gst_adder_finalize (GObject * object)
749 {
750   GstAdder *adder = GST_ADDER (object);
751
752   gst_object_unref (adder->collect);
753   adder->collect = NULL;
754
755   G_OBJECT_CLASS (parent_class)->finalize (object);
756 }
757
758 static GstPad *
759 gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
760     const gchar * unused)
761 {
762   gchar *name;
763   GstAdder *adder;
764   GstPad *newpad;
765   gint padcount;
766
767   if (templ->direction != GST_PAD_SINK)
768     goto not_sink;
769
770   adder = GST_ADDER (element);
771
772   /* increment pad counter */
773   padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
774
775   name = g_strdup_printf ("sink%d", padcount);
776   newpad = gst_pad_new_from_template (templ, name);
777   GST_DEBUG_OBJECT (adder, "request new pad %s", name);
778   g_free (name);
779
780   gst_pad_set_getcaps_function (newpad,
781       GST_DEBUG_FUNCPTR (gst_adder_sink_getcaps));
782   gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_setcaps));
783   gst_collect_pads_add_pad (adder->collect, newpad, sizeof (GstCollectData));
784
785   /* FIXME: hacked way to override/extend the event function of
786    * GstCollectPads; because it sets its own event function giving the
787    * element no access to events */
788   adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
789   gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event));
790
791   /* takes ownership of the pad */
792   if (!gst_element_add_pad (GST_ELEMENT (adder), newpad))
793     goto could_not_add;
794
795   return newpad;
796
797   /* errors */
798 not_sink:
799   {
800     g_warning ("gstadder: request new pad that is not a SINK pad\n");
801     return NULL;
802   }
803 could_not_add:
804   {
805     GST_DEBUG_OBJECT (adder, "could not add pad");
806     gst_collect_pads_remove_pad (adder->collect, newpad);
807     gst_object_unref (newpad);
808     return NULL;
809   }
810 }
811
812 static void
813 gst_adder_release_pad (GstElement * element, GstPad * pad)
814 {
815   GstAdder *adder;
816
817   adder = GST_ADDER (element);
818
819   GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
820
821   gst_collect_pads_remove_pad (adder->collect, pad);
822   gst_element_remove_pad (element, pad);
823 }
824
825 static GstFlowReturn
826 gst_adder_collected (GstCollectPads * pads, gpointer user_data)
827 {
828   /*
829    * combine streams by adding data values
830    * basic algorithm :
831    * - this function is called when all pads have a buffer
832    * - get available bytes on all pads.
833    * - repeat for each input pad :
834    *   - read available bytes, copy or add to target buffer
835    *   - if there's an EOS event, remove the input channel
836    * - push out the output buffer
837    *
838    * todo:
839    * - would be nice to have a mixing mode, where instead of adding we mix
840    *   - for float we could downscale after collect loop
841    *   - for int we need to downscale each input to avoid clipping or
842    *     mix into a temp (float) buffer and scale afterwards as well
843    */
844   GstAdder *adder;
845   GSList *collected;
846   GstFlowReturn ret;
847   GstBuffer *outbuf = NULL;
848   gpointer outdata = NULL;
849   guint outsize;
850   gboolean empty = TRUE;
851
852   adder = GST_ADDER (user_data);
853
854   /* this is fatal */
855   if (G_UNLIKELY (adder->func == NULL))
856     goto not_negotiated;
857
858   /* get available bytes for reading, this can be 0 which could mean empty
859    * buffers or EOS, which we will catch when we loop over the pads. */
860   outsize = gst_collect_pads_available (pads);
861
862   GST_LOG_OBJECT (adder,
863       "starting to cycle through channels, %d bytes available (bps = %d)",
864       outsize, adder->bps);
865
866   for (collected = pads->data; collected; collected = g_slist_next (collected)) {
867     GstCollectData *collect_data;
868     GstBuffer *inbuf;
869     guint8 *indata;
870     guint insize;
871
872     collect_data = (GstCollectData *) collected->data;
873
874     /* get a subbuffer of size bytes */
875     inbuf = gst_collect_pads_take_buffer (pads, collect_data, outsize);
876     /* NULL means EOS or an empty buffer so we still need to flush in
877      * case of an empty buffer. */
878     if (inbuf == NULL) {
879       GST_LOG_OBJECT (adder, "channel %p: no bytes available", collect_data);
880       continue;
881     }
882
883     indata = GST_BUFFER_DATA (inbuf);
884     insize = GST_BUFFER_SIZE (inbuf);
885
886     if (outbuf == NULL) {
887       GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes",
888           collect_data, outsize);
889
890       /* first buffer, alloc outsize.
891        * FIXME: we can easily subbuffer and _make_writable.
892        * FIXME: only create empty buffer for first non-gap buffer, so that we
893        * only use adder function when really adding
894        */
895       outbuf = gst_buffer_new_and_alloc (outsize);
896       outdata = GST_BUFFER_DATA (outbuf);
897       gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
898
899       if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
900         GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p",
901             collect_data, insize, indata);
902         /* clear if we are only going to fill a partial buffer */
903         if (G_UNLIKELY (outsize > insize))
904           memset (outdata + insize, 0, outsize - insize);
905         /* and copy the data into it */
906         memcpy (outdata, indata, insize);
907         empty = FALSE;
908       } else {
909         /* clear whole buffer */
910         GST_LOG_OBJECT (adder, "channel %p: zeroing %d bytes from data %p",
911             collect_data, insize, indata);
912         memset (outdata, 0, outsize);
913       }
914     } else {
915       if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
916         GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
917             collect_data, insize, indata);
918         /* further buffers, need to add them */
919         adder->func ((gpointer) outdata, (gpointer) indata, insize);
920         empty = FALSE;
921       } else {
922         GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p",
923             collect_data, insize, indata);
924       }
925     }
926     gst_buffer_unref (inbuf);
927   }
928
929   /* can only happen when no pads to collect or all EOS */
930   if (outbuf == NULL)
931     goto eos;
932
933   /* our timestamping is very simple, just an ever incrementing
934    * counter, the new segment time will take care of their respective
935    * stream time. */
936   if (adder->segment_pending) {
937     GstEvent *event;
938
939     /* FIXME, use rate/applied_rate as set on all sinkpads.
940      * - currently we just set rate as received from last seek-event
941      * We could potentially figure out the duration as well using
942      * the current segment positions and the stated stop positions.
943      * Also we just start from stream time 0 which is rather
944      * weird. For non-synchronized mixing, the time should be
945      * the min of the stream times of all received segments,
946      * rationale being that the duration is at least going to
947      * be as long as the earliest stream we start mixing. This
948      * would also be correct for synchronized mixing but then
949      * the later streams would be delayed until the stream times
950      * match.
951      */
952     event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
953         1.0, GST_FORMAT_TIME, adder->timestamp, -1, adder->segment_position);
954
955     gst_pad_push_event (adder->srcpad, event);
956     adder->segment_pending = FALSE;
957     adder->segment_position = 0;
958   }
959
960   /* set timestamps on the output buffer */
961   GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
962   GST_BUFFER_OFFSET (outbuf) = adder->offset;
963
964   /* for the next timestamp, use the sample counter, which will
965    * never accumulate rounding errors */
966   adder->offset += outsize / adder->bps;
967   adder->timestamp = gst_util_uint64_scale_int (adder->offset,
968       GST_SECOND, adder->rate);
969
970   /* now we can set the duration of the buffer */
971   GST_BUFFER_DURATION (outbuf) = adder->timestamp -
972       GST_BUFFER_TIMESTAMP (outbuf);
973
974   /* if we only processed silence, mark output again as silence */
975   if (empty)
976     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
977
978   /* send it out */
979   GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
980       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
981   ret = gst_pad_push (adder->srcpad, outbuf);
982
983   return ret;
984
985   /* ERRORS */
986 not_negotiated:
987   {
988     GST_ELEMENT_ERROR (adder, STREAM, FORMAT, (NULL),
989         ("Unknown data received, not negotiated"));
990     return GST_FLOW_NOT_NEGOTIATED;
991   }
992 eos:
993   {
994     GST_DEBUG_OBJECT (adder, "no data available, must be EOS");
995     gst_pad_push_event (adder->srcpad, gst_event_new_eos ());
996     return GST_FLOW_UNEXPECTED;
997   }
998 }
999
1000 static GstStateChangeReturn
1001 gst_adder_change_state (GstElement * element, GstStateChange transition)
1002 {
1003   GstAdder *adder;
1004   GstStateChangeReturn ret;
1005
1006   adder = GST_ADDER (element);
1007
1008   switch (transition) {
1009     case GST_STATE_CHANGE_NULL_TO_READY:
1010       break;
1011     case GST_STATE_CHANGE_READY_TO_PAUSED:
1012       adder->timestamp = 0;
1013       adder->offset = 0;
1014       adder->segment_pending = TRUE;
1015       adder->segment_position = 0;
1016       adder->segment_rate = 1.0;
1017       gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
1018       gst_collect_pads_start (adder->collect);
1019       break;
1020     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1021       break;
1022     case GST_STATE_CHANGE_PAUSED_TO_READY:
1023       /* need to unblock the collectpads before calling the
1024        * parent change_state so that streaming can finish */
1025       gst_collect_pads_stop (adder->collect);
1026       break;
1027     default:
1028       break;
1029   }
1030
1031   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1032
1033   switch (transition) {
1034     default:
1035       break;
1036   }
1037
1038   return ret;
1039 }
1040
1041
1042 static gboolean
1043 plugin_init (GstPlugin * plugin)
1044 {
1045   /*oil_init (); */
1046
1047   if (!gst_element_register (plugin, "adder", GST_RANK_NONE, GST_TYPE_ADDER)) {
1048     return FALSE;
1049   }
1050
1051   return TRUE;
1052 }
1053
1054 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1055     GST_VERSION_MINOR,
1056     "adder",
1057     "Adds multiple streams",
1058     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)