1 /* GStreamer unit tests for the interleave element
2 * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
25 #include <gst/check/gstcheck.h>
26 #include <gst/audio/multichannel.h>
28 GST_START_TEST (test_create_and_unref)
30 GstElement *deinterleave;
32 deinterleave = gst_element_factory_make ("deinterleave", NULL);
33 fail_unless (deinterleave != NULL);
35 gst_element_set_state (deinterleave, GST_STATE_NULL);
36 gst_object_unref (deinterleave);
41 static GstPad *mysrcpad, **mysinkpads;
42 static gint nsinkpads;
44 static GstElement *deinterleave;
46 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
49 GST_STATIC_CAPS ("audio/x-raw-float, "
51 "channels = (int) 1, "
52 "rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER"));
54 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
57 GST_STATIC_CAPS ("audio/x-raw-float, "
59 "channels = (int) { 2, 3 }, "
60 "rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER"));
63 "audio/x-raw-float, " \
64 "width = (int) 32, " \
65 "channels = (int) 2, " \
66 "rate = (int) 32000, " \
67 "endianness = (int) BYTE_ORDER"
70 "audio/x-raw-float, " \
71 "width = (int) 32, " \
72 "channels = (int) 2, " \
73 "rate = (int) 48000, " \
74 "endianness = (int) BYTE_ORDER"
76 #define CAPS_48khz_3CH \
77 "audio/x-raw-float, " \
78 "width = (int) 32, " \
79 "channels = (int) 3, " \
80 "rate = (int) 48000, " \
81 "endianness = (int) BYTE_ORDER"
84 deinterleave_chain_func (GstPad * pad, GstBuffer * buffer)
89 fail_unless (GST_IS_BUFFER (buffer));
90 fail_unless_equals_int (GST_BUFFER_SIZE (buffer), 48000 * sizeof (gfloat));
91 fail_unless (GST_BUFFER_DATA (buffer) != NULL);
93 indata = (gfloat *) GST_BUFFER_DATA (buffer);
95 if (strcmp (GST_PAD_NAME (pad), "sink0") == 0) {
96 for (i = 0; i < 48000; i++)
97 fail_unless_equals_float (indata[i], -1.0);
98 } else if (strcmp (GST_PAD_NAME (pad), "sink1") == 0) {
99 for (i = 0; i < 48000; i++)
100 fail_unless_equals_float (indata[i], 1.0);
102 g_assert_not_reached ();
105 gst_buffer_unref (buffer);
111 deinterleave_pad_added (GstElement * src, GstPad * pad, gpointer data)
114 gint link = GPOINTER_TO_INT (data);
116 if (nsinkpads >= link)
119 name = g_strdup_printf ("sink%d", nsinkpads);
121 mysinkpads[nsinkpads] =
122 gst_pad_new_from_static_template (&sinktemplate, name);
124 fail_if (mysinkpads[nsinkpads] == NULL);
126 gst_pad_set_chain_function (mysinkpads[nsinkpads], deinterleave_chain_func);
127 fail_unless (gst_pad_link (pad, mysinkpads[nsinkpads]) == GST_PAD_LINK_OK);
128 gst_pad_set_active (mysinkpads[nsinkpads], TRUE);
132 GST_START_TEST (test_2_channels)
140 mysinkpads = g_new0 (GstPad *, 2);
143 deinterleave = gst_element_factory_make ("deinterleave", NULL);
144 fail_unless (deinterleave != NULL);
146 mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
147 fail_unless (mysrcpad != NULL);
149 caps = gst_caps_from_string (CAPS_48khz);
150 fail_unless (gst_pad_set_caps (mysrcpad, caps));
151 gst_pad_use_fixed_caps (mysrcpad);
153 sinkpad = gst_element_get_static_pad (deinterleave, "sink");
154 fail_unless (sinkpad != NULL);
155 fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
156 g_object_unref (sinkpad);
158 g_signal_connect (deinterleave, "pad-added",
159 G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
161 bus = gst_bus_new ();
162 gst_element_set_bus (deinterleave, bus);
164 fail_unless (gst_element_set_state (deinterleave,
165 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
167 inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
168 indata = (gfloat *) GST_BUFFER_DATA (inbuf);
169 for (i = 0; i < 2 * 48000; i += 2) {
173 gst_buffer_set_caps (inbuf, caps);
175 fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
177 fail_unless (gst_element_set_state (deinterleave,
178 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
180 for (i = 0; i < nsinkpads; i++)
181 g_object_unref (mysinkpads[i]);
185 g_object_unref (deinterleave);
186 g_object_unref (bus);
187 gst_caps_unref (caps);
192 GST_START_TEST (test_2_channels_1_linked)
201 mysinkpads = g_new0 (GstPad *, 2);
203 deinterleave = gst_element_factory_make ("deinterleave", NULL);
204 fail_unless (deinterleave != NULL);
206 mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
207 fail_unless (mysrcpad != NULL);
209 caps = gst_caps_from_string (CAPS_48khz);
210 fail_unless (gst_pad_set_caps (mysrcpad, caps));
211 gst_pad_use_fixed_caps (mysrcpad);
213 sinkpad = gst_element_get_static_pad (deinterleave, "sink");
214 fail_unless (sinkpad != NULL);
215 fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
216 g_object_unref (sinkpad);
218 g_signal_connect (deinterleave, "pad-added",
219 G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (1));
221 bus = gst_bus_new ();
222 gst_element_set_bus (deinterleave, bus);
224 fail_unless (gst_element_set_state (deinterleave,
225 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
227 inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
228 indata = (gfloat *) GST_BUFFER_DATA (inbuf);
229 for (i = 0; i < 2 * 48000; i += 2) {
233 gst_buffer_set_caps (inbuf, caps);
235 fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
237 fail_unless (gst_element_set_state (deinterleave,
238 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
240 for (i = 0; i < nsinkpads; i++)
241 g_object_unref (mysinkpads[i]);
245 g_object_unref (deinterleave);
246 g_object_unref (bus);
247 gst_caps_unref (caps);
252 GST_START_TEST (test_2_channels_caps_change)
255 GstCaps *caps, *caps2;
261 mysinkpads = g_new0 (GstPad *, 2);
263 deinterleave = gst_element_factory_make ("deinterleave", NULL);
264 fail_unless (deinterleave != NULL);
266 mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
267 fail_unless (mysrcpad != NULL);
269 caps = gst_caps_from_string (CAPS_48khz);
270 fail_unless (gst_pad_set_caps (mysrcpad, caps));
271 gst_pad_use_fixed_caps (mysrcpad);
273 sinkpad = gst_element_get_static_pad (deinterleave, "sink");
274 fail_unless (sinkpad != NULL);
275 fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
276 g_object_unref (sinkpad);
278 g_signal_connect (deinterleave, "pad-added",
279 G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
281 bus = gst_bus_new ();
282 gst_element_set_bus (deinterleave, bus);
284 fail_unless (gst_element_set_state (deinterleave,
285 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
287 inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
288 indata = (gfloat *) GST_BUFFER_DATA (inbuf);
289 for (i = 0; i < 2 * 48000; i += 2) {
293 gst_buffer_set_caps (inbuf, caps);
295 fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
297 caps2 = gst_caps_from_string (CAPS_32khz);
298 gst_pad_set_caps (mysrcpad, caps2);
300 inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
301 indata = (gfloat *) GST_BUFFER_DATA (inbuf);
302 for (i = 0; i < 2 * 48000; i += 2) {
306 gst_buffer_set_caps (inbuf, caps2);
308 /* Should work fine because the caps changed in a compatible way */
309 fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
311 gst_caps_unref (caps2);
313 caps2 = gst_caps_from_string (CAPS_48khz_3CH);
314 gst_pad_set_caps (mysrcpad, caps2);
316 inbuf = gst_buffer_new_and_alloc (3 * 48000 * sizeof (gfloat));
317 indata = (gfloat *) GST_BUFFER_DATA (inbuf);
318 for (i = 0; i < 3 * 48000; i += 3) {
323 gst_buffer_set_caps (inbuf, caps2);
325 /* Should break because the caps changed in an incompatible way */
326 fail_if (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
328 fail_unless (gst_element_set_state (deinterleave,
329 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
331 for (i = 0; i < nsinkpads; i++)
332 g_object_unref (mysinkpads[i]);
336 g_object_unref (deinterleave);
337 g_object_unref (bus);
338 gst_caps_unref (caps);
339 gst_caps_unref (caps2);
345 #define SAMPLES_PER_BUFFER 10
346 #define NUM_CHANNELS 8
347 #define SAMPLE_RATE 44100
349 static guint pads_created;
352 set_channel_positions (GstCaps * caps, int channels,
353 GstAudioChannelPosition * channelpositions)
355 GValue chanpos = { 0 };
357 GstStructure *structure = gst_caps_get_structure (caps, 0);
360 g_value_init (&chanpos, GST_TYPE_ARRAY);
361 g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
363 for (c = 0; c < channels; c++) {
364 g_value_set_enum (&pos, channelpositions[c]);
365 gst_value_array_append_value (&chanpos, &pos);
367 g_value_unset (&pos);
369 gst_structure_set_value (structure, "channel-positions", &chanpos);
370 g_value_unset (&chanpos);
374 src_handoff_float32_8ch (GstElement * src, GstBuffer * buf, GstPad * pad,
377 GstAudioChannelPosition layout[NUM_CHANNELS];
382 caps = gst_caps_new_simple ("audio/x-raw-float",
383 "width", G_TYPE_INT, 32,
384 "depth", G_TYPE_INT, 32,
385 "channels", G_TYPE_INT, NUM_CHANNELS,
386 "rate", G_TYPE_INT, SAMPLE_RATE,
387 "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
389 for (i = 0; i < NUM_CHANNELS; ++i)
390 layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
392 set_channel_positions (caps, NUM_CHANNELS, layout);
394 size = sizeof (gfloat) * SAMPLES_PER_BUFFER * NUM_CHANNELS;
395 data = (gfloat *) g_malloc (size);
397 GST_BUFFER_MALLOCDATA (buf) = (guint8 *) data;
398 GST_BUFFER_DATA (buf) = (guint8 *) data;
399 GST_BUFFER_SIZE (buf) = size;
401 GST_BUFFER_OFFSET (buf) = 0;
402 GST_BUFFER_TIMESTAMP (buf) = 0;
404 GST_BUFFER_CAPS (buf) = caps;
406 for (i = 0; i < SAMPLES_PER_BUFFER; ++i) {
407 for (c = 0; c < NUM_CHANNELS; ++c) {
408 *data = (gfloat) ((i * NUM_CHANNELS) + c);
415 float_buffer_check_probe (GstPad * pad, GstBuffer * buf, gpointer userdata)
418 guint padnum, numpads;
422 GstAudioChannelPosition *pos;
425 fail_unless_equals_int (sscanf (GST_PAD_NAME (pad), "src%u", &padnum), 1);
427 numpads = pads_created;
430 caps = GST_BUFFER_CAPS (buf);
431 fail_unless (caps != NULL);
432 s = gst_caps_get_structure (caps, 0);
433 fail_unless (gst_structure_get_int (s, "channels", &channels));
434 fail_unless_equals_int (channels, 1);
435 fail_unless (gst_structure_has_field (s, "channel-positions"));
436 pos = gst_audio_get_channel_positions (s);
437 fail_unless (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE);
440 data = (gfloat *) GST_BUFFER_DATA (buf);
441 num = GST_BUFFER_SIZE (buf) / sizeof (gfloat);
443 /* Check buffer content */
444 for (i = 0; i < num; ++i) {
447 val = (guint) data[i];
448 GST_LOG ("%s[%u]: %8f", GST_PAD_NAME (pad), i, data[i]);
449 /* can't use the modulo operator in the assertion statement, since due to
450 * the way it gets expanded it would be interpreted as a printf operator
451 * in the failure case, which will result in segfaults */
452 rest = val % numpads;
453 /* check that the first channel is on pad src0, the second on src1 etc. */
454 fail_unless_equals_int (rest, padnum);
457 return TRUE; /* don't drop data */
461 pad_added_setup_data_check_float32_8ch_cb (GstElement * deinterleave,
462 GstPad * pad, GstElement * pipeline)
464 GstElement *queue, *sink;
467 queue = gst_element_factory_make ("queue", NULL);
468 fail_unless (queue != NULL);
470 sink = gst_element_factory_make ("fakesink", NULL);
471 fail_unless (sink != NULL);
473 gst_bin_add_many (GST_BIN (pipeline), queue, sink, NULL);
474 fail_unless (gst_element_link_many (queue, sink, NULL));
476 sinkpad = gst_element_get_static_pad (queue, "sink");
477 fail_unless_equals_int (gst_pad_link (pad, sinkpad), GST_PAD_LINK_OK);
478 gst_object_unref (sinkpad);
480 gst_pad_add_buffer_probe (pad, G_CALLBACK (float_buffer_check_probe), NULL);
482 gst_element_set_state (sink, GST_STATE_PLAYING);
483 gst_element_set_state (queue, GST_STATE_PLAYING);
485 GST_LOG ("new pad: %s", GST_PAD_NAME (pad));
490 make_fake_src_8chans_float32 (void)
494 src = gst_element_factory_make ("fakesrc", "src");
495 fail_unless (src != NULL, "failed to create fakesrc element");
497 g_object_set (src, "num-buffers", 1, NULL);
498 g_object_set (src, "signal-handoffs", TRUE, NULL);
500 g_signal_connect (src, "handoff", G_CALLBACK (src_handoff_float32_8ch), NULL);
505 GST_START_TEST (test_8_channels_float32)
507 GstElement *pipeline, *src, *deinterleave;
510 pipeline = (GstElement *) gst_pipeline_new ("pipeline");
511 fail_unless (pipeline != NULL, "failed to create pipeline");
513 src = make_fake_src_8chans_float32 ();
515 deinterleave = gst_element_factory_make ("deinterleave", "deinterleave");
516 fail_unless (deinterleave != NULL, "failed to create deinterleave element");
517 g_object_set (deinterleave, "keep-positions", TRUE, NULL);
519 gst_bin_add_many (GST_BIN (pipeline), src, deinterleave, NULL);
521 fail_unless (gst_element_link (src, deinterleave),
522 "failed to link src <=> deinterleave");
524 g_signal_connect (deinterleave, "pad-added",
525 G_CALLBACK (pad_added_setup_data_check_float32_8ch_cb), pipeline);
529 gst_element_set_state (pipeline, GST_STATE_PLAYING);
531 msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
532 gst_message_unref (msg);
534 fail_unless_equals_int (pads_created, NUM_CHANNELS);
536 gst_element_set_state (pipeline, GST_STATE_NULL);
537 gst_object_unref (pipeline);
543 deinterleave_suite (void)
545 Suite *s = suite_create ("deinterleave");
546 TCase *tc_chain = tcase_create ("general");
548 suite_add_tcase (s, tc_chain);
549 tcase_set_timeout (tc_chain, 180);
550 tcase_add_test (tc_chain, test_create_and_unref);
551 tcase_add_test (tc_chain, test_2_channels);
552 tcase_add_test (tc_chain, test_2_channels_1_linked);
553 tcase_add_test (tc_chain, test_2_channels_caps_change);
554 tcase_add_test (tc_chain, test_8_channels_float32);
559 GST_CHECK_MAIN (deinterleave);