Merge remote-tracking branch 'origin/0.10'
[platform/upstream/gst-plugins-good.git] / gst / interleave / deinterleave.c
1 /* GStreamer
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>
7  *
8  * deinterleave.c: deinterleave samples
9  *
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.
14  *
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.
19  *
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.
24  */
25
26 /* TODO: 
27  *       - handle changes in number of channels
28  *       - handle changes in channel positions
29  *       - better capsnego by using a buffer alloc function
30  *         and passing downstream caps changes upstream there
31  */
32
33 /**
34  * SECTION:element-deinterleave
35  * @see_also: interleave
36  *
37  * Splits one interleaved multichannel audio stream into many mono audio streams.
38  * 
39  * This element handles all raw audio formats and supports changing the input caps as long as
40  * all downstream elements can handle the new caps and the number of channels and the channel
41  * positions stay the same. This restriction will be removed in later versions by adding or
42  * removing some source pads as required.
43  * 
44  * In most cases a queue and an audioconvert element should be added after each source pad
45  * before further processing of the audio data.
46  * 
47  * <refsect2>
48  * <title>Example launch line</title>
49  * |[
50  * gst-launch filesrc location=/path/to/file.mp3 ! decodebin ! audioconvert ! "audio/x-raw,channels=2 ! deinterleave name=d  d.src_0 ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=channel1.ogg  d.src_1 ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=channel2.ogg
51  * ]| Decodes an MP3 file and encodes the left and right channel into separate
52  * Ogg Vorbis files.
53  * |[
54  * 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
55  * ]| Decodes and deinterleaves a Stereo MP3 file into separate channels and
56  * then interleaves the channels again to a WAV file with the channel with the
57  * channels exchanged.
58  * </refsect2>
59  */
60
61 #ifdef HAVE_CONFIG_H
62 #  include "config.h"
63 #endif
64
65 #include <gst/gst.h>
66 #include <string.h>
67 #include "deinterleave.h"
68
69 GST_DEBUG_CATEGORY_STATIC (gst_deinterleave_debug);
70 #define GST_CAT_DEFAULT gst_deinterleave_debug
71
72 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
73     GST_PAD_SRC,
74     GST_PAD_SOMETIMES,
75     GST_STATIC_CAPS ("audio/x-raw, "
76         "format = (string) " GST_AUDIO_FORMATS_ALL ", "
77         "rate = (int) [ 1, MAX ], "
78         "channels = (int) 1, layout = (string) {non-interleaved, interleaved}"));
79
80 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
81     GST_PAD_SINK,
82     GST_PAD_ALWAYS,
83     GST_STATIC_CAPS ("audio/x-raw, "
84         "format = (string) " GST_AUDIO_FORMATS_ALL ", "
85         "rate = (int) [ 1, MAX ], "
86         "channels = (int) [ 1, MAX ], layout = (string) interleaved"));
87
88 #define MAKE_FUNC(type) \
89 static void deinterleave_##type (guint##type *out, guint##type *in, \
90     guint stride, guint nframes) \
91 { \
92   gint i; \
93   \
94   for (i = 0; i < nframes; i++) { \
95     out[i] = *in; \
96     in += stride; \
97   } \
98 }
99
100 MAKE_FUNC (8);
101 MAKE_FUNC (16);
102 MAKE_FUNC (32);
103 MAKE_FUNC (64);
104
105 static void
106 deinterleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
107 {
108   gint i;
109
110   for (i = 0; i < nframes; i++) {
111     memcpy (out, in, 3);
112     out += 3;
113     in += stride * 3;
114   }
115 }
116
117 #define gst_deinterleave_parent_class parent_class
118 G_DEFINE_TYPE (GstDeinterleave, gst_deinterleave, GST_TYPE_ELEMENT);
119
120 enum
121 {
122   PROP_0,
123   PROP_KEEP_POSITIONS
124 };
125
126 static GstFlowReturn gst_deinterleave_chain (GstPad * pad, GstObject * parent,
127     GstBuffer * buffer);
128
129 static gboolean gst_deinterleave_sink_setcaps (GstDeinterleave * self,
130     GstCaps * caps);
131
132 static GstStateChangeReturn
133 gst_deinterleave_change_state (GstElement * element, GstStateChange transition);
134
135 static gboolean gst_deinterleave_sink_event (GstPad * pad, GstObject * parent,
136     GstEvent * event);
137
138 static gboolean gst_deinterleave_src_query (GstPad * pad, GstObject * parent,
139     GstQuery * query);
140
141 static void gst_deinterleave_set_property (GObject * object,
142     guint prop_id, const GValue * value, GParamSpec * pspec);
143 static void gst_deinterleave_get_property (GObject * object,
144     guint prop_id, GValue * value, GParamSpec * pspec);
145
146
147 static void
148 gst_deinterleave_finalize (GObject * obj)
149 {
150   GstDeinterleave *self = GST_DEINTERLEAVE (obj);
151
152   if (self->pending_events) {
153     g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref, NULL);
154     g_list_free (self->pending_events);
155     self->pending_events = NULL;
156   }
157
158   G_OBJECT_CLASS (parent_class)->finalize (obj);
159 }
160
161 static void
162 gst_deinterleave_class_init (GstDeinterleaveClass * klass)
163 {
164   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
165   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
166
167   GST_DEBUG_CATEGORY_INIT (gst_deinterleave_debug, "deinterleave", 0,
168       "deinterleave element");
169
170   gst_element_class_set_details_simple (gstelement_class, "Audio deinterleaver",
171       "Filter/Converter/Audio",
172       "Splits one interleaved multichannel audio stream into many mono audio streams",
173       "Andy Wingo <wingo at pobox.com>, "
174       "Iain <iain@prettypeople.org>, "
175       "Sebastian Dröge <slomo@circular-chaos.org>");
176
177   gst_element_class_add_pad_template (gstelement_class,
178       gst_static_pad_template_get (&sink_template));
179   gst_element_class_add_pad_template (gstelement_class,
180       gst_static_pad_template_get (&src_template));
181
182   gstelement_class->change_state = gst_deinterleave_change_state;
183
184   gobject_class->finalize = gst_deinterleave_finalize;
185   gobject_class->set_property = gst_deinterleave_set_property;
186   gobject_class->get_property = gst_deinterleave_get_property;
187
188   /**
189    * GstDeinterleave:keep-positions
190    * 
191    * Keep positions: When enable the caps on the output buffers will
192    * contain the original channel positions. This can be used to correctly
193    * interleave the output again later but can also lead to unwanted effects
194    * if the output should be handled as Mono.
195    *
196    */
197   g_object_class_install_property (gobject_class, PROP_KEEP_POSITIONS,
198       g_param_spec_boolean ("keep-positions", "Keep positions",
199           "Keep the original channel positions on the output buffers",
200           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201 }
202
203 static void
204 gst_deinterleave_init (GstDeinterleave * self)
205 {
206   self->keep_positions = FALSE;
207   self->func = NULL;
208   gst_audio_info_init (&self->audio_info);
209
210   /* Add sink pad */
211   self->sink = gst_pad_new_from_static_template (&sink_template, "sink");
212   gst_pad_set_chain_function (self->sink,
213       GST_DEBUG_FUNCPTR (gst_deinterleave_chain));
214   gst_pad_set_event_function (self->sink,
215       GST_DEBUG_FUNCPTR (gst_deinterleave_sink_event));
216   gst_element_add_pad (GST_ELEMENT (self), self->sink);
217 }
218
219 static void
220 gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps)
221 {
222   GstPad *pad;
223
224   guint i;
225
226   for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&self->audio_info); i++) {
227     gchar *name = g_strdup_printf ("src_%u", i);
228
229     GstCaps *srccaps;
230     GstAudioInfo info;
231     GstAudioFormat format = GST_AUDIO_INFO_FORMAT (&self->audio_info);
232     gint rate = GST_AUDIO_INFO_RATE (&self->audio_info);
233     GstAudioChannelPosition position = 0;
234
235     /* Set channel position if we know it */
236     if (self->keep_positions)
237       position = GST_AUDIO_INFO_POSITION (&self->audio_info, i);
238
239     gst_audio_info_init (&info);
240     gst_audio_info_set_format (&info, format, rate, 1, &position);
241
242     srccaps = gst_audio_info_to_caps (&info);
243
244     pad = gst_pad_new_from_static_template (&src_template, name);
245     g_free (name);
246
247     gst_pad_use_fixed_caps (pad);
248     gst_pad_set_query_function (pad,
249         GST_DEBUG_FUNCPTR (gst_deinterleave_src_query));
250     gst_pad_set_active (pad, TRUE);
251     gst_pad_set_caps (pad, srccaps);
252     gst_element_add_pad (GST_ELEMENT (self), pad);
253     self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad));
254
255     gst_caps_unref (srccaps);
256   }
257
258   gst_element_no_more_pads (GST_ELEMENT (self));
259   self->srcpads = g_list_reverse (self->srcpads);
260 }
261
262 static void
263 gst_deinterleave_set_pads_caps (GstDeinterleave * self, GstCaps * caps)
264 {
265   GList *l;
266   gint i;
267
268   for (l = self->srcpads, i = 0; l; l = l->next, i++) {
269     GstPad *pad = GST_PAD (l->data);
270
271     GstCaps *srccaps;
272     GstAudioInfo info;
273     gst_audio_info_from_caps (&info, caps);
274     if (self->keep_positions)
275       GST_AUDIO_INFO_POSITION (&info, i) =
276           GST_AUDIO_INFO_POSITION (&self->audio_info, i);
277
278     srccaps = gst_audio_info_to_caps (&info);
279
280     gst_pad_set_caps (pad, srccaps);
281     gst_caps_unref (srccaps);
282   }
283 }
284
285 static void
286 gst_deinterleave_remove_pads (GstDeinterleave * self)
287 {
288   GList *l;
289
290   GST_INFO_OBJECT (self, "removing pads");
291
292   for (l = self->srcpads; l; l = l->next) {
293     GstPad *pad = GST_PAD (l->data);
294
295     gst_element_remove_pad (GST_ELEMENT_CAST (self), pad);
296     gst_object_unref (pad);
297   }
298   g_list_free (self->srcpads);
299   self->srcpads = NULL;
300
301   gst_caps_replace (&self->sinkcaps, NULL);
302 }
303
304 static gboolean
305 gst_deinterleave_set_process_function (GstDeinterleave * self)
306 {
307   switch (GST_AUDIO_INFO_WIDTH (&self->audio_info)) {
308     case 8:
309       self->func = (GstDeinterleaveFunc) deinterleave_8;
310       break;
311     case 16:
312       self->func = (GstDeinterleaveFunc) deinterleave_16;
313       break;
314     case 24:
315       self->func = (GstDeinterleaveFunc) deinterleave_24;
316       break;
317     case 32:
318       self->func = (GstDeinterleaveFunc) deinterleave_32;
319       break;
320     case 64:
321       self->func = (GstDeinterleaveFunc) deinterleave_64;
322       break;
323     default:
324       return FALSE;
325   }
326   return TRUE;
327 }
328
329 static gboolean
330 gst_deinterleave_sink_setcaps (GstDeinterleave * self, GstCaps * caps)
331 {
332   GstCaps *srccaps;
333   GstStructure *s;
334
335   GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps);
336
337   if (!gst_audio_info_from_caps (&self->audio_info, caps))
338     goto invalid_caps;
339
340   if (!gst_deinterleave_set_process_function (self))
341     goto unsupported_caps;
342
343   if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) {
344     gint i;
345     gboolean same_layout = TRUE;
346     gboolean was_unpositioned;
347     gboolean is_unpositioned =
348         GST_AUDIO_INFO_IS_UNPOSITIONED (&self->audio_info);
349     gint new_channels = GST_AUDIO_INFO_CHANNELS (&self->audio_info);
350     gint old_channels;
351     GstAudioInfo old_info;
352
353     gst_audio_info_init (&old_info);
354     gst_audio_info_from_caps (&old_info, self->sinkcaps);
355     was_unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (&old_info);
356     old_channels = GST_AUDIO_INFO_CHANNELS (&old_info);
357
358     /* We allow caps changes as long as the number of channels doesn't change
359      * and the channel positions stay the same. _getcaps() should've cared
360      * for this already but better be safe.
361      */
362     if (new_channels != old_channels ||
363         !gst_deinterleave_set_process_function (self))
364       goto cannot_change_caps;
365
366     /* Now check the channel positions. If we had no channel positions
367      * and get them or the other way around things have changed.
368      * If we had channel positions and get different ones things have
369      * changed too of course
370      */
371     if ((!was_unpositioned && is_unpositioned) || (was_unpositioned
372             && !is_unpositioned))
373       goto cannot_change_caps;
374
375     if (!is_unpositioned) {
376       if (GST_AUDIO_INFO_CHANNELS (&old_info) !=
377           GST_AUDIO_INFO_CHANNELS (&self->audio_info))
378         goto cannot_change_caps;
379       for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&old_info); i++) {
380         if (self->audio_info.position[i] != old_info.position[i]) {
381           same_layout = FALSE;
382           break;
383         }
384       }
385       if (!same_layout)
386         goto cannot_change_caps;
387     }
388
389   }
390
391   gst_caps_replace (&self->sinkcaps, caps);
392
393   /* Get srcpad caps */
394   srccaps = gst_caps_copy (caps);
395   s = gst_caps_get_structure (srccaps, 0);
396   gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
397   gst_structure_remove_field (s, "channel-mask");
398
399   /* If we already have pads, update the caps otherwise
400    * add new pads */
401   if (self->srcpads) {
402     gst_deinterleave_set_pads_caps (self, srccaps);
403   } else {
404     gst_deinterleave_add_new_pads (self, srccaps);
405   }
406
407   gst_caps_unref (srccaps);
408
409   return TRUE;
410
411 cannot_change_caps:
412   {
413     GST_ERROR_OBJECT (self, "can't set new caps: %" GST_PTR_FORMAT, caps);
414     return FALSE;
415   }
416 unsupported_caps:
417   {
418     GST_ERROR_OBJECT (self, "caps not supported: %" GST_PTR_FORMAT, caps);
419     return FALSE;
420   }
421 invalid_caps:
422   {
423     GST_ERROR_OBJECT (self, "invalid caps");
424     return FALSE;
425   }
426 }
427
428 static void
429 __remove_channels (GstCaps * caps)
430 {
431   GstStructure *s;
432
433   gint i, size;
434
435   size = gst_caps_get_size (caps);
436   for (i = 0; i < size; i++) {
437     s = gst_caps_get_structure (caps, i);
438     gst_structure_remove_field (s, "channel-mask");
439     gst_structure_remove_field (s, "channels");
440   }
441 }
442
443 static void
444 __set_channels (GstCaps * caps, gint channels)
445 {
446   GstStructure *s;
447
448   gint i, size;
449
450   size = gst_caps_get_size (caps);
451   for (i = 0; i < size; i++) {
452     s = gst_caps_get_structure (caps, i);
453     if (channels > 0)
454       gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
455     else
456       gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
457   }
458 }
459
460 static GstCaps *
461 gst_deinterleave_sink_getcaps (GstPad * pad, GstObject * parent,
462     GstCaps * filter)
463 {
464   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
465
466   GstCaps *ret;
467
468   GList *l;
469
470   GST_OBJECT_LOCK (self);
471   /* Intersect all of our pad template caps with the peer caps of the pad
472    * to get all formats that are possible up- and downstream.
473    *
474    * For the pad for which the caps are requested we don't remove the channel
475    * informations as they must be in the returned caps and incompatibilities
476    * will be detected here already
477    */
478   ret = gst_caps_new_any ();
479   for (l = GST_ELEMENT (self)->pads; l != NULL; l = l->next) {
480     GstPad *ourpad = GST_PAD (l->data);
481
482     GstCaps *peercaps = NULL, *ourcaps;
483
484     ourcaps = gst_caps_copy (gst_pad_get_pad_template_caps (ourpad));
485
486     if (pad == ourpad) {
487       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK)
488         __set_channels (ourcaps, GST_AUDIO_INFO_CHANNELS (&self->audio_info));
489       else
490         __set_channels (ourcaps, 1);
491     } else {
492       __remove_channels (ourcaps);
493       /* Only ask for peer caps for other pads than pad
494        * as otherwise gst_pad_peer_get_caps() might call
495        * back into this function and deadlock
496        */
497       peercaps = gst_pad_peer_query_caps (ourpad, NULL);
498       peercaps = gst_caps_make_writable (peercaps);
499     }
500
501     /* If the peer exists and has caps add them to the intersection,
502      * otherwise assume that the peer accepts everything */
503     if (peercaps) {
504       GstCaps *intersection;
505
506       GstCaps *oldret = ret;
507
508       __remove_channels (peercaps);
509
510       intersection = gst_caps_intersect (peercaps, ourcaps);
511
512       ret = gst_caps_intersect (ret, intersection);
513       gst_caps_unref (intersection);
514       gst_caps_unref (peercaps);
515       gst_caps_unref (oldret);
516     } else {
517       GstCaps *oldret = ret;
518
519       ret = gst_caps_intersect (ret, ourcaps);
520       gst_caps_unref (oldret);
521     }
522     gst_caps_unref (ourcaps);
523   }
524   GST_OBJECT_UNLOCK (self);
525
526   GST_DEBUG_OBJECT (pad, "Intersected caps to %" GST_PTR_FORMAT, ret);
527
528   return ret;
529 }
530
531 static gboolean
532 gst_deinterleave_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
533 {
534   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
535
536   gboolean ret;
537
538   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
539       GST_DEBUG_PAD_NAME (pad));
540
541   /* Send FLUSH_STOP, FLUSH_START and EOS immediately, no matter if
542    * we have src pads already or not. Queue all other events and
543    * push them after we have src pads
544    */
545   switch (GST_EVENT_TYPE (event)) {
546     case GST_EVENT_FLUSH_STOP:
547     case GST_EVENT_FLUSH_START:
548     case GST_EVENT_EOS:
549       ret = gst_pad_event_default (pad, parent, event);
550       break;
551     case GST_EVENT_CAPS:
552     {
553       GstCaps *caps;
554
555       gst_event_parse_caps (event, &caps);
556       ret = gst_deinterleave_sink_setcaps (self, caps);
557       gst_event_unref (event);
558       break;
559     }
560
561     default:
562       if (self->srcpads) {
563         ret = gst_pad_event_default (pad, parent, event);
564       } else {
565         GST_OBJECT_LOCK (self);
566         self->pending_events = g_list_append (self->pending_events, event);
567         GST_OBJECT_UNLOCK (self);
568         ret = TRUE;
569       }
570       break;
571   }
572
573   return ret;
574 }
575
576 static gboolean
577 gst_deinterleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
578 {
579   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
580
581   gboolean res;
582
583   res = gst_pad_query_default (pad, parent, query);
584
585   if (res && GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
586     GstFormat format;
587
588     gint64 dur;
589
590     gst_query_parse_duration (query, &format, &dur);
591
592     /* Need to divide by the number of channels in byte format
593      * to get the correct value. All other formats should be fine
594      */
595     if (format == GST_FORMAT_BYTES && dur != -1)
596       gst_query_set_duration (query, format,
597           dur / GST_AUDIO_INFO_CHANNELS (&self->audio_info));
598   } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_POSITION) {
599     GstFormat format;
600
601     gint64 pos;
602
603     gst_query_parse_position (query, &format, &pos);
604
605     /* Need to divide by the number of channels in byte format
606      * to get the correct value. All other formats should be fine
607      */
608     if (format == GST_FORMAT_BYTES && pos != -1)
609       gst_query_set_position (query, format,
610           pos / GST_AUDIO_INFO_CHANNELS (&self->audio_info));
611   } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_CAPS) {
612     GstCaps *filter, *caps;
613
614     gst_query_parse_caps (query, &filter);
615     caps = gst_deinterleave_sink_getcaps (pad, parent, filter);
616     gst_query_set_caps_result (query, caps);
617     gst_caps_unref (caps);
618   }
619
620   return res;
621 }
622
623 static void
624 gst_deinterleave_set_property (GObject * object, guint prop_id,
625     const GValue * value, GParamSpec * pspec)
626 {
627   GstDeinterleave *self = GST_DEINTERLEAVE (object);
628
629   switch (prop_id) {
630     case PROP_KEEP_POSITIONS:
631       self->keep_positions = g_value_get_boolean (value);
632       break;
633     default:
634       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
635       break;
636   }
637 }
638
639 static void
640 gst_deinterleave_get_property (GObject * object, guint prop_id,
641     GValue * value, GParamSpec * pspec)
642 {
643   GstDeinterleave *self = GST_DEINTERLEAVE (object);
644
645   switch (prop_id) {
646     case PROP_KEEP_POSITIONS:
647       g_value_set_boolean (value, self->keep_positions);
648       break;
649     default:
650       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
651       break;
652   }
653 }
654
655 static GstFlowReturn
656 gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
657 {
658   GstFlowReturn ret = GST_FLOW_OK;
659
660   guint channels = GST_AUDIO_INFO_CHANNELS (&self->audio_info);
661
662   guint pads_pushed = 0, buffers_allocated = 0;
663
664   guint nframes =
665       gst_buffer_get_size (buf) / channels /
666       (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
667
668   guint bufsize = nframes * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
669
670   guint i;
671
672   GList *srcs;
673
674   GstBuffer **buffers_out = g_new0 (GstBuffer *, channels);
675
676   guint8 *in, *out;
677
678   GstMapInfo read_info;
679   gst_buffer_map (buf, &read_info, GST_MAP_READ);
680
681   /* Send any pending events to all src pads */
682   GST_OBJECT_LOCK (self);
683   if (self->pending_events) {
684     GList *events;
685
686     GstEvent *event;
687
688     GST_DEBUG_OBJECT (self, "Sending pending events to all src pads");
689
690     for (events = self->pending_events; events != NULL; events = events->next) {
691       event = GST_EVENT (events->data);
692
693       for (srcs = self->srcpads; srcs != NULL; srcs = srcs->next)
694         gst_pad_push_event (GST_PAD (srcs->data), gst_event_ref (event));
695       gst_event_unref (event);
696     }
697
698     g_list_free (self->pending_events);
699     self->pending_events = NULL;
700   }
701   GST_OBJECT_UNLOCK (self);
702
703   /* Allocate buffers */
704   for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
705     buffers_out[i] = gst_buffer_new_allocate (NULL, bufsize, NULL);
706
707     /* Make sure we got a correct buffer. The only other case we allow
708      * here is an unliked pad */
709     if (!buffers_out[i])
710       goto alloc_buffer_failed;
711     else if (buffers_out[i] && gst_buffer_get_size (buffers_out[i]) != bufsize)
712       goto alloc_buffer_bad_size;
713
714     if (buffers_out[i]) {
715       gst_buffer_copy_into (buffers_out[i], buf, GST_BUFFER_COPY_METADATA, 0,
716           -1);
717       buffers_allocated++;
718     }
719   }
720
721   /* Return NOT_LINKED if no pad was linked */
722   if (!buffers_allocated) {
723     GST_WARNING_OBJECT (self,
724         "Couldn't allocate any buffers because no pad was linked");
725     ret = GST_FLOW_NOT_LINKED;
726     goto done;
727   }
728
729   /* deinterleave */
730   for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
731     GstPad *pad = (GstPad *) srcs->data;
732     GstMapInfo write_info;
733
734
735     in = (guint8 *) read_info.data;
736     in += i * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
737     if (buffers_out[i]) {
738       gst_buffer_map (buffers_out[i], &write_info, GST_MAP_WRITE);
739
740       out = (guint8 *) write_info.data;
741
742       self->func (out, in, channels, nframes);
743
744       gst_buffer_unmap (buffers_out[i], &write_info);
745
746       ret = gst_pad_push (pad, buffers_out[i]);
747       buffers_out[i] = NULL;
748       if (ret == GST_FLOW_OK)
749         pads_pushed++;
750       else if (ret == GST_FLOW_NOT_LINKED)
751         ret = GST_FLOW_OK;
752       else
753         goto push_failed;
754     }
755   }
756
757   /* Return NOT_LINKED if no pad was linked */
758   if (!pads_pushed)
759     ret = GST_FLOW_NOT_LINKED;
760
761 done:
762   gst_buffer_unmap (buf, &read_info);
763   gst_buffer_unref (buf);
764   g_free (buffers_out);
765   return ret;
766
767 alloc_buffer_failed:
768   {
769     GST_WARNING ("gst_pad_alloc_buffer() returned %s", gst_flow_get_name (ret));
770     goto clean_buffers;
771
772   }
773 alloc_buffer_bad_size:
774   {
775     GST_WARNING ("called alloc_buffer(), but didn't get requested bytes");
776     ret = GST_FLOW_NOT_NEGOTIATED;
777     goto clean_buffers;
778   }
779 push_failed:
780   {
781     GST_DEBUG ("push() failed, flow = %s", gst_flow_get_name (ret));
782     goto clean_buffers;
783   }
784 clean_buffers:
785   {
786     gst_buffer_unmap (buf, &read_info);
787     for (i = 0; i < channels; i++) {
788       if (buffers_out[i])
789         gst_buffer_unref (buffers_out[i]);
790     }
791     gst_buffer_unref (buf);
792     g_free (buffers_out);
793     return ret;
794   }
795 }
796
797 static GstFlowReturn
798 gst_deinterleave_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
799 {
800   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
801
802   GstFlowReturn ret;
803
804   g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
805   g_return_val_if_fail (GST_AUDIO_INFO_WIDTH (&self->audio_info) > 0,
806       GST_FLOW_NOT_NEGOTIATED);
807   g_return_val_if_fail (GST_AUDIO_INFO_CHANNELS (&self->audio_info) > 0,
808       GST_FLOW_NOT_NEGOTIATED);
809
810   ret = gst_deinterleave_process (self, buffer);
811
812   if (ret != GST_FLOW_OK)
813     GST_DEBUG_OBJECT (self, "flow return: %s", gst_flow_get_name (ret));
814
815   return ret;
816 }
817
818 static GstStateChangeReturn
819 gst_deinterleave_change_state (GstElement * element, GstStateChange transition)
820 {
821   GstStateChangeReturn ret;
822   GstDeinterleave *self = GST_DEINTERLEAVE (element);
823
824   switch (transition) {
825     case GST_STATE_CHANGE_NULL_TO_READY:
826       break;
827     case GST_STATE_CHANGE_READY_TO_PAUSED:
828       gst_deinterleave_remove_pads (self);
829
830       self->func = NULL;
831
832       if (self->pending_events) {
833         g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref,
834             NULL);
835         g_list_free (self->pending_events);
836         self->pending_events = NULL;
837       }
838       break;
839     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
840       break;
841     default:
842       break;
843   }
844
845   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
846
847   switch (transition) {
848     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
849       break;
850     case GST_STATE_CHANGE_PAUSED_TO_READY:
851       gst_deinterleave_remove_pads (self);
852
853       self->func = NULL;
854
855       if (self->pending_events) {
856         g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref,
857             NULL);
858         g_list_free (self->pending_events);
859         self->pending_events = NULL;
860       }
861       break;
862     case GST_STATE_CHANGE_READY_TO_NULL:
863       break;
864     default:
865       break;
866   }
867   return ret;
868 }