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