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