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,channels=2" ! deinterleave name=d interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav d.src_0 ! queue ! audioconvert ! i.sink_1 d.src_1 ! queue ! audioconvert ! i.sink_0
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,channels=1" ! queue ! i.sink_0 filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1" ! queue ! i.sink_1
56 * ]| Interleaves two Mono WAV files to a single Stereo WAV file.
66 #include "interleave.h"
68 #include <gst/audio/audio.h>
69 #include <gst/audio/audio-enumtypes.h>
71 GST_DEBUG_CATEGORY_STATIC (gst_interleave_debug);
72 #define GST_CAT_DEFAULT gst_interleave_debug
74 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
77 GST_STATIC_CAPS ("audio/x-raw, "
78 "rate = (int) [ 1, MAX ], "
79 "channels = (int) 1, "
80 "format = (string) " GST_AUDIO_FORMATS_ALL ", "
81 "layout = (string) {non-interleaved, interleaved}")
84 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
87 GST_STATIC_CAPS ("audio/x-raw, "
88 "rate = (int) [ 1, MAX ], "
89 "channels = (int) [ 1, MAX ], "
90 "format = (string) " GST_AUDIO_FORMATS_ALL ", "
91 "layout = (string) interleaved")
94 #define MAKE_FUNC(type) \
95 static void interleave_##type (guint##type *out, guint##type *in, \
96 guint stride, guint nframes) \
100 for (i = 0; i < nframes; i++) { \
112 interleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
116 for (i = 0; i < nframes; i++) {
135 static void gst_interleave_pad_class_init (GstPadClass * klass);
137 #define GST_TYPE_INTERLEAVE_PAD (gst_interleave_pad_get_type())
138 #define GST_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_INTERLEAVE_PAD,GstInterleavePad))
139 #define GST_INTERLEAVE_PAD_CAST(pad) ((GstInterleavePad *) pad)
140 #define GST_IS_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_INTERLEAVE_PAD))
142 gst_interleave_pad_get_type (void)
144 static GType type = 0;
146 if (G_UNLIKELY (type == 0)) {
147 type = g_type_register_static_simple (GST_TYPE_PAD,
148 g_intern_static_string ("GstInterleavePad"), sizeof (GstPadClass),
149 (GClassInitFunc) gst_interleave_pad_class_init,
150 sizeof (GstInterleavePad), NULL, 0);
156 gst_interleave_pad_get_property (GObject * object,
157 guint prop_id, GValue * value, GParamSpec * pspec)
159 GstInterleavePad *self = GST_INTERLEAVE_PAD (object);
162 case PROP_PAD_CHANNEL:
163 g_value_set_uint (value, self->channel);
166 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
172 gst_interleave_pad_class_init (GstPadClass * klass)
174 GObjectClass *gobject_class = (GObjectClass *) klass;
176 gobject_class->get_property = gst_interleave_pad_get_property;
178 g_object_class_install_property (gobject_class,
180 g_param_spec_uint ("channel",
182 "Number of the channel of this pad in the output", 0, G_MAXUINT, 0,
183 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
186 #define gst_interleave_parent_class parent_class
187 G_DEFINE_TYPE (GstInterleave, gst_interleave, GST_TYPE_ELEMENT);
192 PROP_CHANNEL_POSITIONS,
193 PROP_CHANNEL_POSITIONS_FROM_INPUT
196 static void gst_interleave_set_property (GObject * object,
197 guint prop_id, const GValue * value, GParamSpec * pspec);
198 static void gst_interleave_get_property (GObject * object,
199 guint prop_id, GValue * value, GParamSpec * pspec);
201 static GstPad *gst_interleave_request_new_pad (GstElement * element,
202 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
203 static void gst_interleave_release_pad (GstElement * element, GstPad * pad);
205 static GstStateChangeReturn gst_interleave_change_state (GstElement * element,
206 GstStateChange transition);
208 static gboolean gst_interleave_src_query (GstPad * pad, GstObject * parent,
211 static gboolean gst_interleave_src_event (GstPad * pad, GstObject * parent,
214 static gboolean gst_interleave_sink_event (GstCollectPads2 * pads,
215 GstCollectData2 * data, GstEvent * event, gpointer user_data);
217 static gboolean gst_interleave_sink_setcaps (GstInterleave * self,
218 GstPad * pad, const GstCaps * caps);
220 static GstCaps *gst_interleave_sink_getcaps (GstPad * pad, GstObject * parent,
223 static GstFlowReturn gst_interleave_collected (GstCollectPads2 * pads,
224 GstInterleave * self);
227 gst_interleave_finalize (GObject * object)
229 GstInterleave *self = GST_INTERLEAVE (object);
232 gst_object_unref (self->collect);
233 self->collect = NULL;
236 if (self->channel_positions
237 && self->channel_positions != self->input_channel_positions) {
238 g_value_array_free (self->channel_positions);
239 self->channel_positions = NULL;
242 if (self->input_channel_positions) {
243 g_value_array_free (self->input_channel_positions);
244 self->input_channel_positions = NULL;
247 gst_caps_replace (&self->sinkcaps, NULL);
249 G_OBJECT_CLASS (parent_class)->finalize (object);
253 gst_interleave_check_channel_positions (GValueArray * positions)
257 GstAudioChannelPosition *pos;
260 channels = positions->n_values;
261 pos = g_new (GstAudioChannelPosition, channels);
263 for (i = 0; i < channels; i++) {
266 val = g_value_array_get_nth (positions, i);
267 pos[i] = g_value_get_enum (val);
270 ret = gst_audio_check_valid_channel_positions (pos, channels, FALSE);
277 gst_interleave_set_channel_positions (GstInterleave * self, GstStructure * s)
280 guint64 channel_mask = 0;
282 if (self->channel_positions != NULL &&
283 self->channels == self->channel_positions->n_values
284 && gst_interleave_check_channel_positions (self->channel_positions)) {
285 GST_DEBUG_OBJECT (self, "Using provided channel positions");
286 for (i = 0; i < self->channels; i++) {
289 val = g_value_array_get_nth (self->channel_positions, i);
290 channel_mask |= G_GUINT64_CONSTANT (1) << g_value_get_enum (val);
293 GST_WARNING_OBJECT (self, "Using NONE channel positions");
295 gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL);
299 gst_interleave_class_init (GstInterleaveClass * klass)
301 GstElementClass *gstelement_class;
302 GObjectClass *gobject_class;
304 gobject_class = G_OBJECT_CLASS (klass);
305 gstelement_class = GST_ELEMENT_CLASS (klass);
307 GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0,
308 "interleave element");
310 gst_element_class_set_static_metadata (gstelement_class, "Audio interleaver",
311 "Filter/Converter/Audio",
312 "Folds many mono channels into one interleaved audio stream",
313 "Andy Wingo <wingo at pobox.com>, "
314 "Sebastian Dröge <slomo@circular-chaos.org>");
316 gst_element_class_add_pad_template (gstelement_class,
317 gst_static_pad_template_get (&sink_template));
318 gst_element_class_add_pad_template (gstelement_class,
319 gst_static_pad_template_get (&src_template));
321 /* Reference GstInterleavePad class to have the type registered from
322 * a threadsafe context
324 g_type_class_ref (GST_TYPE_INTERLEAVE_PAD);
326 gobject_class->finalize = gst_interleave_finalize;
327 gobject_class->set_property = gst_interleave_set_property;
328 gobject_class->get_property = gst_interleave_get_property;
331 * GstInterleave:channel-positions
333 * Channel positions: This property controls the channel positions
334 * that are used on the src caps. The number of elements should be
335 * the same as the number of sink pads and the array should contain
336 * a valid list of channel positions. The n-th element of the array
337 * is the position of the n-th sink pad.
339 * These channel positions will only be used if they're valid and the
340 * number of elements is the same as the number of channels. If this
341 * is not given a NONE layout will be used.
344 g_object_class_install_property (gobject_class, PROP_CHANNEL_POSITIONS,
345 g_param_spec_value_array ("channel-positions", "Channel positions",
346 "Channel positions used on the output",
347 g_param_spec_enum ("channel-position", "Channel position",
348 "Channel position of the n-th input",
349 GST_TYPE_AUDIO_CHANNEL_POSITION,
350 GST_AUDIO_CHANNEL_POSITION_NONE,
351 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
352 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
355 * GstInterleave:channel-positions-from-input
357 * Channel positions from input: If this property is set to %TRUE the channel
358 * positions will be taken from the input caps if valid channel positions for
359 * the output can be constructed from them. If this is set to %TRUE setting the
360 * channel-positions property overwrites this property again.
363 g_object_class_install_property (gobject_class,
364 PROP_CHANNEL_POSITIONS_FROM_INPUT,
365 g_param_spec_boolean ("channel-positions-from-input",
366 "Channel positions from input",
367 "Take channel positions from the input", TRUE,
368 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370 gstelement_class->request_new_pad =
371 GST_DEBUG_FUNCPTR (gst_interleave_request_new_pad);
372 gstelement_class->release_pad =
373 GST_DEBUG_FUNCPTR (gst_interleave_release_pad);
374 gstelement_class->change_state =
375 GST_DEBUG_FUNCPTR (gst_interleave_change_state);
379 gst_interleave_init (GstInterleave * self)
381 self->src = gst_pad_new_from_static_template (&src_template, "src");
383 gst_pad_set_query_function (self->src,
384 GST_DEBUG_FUNCPTR (gst_interleave_src_query));
385 gst_pad_set_event_function (self->src,
386 GST_DEBUG_FUNCPTR (gst_interleave_src_event));
388 gst_pad_set_active (self->src, TRUE);
389 gst_element_add_pad (GST_ELEMENT (self), self->src);
391 self->collect = gst_collect_pads2_new ();
392 gst_collect_pads2_set_function (self->collect,
393 (GstCollectPads2Function) gst_interleave_collected, self);
395 self->input_channel_positions = g_value_array_new (0);
396 self->channel_positions_from_input = TRUE;
397 self->channel_positions = self->input_channel_positions;
401 gst_interleave_set_property (GObject * object, guint prop_id,
402 const GValue * value, GParamSpec * pspec)
404 GstInterleave *self = GST_INTERLEAVE (object);
407 case PROP_CHANNEL_POSITIONS:
408 if (self->channel_positions &&
409 self->channel_positions != self->input_channel_positions)
410 g_value_array_free (self->channel_positions);
412 self->channel_positions = g_value_dup_boxed (value);
413 self->channel_positions_from_input = FALSE;
414 self->channels = self->channel_positions->n_values;
416 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
417 self->channel_positions_from_input = g_value_get_boolean (value);
419 if (self->channel_positions_from_input) {
420 if (self->channel_positions &&
421 self->channel_positions != self->input_channel_positions)
422 g_value_array_free (self->channel_positions);
423 self->channel_positions = self->input_channel_positions;
427 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
433 gst_interleave_get_property (GObject * object, guint prop_id,
434 GValue * value, GParamSpec * pspec)
436 GstInterleave *self = GST_INTERLEAVE (object);
439 case PROP_CHANNEL_POSITIONS:
440 g_value_set_boxed (value, self->channel_positions);
442 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
443 g_value_set_boolean (value, self->channel_positions_from_input);
446 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
452 gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
453 const gchar * req_name, const GstCaps * caps)
455 GstInterleave *self = GST_INTERLEAVE (element);
458 gint channels, padnumber;
461 if (templ->direction != GST_PAD_SINK)
464 padnumber = g_atomic_int_add (&self->padcounter, 1);
465 if (self->channel_positions_from_input)
466 channels = g_atomic_int_add (&self->channels, 1);
468 channels = padnumber;
470 pad_name = g_strdup_printf ("sink_%u", padnumber);
471 new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
472 "name", pad_name, "direction", templ->direction,
473 "template", templ, NULL));
474 GST_INTERLEAVE_PAD_CAST (new_pad)->channel = channels;
475 GST_DEBUG_OBJECT (self, "requested new pad %s", pad_name);
478 gst_pad_use_fixed_caps (new_pad);
480 gst_collect_pads2_add_pad (self->collect, new_pad, sizeof (GstCollectData2));
482 gst_collect_pads2_set_event_function (self->collect,
483 (GstCollectPads2EventFunction)
484 GST_DEBUG_FUNCPTR (gst_interleave_sink_event), self);
486 if (!gst_element_add_pad (element, new_pad))
489 g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
490 g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE);
491 self->input_channel_positions =
492 g_value_array_append (self->input_channel_positions, &val);
493 g_value_unset (&val);
495 /* Update the src caps if we already have them */
496 if (self->sinkcaps) {
500 /* Take lock to make sure processing finishes first */
501 GST_OBJECT_LOCK (self->collect);
503 srccaps = gst_caps_copy (self->sinkcaps);
504 s = gst_caps_get_structure (srccaps, 0);
506 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
507 gst_interleave_set_channel_positions (self, s);
509 gst_pad_set_active (self->src, TRUE);
510 gst_pad_set_caps (self->src, srccaps);
511 gst_caps_unref (srccaps);
513 GST_OBJECT_UNLOCK (self->collect);
521 g_warning ("interleave: requested new pad that is not a SINK pad\n");
526 GST_DEBUG_OBJECT (self, "could not add pad %s", GST_PAD_NAME (new_pad));
527 gst_collect_pads2_remove_pad (self->collect, new_pad);
528 gst_object_unref (new_pad);
534 gst_interleave_release_pad (GstElement * element, GstPad * pad)
536 GstInterleave *self = GST_INTERLEAVE (element);
538 GstAudioChannelPosition position;
540 g_return_if_fail (GST_IS_INTERLEAVE_PAD (pad));
542 /* Take lock to make sure we're not changing this when processing buffers */
543 GST_OBJECT_LOCK (self->collect);
545 g_atomic_int_add (&self->channels, -1);
547 position = GST_INTERLEAVE_PAD_CAST (pad)->channel;
548 g_value_array_remove (self->input_channel_positions, position);
550 /* Update channel numbers */
551 GST_OBJECT_LOCK (self);
552 for (l = GST_ELEMENT_CAST (self)->sinkpads; l != NULL; l = l->next) {
553 GstInterleavePad *ipad = GST_INTERLEAVE_PAD (l->data);
555 if (GST_INTERLEAVE_PAD_CAST (pad)->channel < ipad->channel)
558 GST_OBJECT_UNLOCK (self);
560 /* Update the src caps if we already have them */
561 if (self->sinkcaps) {
562 if (self->channels > 0) {
566 srccaps = gst_caps_copy (self->sinkcaps);
567 s = gst_caps_get_structure (srccaps, 0);
569 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
570 gst_interleave_set_channel_positions (self, s);
572 gst_pad_set_active (self->src, TRUE);
573 gst_pad_set_caps (self->src, srccaps);
574 gst_caps_unref (srccaps);
576 gst_caps_replace (&self->sinkcaps, NULL);
580 GST_OBJECT_UNLOCK (self->collect);
582 gst_collect_pads2_remove_pad (self->collect, pad);
583 gst_element_remove_pad (element, pad);
586 static GstStateChangeReturn
587 gst_interleave_change_state (GstElement * element, GstStateChange transition)
590 GstStateChangeReturn ret;
592 self = GST_INTERLEAVE (element);
594 switch (transition) {
595 case GST_STATE_CHANGE_NULL_TO_READY:
597 case GST_STATE_CHANGE_READY_TO_PAUSED:
600 self->segment_pending = TRUE;
601 self->segment_position = 0;
602 self->segment_rate = 1.0;
603 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
604 gst_collect_pads2_start (self->collect);
606 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
612 /* Stop before calling the parent's state change function as
613 * GstCollectPads2 might take locks and we would deadlock in that
616 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
617 gst_collect_pads2_stop (self->collect);
619 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
621 switch (transition) {
622 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
624 case GST_STATE_CHANGE_PAUSED_TO_READY:
625 gst_caps_replace (&self->sinkcaps, NULL);
627 case GST_STATE_CHANGE_READY_TO_NULL:
637 __remove_channels (GstCaps * caps)
642 size = gst_caps_get_size (caps);
643 for (i = 0; i < size; i++) {
644 s = gst_caps_get_structure (caps, i);
645 gst_structure_remove_field (s, "channel-mask");
646 gst_structure_remove_field (s, "channels");
651 __set_channels (GstCaps * caps, gint channels)
656 size = gst_caps_get_size (caps);
657 for (i = 0; i < size; i++) {
658 s = gst_caps_get_structure (caps, i);
660 gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
662 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
666 /* we can only accept caps that we and downstream can handle. */
668 gst_interleave_sink_getcaps (GstPad * pad, GstObject * parent, GstCaps * filter)
670 GstInterleave *self = GST_INTERLEAVE (parent);
671 GstCaps *result, *peercaps, *sinkcaps;
673 GST_OBJECT_LOCK (self);
675 /* If we already have caps on one of the sink pads return them */
676 if (self->sinkcaps) {
677 result = gst_caps_copy (self->sinkcaps);
679 /* get the downstream possible caps */
680 peercaps = gst_pad_peer_query_caps (self->src, NULL);
682 /* get the allowed caps on this sinkpad */
683 sinkcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
684 __remove_channels (sinkcaps);
686 __remove_channels (peercaps);
687 /* if the peer has caps, intersect */
688 GST_DEBUG_OBJECT (pad, "intersecting peer and template caps");
689 result = gst_caps_intersect (peercaps, sinkcaps);
690 gst_caps_unref (peercaps);
691 gst_caps_unref (sinkcaps);
693 /* the peer has no caps (or there is no peer), just use the allowed caps
694 * of this sinkpad. */
695 GST_DEBUG_OBJECT (pad, "no peer caps, using sinkcaps");
698 __set_channels (result, 1);
701 GST_OBJECT_UNLOCK (self);
703 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, result);
709 gst_interleave_set_process_function (GstInterleave * self)
711 switch (self->width) {
713 self->func = (GstInterleaveFunc) interleave_8;
716 self->func = (GstInterleaveFunc) interleave_16;
719 self->func = (GstInterleaveFunc) interleave_24;
722 self->func = (GstInterleaveFunc) interleave_32;
725 self->func = (GstInterleaveFunc) interleave_64;
728 g_assert_not_reached ();
734 gst_interleave_sink_setcaps (GstInterleave * self, GstPad * pad,
735 const GstCaps * caps)
737 g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE);
739 /* First caps that are set on a sink pad are used as output caps */
740 /* TODO: handle caps changes */
741 if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) {
742 goto cannot_change_caps;
751 if (!gst_audio_info_from_caps (&info, caps))
754 self->width = GST_AUDIO_INFO_WIDTH (&info);
755 self->rate = GST_AUDIO_INFO_RATE (&info);
758 gst_interleave_set_process_function (self);
759 channel = GST_INTERLEAVE_PAD_CAST (pad)->channel;
761 if (self->channel_positions_from_input
762 && GST_AUDIO_INFO_CHANNELS (&info) == 1) {
763 val = g_value_array_get_nth (self->input_channel_positions, channel);
764 g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0));
767 srccaps = gst_caps_copy (caps);
768 s = gst_caps_get_structure (srccaps, 0);
770 gst_structure_remove_field (s, "channel-mask");
772 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
773 gst_interleave_set_channel_positions (self, s);
775 gst_pad_set_active (self->src, TRUE);
776 res = gst_pad_set_caps (self->src, srccaps);
777 gst_caps_unref (srccaps);
780 goto src_did_not_accept;
783 if (!self->sinkcaps) {
784 GstCaps *sinkcaps = gst_caps_copy (caps);
785 GstStructure *s = gst_caps_get_structure (sinkcaps, 0);
787 gst_structure_remove_field (s, "channel-mask");
789 gst_caps_replace (&self->sinkcaps, sinkcaps);
791 gst_caps_unref (sinkcaps);
798 GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
799 "change", self->sinkcaps);
804 GST_WARNING_OBJECT (self, "src did not accept setcaps()");
809 GST_WARNING_OBJECT (self, "invalid sink caps");
815 gst_interleave_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
816 GstEvent * event, gpointer user_data)
818 GstInterleave *self = GST_INTERLEAVE (user_data);
819 gboolean ret = FALSE;
821 GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
822 GST_DEBUG_PAD_NAME (data->pad));
824 switch (GST_EVENT_TYPE (event)) {
825 case GST_EVENT_FLUSH_STOP:
826 /* mark a pending new segment. This event is synchronized
827 * with the streaming thread so we can safely update the
828 * variable without races. It's somewhat weird because we
829 * assume the collectpads forwarded the FLUSH_STOP past us
830 * and downstream (using our source pad, the bastard!).
832 self->segment_pending = TRUE;
838 gst_event_parse_caps (event, &caps);
839 ret = gst_interleave_sink_setcaps (self, data->pad, caps);
840 gst_event_unref (event);
844 ret = gst_pad_event_default (data->pad, GST_OBJECT (self), event);
848 /* now GstCollectPads2 can take care of the rest, e.g. EOS */
853 gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
862 gst_query_parse_duration (query, &format, NULL);
868 /* Take maximum of all durations */
869 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
871 GstIteratorResult ires;
873 GValue item = { 0, };
875 ires = gst_iterator_next (it, &item);
877 case GST_ITERATOR_DONE:
880 case GST_ITERATOR_OK:
882 GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item));
886 /* ask sink peer for duration */
887 res &= gst_pad_peer_query_duration (pad, format, &duration);
888 /* take max from all valid return values */
890 /* valid unknown length, stop searching */
891 if (duration == -1) {
895 /* else see if bigger than current max */
896 else if (duration > max)
899 gst_object_unref (pad);
900 g_value_unset (&item);
903 case GST_ITERATOR_RESYNC:
906 gst_iterator_resync (it);
914 gst_iterator_free (it);
917 /* If in bytes format we have to multiply with the number of channels
918 * to get the correct results. All other formats should be fine */
919 if (format == GST_FORMAT_BYTES && max != -1)
920 max *= self->channels;
922 /* and store the max */
923 GST_DEBUG_OBJECT (self, "Total duration in format %s: %"
924 GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
925 gst_query_set_duration (query, format, max);
932 gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query)
934 GstClockTime min, max;
945 max = GST_CLOCK_TIME_NONE;
947 /* Take maximum of all latency values */
948 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
950 GstIteratorResult ires;
951 GValue item = { 0, };
953 ires = gst_iterator_next (it, &item);
955 case GST_ITERATOR_DONE:
958 case GST_ITERATOR_OK:
960 GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item));
962 GstClockTime min_cur, max_cur;
965 peerquery = gst_query_new_latency ();
967 /* Ask peer for latency */
968 res &= gst_pad_peer_query (pad, peerquery);
970 /* take max from all valid return values */
972 gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur);
977 if (max_cur != GST_CLOCK_TIME_NONE &&
978 ((max != GST_CLOCK_TIME_NONE && max_cur > max) ||
979 (max == GST_CLOCK_TIME_NONE)))
982 live = live || live_cur;
985 gst_query_unref (peerquery);
986 gst_object_unref (pad);
987 g_value_unset (&item);
990 case GST_ITERATOR_RESYNC:
993 max = GST_CLOCK_TIME_NONE;
995 gst_iterator_resync (it);
1003 gst_iterator_free (it);
1006 /* store the results */
1007 GST_DEBUG_OBJECT (self, "Calculated total latency: live %s, min %"
1008 GST_TIME_FORMAT ", max %" GST_TIME_FORMAT,
1009 (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1010 gst_query_set_latency (query, live, min, max);
1017 gst_interleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1019 GstInterleave *self = GST_INTERLEAVE (parent);
1020 gboolean res = FALSE;
1022 switch (GST_QUERY_TYPE (query)) {
1023 case GST_QUERY_POSITION:
1027 gst_query_parse_position (query, &format, NULL);
1030 case GST_FORMAT_TIME:
1031 /* FIXME, bring to stream time, might be tricky */
1032 gst_query_set_position (query, format, self->timestamp);
1035 case GST_FORMAT_BYTES:
1036 gst_query_set_position (query, format,
1037 self->offset * self->channels * self->width);
1040 case GST_FORMAT_DEFAULT:
1041 gst_query_set_position (query, format, self->offset);
1049 case GST_QUERY_DURATION:
1050 res = gst_interleave_src_query_duration (self, query);
1052 case GST_QUERY_LATENCY:
1053 res = gst_interleave_src_query_latency (self, query);
1055 case GST_QUERY_CAPS:
1057 GstCaps *filter, *caps;
1059 gst_query_parse_caps (query, &filter);
1060 caps = gst_interleave_sink_getcaps (pad, parent, filter);
1061 gst_query_set_caps_result (query, caps);
1062 gst_caps_unref (caps);
1066 /* FIXME, needs a custom query handler because we have multiple
1068 res = gst_pad_query_default (pad, parent, query);
1076 forward_event_func (const GValue * item, GValue * ret, GstEvent * event)
1078 GstPad *pad = GST_PAD_CAST (g_value_dup_object (item));
1079 gst_event_ref (event);
1080 GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
1081 if (!gst_pad_push_event (pad, event)) {
1082 g_value_set_boolean (ret, FALSE);
1083 GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.",
1084 event, GST_EVENT_TYPE_NAME (event));
1086 GST_LOG_OBJECT (pad, "Sent event %p (%s).",
1087 event, GST_EVENT_TYPE_NAME (event));
1089 gst_object_unref (pad);
1094 forward_event (GstInterleave * self, GstEvent * event)
1097 GValue vret = { 0 };
1099 GST_LOG_OBJECT (self, "Forwarding event %p (%s)", event,
1100 GST_EVENT_TYPE_NAME (event));
1102 g_value_init (&vret, G_TYPE_BOOLEAN);
1103 g_value_set_boolean (&vret, TRUE);
1104 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
1105 gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
1107 gst_iterator_free (it);
1108 gst_event_unref (event);
1110 return g_value_get_boolean (&vret);
1115 gst_interleave_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1117 GstInterleave *self = GST_INTERLEAVE (parent);
1120 switch (GST_EVENT_TYPE (event)) {
1122 /* QoS might be tricky */
1125 case GST_EVENT_SEEK:
1128 GstSeekType curtype;
1131 /* parse the seek parameters */
1132 gst_event_parse_seek (event, &self->segment_rate, NULL, &flags, &curtype,
1135 /* check if we are flushing */
1136 if (flags & GST_SEEK_FLAG_FLUSH) {
1137 /* make sure we accept nothing anymore and return WRONG_STATE */
1138 gst_collect_pads2_set_flushing (self->collect, TRUE);
1140 /* flushing seek, start flush downstream, the flush will be done
1141 * when all pads received a FLUSH_STOP. */
1142 gst_pad_push_event (self->src, gst_event_new_flush_start ());
1145 /* now wait for the collected to be finished and mark a new
1147 GST_OBJECT_LOCK (self->collect);
1148 if (curtype == GST_SEEK_TYPE_SET)
1149 self->segment_position = cur;
1151 self->segment_position = 0;
1152 self->segment_pending = TRUE;
1153 GST_OBJECT_UNLOCK (self->collect);
1155 result = forward_event (self, event);
1158 case GST_EVENT_NAVIGATION:
1159 /* navigation is rather pointless. */
1163 /* just forward the rest for now */
1164 result = forward_event (self, event);
1171 static GstFlowReturn
1172 gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self)
1176 GstFlowReturn ret = GST_FLOW_OK;
1179 guint ncollected = 0;
1180 gboolean empty = TRUE;
1181 gint width = self->width / 8;
1182 GstMapInfo write_info;
1184 g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
1185 g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED);
1186 g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED);
1187 g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED);
1189 size = gst_collect_pads2_available (pads);
1191 g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR);
1193 GST_DEBUG_OBJECT (self, "Starting to collect %u bytes from %d channels", size,
1196 nsamples = size / width;
1198 outbuf = gst_buffer_new_allocate (NULL, size * self->channels, NULL);
1200 if (outbuf == NULL || gst_buffer_get_size (outbuf) < size * self->channels) {
1201 gst_buffer_unref (outbuf);
1202 return GST_FLOW_NOT_NEGOTIATED;
1205 gst_buffer_map (outbuf, &write_info, GST_MAP_WRITE);
1206 memset (write_info.data, 0, size * self->channels);
1208 for (collected = pads->data; collected != NULL; collected = collected->next) {
1209 GstCollectData2 *cdata;
1212 GstMapInfo input_info;
1214 cdata = (GstCollectData2 *) collected->data;
1216 inbuf = gst_collect_pads2_take_buffer (pads, cdata, size);
1217 if (inbuf == NULL) {
1218 GST_DEBUG_OBJECT (cdata->pad, "No buffer available");
1222 gst_buffer_map (inbuf, &input_info, GST_MAP_READ);
1224 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))
1229 write_info.data + width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
1231 self->func (outdata, input_info.data, self->channels, nsamples);
1232 gst_buffer_unmap (inbuf, &input_info);
1236 gst_buffer_unref (inbuf);
1239 if (ncollected == 0) {
1240 gst_buffer_unmap (outbuf, &write_info);
1244 if (self->segment_pending) {
1247 self->segment.format = GST_FORMAT_TIME;
1248 event = gst_event_new_segment (&self->segment);
1250 gst_pad_push_event (self->src, event);
1251 self->segment_pending = FALSE;
1252 self->segment_position = 0;
1255 GST_BUFFER_TIMESTAMP (outbuf) = self->timestamp;
1256 GST_BUFFER_OFFSET (outbuf) = self->offset;
1258 self->offset += nsamples;
1259 self->timestamp = gst_util_uint64_scale_int (self->offset,
1260 GST_SECOND, self->rate);
1262 GST_BUFFER_DURATION (outbuf) = self->timestamp -
1263 GST_BUFFER_TIMESTAMP (outbuf);
1266 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
1268 gst_buffer_unmap (outbuf, &write_info);
1270 GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
1271 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
1272 ret = gst_pad_push (self->src, outbuf);
1278 GST_DEBUG_OBJECT (self, "no data available, must be EOS");
1279 gst_buffer_unref (outbuf);
1280 gst_pad_push_event (self->src, gst_event_new_eos ());
1281 return GST_FLOW_EOS;