2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 * 2005 Wim Taymans <wim@fluendo.com>
5 * 2007 Andy Wingo <wingo at pobox.com>
6 * 2008 Sebastian Dröge <slomo@circular-chaos.rg>
8 * interleave.c: interleave samples, mostly based on adder.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
27 * - handle caps changes
28 * - handle more queries/events
32 * SECTION:element-interleave
33 * @see_also: deinterleave
35 * Merges separate mono inputs into one interleaved stream.
37 * This element handles all raw floating point sample formats and all signed integer sample formats. The first
38 * caps on one of the sinkpads will set the caps of the output so usually an audioconvert element should be
39 * placed before every sinkpad of interleave.
41 * It's possible to change the number of channels while the pipeline is running by adding or removing
42 * some of the request pads but this will change the caps of the output buffers. Changing the input
43 * caps is _not_ supported yet.
45 * The channel number of every sinkpad in the out can be retrieved from the "channel" property of the pad.
48 * <title>Example launch line</title>
50 * gst-launch filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw-int,channels=2" ! deinterleave name=d interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav d.src0 ! queue ! audioconvert ! i.sink1 d.src1 ! queue ! audioconvert ! i.sink0
51 * ]| Decodes and deinterleaves a Stereo MP3 file into separate channels and
52 * then interleaves the channels again to a WAV file with the channel with the
55 * gst-launch interleave name=i ! audioconvert ! wavenc ! filesink location=file.wav filesrc location=file1.wav ! decodebin ! audioconvert ! "audio/x-raw-int,channels=1" ! queue ! i.sink0 filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw-int,channels=1" ! queue ! i.sink1
56 * ]| Interleaves two Mono WAV files to a single Stereo WAV file.
66 #include "interleave.h"
68 #include <gst/audio/multichannel.h>
70 GST_DEBUG_CATEGORY_STATIC (gst_interleave_debug);
71 #define GST_CAT_DEFAULT gst_interleave_debug
73 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
76 GST_STATIC_CAPS ("audio/x-raw-int, "
77 "rate = (int) [ 1, MAX ], "
78 "channels = (int) 1, "
79 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
80 "width = (int) { 8, 16, 24, 32 }, "
81 "depth = (int) [ 1, 32 ], "
82 "signed = (boolean) true; "
84 "rate = (int) [ 1, MAX ], "
85 "channels = (int) 1, "
86 "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
87 "width = (int) { 32, 64 }")
90 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
93 GST_STATIC_CAPS ("audio/x-raw-int, "
94 "rate = (int) [ 1, MAX ], "
95 "channels = (int) [ 1, MAX ], "
96 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
97 "width = (int) { 8, 16, 24, 32 }, "
98 "depth = (int) [ 1, 32 ], "
99 "signed = (boolean) true; "
100 "audio/x-raw-float, "
101 "rate = (int) [ 1, MAX ], "
102 "channels = (int) [ 1, MAX ], "
103 "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
104 "width = (int) { 32, 64 }")
107 #define MAKE_FUNC(type) \
108 static void interleave_##type (guint##type *out, guint##type *in, \
109 guint stride, guint nframes) \
113 for (i = 0; i < nframes; i++) { \
125 interleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
129 for (i = 0; i < nframes; i++) {
148 static void gst_interleave_pad_class_init (GstPadClass * klass);
150 #define GST_TYPE_INTERLEAVE_PAD (gst_interleave_pad_get_type())
151 #define GST_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_INTERLEAVE_PAD,GstInterleavePad))
152 #define GST_INTERLEAVE_PAD_CAST(pad) ((GstInterleavePad *) pad)
153 #define GST_IS_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_INTERLEAVE_PAD))
155 gst_interleave_pad_get_type (void)
157 static GType type = 0;
159 if (G_UNLIKELY (type == 0)) {
160 type = g_type_register_static_simple (GST_TYPE_PAD,
161 g_intern_static_string ("GstInterleavePad"), sizeof (GstPadClass),
162 (GClassInitFunc) gst_interleave_pad_class_init,
163 sizeof (GstInterleavePad), NULL, 0);
169 gst_interleave_pad_get_property (GObject * object,
170 guint prop_id, GValue * value, GParamSpec * pspec)
172 GstInterleavePad *self = GST_INTERLEAVE_PAD (object);
175 case PROP_PAD_CHANNEL:
176 g_value_set_uint (value, self->channel);
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185 gst_interleave_pad_class_init (GstPadClass * klass)
187 GObjectClass *gobject_class = (GObjectClass *) klass;
189 gobject_class->get_property = gst_interleave_pad_get_property;
191 g_object_class_install_property (gobject_class,
193 g_param_spec_uint ("channel",
195 "Number of the channel of this pad in the output", 0, G_MAXUINT, 0,
196 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
199 GST_BOILERPLATE (GstInterleave, gst_interleave, GstElement, GST_TYPE_ELEMENT);
204 PROP_CHANNEL_POSITIONS,
205 PROP_CHANNEL_POSITIONS_FROM_INPUT
208 static void gst_interleave_set_property (GObject * object,
209 guint prop_id, const GValue * value, GParamSpec * pspec);
210 static void gst_interleave_get_property (GObject * object,
211 guint prop_id, GValue * value, GParamSpec * pspec);
213 static GstPad *gst_interleave_request_new_pad (GstElement * element,
214 GstPadTemplate * templ, const gchar * name);
215 static void gst_interleave_release_pad (GstElement * element, GstPad * pad);
217 static GstStateChangeReturn gst_interleave_change_state (GstElement * element,
218 GstStateChange transition);
220 static gboolean gst_interleave_src_query (GstPad * pad, GstQuery * query);
222 static gboolean gst_interleave_src_event (GstPad * pad, GstEvent * event);
224 static gboolean gst_interleave_sink_event (GstPad * pad, GstEvent * event);
226 static gboolean gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps);
228 static GstCaps *gst_interleave_sink_getcaps (GstPad * pad);
230 static GstFlowReturn gst_interleave_collected (GstCollectPads * pads,
231 GstInterleave * self);
234 gst_interleave_finalize (GObject * object)
236 GstInterleave *self = GST_INTERLEAVE (object);
239 gst_object_unref (self->collect);
240 self->collect = NULL;
243 if (self->channel_positions
244 && self->channel_positions != self->input_channel_positions) {
245 g_value_array_free (self->channel_positions);
246 self->channel_positions = NULL;
249 if (self->input_channel_positions) {
250 g_value_array_free (self->input_channel_positions);
251 self->input_channel_positions = NULL;
254 gst_caps_replace (&self->sinkcaps, NULL);
256 G_OBJECT_CLASS (parent_class)->finalize (object);
260 gst_interleave_check_channel_positions (GValueArray * positions)
264 GstAudioChannelPosition *pos;
267 channels = positions->n_values;
268 pos = g_new (GstAudioChannelPosition, positions->n_values);
270 for (i = 0; i < channels; i++) {
271 GValue *v = g_value_array_get_nth (positions, i);
273 pos[i] = g_value_get_enum (v);
276 ret = gst_audio_check_channel_positions (pos, channels);
283 gst_interleave_set_channel_positions (GstInterleave * self, GstStructure * s)
285 GValue pos_array = { 0, };
288 g_value_init (&pos_array, GST_TYPE_ARRAY);
290 if (self->channel_positions
291 && self->channels == self->channel_positions->n_values
292 && gst_interleave_check_channel_positions (self->channel_positions)) {
293 GST_DEBUG_OBJECT (self, "Using provided channel positions");
294 for (i = 0; i < self->channels; i++)
295 gst_value_array_append_value (&pos_array,
296 g_value_array_get_nth (self->channel_positions, i));
298 GValue pos_none = { 0, };
300 GST_WARNING_OBJECT (self, "Using NONE channel positions");
302 g_value_init (&pos_none, GST_TYPE_AUDIO_CHANNEL_POSITION);
303 g_value_set_enum (&pos_none, GST_AUDIO_CHANNEL_POSITION_NONE);
305 for (i = 0; i < self->channels; i++)
306 gst_value_array_append_value (&pos_array, &pos_none);
308 g_value_unset (&pos_none);
310 gst_structure_set_value (s, "channel-positions", &pos_array);
311 g_value_unset (&pos_array);
315 gst_interleave_base_init (gpointer g_class)
317 gst_element_class_set_details_simple (g_class, "Audio interleaver",
318 "Filter/Converter/Audio",
319 "Folds many mono channels into one interleaved audio stream",
320 "Andy Wingo <wingo at pobox.com>, "
321 "Sebastian Dröge <slomo@circular-chaos.org>");
323 gst_element_class_add_static_pad_template (g_class, &sink_template);
324 gst_element_class_add_static_pad_template (g_class, &src_template);
328 gst_interleave_class_init (GstInterleaveClass * klass)
330 GstElementClass *gstelement_class;
331 GObjectClass *gobject_class;
333 gobject_class = G_OBJECT_CLASS (klass);
334 gstelement_class = GST_ELEMENT_CLASS (klass);
336 GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0,
337 "interleave element");
339 /* Reference GstInterleavePad class to have the type registered from
340 * a threadsafe context
342 g_type_class_ref (GST_TYPE_INTERLEAVE_PAD);
344 gobject_class->finalize = gst_interleave_finalize;
345 gobject_class->set_property = gst_interleave_set_property;
346 gobject_class->get_property = gst_interleave_get_property;
349 * GstInterleave:channel-positions
351 * Channel positions: This property controls the channel positions
352 * that are used on the src caps. The number of elements should be
353 * the same as the number of sink pads and the array should contain
354 * a valid list of channel positions. The n-th element of the array
355 * is the position of the n-th sink pad.
357 * These channel positions will only be used if they're valid and the
358 * number of elements is the same as the number of channels. If this
359 * is not given a NONE layout will be used.
362 g_object_class_install_property (gobject_class, PROP_CHANNEL_POSITIONS,
363 g_param_spec_value_array ("channel-positions", "Channel positions",
364 "Channel positions used on the output",
365 g_param_spec_enum ("channel-position", "Channel position",
366 "Channel position of the n-th input",
367 GST_TYPE_AUDIO_CHANNEL_POSITION,
368 GST_AUDIO_CHANNEL_POSITION_NONE,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
370 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373 * GstInterleave:channel-positions-from-input
375 * Channel positions from input: If this property is set to %TRUE the channel
376 * positions will be taken from the input caps if valid channel positions for
377 * the output can be constructed from them. If this is set to %TRUE setting the
378 * channel-positions property overwrites this property again.
381 g_object_class_install_property (gobject_class,
382 PROP_CHANNEL_POSITIONS_FROM_INPUT,
383 g_param_spec_boolean ("channel-positions-from-input",
384 "Channel positions from input",
385 "Take channel positions from the input", TRUE,
386 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
388 gstelement_class->request_new_pad =
389 GST_DEBUG_FUNCPTR (gst_interleave_request_new_pad);
390 gstelement_class->release_pad =
391 GST_DEBUG_FUNCPTR (gst_interleave_release_pad);
392 gstelement_class->change_state =
393 GST_DEBUG_FUNCPTR (gst_interleave_change_state);
397 gst_interleave_init (GstInterleave * self, GstInterleaveClass * klass)
399 self->src = gst_pad_new_from_static_template (&src_template, "src");
401 gst_pad_set_query_function (self->src,
402 GST_DEBUG_FUNCPTR (gst_interleave_src_query));
403 gst_pad_set_event_function (self->src,
404 GST_DEBUG_FUNCPTR (gst_interleave_src_event));
406 gst_element_add_pad (GST_ELEMENT (self), self->src);
408 self->collect = gst_collect_pads_new ();
409 gst_collect_pads_set_function (self->collect,
410 (GstCollectPadsFunction) gst_interleave_collected, self);
412 self->input_channel_positions = g_value_array_new (0);
413 self->channel_positions_from_input = TRUE;
414 self->channel_positions = self->input_channel_positions;
418 gst_interleave_set_property (GObject * object, guint prop_id,
419 const GValue * value, GParamSpec * pspec)
421 GstInterleave *self = GST_INTERLEAVE (object);
424 case PROP_CHANNEL_POSITIONS:
425 if (self->channel_positions &&
426 self->channel_positions != self->input_channel_positions)
427 g_value_array_free (self->channel_positions);
429 self->channel_positions = g_value_dup_boxed (value);
430 self->channel_positions_from_input = FALSE;
432 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
433 self->channel_positions_from_input = g_value_get_boolean (value);
435 if (self->channel_positions_from_input) {
436 if (self->channel_positions &&
437 self->channel_positions != self->input_channel_positions)
438 g_value_array_free (self->channel_positions);
439 self->channel_positions = self->input_channel_positions;
443 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
449 gst_interleave_get_property (GObject * object, guint prop_id,
450 GValue * value, GParamSpec * pspec)
452 GstInterleave *self = GST_INTERLEAVE (object);
455 case PROP_CHANNEL_POSITIONS:
456 g_value_set_boxed (value, self->channel_positions);
458 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
459 g_value_set_boolean (value, self->channel_positions_from_input);
462 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
468 gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
469 const gchar * req_name)
471 GstInterleave *self = GST_INTERLEAVE (element);
474 gint channels, padnumber;
477 if (templ->direction != GST_PAD_SINK)
480 #if GLIB_CHECK_VERSION(2,29,5)
481 channels = g_atomic_int_add (&self->channels, 1);
482 padnumber = g_atomic_int_add (&self->padcounter, 1);
484 channels = g_atomic_int_exchange_and_add (&self->channels, 1);
485 padnumber = g_atomic_int_exchange_and_add (&self->padcounter, 1);
488 pad_name = g_strdup_printf ("sink%d", padnumber);
489 new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
490 "name", pad_name, "direction", templ->direction,
491 "template", templ, NULL));
492 GST_INTERLEAVE_PAD_CAST (new_pad)->channel = channels;
493 GST_DEBUG_OBJECT (self, "requested new pad %s", pad_name);
496 gst_pad_set_setcaps_function (new_pad,
497 GST_DEBUG_FUNCPTR (gst_interleave_sink_setcaps));
498 gst_pad_set_getcaps_function (new_pad,
499 GST_DEBUG_FUNCPTR (gst_interleave_sink_getcaps));
501 gst_collect_pads_add_pad (self->collect, new_pad, sizeof (GstCollectData));
503 /* FIXME: hacked way to override/extend the event function of
504 * GstCollectPads; because it sets its own event function giving the
505 * element no access to events */
506 self->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (new_pad);
507 gst_pad_set_event_function (new_pad,
508 GST_DEBUG_FUNCPTR (gst_interleave_sink_event));
510 if (!gst_element_add_pad (element, new_pad))
513 g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
514 g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE);
515 self->input_channel_positions =
516 g_value_array_append (self->input_channel_positions, &val);
517 g_value_unset (&val);
519 /* Update the src caps if we already have them */
520 if (self->sinkcaps) {
524 /* Take lock to make sure processing finishes first */
525 GST_OBJECT_LOCK (self->collect);
527 srccaps = gst_caps_copy (self->sinkcaps);
528 s = gst_caps_get_structure (srccaps, 0);
530 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
531 gst_interleave_set_channel_positions (self, s);
533 gst_pad_set_caps (self->src, srccaps);
534 gst_caps_unref (srccaps);
536 GST_OBJECT_UNLOCK (self->collect);
544 g_warning ("interleave: requested new pad that is not a SINK pad\n");
549 GST_DEBUG_OBJECT (self, "could not add pad %s", GST_PAD_NAME (new_pad));
550 gst_collect_pads_remove_pad (self->collect, new_pad);
551 gst_object_unref (new_pad);
557 gst_interleave_release_pad (GstElement * element, GstPad * pad)
559 GstInterleave *self = GST_INTERLEAVE (element);
562 g_return_if_fail (GST_IS_INTERLEAVE_PAD (pad));
564 /* Take lock to make sure we're not changing this when processing buffers */
565 GST_OBJECT_LOCK (self->collect);
567 g_atomic_int_add (&self->channels, -1);
569 g_value_array_remove (self->input_channel_positions,
570 GST_INTERLEAVE_PAD_CAST (pad)->channel);
572 /* Update channel numbers */
573 GST_OBJECT_LOCK (self);
574 for (l = GST_ELEMENT_CAST (self)->sinkpads; l != NULL; l = l->next) {
575 GstInterleavePad *ipad = GST_INTERLEAVE_PAD (l->data);
577 if (GST_INTERLEAVE_PAD_CAST (pad)->channel < ipad->channel)
580 GST_OBJECT_UNLOCK (self);
582 /* Update the src caps if we already have them */
583 if (self->sinkcaps) {
584 if (self->channels > 0) {
588 srccaps = gst_caps_copy (self->sinkcaps);
589 s = gst_caps_get_structure (srccaps, 0);
591 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
592 gst_interleave_set_channel_positions (self, s);
594 gst_pad_set_caps (self->src, srccaps);
595 gst_caps_unref (srccaps);
597 gst_caps_replace (&self->sinkcaps, NULL);
598 gst_pad_set_caps (self->src, NULL);
602 GST_OBJECT_UNLOCK (self->collect);
604 gst_collect_pads_remove_pad (self->collect, pad);
605 gst_element_remove_pad (element, pad);
608 static GstStateChangeReturn
609 gst_interleave_change_state (GstElement * element, GstStateChange transition)
612 GstStateChangeReturn ret;
614 self = GST_INTERLEAVE (element);
616 switch (transition) {
617 case GST_STATE_CHANGE_NULL_TO_READY:
619 case GST_STATE_CHANGE_READY_TO_PAUSED:
622 self->segment_pending = TRUE;
623 self->segment_position = 0;
624 self->segment_rate = 1.0;
625 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
626 gst_collect_pads_start (self->collect);
628 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
634 /* Stop before calling the parent's state change function as
635 * GstCollectPads might take locks and we would deadlock in that
638 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
639 gst_collect_pads_stop (self->collect);
641 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
643 switch (transition) {
644 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
646 case GST_STATE_CHANGE_PAUSED_TO_READY:
647 gst_pad_set_caps (self->src, NULL);
648 gst_caps_replace (&self->sinkcaps, NULL);
650 case GST_STATE_CHANGE_READY_TO_NULL:
660 __remove_channels (GstCaps * caps)
665 size = gst_caps_get_size (caps);
666 for (i = 0; i < size; i++) {
667 s = gst_caps_get_structure (caps, i);
668 gst_structure_remove_field (s, "channel-positions");
669 gst_structure_remove_field (s, "channels");
674 __set_channels (GstCaps * caps, gint channels)
679 size = gst_caps_get_size (caps);
680 for (i = 0; i < size; i++) {
681 s = gst_caps_get_structure (caps, i);
683 gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
685 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
689 /* we can only accept caps that we and downstream can handle. */
691 gst_interleave_sink_getcaps (GstPad * pad)
693 GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
694 GstCaps *result, *peercaps, *sinkcaps;
696 GST_OBJECT_LOCK (self);
698 /* If we already have caps on one of the sink pads return them */
699 if (self->sinkcaps) {
700 result = gst_caps_copy (self->sinkcaps);
702 /* get the downstream possible caps */
703 peercaps = gst_pad_peer_get_caps (self->src);
704 /* get the allowed caps on this sinkpad */
705 sinkcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
706 __remove_channels (sinkcaps);
708 __remove_channels (peercaps);
709 /* if the peer has caps, intersect */
710 GST_DEBUG_OBJECT (pad, "intersecting peer and template caps");
711 result = gst_caps_intersect (peercaps, sinkcaps);
712 gst_caps_unref (peercaps);
713 gst_caps_unref (sinkcaps);
715 /* the peer has no caps (or there is no peer), just use the allowed caps
716 * of this sinkpad. */
717 GST_DEBUG_OBJECT (pad, "no peer caps, using sinkcaps");
720 __set_channels (result, 1);
723 GST_OBJECT_UNLOCK (self);
725 gst_object_unref (self);
727 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, result);
733 gst_interleave_set_process_function (GstInterleave * self)
735 switch (self->width) {
737 self->func = (GstInterleaveFunc) interleave_8;
740 self->func = (GstInterleaveFunc) interleave_16;
743 self->func = (GstInterleaveFunc) interleave_24;
746 self->func = (GstInterleaveFunc) interleave_32;
749 self->func = (GstInterleaveFunc) interleave_64;
752 g_assert_not_reached ();
758 gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps)
762 g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE);
764 self = GST_INTERLEAVE (gst_pad_get_parent (pad));
766 /* First caps that are set on a sink pad are used as output caps */
767 /* TODO: handle caps changes */
768 if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) {
769 goto cannot_change_caps;
775 s = gst_caps_get_structure (caps, 0);
777 if (!gst_structure_get_int (s, "width", &self->width))
780 if (!gst_structure_get_int (s, "rate", &self->rate))
783 gst_interleave_set_process_function (self);
785 if (gst_structure_has_field (s, "channel-positions")) {
786 const GValue *pos_array;
788 pos_array = gst_structure_get_value (s, "channel-positions");
789 if (GST_VALUE_HOLDS_ARRAY (pos_array)
790 && gst_value_array_get_size (pos_array) == 1) {
791 const GValue *pos = gst_value_array_get_value (pos_array, 0);
793 GValue *apos = g_value_array_get_nth (self->input_channel_positions,
794 GST_INTERLEAVE_PAD_CAST (pad)->channel);
796 g_value_set_enum (apos, g_value_get_enum (pos));
800 srccaps = gst_caps_copy (caps);
801 s = gst_caps_get_structure (srccaps, 0);
803 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
804 gst_interleave_set_channel_positions (self, s);
806 res = gst_pad_set_caps (self->src, srccaps);
807 gst_caps_unref (srccaps);
810 goto src_did_not_accept;
813 if (!self->sinkcaps) {
814 GstCaps *sinkcaps = gst_caps_copy (caps);
815 GstStructure *s = gst_caps_get_structure (sinkcaps, 0);
817 gst_structure_remove_field (s, "channel-positions");
819 gst_caps_replace (&self->sinkcaps, sinkcaps);
821 gst_caps_unref (sinkcaps);
824 gst_object_unref (self);
830 GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
831 "change", self->sinkcaps);
832 gst_object_unref (self);
837 GST_WARNING_OBJECT (self, "src did not accept setcaps()");
838 gst_object_unref (self);
843 GST_WARNING_OBJECT (self, "caps did not have width: %" GST_PTR_FORMAT,
845 gst_object_unref (self);
850 GST_WARNING_OBJECT (self, "caps did not have rate: %" GST_PTR_FORMAT, caps);
851 gst_object_unref (self);
857 gst_interleave_sink_event (GstPad * pad, GstEvent * event)
859 GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
862 GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
863 GST_DEBUG_PAD_NAME (pad));
865 switch (GST_EVENT_TYPE (event)) {
866 case GST_EVENT_FLUSH_STOP:
867 /* mark a pending new segment. This event is synchronized
868 * with the streaming thread so we can safely update the
869 * variable without races. It's somewhat weird because we
870 * assume the collectpads forwarded the FLUSH_STOP past us
871 * and downstream (using our source pad, the bastard!).
873 self->segment_pending = TRUE;
879 /* now GstCollectPads can take care of the rest, e.g. EOS */
880 ret = self->collect_event (pad, event);
882 gst_object_unref (self);
887 gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
896 gst_query_parse_duration (query, &format, NULL);
902 /* Take maximum of all durations */
903 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
905 GstIteratorResult ires;
909 ires = gst_iterator_next (it, &item);
911 case GST_ITERATOR_DONE:
914 case GST_ITERATOR_OK:
916 GstPad *pad = GST_PAD_CAST (item);
920 /* ask sink peer for duration */
921 res &= gst_pad_query_peer_duration (pad, &format, &duration);
922 /* take max from all valid return values */
924 /* valid unknown length, stop searching */
925 if (duration == -1) {
929 /* else see if bigger than current max */
930 else if (duration > max)
933 gst_object_unref (pad);
936 case GST_ITERATOR_RESYNC:
939 gst_iterator_resync (it);
947 gst_iterator_free (it);
950 /* If in bytes format we have to multiply with the number of channels
951 * to get the correct results. All other formats should be fine */
952 if (format == GST_FORMAT_BYTES && max != -1)
953 max *= self->channels;
955 /* and store the max */
956 GST_DEBUG_OBJECT (self, "Total duration in format %s: %"
957 GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
958 gst_query_set_duration (query, format, max);
965 gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query)
967 GstClockTime min, max;
978 max = GST_CLOCK_TIME_NONE;
980 /* Take maximum of all latency values */
981 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
983 GstIteratorResult ires;
986 ires = gst_iterator_next (it, &item);
988 case GST_ITERATOR_DONE:
991 case GST_ITERATOR_OK:
993 GstPad *pad = GST_PAD_CAST (item);
995 GstClockTime min_cur, max_cur;
998 peerquery = gst_query_new_latency ();
1000 /* Ask peer for latency */
1001 res &= gst_pad_peer_query (pad, peerquery);
1003 /* take max from all valid return values */
1005 gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
1010 if (max_cur != GST_CLOCK_TIME_NONE &&
1011 ((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
1012 (max == GST_CLOCK_TIME_NONE)))
1015 live = live || live_cur;
1018 gst_query_unref (peerquery);
1019 gst_object_unref (pad);
1022 case GST_ITERATOR_RESYNC:
1025 max = GST_CLOCK_TIME_NONE;
1027 gst_iterator_resync (it);
1035 gst_iterator_free (it);
1038 /* store the results */
1039 GST_DEBUG_OBJECT (self, "Calculated total latency: live %s, min %"
1040 GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
1041 (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1042 gst_query_set_latency (query, live, min, max);
1049 gst_interleave_src_query (GstPad * pad, GstQuery * query)
1051 GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
1052 gboolean res = FALSE;
1054 switch (GST_QUERY_TYPE (query)) {
1055 case GST_QUERY_POSITION:
1059 gst_query_parse_position (query, &format, NULL);
1062 case GST_FORMAT_TIME:
1063 /* FIXME, bring to stream time, might be tricky */
1064 gst_query_set_position (query, format, self->timestamp);
1067 case GST_FORMAT_BYTES:
1068 gst_query_set_position (query, format,
1069 self->offset * self->channels * self->width);
1072 case GST_FORMAT_DEFAULT:
1073 gst_query_set_position (query, format, self->offset);
1081 case GST_QUERY_DURATION:
1082 res = gst_interleave_src_query_duration (self, query);
1084 case GST_QUERY_LATENCY:
1085 res = gst_interleave_src_query_latency (self, query);
1088 /* FIXME, needs a custom query handler because we have multiple
1090 res = gst_pad_query_default (pad, query);
1094 gst_object_unref (self);
1099 forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
1101 gst_event_ref (event);
1102 GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
1103 if (!gst_pad_push_event (pad, event)) {
1104 g_value_set_boolean (ret, FALSE);
1105 GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.",
1106 event, GST_EVENT_TYPE_NAME (event));
1108 GST_LOG_OBJECT (pad, "Sent event %p (%s).",
1109 event, GST_EVENT_TYPE_NAME (event));
1111 gst_object_unref (pad);
1116 forward_event (GstInterleave * self, GstEvent * event)
1119 GValue vret = { 0 };
1121 GST_LOG_OBJECT (self, "Forwarding event %p (%s)", event,
1122 GST_EVENT_TYPE_NAME (event));
1124 g_value_init (&vret, G_TYPE_BOOLEAN);
1125 g_value_set_boolean (&vret, TRUE);
1126 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
1127 gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
1129 gst_iterator_free (it);
1130 gst_event_unref (event);
1132 return g_value_get_boolean (&vret);
1137 gst_interleave_src_event (GstPad * pad, GstEvent * event)
1139 GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
1142 switch (GST_EVENT_TYPE (event)) {
1144 /* QoS might be tricky */
1147 case GST_EVENT_SEEK:
1150 GstSeekType curtype;
1153 /* parse the seek parameters */
1154 gst_event_parse_seek (event, &self->segment_rate, NULL, &flags, &curtype,
1157 /* check if we are flushing */
1158 if (flags & GST_SEEK_FLAG_FLUSH) {
1159 /* make sure we accept nothing anymore and return WRONG_STATE */
1160 gst_collect_pads_set_flushing (self->collect, TRUE);
1162 /* flushing seek, start flush downstream, the flush will be done
1163 * when all pads received a FLUSH_STOP. */
1164 gst_pad_push_event (self->src, gst_event_new_flush_start ());
1167 /* now wait for the collected to be finished and mark a new
1169 GST_OBJECT_LOCK (self->collect);
1170 if (curtype == GST_SEEK_TYPE_SET)
1171 self->segment_position = cur;
1173 self->segment_position = 0;
1174 self->segment_pending = TRUE;
1175 GST_OBJECT_UNLOCK (self->collect);
1177 result = forward_event (self, event);
1180 case GST_EVENT_NAVIGATION:
1181 /* navigation is rather pointless. */
1185 /* just forward the rest for now */
1186 result = forward_event (self, event);
1189 gst_object_unref (self);
1194 static GstFlowReturn
1195 gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
1199 GstFlowReturn ret = GST_FLOW_OK;
1202 guint ncollected = 0;
1203 gboolean empty = TRUE;
1204 gint width = self->width / 8;
1206 g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
1207 g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED);
1208 g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED);
1209 g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED);
1211 size = gst_collect_pads_available (pads);
1213 g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR);
1215 GST_DEBUG_OBJECT (self, "Starting to collect %u bytes from %d channels", size,
1218 nsamples = size / width;
1221 gst_pad_alloc_buffer (self->src, GST_BUFFER_OFFSET_NONE,
1222 size * self->channels, GST_PAD_CAPS (self->src), &outbuf);
1224 if (ret != GST_FLOW_OK) {
1226 } else if (outbuf == NULL || GST_BUFFER_SIZE (outbuf) < size * self->channels) {
1227 gst_buffer_unref (outbuf);
1228 return GST_FLOW_NOT_NEGOTIATED;
1229 } else if (!gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
1230 GST_PAD_CAPS (self->src))) {
1231 gst_buffer_unref (outbuf);
1232 return GST_FLOW_NOT_NEGOTIATED;
1235 memset (GST_BUFFER_DATA (outbuf), 0, size * self->channels);
1237 for (collected = pads->data; collected != NULL; collected = collected->next) {
1238 GstCollectData *cdata;
1242 cdata = (GstCollectData *) collected->data;
1244 inbuf = gst_collect_pads_take_buffer (pads, cdata, size);
1245 if (inbuf == NULL) {
1246 GST_DEBUG_OBJECT (cdata->pad, "No buffer available");
1251 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))
1256 GST_BUFFER_DATA (outbuf) +
1257 width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
1259 self->func (outdata, GST_BUFFER_DATA (inbuf), self->channels, nsamples);
1263 gst_buffer_unref (inbuf);
1266 if (ncollected == 0)
1269 if (self->segment_pending) {
1272 event = gst_event_new_new_segment_full (FALSE, self->segment_rate,
1273 1.0, GST_FORMAT_TIME, self->timestamp, -1, self->segment_position);
1275 gst_pad_push_event (self->src, event);
1276 self->segment_pending = FALSE;
1277 self->segment_position = 0;
1280 GST_BUFFER_TIMESTAMP (outbuf) = self->timestamp;
1281 GST_BUFFER_OFFSET (outbuf) = self->offset;
1283 self->offset += nsamples;
1284 self->timestamp = gst_util_uint64_scale_int (self->offset,
1285 GST_SECOND, self->rate);
1287 GST_BUFFER_DURATION (outbuf) = self->timestamp -
1288 GST_BUFFER_TIMESTAMP (outbuf);
1291 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
1293 GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
1294 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
1295 ret = gst_pad_push (self->src, outbuf);
1301 GST_DEBUG_OBJECT (self, "no data available, must be EOS");
1302 gst_buffer_unref (outbuf);
1303 gst_pad_push_event (self->src, gst_event_new_eos ());
1304 return GST_FLOW_UNEXPECTED;