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>
6 * adder.c: Adder element, N in, one out, samples are added
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.
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.
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.
24 * SECTION:element-adder
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.
29 * The adder currently mixes all data received on the sinkpads as soon as
30 * possible without trying to synchronize the streams.
33 * <title>Example launch line</title>
35 * gst-launch audiotestsrc freq=100 ! adder name=mix ! audioconvert ! alsasink audiotestsrc freq=500 ! mix.
36 * ]| This pipeline produces two sine waves mixed together.
39 * Last reviewed on 2006-05-09 (0.10.7)
41 /* Element-Checklist-Version: 5 */
47 #include <gst/audio/audio.h>
48 #include <string.h> /* strcmp */
50 /* highest positive/lowest negative x-bit value we can use for clamping */
51 #define MAX_INT_32 ((gint32) (0x7fffffff))
52 #define MAX_INT_16 ((gint16) (0x7fff))
53 #define MAX_INT_8 ((gint8) (0x7f))
54 #define MAX_UINT_32 ((guint32)(0xffffffff))
55 #define MAX_UINT_16 ((guint16)(0xffff))
56 #define MAX_UINT_8 ((guint8) (0xff))
58 #define MIN_INT_32 ((gint32) (0x80000000))
59 #define MIN_INT_16 ((gint16) (0x8000))
60 #define MIN_INT_8 ((gint8) (0x80))
61 #define MIN_UINT_32 ((guint32)(0x00000000))
62 #define MIN_UINT_16 ((guint16)(0x0000))
63 #define MIN_UINT_8 ((guint8) (0x00))
65 #define GST_CAT_DEFAULT gst_adder_debug
66 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
68 /* elementfactory information */
72 "rate = (int) [ 1, MAX ], " \
73 "channels = (int) [ 1, MAX ], " \
74 "endianness = (int) BYTE_ORDER, " \
75 "width = (int) 32, " \
76 "depth = (int) 32, " \
77 "signed = (boolean) { true, false } ;" \
79 "rate = (int) [ 1, MAX ], " \
80 "channels = (int) [ 1, MAX ], " \
81 "endianness = (int) BYTE_ORDER, " \
82 "width = (int) 16, " \
83 "depth = (int) 16, " \
84 "signed = (boolean) { true, false } ;" \
86 "rate = (int) [ 1, MAX ], " \
87 "channels = (int) [ 1, MAX ], " \
88 "endianness = (int) BYTE_ORDER, " \
91 "signed = (boolean) { true, false } ;" \
92 "audio/x-raw-float, " \
93 "rate = (int) [ 1, MAX ], " \
94 "channels = (int) [ 1, MAX ], " \
95 "endianness = (int) BYTE_ORDER, " \
96 "width = (int) { 32, 64 }"
98 static GstStaticPadTemplate gst_adder_src_template =
99 GST_STATIC_PAD_TEMPLATE ("src",
102 GST_STATIC_CAPS (CAPS)
105 static GstStaticPadTemplate gst_adder_sink_template =
106 GST_STATIC_PAD_TEMPLATE ("sink%d",
109 GST_STATIC_CAPS (CAPS)
112 static void gst_adder_class_init (GstAdderClass * klass);
113 static void gst_adder_init (GstAdder * adder);
114 static void gst_adder_finalize (GObject * object);
116 static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
117 static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
118 static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
119 static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
121 static GstPad *gst_adder_request_new_pad (GstElement * element,
122 GstPadTemplate * temp, const gchar * unused);
123 static void gst_adder_release_pad (GstElement * element, GstPad * pad);
125 static GstStateChangeReturn gst_adder_change_state (GstElement * element,
126 GstStateChange transition);
128 static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
131 static GstElementClass *parent_class = NULL;
134 gst_adder_get_type (void)
136 static GType adder_type = 0;
138 if (G_UNLIKELY (adder_type == 0)) {
139 static const GTypeInfo adder_info = {
140 sizeof (GstAdderClass), NULL, NULL,
141 (GClassInitFunc) gst_adder_class_init, NULL, NULL,
142 sizeof (GstAdder), 0,
143 (GInstanceInitFunc) gst_adder_init,
146 adder_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAdder",
148 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "adder", 0,
149 "audio channel mixing element");
154 /* clipping versions */
155 #define MAKE_FUNC(name,type,ttype,min,max) \
156 static void name (type *out, type *in, gint bytes) { \
158 for (i = 0; i < bytes / sizeof (type); i++) \
159 out[i] = CLAMP ((ttype)out[i] + (ttype)in[i], min, max); \
162 /* non-clipping versions (for float) */
163 #define MAKE_FUNC_NC(name,type,ttype) \
164 static void name (type *out, type *in, gint bytes) { \
166 for (i = 0; i < bytes / sizeof (type); i++) \
167 out[i] = (ttype)out[i] + (ttype)in[i]; \
171 MAKE_FUNC (add_int32, gint32, gint64, MIN_INT_32, MAX_INT_32)
172 MAKE_FUNC (add_int16, gint16, gint32, MIN_INT_16, MAX_INT_16)
173 MAKE_FUNC (add_int8, gint8, gint16, MIN_INT_8, MAX_INT_8)
174 MAKE_FUNC (add_uint32, guint32, guint64, MIN_UINT_32, MAX_UINT_32)
175 MAKE_FUNC (add_uint16, guint16, guint32, MIN_UINT_16, MAX_UINT_16)
176 MAKE_FUNC (add_uint8, guint8, guint16, MIN_UINT_8, MAX_UINT_8)
177 MAKE_FUNC_NC (add_float64, gdouble, gdouble)
178 MAKE_FUNC_NC (add_float32, gfloat, gfloat)
181 /* we can only accept caps that we and downstream can handle. */
183 gst_adder_sink_getcaps (GstPad * pad)
186 GstCaps *result, *peercaps, *sinkcaps;
188 adder = GST_ADDER (GST_PAD_PARENT (pad));
190 GST_OBJECT_LOCK (adder);
191 /* get the downstream possible caps */
192 peercaps = gst_pad_peer_get_caps (adder->srcpad);
193 /* get the allowed caps on this sinkpad, we use the fixed caps function so
194 * that it does not call recursively in this function. */
195 sinkcaps = gst_pad_get_fixed_caps_func (pad);
197 /* if the peer has caps, intersect */
198 GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
199 result = gst_caps_intersect (peercaps, sinkcaps);
200 gst_caps_unref (peercaps);
201 gst_caps_unref (sinkcaps);
203 /* the peer has no caps (or there is no peer), just use the allowed caps
204 * of this sinkpad. */
205 GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
208 GST_OBJECT_UNLOCK (adder);
213 /* the first caps we receive on any of the sinkpads will define the caps for all
214 * the other sinkpads because we can only mix streams with the same caps.
217 gst_adder_setcaps (GstPad * pad, GstCaps * caps)
221 GstStructure *structure;
222 const char *media_type;
224 adder = GST_ADDER (GST_PAD_PARENT (pad));
226 GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
227 GST_PAD_NAME (pad), caps);
229 /* FIXME, see if the other pads can accept the format. Also lock the
230 * format on the other pads to this new format. */
231 GST_OBJECT_LOCK (adder);
232 pads = GST_ELEMENT (adder)->pads;
234 GstPad *otherpad = GST_PAD (pads->data);
236 if (otherpad != pad) {
237 gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
239 pads = g_list_next (pads);
241 GST_OBJECT_UNLOCK (adder);
244 structure = gst_caps_get_structure (caps, 0);
245 media_type = gst_structure_get_name (structure);
246 if (strcmp (media_type, "audio/x-raw-int") == 0) {
247 GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format int");
248 adder->format = GST_ADDER_FORMAT_INT;
249 gst_structure_get_int (structure, "width", &adder->width);
250 gst_structure_get_int (structure, "depth", &adder->depth);
251 gst_structure_get_int (structure, "endianness", &adder->endianness);
252 gst_structure_get_boolean (structure, "signed", &adder->is_signed);
254 if (adder->endianness != G_BYTE_ORDER)
257 switch (adder->width) {
259 adder->func = (adder->is_signed ?
260 (GstAdderFunction) add_int8 : (GstAdderFunction) add_uint8);
263 adder->func = (adder->is_signed ?
264 (GstAdderFunction) add_int16 : (GstAdderFunction) add_uint16);
267 adder->func = (adder->is_signed ?
268 (GstAdderFunction) add_int32 : (GstAdderFunction) add_uint32);
273 } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
274 GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format float");
275 adder->format = GST_ADDER_FORMAT_FLOAT;
276 gst_structure_get_int (structure, "width", &adder->width);
277 gst_structure_get_int (structure, "endianness", &adder->endianness);
279 if (adder->endianness != G_BYTE_ORDER)
282 switch (adder->width) {
284 adder->func = (GstAdderFunction) add_float32;
287 adder->func = (GstAdderFunction) add_float64;
296 gst_structure_get_int (structure, "channels", &adder->channels);
297 gst_structure_get_int (structure, "rate", &adder->rate);
299 adder->bps = (adder->width / 8) * adder->channels;
306 GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
311 /* FIXME, the duration query should reflect how long you will produce
312 * data, that is the amount of stream time until you will emit EOS.
314 * For synchronized mixing this is always the max of all the durations
315 * of upstream since we emit EOS when all of them finished.
317 * We don't do synchronized mixing so this really depends on where the
318 * streams where punched in and what their relative offsets are against
319 * eachother which we can get from the first timestamps we see.
321 * When we add a new stream (or remove a stream) the duration might
322 * also become invalid again and we need to post a new DURATION
323 * message to notify this fact to the parent.
324 * For now we take the max of all the upstream elements so the simple
325 * cases work at least somewhat.
328 gst_adder_query_duration (GstAdder * adder, GstQuery * query)
337 gst_query_parse_duration (query, &format, NULL);
343 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
345 GstIteratorResult ires;
349 ires = gst_iterator_next (it, &item);
351 case GST_ITERATOR_DONE:
354 case GST_ITERATOR_OK:
356 GstPad *pad = GST_PAD_CAST (item);
360 /* ask sink peer for duration */
361 res &= gst_pad_query_peer_duration (pad, &format, &duration);
362 /* take max from all valid return values */
364 /* valid unknown length, stop searching */
365 if (duration == -1) {
369 /* else see if bigger than current max */
370 else if (duration > max)
373 gst_object_unref (pad);
376 case GST_ITERATOR_RESYNC:
379 gst_iterator_resync (it);
387 gst_iterator_free (it);
390 /* and store the max */
391 GST_DEBUG_OBJECT (adder, "Total duration in format %s: %"
392 GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
393 gst_query_set_duration (query, format, max);
400 gst_adder_query_latency (GstAdder * adder, GstQuery * query)
402 GstClockTime min, max;
413 max = GST_CLOCK_TIME_NONE;
415 /* Take maximum of all latency values */
416 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
418 GstIteratorResult ires;
422 ires = gst_iterator_next (it, &item);
424 case GST_ITERATOR_DONE:
427 case GST_ITERATOR_OK:
429 GstPad *pad = GST_PAD_CAST (item);
431 GstClockTime min_cur, max_cur;
434 peerquery = gst_query_new_latency ();
436 /* Ask peer for latency */
437 res &= gst_pad_peer_query (pad, peerquery);
439 /* take max from all valid return values */
441 gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
446 if (max_cur != GST_CLOCK_TIME_NONE &&
447 ((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
448 (max == GST_CLOCK_TIME_NONE)))
451 live = live || live_cur;
454 gst_query_unref (peerquery);
455 gst_object_unref (pad);
458 case GST_ITERATOR_RESYNC:
461 max = GST_CLOCK_TIME_NONE;
463 gst_iterator_resync (it);
471 gst_iterator_free (it);
474 /* store the results */
475 GST_DEBUG_OBJECT (adder, "Calculated total latency: live %s, min %"
476 GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
477 (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
478 gst_query_set_latency (query, live, min, max);
485 gst_adder_query (GstPad * pad, GstQuery * query)
487 GstAdder *adder = GST_ADDER (gst_pad_get_parent (pad));
488 gboolean res = FALSE;
490 switch (GST_QUERY_TYPE (query)) {
491 case GST_QUERY_POSITION:
495 gst_query_parse_position (query, &format, NULL);
498 case GST_FORMAT_TIME:
499 /* FIXME, bring to stream time, might be tricky */
500 gst_query_set_position (query, format, adder->timestamp);
503 case GST_FORMAT_DEFAULT:
504 gst_query_set_position (query, format, adder->offset);
512 case GST_QUERY_DURATION:
513 res = gst_adder_query_duration (adder, query);
515 case GST_QUERY_LATENCY:
516 res = gst_adder_query_latency (adder, query);
519 /* FIXME, needs a custom query handler because we have multiple
521 res = gst_pad_query_default (pad, query);
525 gst_object_unref (adder);
530 forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
532 gst_event_ref (event);
533 GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
534 if (!gst_pad_push_event (pad, event)) {
535 g_value_set_boolean (ret, FALSE);
536 GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.",
537 event, GST_EVENT_TYPE_NAME (event));
539 GST_LOG_OBJECT (pad, "Sent event %p (%s).",
540 event, GST_EVENT_TYPE_NAME (event));
542 gst_object_unref (pad);
546 /* forwards the event to all sinkpads, takes ownership of the
549 * Returns: TRUE if the event could be forwarded on all
553 forward_event (GstAdder * adder, GstEvent * event)
559 GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event,
560 GST_EVENT_TYPE_NAME (event));
564 g_value_init (&vret, G_TYPE_BOOLEAN);
565 g_value_set_boolean (&vret, TRUE);
566 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
567 gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
569 gst_iterator_free (it);
570 gst_event_unref (event);
572 ret = g_value_get_boolean (&vret);
578 gst_adder_src_event (GstPad * pad, GstEvent * event)
583 adder = GST_ADDER (gst_pad_get_parent (pad));
585 switch (GST_EVENT_TYPE (event)) {
587 /* QoS might be tricky */
596 /* parse the seek parameters */
597 gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
600 /* check if we are flushing */
601 if (flags & GST_SEEK_FLAG_FLUSH) {
602 /* make sure we accept nothing anymore and return WRONG_STATE */
603 gst_collect_pads_set_flushing (adder->collect, TRUE);
605 /* flushing seek, start flush downstream, the flush will be done
606 * when all pads received a FLUSH_STOP. */
607 gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
609 /* now wait for the collected to be finished and mark a new
611 GST_OBJECT_LOCK (adder->collect);
612 if (curtype == GST_SEEK_TYPE_SET)
613 adder->segment_position = cur;
615 adder->segment_position = 0;
616 adder->segment_pending = TRUE;
617 GST_OBJECT_UNLOCK (adder->collect);
619 result = forward_event (adder, event);
622 case GST_EVENT_NAVIGATION:
623 /* navigation is rather pointless. */
627 /* just forward the rest for now */
628 result = forward_event (adder, event);
631 gst_object_unref (adder);
637 gst_adder_sink_event (GstPad * pad, GstEvent * event)
642 adder = GST_ADDER (gst_pad_get_parent (pad));
644 GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
645 GST_DEBUG_PAD_NAME (pad));
647 switch (GST_EVENT_TYPE (event)) {
648 case GST_EVENT_FLUSH_STOP:
649 /* mark a pending new segment. This event is synchronized
650 * with the streaming thread so we can safely update the
651 * variable without races. It's somewhat weird because we
652 * assume the collectpads forwarded the FLUSH_STOP past us
653 * and downstream (using our source pad, the bastard!).
655 adder->segment_pending = TRUE;
661 /* now GstCollectPads can take care of the rest, e.g. EOS */
662 ret = adder->collect_event (pad, event);
664 gst_object_unref (adder);
669 gst_adder_class_init (GstAdderClass * klass)
671 GObjectClass *gobject_class = (GObjectClass *) klass;
672 GstElementClass *gstelement_class = (GstElementClass *) klass;
674 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_adder_finalize);
676 gst_element_class_add_pad_template (gstelement_class,
677 gst_static_pad_template_get (&gst_adder_src_template));
678 gst_element_class_add_pad_template (gstelement_class,
679 gst_static_pad_template_get (&gst_adder_sink_template));
680 gst_element_class_set_details_simple (gstelement_class, "Adder",
682 "Add N audio channels together",
683 "Thomas Vander Stichele <thomas at apestaart dot org>");
685 parent_class = g_type_class_peek_parent (klass);
687 gstelement_class->request_new_pad =
688 GST_DEBUG_FUNCPTR (gst_adder_request_new_pad);
689 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_adder_release_pad);
690 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_adder_change_state);
694 gst_adder_init (GstAdder * adder)
696 GstPadTemplate *template;
698 template = gst_static_pad_template_get (&gst_adder_src_template);
699 adder->srcpad = gst_pad_new_from_template (template, "src");
700 gst_object_unref (template);
702 gst_pad_set_getcaps_function (adder->srcpad,
703 GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
704 gst_pad_set_setcaps_function (adder->srcpad,
705 GST_DEBUG_FUNCPTR (gst_adder_setcaps));
706 gst_pad_set_query_function (adder->srcpad,
707 GST_DEBUG_FUNCPTR (gst_adder_query));
708 gst_pad_set_event_function (adder->srcpad,
709 GST_DEBUG_FUNCPTR (gst_adder_src_event));
710 gst_element_add_pad (GST_ELEMENT (adder), adder->srcpad);
712 adder->format = GST_ADDER_FORMAT_UNSET;
716 /* keep track of the sinkpads requested */
717 adder->collect = gst_collect_pads_new ();
718 gst_collect_pads_set_function (adder->collect,
719 GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
723 gst_adder_finalize (GObject * object)
725 GstAdder *adder = GST_ADDER (object);
727 gst_object_unref (adder->collect);
728 adder->collect = NULL;
730 G_OBJECT_CLASS (parent_class)->finalize (object);
734 gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
735 const gchar * unused)
742 if (templ->direction != GST_PAD_SINK)
745 adder = GST_ADDER (element);
747 /* increment pad counter */
748 padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
750 name = g_strdup_printf ("sink%d", padcount);
751 newpad = gst_pad_new_from_template (templ, name);
752 GST_DEBUG_OBJECT (adder, "request new pad %s", name);
755 gst_pad_set_getcaps_function (newpad,
756 GST_DEBUG_FUNCPTR (gst_adder_sink_getcaps));
757 gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_setcaps));
758 gst_collect_pads_add_pad (adder->collect, newpad, sizeof (GstCollectData));
760 /* FIXME: hacked way to override/extend the event function of
761 * GstCollectPads; because it sets its own event function giving the
762 * element no access to events */
763 adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
764 gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event));
766 /* takes ownership of the pad */
767 if (!gst_element_add_pad (GST_ELEMENT (adder), newpad))
775 g_warning ("gstadder: request new pad that is not a SINK pad\n");
780 GST_DEBUG_OBJECT (adder, "could not add pad");
781 gst_collect_pads_remove_pad (adder->collect, newpad);
782 gst_object_unref (newpad);
788 gst_adder_release_pad (GstElement * element, GstPad * pad)
792 adder = GST_ADDER (element);
794 GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
796 gst_collect_pads_remove_pad (adder->collect, pad);
797 gst_element_remove_pad (element, pad);
801 gst_adder_collected (GstCollectPads * pads, gpointer user_data)
804 * combine channels by adding sample values
806 * - this function is called when all pads have a buffer
807 * - get available bytes on all pads.
808 * - repeat for each input pad :
809 * - read available bytes, copy or add to target buffer
810 * - if there's an EOS event, remove the input channel
811 * - push out the output buffer
819 gboolean empty = TRUE;
821 adder = GST_ADDER (user_data);
824 if (G_UNLIKELY (adder->func == NULL))
827 /* get available bytes for reading, this can be 0 which could mean
828 * empty buffers or EOS, which we will catch when we loop over the
830 size = gst_collect_pads_available (pads);
832 GST_LOG_OBJECT (adder,
833 "starting to cycle through channels, %d bytes available (bps = %d)", size,
839 for (collected = pads->data; collected; collected = g_slist_next (collected)) {
840 GstCollectData *data;
845 data = (GstCollectData *) collected->data;
847 /* get a subbuffer of size bytes */
848 inbuf = gst_collect_pads_take_buffer (pads, data, size);
849 /* NULL means EOS or an empty buffer so we still need to flush in
850 * case of an empty buffer. */
852 GST_LOG_OBJECT (adder, "channel %p: no bytes available", data);
856 bytes = GST_BUFFER_DATA (inbuf);
857 len = GST_BUFFER_SIZE (inbuf);
859 if (outbuf == NULL) {
860 GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes",
863 /* first buffer, alloc size bytes. FIXME, we can easily subbuffer
864 * and _make_writable. */
865 outbuf = gst_buffer_new_and_alloc (size);
866 outbytes = GST_BUFFER_DATA (outbuf);
867 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
869 if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
870 /* clear if we are only going to fill a partial buffer */
871 if (G_UNLIKELY (size > len))
872 memset (outbytes, 0, size);
874 GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p",
877 /* and copy the data into it */
878 memcpy (outbytes, bytes, len);
881 GST_LOG_OBJECT (adder, "channel %p: zeroing %d bytes from data %p",
883 memset (outbytes, 0, size);
886 if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
887 GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p",
889 /* other buffers, need to add them */
890 adder->func ((gpointer) outbytes, (gpointer) bytes, len);
893 GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p",
899 gst_buffer_unref (inbuf);
902 /* can only happen when no pads to collect or all EOS */
906 /* our timestamping is very simple, just an ever incrementing
907 * counter, the new segment time will take care of their respective
909 if (adder->segment_pending) {
912 /* FIXME, use rate/applied_rate as set on all sinkpads.
913 * - currently we just set rate as received from last seek-event
914 * We could potentially figure out the duration as well using
915 * the current segment positions and the stated stop positions.
916 * Also we just start from stream time 0 which is rather
917 * weird. For non-synchronized mixing, the time should be
918 * the min of the stream times of all received segments,
919 * rationale being that the duration is at least going to
920 * be as long as the earliest stream we start mixing. This
921 * would also be correct for synchronized mixing but then
922 * the later streams would be delayed until the stream times
925 event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
926 1.0, GST_FORMAT_TIME, adder->timestamp, -1, adder->segment_position);
928 gst_pad_push_event (adder->srcpad, event);
929 adder->segment_pending = FALSE;
930 adder->segment_position = 0;
933 /* set timestamps on the output buffer */
934 GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
935 GST_BUFFER_OFFSET (outbuf) = adder->offset;
937 /* for the next timestamp, use the sample counter, which will
938 * never accumulate rounding errors */
939 adder->offset += size / adder->bps;
940 adder->timestamp = gst_util_uint64_scale_int (adder->offset,
941 GST_SECOND, adder->rate);
943 /* now we can set the duration of the buffer */
944 GST_BUFFER_DURATION (outbuf) = adder->timestamp -
945 GST_BUFFER_TIMESTAMP (outbuf);
947 /* if we only processed silence, mark output again as silence */
949 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
952 GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
953 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
954 ret = gst_pad_push (adder->srcpad, outbuf);
961 GST_ELEMENT_ERROR (adder, STREAM, FORMAT, (NULL),
962 ("Unknown data received, not negotiated"));
963 return GST_FLOW_NOT_NEGOTIATED;
967 GST_DEBUG_OBJECT (adder, "no data available, must be EOS");
968 gst_pad_push_event (adder->srcpad, gst_event_new_eos ());
969 return GST_FLOW_UNEXPECTED;
973 static GstStateChangeReturn
974 gst_adder_change_state (GstElement * element, GstStateChange transition)
977 GstStateChangeReturn ret;
979 adder = GST_ADDER (element);
981 switch (transition) {
982 case GST_STATE_CHANGE_NULL_TO_READY:
984 case GST_STATE_CHANGE_READY_TO_PAUSED:
985 adder->timestamp = 0;
987 adder->segment_pending = TRUE;
988 adder->segment_position = 0;
989 adder->segment_rate = 1.0;
990 gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
991 gst_collect_pads_start (adder->collect);
993 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
995 case GST_STATE_CHANGE_PAUSED_TO_READY:
996 /* need to unblock the collectpads before calling the
997 * parent change_state so that streaming can finish */
998 gst_collect_pads_stop (adder->collect);
1004 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1006 switch (transition) {
1016 plugin_init (GstPlugin * plugin)
1018 if (!gst_element_register (plugin, "adder", GST_RANK_NONE, GST_TYPE_ADDER)) {
1025 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1028 "Adds multiple streams",
1029 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)