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