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., 51 Franklin St, Fifth Floor,
23  * Boston, MA 02110-1301, 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
deinterleave_24(guint8 * out,guint8 * in,guint stride,guint nframes)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 static gboolean gst_deinterleave_sink_query (GstPad * pad, GstObject * parent,
138     GstQuery * query);
139 
140 static gboolean gst_deinterleave_src_query (GstPad * pad, GstObject * parent,
141     GstQuery * query);
142 
143 static void gst_deinterleave_set_property (GObject * object,
144     guint prop_id, const GValue * value, GParamSpec * pspec);
145 static void gst_deinterleave_get_property (GObject * object,
146     guint prop_id, GValue * value, GParamSpec * pspec);
147 
148 
149 static void
gst_deinterleave_finalize(GObject * obj)150 gst_deinterleave_finalize (GObject * obj)
151 {
152   GstDeinterleave *self = GST_DEINTERLEAVE (obj);
153 
154   if (self->pending_events) {
155     g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref, NULL);
156     g_list_free (self->pending_events);
157     self->pending_events = NULL;
158   }
159 
160   G_OBJECT_CLASS (parent_class)->finalize (obj);
161 }
162 
163 static void
gst_deinterleave_class_init(GstDeinterleaveClass * klass)164 gst_deinterleave_class_init (GstDeinterleaveClass * klass)
165 {
166   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
167   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
168 
169   GST_DEBUG_CATEGORY_INIT (gst_deinterleave_debug, "deinterleave", 0,
170       "deinterleave element");
171 
172   gst_element_class_set_static_metadata (gstelement_class,
173       "Audio deinterleaver", "Filter/Converter/Audio",
174       "Splits one interleaved multichannel audio stream into many mono audio streams",
175       "Andy Wingo <wingo at pobox.com>, " "Iain <iain@prettypeople.org>, "
176       "Sebastian Dröge <slomo@circular-chaos.org>");
177 
178   gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
179   gst_element_class_add_static_pad_template (gstelement_class, &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
gst_deinterleave_init(GstDeinterleave * self)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_pad_set_query_function (self->sink,
216       GST_DEBUG_FUNCPTR (gst_deinterleave_sink_query));
217   gst_element_add_pad (GST_ELEMENT (self), self->sink);
218 }
219 
220 typedef struct
221 {
222   GstCaps *caps;
223   GstPad *pad;
224 } CopyStickyEventsData;
225 
226 static gboolean
copy_sticky_events(GstPad * pad,GstEvent ** event,gpointer user_data)227 copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
228 {
229   CopyStickyEventsData *data = user_data;
230 
231   if (GST_EVENT_TYPE (*event) >= GST_EVENT_CAPS && data->caps) {
232     gst_pad_set_caps (data->pad, data->caps);
233     data->caps = NULL;
234   }
235 
236   if (GST_EVENT_TYPE (*event) != GST_EVENT_CAPS)
237     gst_pad_push_event (data->pad, gst_event_ref (*event));
238 
239   return TRUE;
240 }
241 
242 static void
gst_deinterleave_add_new_pads(GstDeinterleave * self,GstCaps * caps)243 gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps)
244 {
245   GstPad *pad;
246   guint i;
247 
248   for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&self->audio_info); i++) {
249     gchar *name = g_strdup_printf ("src_%u", i);
250     GstCaps *srccaps;
251     GstAudioInfo info;
252     GstAudioFormat format = GST_AUDIO_INFO_FORMAT (&self->audio_info);
253     gint rate = GST_AUDIO_INFO_RATE (&self->audio_info);
254     GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_MONO;
255     CopyStickyEventsData data;
256 
257     /* Set channel position if we know it */
258     if (self->keep_positions)
259       position = GST_AUDIO_INFO_POSITION (&self->audio_info, i);
260 
261     gst_audio_info_init (&info);
262     gst_audio_info_set_format (&info, format, rate, 1, &position);
263 
264     srccaps = gst_audio_info_to_caps (&info);
265 
266     pad = gst_pad_new_from_static_template (&src_template, name);
267     g_free (name);
268 
269     gst_pad_use_fixed_caps (pad);
270     gst_pad_set_query_function (pad,
271         GST_DEBUG_FUNCPTR (gst_deinterleave_src_query));
272     gst_pad_set_active (pad, TRUE);
273 
274     data.pad = pad;
275     data.caps = srccaps;
276     gst_pad_sticky_events_foreach (self->sink, copy_sticky_events, &data);
277     if (data.caps)
278       gst_pad_set_caps (pad, data.caps);
279     gst_element_add_pad (GST_ELEMENT (self), pad);
280     self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad));
281 
282     gst_caps_unref (srccaps);
283   }
284 
285   gst_element_no_more_pads (GST_ELEMENT (self));
286   self->srcpads = g_list_reverse (self->srcpads);
287 }
288 
289 static gboolean
gst_deinterleave_set_pads_caps(GstDeinterleave * self,GstCaps * caps)290 gst_deinterleave_set_pads_caps (GstDeinterleave * self, GstCaps * caps)
291 {
292   GList *l;
293   gint i;
294   gboolean ret = TRUE;
295 
296   for (l = self->srcpads, i = 0; l; l = l->next, i++) {
297     GstPad *pad = GST_PAD (l->data);
298     GstCaps *srccaps;
299     GstAudioInfo info;
300 
301     if (!gst_audio_info_from_caps (&info, caps)) {
302       ret = FALSE;
303       continue;
304     }
305     if (self->keep_positions)
306       GST_AUDIO_INFO_POSITION (&info, 0) =
307           GST_AUDIO_INFO_POSITION (&self->audio_info, i);
308 
309     srccaps = gst_audio_info_to_caps (&info);
310 
311     gst_pad_set_caps (pad, srccaps);
312     gst_caps_unref (srccaps);
313   }
314   return ret;
315 }
316 
317 static void
gst_deinterleave_remove_pads(GstDeinterleave * self)318 gst_deinterleave_remove_pads (GstDeinterleave * self)
319 {
320   GList *l;
321 
322   GST_INFO_OBJECT (self, "removing pads");
323 
324   for (l = self->srcpads; l; l = l->next) {
325     GstPad *pad = GST_PAD (l->data);
326 
327     gst_element_remove_pad (GST_ELEMENT_CAST (self), pad);
328     gst_object_unref (pad);
329   }
330   g_list_free (self->srcpads);
331   self->srcpads = NULL;
332 
333   gst_caps_replace (&self->sinkcaps, NULL);
334 }
335 
336 static gboolean
gst_deinterleave_set_process_function(GstDeinterleave * self)337 gst_deinterleave_set_process_function (GstDeinterleave * self)
338 {
339   switch (GST_AUDIO_INFO_WIDTH (&self->audio_info)) {
340     case 8:
341       self->func = (GstDeinterleaveFunc) deinterleave_8;
342       break;
343     case 16:
344       self->func = (GstDeinterleaveFunc) deinterleave_16;
345       break;
346     case 24:
347       self->func = (GstDeinterleaveFunc) deinterleave_24;
348       break;
349     case 32:
350       self->func = (GstDeinterleaveFunc) deinterleave_32;
351       break;
352     case 64:
353       self->func = (GstDeinterleaveFunc) deinterleave_64;
354       break;
355     default:
356       return FALSE;
357   }
358   return TRUE;
359 }
360 
361 static gboolean
gst_deinterleave_check_caps_change(GstDeinterleave * self,GstAudioInfo * old_info,GstAudioInfo * new_info)362 gst_deinterleave_check_caps_change (GstDeinterleave * self,
363     GstAudioInfo * old_info, GstAudioInfo * new_info)
364 {
365   gint i;
366   gboolean same_layout = TRUE;
367   gboolean was_unpositioned;
368   gboolean is_unpositioned;
369   gint new_channels;
370   gint old_channels;
371 
372   new_channels = GST_AUDIO_INFO_CHANNELS (new_info);
373   old_channels = GST_AUDIO_INFO_CHANNELS (old_info);
374 
375   if (GST_AUDIO_INFO_IS_UNPOSITIONED (new_info) || new_channels == 1)
376     is_unpositioned = TRUE;
377   else
378     is_unpositioned = FALSE;
379 
380   if (GST_AUDIO_INFO_IS_UNPOSITIONED (old_info) || old_channels == 1)
381     was_unpositioned = TRUE;
382   else
383     was_unpositioned = FALSE;
384 
385   /* We allow caps changes as long as the number of channels doesn't change
386    * and the channel positions stay the same. _getcaps() should've cared
387    * for this already but better be safe.
388    */
389   if (new_channels != old_channels)
390     goto cannot_change_caps;
391 
392   /* Now check the channel positions. If we had no channel positions
393    * and get them or the other way around things have changed.
394    * If we had channel positions and get different ones things have
395    * changed too of course
396    */
397   if ((!was_unpositioned && is_unpositioned) || (was_unpositioned
398           && !is_unpositioned))
399     goto cannot_change_caps;
400 
401   if (!is_unpositioned) {
402     if (GST_AUDIO_INFO_CHANNELS (old_info) !=
403         GST_AUDIO_INFO_CHANNELS (new_info))
404       goto cannot_change_caps;
405     for (i = 0; i < GST_AUDIO_INFO_CHANNELS (old_info); i++) {
406       if (new_info->position[i] != old_info->position[i]) {
407         same_layout = FALSE;
408         break;
409       }
410     }
411     if (!same_layout)
412       goto cannot_change_caps;
413   }
414 
415   return TRUE;
416 
417 cannot_change_caps:
418   return FALSE;
419 }
420 
421 static gboolean
gst_deinterleave_sink_setcaps(GstDeinterleave * self,GstCaps * caps)422 gst_deinterleave_sink_setcaps (GstDeinterleave * self, GstCaps * caps)
423 {
424   GstCaps *srccaps;
425   GstStructure *s;
426 
427   GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps);
428 
429   if (!gst_audio_info_from_caps (&self->audio_info, caps))
430     goto invalid_caps;
431 
432   if (!gst_deinterleave_set_process_function (self))
433     goto unsupported_caps;
434 
435   if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) {
436     GstAudioInfo old_info;
437 
438     gst_audio_info_init (&old_info);
439     if (!gst_audio_info_from_caps (&old_info, self->sinkcaps))
440       goto info_from_caps_failed;
441 
442     if (gst_deinterleave_check_caps_change (self, &old_info, &self->audio_info)) {
443       if (!gst_deinterleave_set_process_function (self))
444         goto cannot_change_caps;
445     } else
446       goto cannot_change_caps;
447 
448   }
449 
450   gst_caps_replace (&self->sinkcaps, caps);
451 
452   /* Get srcpad caps */
453   srccaps = gst_caps_copy (caps);
454   s = gst_caps_get_structure (srccaps, 0);
455   gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
456   gst_structure_remove_field (s, "channel-mask");
457 
458   /* If we already have pads, update the caps otherwise
459    * add new pads */
460   if (self->srcpads) {
461     if (!gst_deinterleave_set_pads_caps (self, srccaps))
462       goto set_caps_failed;
463   } else {
464     gst_deinterleave_add_new_pads (self, srccaps);
465   }
466 
467   gst_caps_unref (srccaps);
468 
469   return TRUE;
470 
471 cannot_change_caps:
472   {
473     GST_WARNING_OBJECT (self, "caps change from %" GST_PTR_FORMAT
474         " to %" GST_PTR_FORMAT " not supported: channel number or channel "
475         "positions change", self->sinkcaps, caps);
476     return FALSE;
477   }
478 unsupported_caps:
479   {
480     GST_ERROR_OBJECT (self, "caps not supported: %" GST_PTR_FORMAT, caps);
481     return FALSE;
482   }
483 invalid_caps:
484   {
485     GST_ERROR_OBJECT (self, "invalid caps");
486     return FALSE;
487   }
488 set_caps_failed:
489   {
490     GST_ERROR_OBJECT (self, "set_caps failed");
491     gst_caps_unref (srccaps);
492     return FALSE;
493   }
494 info_from_caps_failed:
495   {
496     GST_ERROR_OBJECT (self, "coud not get info from caps");
497     return FALSE;
498   }
499 }
500 
501 static void
__remove_channels(GstCaps * caps)502 __remove_channels (GstCaps * caps)
503 {
504   GstStructure *s;
505   gint i, size;
506 
507   size = gst_caps_get_size (caps);
508   for (i = 0; i < size; i++) {
509     s = gst_caps_get_structure (caps, i);
510     gst_structure_remove_field (s, "channel-mask");
511     gst_structure_remove_field (s, "channels");
512   }
513 }
514 
515 static void
__set_channels(GstCaps * caps,gint channels)516 __set_channels (GstCaps * caps, gint channels)
517 {
518   GstStructure *s;
519   gint i, size;
520 
521   size = gst_caps_get_size (caps);
522   for (i = 0; i < size; i++) {
523     s = gst_caps_get_structure (caps, i);
524     if (channels > 0)
525       gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
526     else
527       gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
528   }
529 }
530 
531 static gboolean
gst_deinterleave_sink_acceptcaps(GstPad * pad,GstObject * parent,GstCaps * caps)532 gst_deinterleave_sink_acceptcaps (GstPad * pad, GstObject * parent,
533     GstCaps * caps)
534 {
535   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
536   GstCaps *templ_caps = gst_pad_get_pad_template_caps (pad);
537   gboolean ret;
538 
539   ret = gst_caps_can_intersect (templ_caps, caps);
540   gst_caps_unref (templ_caps);
541   if (ret && self->sinkcaps) {
542     GstAudioInfo new_info;
543 
544     gst_audio_info_init (&new_info);
545     if (!gst_audio_info_from_caps (&new_info, caps))
546       goto info_from_caps_failed;
547     ret =
548         gst_deinterleave_check_caps_change (self, &self->audio_info, &new_info);
549   }
550 
551   return ret;
552 
553 info_from_caps_failed:
554   {
555     GST_ERROR_OBJECT (self, "coud not get info from caps");
556     return FALSE;
557   }
558 }
559 
560 static GstCaps *
gst_deinterleave_getcaps(GstPad * pad,GstObject * parent,GstCaps * filter)561 gst_deinterleave_getcaps (GstPad * pad, GstObject * parent, GstCaps * filter)
562 {
563   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
564   GstCaps *ret;
565   GstIterator *it;
566   GstIteratorResult res;
567   GValue v = G_VALUE_INIT;
568 
569   if (pad != self->sink) {
570     ret = gst_pad_get_current_caps (pad);
571     if (ret) {
572       if (filter) {
573         GstCaps *tmp =
574             gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
575         gst_caps_unref (ret);
576         ret = tmp;
577       }
578       return ret;
579     }
580   }
581 
582   /* Intersect all of our pad template caps with the peer caps of the pad
583    * to get all formats that are possible up- and downstream.
584    *
585    * For the pad for which the caps are requested we don't remove the channel
586    * informations as they must be in the returned caps and incompatibilities
587    * will be detected here already
588    */
589   ret = gst_caps_new_any ();
590   it = gst_element_iterate_pads (GST_ELEMENT_CAST (self));
591 
592   do {
593     res = gst_iterator_next (it, &v);
594     switch (res) {
595       case GST_ITERATOR_OK:{
596         GstPad *ourpad = GST_PAD (g_value_get_object (&v));
597         GstCaps *peercaps = NULL, *ourcaps;
598         GstCaps *templ_caps = gst_pad_get_pad_template_caps (ourpad);
599 
600         ourcaps = gst_caps_copy (templ_caps);
601         gst_caps_unref (templ_caps);
602 
603         if (pad == ourpad) {
604           if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK)
605             __set_channels (ourcaps,
606                 GST_AUDIO_INFO_CHANNELS (&self->audio_info));
607           else
608             __set_channels (ourcaps, 1);
609         } else {
610           __remove_channels (ourcaps);
611           /* Only ask for peer caps for other pads than pad
612            * as otherwise gst_pad_peer_get_caps() might call
613            * back into this function and deadlock
614            */
615           peercaps = gst_pad_peer_query_caps (ourpad, NULL);
616           peercaps = gst_caps_make_writable (peercaps);
617         }
618 
619         /* If the peer exists and has caps add them to the intersection,
620          * otherwise assume that the peer accepts everything */
621         if (peercaps) {
622           GstCaps *intersection;
623           GstCaps *oldret = ret;
624 
625           __remove_channels (peercaps);
626 
627           intersection = gst_caps_intersect (peercaps, ourcaps);
628 
629           ret = gst_caps_intersect (ret, intersection);
630           gst_caps_unref (intersection);
631           gst_caps_unref (peercaps);
632           gst_caps_unref (oldret);
633         } else {
634           GstCaps *oldret = ret;
635 
636           ret = gst_caps_intersect (ret, ourcaps);
637           gst_caps_unref (oldret);
638         }
639         gst_caps_unref (ourcaps);
640         g_value_reset (&v);
641         break;
642       }
643       case GST_ITERATOR_DONE:
644         break;
645       case GST_ITERATOR_ERROR:
646         gst_caps_unref (ret);
647         ret = gst_caps_new_empty ();
648         break;
649       case GST_ITERATOR_RESYNC:
650         gst_caps_unref (ret);
651         ret = gst_caps_new_any ();
652         gst_iterator_resync (it);
653         break;
654     }
655   } while (res != GST_ITERATOR_DONE && res != GST_ITERATOR_ERROR);
656   g_value_unset (&v);
657   gst_iterator_free (it);
658 
659   if (filter) {
660     GstCaps *aux;
661 
662     aux = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
663     gst_caps_unref (ret);
664     ret = aux;
665   }
666 
667   GST_DEBUG_OBJECT (pad, "Intersected caps to %" GST_PTR_FORMAT, ret);
668 
669   return ret;
670 }
671 
672 static gboolean
gst_deinterleave_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)673 gst_deinterleave_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
674 {
675   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
676   gboolean ret;
677 
678   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
679       GST_DEBUG_PAD_NAME (pad));
680 
681   /* Send FLUSH_STOP, FLUSH_START and EOS immediately, no matter if
682    * we have src pads already or not. Queue all other events and
683    * push them after we have src pads
684    */
685   switch (GST_EVENT_TYPE (event)) {
686     case GST_EVENT_FLUSH_STOP:
687     case GST_EVENT_FLUSH_START:
688     case GST_EVENT_EOS:
689       ret = gst_pad_event_default (pad, parent, event);
690       break;
691     case GST_EVENT_CAPS:
692     {
693       GstCaps *caps;
694 
695       gst_event_parse_caps (event, &caps);
696       ret = gst_deinterleave_sink_setcaps (self, caps);
697       gst_event_unref (event);
698       break;
699     }
700 
701     default:
702       if (!self->srcpads && !GST_EVENT_IS_STICKY (event)) {
703         /* Sticky events are copied when creating a new pad */
704         GST_OBJECT_LOCK (self);
705         self->pending_events = g_list_append (self->pending_events, event);
706         GST_OBJECT_UNLOCK (self);
707         ret = TRUE;
708       } else {
709         ret = gst_pad_event_default (pad, parent, event);
710       }
711       break;
712   }
713 
714   return ret;
715 }
716 
717 static gboolean
gst_deinterleave_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)718 gst_deinterleave_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
719 {
720   gboolean res;
721 
722   switch (GST_QUERY_TYPE (query)) {
723     case GST_QUERY_CAPS:{
724       GstCaps *filter;
725       GstCaps *caps;
726 
727       gst_query_parse_caps (query, &filter);
728       caps = gst_deinterleave_getcaps (pad, parent, filter);
729       gst_query_set_caps_result (query, caps);
730       gst_caps_unref (caps);
731       res = TRUE;
732       break;
733     }
734     case GST_QUERY_ACCEPT_CAPS:{
735       GstCaps *caps;
736       gboolean ret;
737 
738       gst_query_parse_accept_caps (query, &caps);
739       ret = gst_deinterleave_sink_acceptcaps (pad, parent, caps);
740       gst_query_set_accept_caps_result (query, ret);
741       res = TRUE;
742       break;
743     }
744     default:
745       res = gst_pad_query_default (pad, parent, query);
746       break;
747   }
748 
749   return res;
750 }
751 
752 static gboolean
gst_deinterleave_src_query(GstPad * pad,GstObject * parent,GstQuery * query)753 gst_deinterleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
754 {
755   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
756   gboolean res;
757 
758   res = gst_pad_query_default (pad, parent, query);
759 
760   if (res && GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
761     GstFormat format;
762     gint64 dur;
763 
764     gst_query_parse_duration (query, &format, &dur);
765 
766     /* Need to divide by the number of channels in byte format
767      * to get the correct value. All other formats should be fine
768      */
769     if (format == GST_FORMAT_BYTES && dur != -1)
770       gst_query_set_duration (query, format,
771           dur / GST_AUDIO_INFO_CHANNELS (&self->audio_info));
772   } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_POSITION) {
773     GstFormat format;
774     gint64 pos;
775 
776     gst_query_parse_position (query, &format, &pos);
777 
778     /* Need to divide by the number of channels in byte format
779      * to get the correct value. All other formats should be fine
780      */
781     if (format == GST_FORMAT_BYTES && pos != -1)
782       gst_query_set_position (query, format,
783           pos / GST_AUDIO_INFO_CHANNELS (&self->audio_info));
784   } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_CAPS) {
785     GstCaps *filter, *caps;
786 
787     gst_query_parse_caps (query, &filter);
788     caps = gst_deinterleave_getcaps (pad, parent, filter);
789     gst_query_set_caps_result (query, caps);
790     gst_caps_unref (caps);
791   }
792 
793   return res;
794 }
795 
796 static void
gst_deinterleave_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)797 gst_deinterleave_set_property (GObject * object, guint prop_id,
798     const GValue * value, GParamSpec * pspec)
799 {
800   GstDeinterleave *self = GST_DEINTERLEAVE (object);
801 
802   switch (prop_id) {
803     case PROP_KEEP_POSITIONS:
804       self->keep_positions = g_value_get_boolean (value);
805       break;
806     default:
807       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
808       break;
809   }
810 }
811 
812 static void
gst_deinterleave_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)813 gst_deinterleave_get_property (GObject * object, guint prop_id,
814     GValue * value, GParamSpec * pspec)
815 {
816   GstDeinterleave *self = GST_DEINTERLEAVE (object);
817 
818   switch (prop_id) {
819     case PROP_KEEP_POSITIONS:
820       g_value_set_boolean (value, self->keep_positions);
821       break;
822     default:
823       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
824       break;
825   }
826 }
827 
828 static GstFlowReturn
gst_deinterleave_process(GstDeinterleave * self,GstBuffer * buf)829 gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
830 {
831   GstFlowReturn ret = GST_FLOW_OK;
832   guint channels = GST_AUDIO_INFO_CHANNELS (&self->audio_info);
833   guint pads_pushed = 0, buffers_allocated = 0;
834   guint nframes =
835       gst_buffer_get_size (buf) / channels /
836       (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
837   guint bufsize = nframes * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
838   guint i;
839   GList *srcs;
840   GstBuffer **buffers_out = g_new0 (GstBuffer *, channels);
841   guint8 *in, *out;
842   GstMapInfo read_info;
843   GList *pending_events, *l;
844 
845   /* Send any pending events to all src pads */
846   GST_OBJECT_LOCK (self);
847   pending_events = self->pending_events;
848   self->pending_events = NULL;
849   GST_OBJECT_UNLOCK (self);
850 
851   if (pending_events) {
852     GstEvent *event;
853 
854     GST_DEBUG_OBJECT (self, "Sending pending events to all src pads");
855     for (l = pending_events; l; l = l->next) {
856       event = l->data;
857       for (srcs = self->srcpads; srcs != NULL; srcs = srcs->next)
858         gst_pad_push_event (GST_PAD (srcs->data), gst_event_ref (event));
859       gst_event_unref (event);
860     }
861     g_list_free (pending_events);
862   }
863 
864   gst_buffer_map (buf, &read_info, GST_MAP_READ);
865 
866   /* Allocate buffers */
867   for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
868     buffers_out[i] = gst_buffer_new_allocate (NULL, bufsize, NULL);
869 
870     /* Make sure we got a correct buffer. The only other case we allow
871      * here is an unliked pad */
872     if (!buffers_out[i])
873       goto alloc_buffer_failed;
874     else if (buffers_out[i]
875         && gst_buffer_get_size (buffers_out[i]) != bufsize)
876       goto alloc_buffer_bad_size;
877 
878     if (buffers_out[i]) {
879       gst_buffer_copy_into (buffers_out[i], buf, GST_BUFFER_COPY_METADATA, 0,
880           -1);
881       buffers_allocated++;
882     }
883   }
884 
885   /* Return NOT_LINKED if no pad was linked */
886   if (!buffers_allocated) {
887     GST_WARNING_OBJECT (self,
888         "Couldn't allocate any buffers because no pad was linked");
889     ret = GST_FLOW_NOT_LINKED;
890     goto done;
891   }
892 
893   /* deinterleave */
894   for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
895     GstPad *pad = (GstPad *) srcs->data;
896     GstMapInfo write_info;
897 
898     in = (guint8 *) read_info.data;
899     in += i * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8);
900     if (buffers_out[i]) {
901       gst_buffer_map (buffers_out[i], &write_info, GST_MAP_WRITE);
902       out = (guint8 *) write_info.data;
903       self->func (out, in, channels, nframes);
904       gst_buffer_unmap (buffers_out[i], &write_info);
905 
906       ret = gst_pad_push (pad, buffers_out[i]);
907       buffers_out[i] = NULL;
908       if (ret == GST_FLOW_OK)
909         pads_pushed++;
910       else if (ret == GST_FLOW_NOT_LINKED)
911         ret = GST_FLOW_OK;
912       else
913         goto push_failed;
914     }
915   }
916 
917   /* Return NOT_LINKED if no pad was linked */
918   if (!pads_pushed)
919     ret = GST_FLOW_NOT_LINKED;
920 
921   GST_DEBUG_OBJECT (self, "Pushed on %d pads", pads_pushed);
922 
923 done:
924   gst_buffer_unmap (buf, &read_info);
925   gst_buffer_unref (buf);
926   g_free (buffers_out);
927   return ret;
928 
929 alloc_buffer_failed:
930   {
931     GST_WARNING ("gst_pad_alloc_buffer() returned %s", gst_flow_get_name (ret));
932     goto clean_buffers;
933 
934   }
935 alloc_buffer_bad_size:
936   {
937     GST_WARNING ("called alloc_buffer(), but didn't get requested bytes");
938     ret = GST_FLOW_NOT_NEGOTIATED;
939     goto clean_buffers;
940   }
941 push_failed:
942   {
943     GST_DEBUG ("push() failed, flow = %s", gst_flow_get_name (ret));
944     goto clean_buffers;
945   }
946 clean_buffers:
947   {
948     gst_buffer_unmap (buf, &read_info);
949     for (i = 0; i < channels; i++) {
950       if (buffers_out[i])
951         gst_buffer_unref (buffers_out[i]);
952     }
953     gst_buffer_unref (buf);
954     g_free (buffers_out);
955     return ret;
956   }
957 }
958 
959 static GstFlowReturn
gst_deinterleave_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)960 gst_deinterleave_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
961 {
962   GstDeinterleave *self = GST_DEINTERLEAVE (parent);
963   GstFlowReturn ret;
964 
965   g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
966   g_return_val_if_fail (GST_AUDIO_INFO_WIDTH (&self->audio_info) > 0,
967       GST_FLOW_NOT_NEGOTIATED);
968   g_return_val_if_fail (GST_AUDIO_INFO_CHANNELS (&self->audio_info) > 0,
969       GST_FLOW_NOT_NEGOTIATED);
970 
971   ret = gst_deinterleave_process (self, buffer);
972 
973   if (ret != GST_FLOW_OK)
974     GST_DEBUG_OBJECT (self, "flow return: %s", gst_flow_get_name (ret));
975 
976   return ret;
977 }
978 
979 static GstStateChangeReturn
gst_deinterleave_change_state(GstElement * element,GstStateChange transition)980 gst_deinterleave_change_state (GstElement * element, GstStateChange transition)
981 {
982   GstStateChangeReturn ret;
983   GstDeinterleave *self = GST_DEINTERLEAVE (element);
984 
985   switch (transition) {
986     case GST_STATE_CHANGE_NULL_TO_READY:
987       break;
988     case GST_STATE_CHANGE_READY_TO_PAUSED:
989       gst_deinterleave_remove_pads (self);
990 
991       self->func = NULL;
992 
993       if (self->pending_events) {
994         g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref,
995             NULL);
996         g_list_free (self->pending_events);
997         self->pending_events = NULL;
998       }
999       break;
1000     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1001       break;
1002     default:
1003       break;
1004   }
1005 
1006   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1007 
1008   switch (transition) {
1009     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1010       break;
1011     case GST_STATE_CHANGE_PAUSED_TO_READY:
1012       gst_deinterleave_remove_pads (self);
1013 
1014       self->func = NULL;
1015 
1016       if (self->pending_events) {
1017         g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref,
1018             NULL);
1019         g_list_free (self->pending_events);
1020         self->pending_events = NULL;
1021       }
1022       break;
1023     case GST_STATE_CHANGE_READY_TO_NULL:
1024       break;
1025     default:
1026       break;
1027   }
1028   return ret;
1029 }
1030