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