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.org>
8 * Olivier Crete <olivier.crete@collabora.com>
10 * gstaudiointerleave.c: audiointerleave element, N in, one out,
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
29 * SECTION:element-audiointerleave
30 * @title: audiointerleave
34 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
35 * with newer GLib versions (>= 2.31.0) */
36 #define GLIB_DISABLE_DEPRECATION_WARNINGS
42 #include "gstaudiointerleave.h"
43 #include <gst/audio/audio.h>
47 #define GST_CAT_DEFAULT gst_audio_interleave_debug
48 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
56 G_DEFINE_TYPE (GstAudioInterleavePad, gst_audio_interleave_pad,
57 GST_TYPE_AUDIO_AGGREGATOR_PAD);
60 gst_audio_interleave_pad_get_property (GObject * object, guint prop_id,
61 GValue * value, GParamSpec * pspec)
63 GstAudioInterleavePad *pad = GST_AUDIO_INTERLEAVE_PAD (object);
66 case PROP_PAD_CHANNEL:
67 g_value_set_uint (value, pad->channel);
70 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
77 gst_audio_interleave_pad_class_init (GstAudioInterleavePadClass * klass)
79 GObjectClass *gobject_class = (GObjectClass *) klass;
81 gobject_class->get_property = gst_audio_interleave_pad_get_property;
83 g_object_class_install_property (gobject_class,
85 g_param_spec_uint ("channel",
87 "Number of the channel of this pad in the output", 0, G_MAXUINT, 0,
88 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
92 gst_audio_interleave_pad_init (GstAudioInterleavePad * pad)
99 PROP_CHANNEL_POSITIONS,
100 PROP_CHANNEL_POSITIONS_FROM_INPUT
103 /* elementfactory information */
105 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
107 GST_AUDIO_CAPS_MAKE ("{ S32LE, U32LE, S16LE, U16LE, S8, U8, F32LE, F64LE }") \
108 ", layout = (string) { interleaved, non-interleaved }"
111 GST_AUDIO_CAPS_MAKE ("{ S32BE, U32BE, S16BE, U16BE, S8, U8, F32BE, F64BE }") \
112 ", layout = (string) { interleaved, non-interleaved }"
115 static GstStaticPadTemplate gst_audio_interleave_sink_template =
116 GST_STATIC_PAD_TEMPLATE ("sink_%u",
119 GST_STATIC_CAPS ("audio/x-raw, "
120 "rate = (int) [ 1, MAX ], "
121 "channels = (int) 1, "
122 "format = (string) " GST_AUDIO_FORMATS_ALL ", "
123 "layout = (string) {non-interleaved, interleaved}")
126 static GstStaticPadTemplate gst_audio_interleave_src_template =
127 GST_STATIC_PAD_TEMPLATE ("src",
130 GST_STATIC_CAPS ("audio/x-raw, "
131 "rate = (int) [ 1, MAX ], "
132 "channels = (int) [ 1, MAX ], "
133 "format = (string) " GST_AUDIO_FORMATS_ALL ", "
134 "layout = (string) interleaved")
137 static void gst_audio_interleave_child_proxy_init (gpointer g_iface,
138 gpointer iface_data);
140 #define gst_audio_interleave_parent_class parent_class
141 G_DEFINE_TYPE_WITH_CODE (GstAudioInterleave, gst_audio_interleave,
142 GST_TYPE_AUDIO_AGGREGATOR, G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
143 gst_audio_interleave_child_proxy_init));
145 static void gst_audio_interleave_finalize (GObject * object);
146 static void gst_audio_interleave_set_property (GObject * object, guint prop_id,
147 const GValue * value, GParamSpec * pspec);
148 static void gst_audio_interleave_get_property (GObject * object, guint prop_id,
149 GValue * value, GParamSpec * pspec);
151 static gboolean gst_audio_interleave_setcaps (GstAudioInterleave * self,
152 GstPad * pad, GstCaps * caps);
153 static GstPad *gst_audio_interleave_request_new_pad (GstElement * element,
154 GstPadTemplate * temp, const gchar * req_name, const GstCaps * caps);
155 static void gst_audio_interleave_release_pad (GstElement * element,
158 static gboolean gst_audio_interleave_stop (GstAggregator * agg);
161 gst_audio_interleave_aggregate_one_buffer (GstAudioAggregator * aagg,
162 GstAudioAggregatorPad * aaggpad, GstBuffer * inbuf, guint in_offset,
163 GstBuffer * outbuf, guint out_offset, guint num_samples);
167 __remove_channels (GstCaps * caps)
172 size = gst_caps_get_size (caps);
173 for (i = 0; i < size; i++) {
174 s = gst_caps_get_structure (caps, i);
175 gst_structure_remove_field (s, "channel-mask");
176 gst_structure_remove_field (s, "channels");
181 __set_channels (GstCaps * caps, gint channels)
186 size = gst_caps_get_size (caps);
187 for (i = 0; i < size; i++) {
188 s = gst_caps_get_structure (caps, i);
190 gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
192 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
196 /* we can only accept caps that we and downstream can handle.
197 * if we have filtercaps set, use those to constrain the target caps.
200 gst_audio_interleave_sink_getcaps (GstAggregator * agg, GstPad * pad,
203 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
204 GstCaps *result = NULL, *peercaps, *sinkcaps;
206 GST_OBJECT_LOCK (self);
207 /* If we already have caps on one of the sink pads return them */
209 result = gst_caps_copy (self->sinkcaps);
210 GST_OBJECT_UNLOCK (self);
212 if (result == NULL) {
213 /* get the downstream possible caps */
214 peercaps = gst_pad_peer_query_caps (agg->srcpad, NULL);
216 /* get the allowed caps on this sinkpad */
217 sinkcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
218 __remove_channels (sinkcaps);
220 peercaps = gst_caps_make_writable (peercaps);
221 __remove_channels (peercaps);
222 /* if the peer has caps, intersect */
223 GST_DEBUG_OBJECT (pad, "intersecting peer and template caps");
224 result = gst_caps_intersect (peercaps, sinkcaps);
225 gst_caps_unref (peercaps);
226 gst_caps_unref (sinkcaps);
228 /* the peer has no caps (or there is no peer), just use the allowed caps
229 * of this sinkpad. */
230 GST_DEBUG_OBJECT (pad, "no peer caps, using sinkcaps");
233 __set_channels (result, 1);
236 if (filter != NULL) {
237 GstCaps *caps = result;
239 GST_LOG_OBJECT (pad, "intersecting filter caps %" GST_PTR_FORMAT " with "
240 "preliminary result %" GST_PTR_FORMAT, filter, caps);
242 result = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
243 gst_caps_unref (caps);
246 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, result);
252 gst_audio_interleave_sink_query (GstAggregator * agg, GstAggregatorPad * aggpad,
255 gboolean res = FALSE;
257 switch (GST_QUERY_TYPE (query)) {
260 GstCaps *filter, *caps;
262 gst_query_parse_caps (query, &filter);
263 caps = gst_audio_interleave_sink_getcaps (agg, GST_PAD (aggpad), filter);
264 gst_query_set_caps_result (query, caps);
265 gst_caps_unref (caps);
271 GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, aggpad, query);
279 compare_positions (gconstpointer a, gconstpointer b, gpointer user_data)
281 const gint i = *(const gint *) a;
282 const gint j = *(const gint *) b;
283 const gint *pos = (const gint *) user_data;
287 else if (pos[i] > pos[j])
294 gst_audio_interleave_channel_positions_to_mask (GValueArray * positions,
295 gint default_ordering_map[64], guint64 * mask)
299 GstAudioChannelPosition *pos;
302 channels = positions->n_values;
303 pos = g_new (GstAudioChannelPosition, channels);
305 for (i = 0; i < channels; i++) {
308 val = g_value_array_get_nth (positions, i);
309 pos[i] = g_value_get_enum (val);
312 /* sort the default ordering map according to the position order */
313 for (i = 0; i < channels; i++) {
314 default_ordering_map[i] = i;
316 g_qsort_with_data (default_ordering_map, channels,
317 sizeof (*default_ordering_map), compare_positions, pos);
319 ret = gst_audio_channel_positions_to_mask (pos, channels, FALSE, mask);
326 /* Must be called with the object lock held */
329 gst_audio_interleave_get_channel_mask (GstAudioInterleave * self)
331 guint64 channel_mask = 0;
333 if (self->channels <= 64 &&
334 self->channel_positions != NULL &&
335 self->channels == self->channel_positions->n_values) {
336 if (!gst_audio_interleave_channel_positions_to_mask
337 (self->channel_positions, self->default_channels_ordering_map,
339 GST_WARNING_OBJECT (self, "Invalid channel positions, using NONE");
342 } else if (self->channels <= 64) {
343 GST_WARNING_OBJECT (self, "Using NONE channel positions");
350 #define MAKE_FUNC(type) \
351 static void interleave_##type (guint##type *out, guint##type *in, \
352 guint stride, guint nframes) \
356 for (i = 0; i < nframes; i++) { \
368 interleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
372 for (i = 0; i < nframes; i++) {
380 gst_audio_interleave_set_process_function (GstAudioInterleave * self,
383 switch (GST_AUDIO_INFO_WIDTH (info)) {
385 self->func = (GstInterleaveFunc) interleave_8;
388 self->func = (GstInterleaveFunc) interleave_16;
391 self->func = (GstInterleaveFunc) interleave_24;
394 self->func = (GstInterleaveFunc) interleave_32;
397 self->func = (GstInterleaveFunc) interleave_64;
400 g_assert_not_reached ();
406 /* the first caps we receive on any of the sinkpads will define the caps for all
407 * the other sinkpads because we can only mix streams with the same caps.
410 gst_audio_interleave_setcaps (GstAudioInterleave * self, GstPad * pad,
413 GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (self);
417 gboolean new = FALSE;
419 if (!gst_audio_info_from_caps (&info, caps))
422 GST_OBJECT_LOCK (self);
423 if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps))
424 goto cannot_change_caps;
426 if (!self->sinkcaps) {
427 GstCaps *sinkcaps = gst_caps_copy (caps);
428 GstStructure *s = gst_caps_get_structure (sinkcaps, 0);
430 gst_structure_remove_field (s, "channel-mask");
432 GST_DEBUG_OBJECT (self, "setting sinkcaps %" GST_PTR_FORMAT, sinkcaps);
434 gst_caps_replace (&self->sinkcaps, sinkcaps);
435 gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (aagg));
437 gst_caps_unref (sinkcaps);
441 if (self->channel_positions_from_input
442 && GST_AUDIO_INFO_CHANNELS (&info) == 1) {
443 channel = GST_AUDIO_INTERLEAVE_PAD (pad)->channel;
444 val = g_value_array_get_nth (self->input_channel_positions, channel);
445 g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0));
447 GST_OBJECT_UNLOCK (self);
449 gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad),
455 GST_INFO_OBJECT (pad, "handle caps change to %" GST_PTR_FORMAT, caps);
462 GST_WARNING_OBJECT (self, "invalid format set as caps: %" GST_PTR_FORMAT,
468 GST_OBJECT_UNLOCK (self);
469 GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
470 "change", self->sinkcaps);
476 gst_audio_interleave_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
479 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
482 GST_DEBUG_OBJECT (aggpad, "Got %s event on sink pad",
483 GST_EVENT_TYPE_NAME (event));
485 switch (GST_EVENT_TYPE (event)) {
490 gst_event_parse_caps (event, &caps);
491 res = gst_audio_interleave_setcaps (self, GST_PAD_CAST (aggpad), caps);
492 gst_event_unref (event);
501 return GST_AGGREGATOR_CLASS (parent_class)->sink_event (agg, aggpad, event);
507 gst_audio_interleave_update_src_caps (GstAggregator * agg, GstCaps * caps,
510 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
513 /* This means that either no caps have been set on the sink pad (if
514 * sinkcaps is NULL) or that there is no sink pad (if channels == 0).
516 GST_OBJECT_LOCK (self);
517 if (self->sinkcaps == NULL || self->channels == 0) {
518 GST_OBJECT_UNLOCK (self);
519 return GST_FLOW_NOT_NEGOTIATED;
522 *ret = gst_caps_copy (self->sinkcaps);
523 s = gst_caps_get_structure (*ret, 0);
525 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
526 G_TYPE_STRING, "interleaved", "channel-mask", GST_TYPE_BITMASK,
527 gst_audio_interleave_get_channel_mask (self), NULL);
529 GST_OBJECT_UNLOCK (self);
535 gst_audio_interleave_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
537 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
538 GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (self);
540 if (!GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps))
543 gst_audio_interleave_set_process_function (self, &aagg->info);
549 gst_audio_interleave_class_init (GstAudioInterleaveClass * klass)
551 GObjectClass *gobject_class = (GObjectClass *) klass;
552 GstElementClass *gstelement_class = (GstElementClass *) klass;
553 GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
554 GstAudioAggregatorClass *aagg_class = (GstAudioAggregatorClass *) klass;
556 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "audiointerleave", 0,
557 "audio interleaving element");
559 gobject_class->set_property = gst_audio_interleave_set_property;
560 gobject_class->get_property = gst_audio_interleave_get_property;
561 gobject_class->finalize = gst_audio_interleave_finalize;
563 gst_element_class_add_static_pad_template (gstelement_class,
564 &gst_audio_interleave_src_template);
565 gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
566 &gst_audio_interleave_sink_template, GST_TYPE_AUDIO_INTERLEAVE_PAD);
567 gst_element_class_set_static_metadata (gstelement_class, "AudioInterleave",
568 "Generic/Audio", "Mixes multiple audio streams",
569 "Olivier Crete <olivier.crete@collabora.com>");
571 gstelement_class->request_new_pad =
572 GST_DEBUG_FUNCPTR (gst_audio_interleave_request_new_pad);
573 gstelement_class->release_pad =
574 GST_DEBUG_FUNCPTR (gst_audio_interleave_release_pad);
576 agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_query);
577 agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_event);
578 agg_class->stop = gst_audio_interleave_stop;
579 agg_class->update_src_caps = gst_audio_interleave_update_src_caps;
580 agg_class->negotiated_src_caps = gst_audio_interleave_negotiated_src_caps;
582 aagg_class->aggregate_one_buffer = gst_audio_interleave_aggregate_one_buffer;
586 * GstInterleave:channel-positions
588 * Channel positions: This property controls the channel positions
589 * that are used on the src caps. The number of elements should be
590 * the same as the number of sink pads and the array should contain
591 * a valid list of channel positions. The n-th element of the array
592 * is the position of the n-th sink pad.
594 * These channel positions will only be used if they're valid and the
595 * number of elements is the same as the number of channels. If this
596 * is not given a NONE layout will be used.
599 g_object_class_install_property (gobject_class, PROP_CHANNEL_POSITIONS,
600 g_param_spec_value_array ("channel-positions", "Channel positions",
601 "Channel positions used on the output",
602 g_param_spec_enum ("channel-position", "Channel position",
603 "Channel position of the n-th input",
604 GST_TYPE_AUDIO_CHANNEL_POSITION,
605 GST_AUDIO_CHANNEL_POSITION_NONE,
606 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
607 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
610 * GstInterleave:channel-positions-from-input
612 * Channel positions from input: If this property is set to %TRUE the channel
613 * positions will be taken from the input caps if valid channel positions for
614 * the output can be constructed from them. If this is set to %TRUE setting the
615 * channel-positions property overwrites this property again.
618 g_object_class_install_property (gobject_class,
619 PROP_CHANNEL_POSITIONS_FROM_INPUT,
620 g_param_spec_boolean ("channel-positions-from-input",
621 "Channel positions from input",
622 "Take channel positions from the input", TRUE,
623 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
627 gst_audio_interleave_init (GstAudioInterleave * self)
629 self->input_channel_positions = g_value_array_new (0);
630 self->channel_positions_from_input = TRUE;
631 self->channel_positions = self->input_channel_positions;
635 gst_audio_interleave_finalize (GObject * object)
637 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (object);
639 if (self->channel_positions
640 && self->channel_positions != self->input_channel_positions) {
641 g_value_array_free (self->channel_positions);
642 self->channel_positions = NULL;
645 if (self->input_channel_positions) {
646 g_value_array_free (self->input_channel_positions);
647 self->input_channel_positions = NULL;
650 G_OBJECT_CLASS (parent_class)->finalize (object);
654 gst_audio_interleave_set_property (GObject * object, guint prop_id,
655 const GValue * value, GParamSpec * pspec)
657 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (object);
660 case PROP_CHANNEL_POSITIONS:
662 ((GValueArray *) g_value_get_boxed (value))->n_values > 0);
664 if (self->channel_positions &&
665 self->channel_positions != self->input_channel_positions)
666 g_value_array_free (self->channel_positions);
668 self->channel_positions = g_value_dup_boxed (value);
669 self->channel_positions_from_input = FALSE;
671 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
672 self->channel_positions_from_input = g_value_get_boolean (value);
674 if (self->channel_positions_from_input) {
675 if (self->channel_positions &&
676 self->channel_positions != self->input_channel_positions)
677 g_value_array_free (self->channel_positions);
678 self->channel_positions = self->input_channel_positions;
682 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
688 gst_audio_interleave_get_property (GObject * object, guint prop_id,
689 GValue * value, GParamSpec * pspec)
691 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (object);
694 case PROP_CHANNEL_POSITIONS:
695 g_value_set_boxed (value, self->channel_positions);
697 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
698 g_value_set_boolean (value, self->channel_positions_from_input);
701 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
707 gst_audio_interleave_stop (GstAggregator * agg)
709 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
711 if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg))
714 gst_caps_replace (&self->sinkcaps, NULL);
720 gst_audio_interleave_request_new_pad (GstElement * element,
721 GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
723 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (element);
724 GstAudioInterleavePad *newpad;
726 gint channel, padnumber;
729 /* FIXME: We ignore req_name, this is evil! */
731 GST_OBJECT_LOCK (self);
732 padnumber = g_atomic_int_add (&self->padcounter, 1);
733 channel = self->channels++;
734 if (!self->channel_positions_from_input)
736 GST_OBJECT_UNLOCK (self);
738 pad_name = g_strdup_printf ("sink_%u", padnumber);
739 newpad = (GstAudioInterleavePad *)
740 GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
741 templ, pad_name, caps);
744 goto could_not_create;
746 newpad->channel = channel;
747 gst_pad_use_fixed_caps (GST_PAD (newpad));
749 gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
750 GST_OBJECT_NAME (newpad));
753 g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
754 g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE);
755 self->input_channel_positions =
756 g_value_array_append (self->input_channel_positions, &val);
757 g_value_unset (&val);
759 /* Update the src caps if we already have them */
760 gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
762 return GST_PAD_CAST (newpad);
766 GST_DEBUG_OBJECT (element, "could not create/add pad");
772 gst_audio_interleave_release_pad (GstElement * element, GstPad * pad)
774 GstAudioInterleave *self;
778 self = GST_AUDIO_INTERLEAVE (element);
780 /* Take lock to make sure we're not changing this when processing buffers */
781 GST_OBJECT_LOCK (self);
785 position = GST_AUDIO_INTERLEAVE_PAD (pad)->channel;
786 g_value_array_remove (self->input_channel_positions, position);
788 /* Update channel numbers */
789 /* Taken above, GST_OBJECT_LOCK (self); */
790 for (l = GST_ELEMENT_CAST (self)->sinkpads; l != NULL; l = l->next) {
791 GstAudioInterleavePad *ipad = GST_AUDIO_INTERLEAVE_PAD (l->data);
793 if (GST_AUDIO_INTERLEAVE_PAD (pad)->channel < ipad->channel)
797 gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
798 GST_OBJECT_UNLOCK (self);
801 GST_DEBUG_OBJECT (self, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
803 gst_child_proxy_child_removed (GST_CHILD_PROXY (self), G_OBJECT (pad),
804 GST_OBJECT_NAME (pad));
806 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
810 /* Called with object lock and pad object lock held */
812 gst_audio_interleave_aggregate_one_buffer (GstAudioAggregator * aagg,
813 GstAudioAggregatorPad * aaggpad, GstBuffer * inbuf, guint in_offset,
814 GstBuffer * outbuf, guint out_offset, guint num_frames)
816 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (aagg);
817 GstAudioInterleavePad *pad = GST_AUDIO_INTERLEAVE_PAD (aaggpad);
820 gint out_width, in_bpf, out_bpf, out_channels, channel;
823 GST_OBJECT_LOCK (aagg);
824 GST_OBJECT_LOCK (aaggpad);
826 out_width = GST_AUDIO_INFO_WIDTH (&aagg->info) / 8;
827 in_bpf = GST_AUDIO_INFO_BPF (&aaggpad->info);
828 out_bpf = GST_AUDIO_INFO_BPF (&aagg->info);
829 out_channels = GST_AUDIO_INFO_CHANNELS (&aagg->info);
831 gst_buffer_map (outbuf, &outmap, GST_MAP_READWRITE);
832 gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
833 GST_LOG_OBJECT (pad, "interleaves %u frames on channel %d/%d at offset %u"
834 " from offset %u", num_frames, pad->channel, out_channels,
835 out_offset * out_bpf, in_offset * in_bpf);
837 if (self->channels > 64) {
838 channel = pad->channel;
840 channel = self->default_channels_ordering_map[pad->channel];
843 outdata = outmap.data + (out_offset * out_bpf) + (out_width * channel);
846 self->func (outdata, inmap.data + (in_offset * in_bpf), out_channels,
850 gst_buffer_unmap (inbuf, &inmap);
851 gst_buffer_unmap (outbuf, &outmap);
853 GST_OBJECT_UNLOCK (aaggpad);
854 GST_OBJECT_UNLOCK (aagg);
860 /* GstChildProxy implementation */
862 gst_audio_interleave_child_proxy_get_child_by_index (GstChildProxy *
863 child_proxy, guint index)
865 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (child_proxy);
868 GST_OBJECT_LOCK (self);
869 obj = g_list_nth_data (GST_ELEMENT_CAST (self)->sinkpads, index);
871 gst_object_ref (obj);
872 GST_OBJECT_UNLOCK (self);
878 gst_audio_interleave_child_proxy_get_children_count (GstChildProxy *
882 GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (child_proxy);
884 GST_OBJECT_LOCK (self);
885 count = GST_ELEMENT_CAST (self)->numsinkpads;
886 GST_OBJECT_UNLOCK (self);
887 GST_INFO_OBJECT (self, "Children Count: %d", count);
893 gst_audio_interleave_child_proxy_init (gpointer g_iface, gpointer iface_data)
895 GstChildProxyInterface *iface = g_iface;
897 GST_INFO ("intializing child proxy interface");
898 iface->get_child_by_index =
899 gst_audio_interleave_child_proxy_get_child_by_index;
900 iface->get_children_count =
901 gst_audio_interleave_child_proxy_get_children_count;