Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / tests / check / elements / deinterleave.c
1 /* GStreamer unit tests for the interleave element
2  * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <gst/check/gstcheck.h>
26 #include <gst/audio/multichannel.h>
27
28 GST_START_TEST (test_create_and_unref)
29 {
30   GstElement *deinterleave;
31
32   deinterleave = gst_element_factory_make ("deinterleave", NULL);
33   fail_unless (deinterleave != NULL);
34
35   gst_element_set_state (deinterleave, GST_STATE_NULL);
36   gst_object_unref (deinterleave);
37 }
38
39 GST_END_TEST;
40
41 static GstPad *mysrcpad, **mysinkpads;
42 static gint nsinkpads;
43 static GstBus *bus;
44 static GstElement *deinterleave;
45
46 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
47     GST_PAD_SINK,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS ("audio/x-raw-float, "
50         "width = (int) 32, "
51         "channels = (int) 1, "
52         "rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER"));
53
54 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
55     GST_PAD_SRC,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS ("audio/x-raw-float, "
58         "width = (int) 32, "
59         "channels = (int) { 2, 3 }, "
60         "rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER"));
61
62 #define CAPS_32khz \
63          "audio/x-raw-float, " \
64         "width = (int) 32, " \
65         "channels = (int) 2, " \
66         "rate = (int) 32000, " \
67         "endianness = (int) BYTE_ORDER"
68
69 #define CAPS_48khz \
70          "audio/x-raw-float, " \
71         "width = (int) 32, " \
72         "channels = (int) 2, " \
73         "rate = (int) 48000, " \
74         "endianness = (int) BYTE_ORDER"
75
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"
82
83 static GstFlowReturn
84 deinterleave_chain_func (GstPad * pad, GstBuffer * buffer)
85 {
86   gint i;
87   gfloat *indata;
88
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);
92
93   indata = (gfloat *) GST_BUFFER_DATA (buffer);
94
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);
101   } else {
102     g_assert_not_reached ();
103   }
104
105   gst_buffer_unref (buffer);
106
107   return GST_FLOW_OK;
108 }
109
110 static void
111 deinterleave_pad_added (GstElement * src, GstPad * pad, gpointer data)
112 {
113   gchar *name;
114   gint link = GPOINTER_TO_INT (data);
115
116   if (nsinkpads >= link)
117     return;
118
119   name = g_strdup_printf ("sink%d", nsinkpads);
120
121   mysinkpads[nsinkpads] =
122       gst_pad_new_from_static_template (&sinktemplate, name);
123   g_free (name);
124   fail_if (mysinkpads[nsinkpads] == NULL);
125
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);
129   nsinkpads++;
130 }
131
132 GST_START_TEST (test_2_channels)
133 {
134   GstPad *sinkpad;
135   gint i;
136   GstBuffer *inbuf;
137   GstCaps *caps;
138   gfloat *indata;
139
140   mysinkpads = g_new0 (GstPad *, 2);
141   nsinkpads = 0;
142
143   deinterleave = gst_element_factory_make ("deinterleave", NULL);
144   fail_unless (deinterleave != NULL);
145
146   mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
147   fail_unless (mysrcpad != NULL);
148
149   caps = gst_caps_from_string (CAPS_48khz);
150   fail_unless (gst_pad_set_caps (mysrcpad, caps));
151   gst_pad_use_fixed_caps (mysrcpad);
152
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);
157
158   g_signal_connect (deinterleave, "pad-added",
159       G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
160
161   bus = gst_bus_new ();
162   gst_element_set_bus (deinterleave, bus);
163
164   fail_unless (gst_element_set_state (deinterleave,
165           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
166
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) {
170     indata[i] = -1.0;
171     indata[i + 1] = 1.0;
172   }
173   gst_buffer_set_caps (inbuf, caps);
174
175   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
176
177   fail_unless (gst_element_set_state (deinterleave,
178           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
179
180   for (i = 0; i < nsinkpads; i++)
181     g_object_unref (mysinkpads[i]);
182   g_free (mysinkpads);
183   mysinkpads = NULL;
184
185   g_object_unref (deinterleave);
186   g_object_unref (bus);
187   gst_caps_unref (caps);
188 }
189
190 GST_END_TEST;
191
192 GST_START_TEST (test_2_channels_1_linked)
193 {
194   GstPad *sinkpad;
195   gint i;
196   GstBuffer *inbuf;
197   GstCaps *caps;
198   gfloat *indata;
199
200   nsinkpads = 0;
201   mysinkpads = g_new0 (GstPad *, 2);
202
203   deinterleave = gst_element_factory_make ("deinterleave", NULL);
204   fail_unless (deinterleave != NULL);
205
206   mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
207   fail_unless (mysrcpad != NULL);
208
209   caps = gst_caps_from_string (CAPS_48khz);
210   fail_unless (gst_pad_set_caps (mysrcpad, caps));
211   gst_pad_use_fixed_caps (mysrcpad);
212
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);
217
218   g_signal_connect (deinterleave, "pad-added",
219       G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (1));
220
221   bus = gst_bus_new ();
222   gst_element_set_bus (deinterleave, bus);
223
224   fail_unless (gst_element_set_state (deinterleave,
225           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
226
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) {
230     indata[i] = -1.0;
231     indata[i + 1] = 1.0;
232   }
233   gst_buffer_set_caps (inbuf, caps);
234
235   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
236
237   fail_unless (gst_element_set_state (deinterleave,
238           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
239
240   for (i = 0; i < nsinkpads; i++)
241     g_object_unref (mysinkpads[i]);
242   g_free (mysinkpads);
243   mysinkpads = NULL;
244
245   g_object_unref (deinterleave);
246   g_object_unref (bus);
247   gst_caps_unref (caps);
248 }
249
250 GST_END_TEST;
251
252 GST_START_TEST (test_2_channels_caps_change)
253 {
254   GstPad *sinkpad;
255   GstCaps *caps, *caps2;
256   gint i;
257   GstBuffer *inbuf;
258   gfloat *indata;
259
260   nsinkpads = 0;
261   mysinkpads = g_new0 (GstPad *, 2);
262
263   deinterleave = gst_element_factory_make ("deinterleave", NULL);
264   fail_unless (deinterleave != NULL);
265
266   mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
267   fail_unless (mysrcpad != NULL);
268
269   caps = gst_caps_from_string (CAPS_48khz);
270   fail_unless (gst_pad_set_caps (mysrcpad, caps));
271   gst_pad_use_fixed_caps (mysrcpad);
272
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);
277
278   g_signal_connect (deinterleave, "pad-added",
279       G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
280
281   bus = gst_bus_new ();
282   gst_element_set_bus (deinterleave, bus);
283
284   fail_unless (gst_element_set_state (deinterleave,
285           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
286
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) {
290     indata[i] = -1.0;
291     indata[i + 1] = 1.0;
292   }
293   gst_buffer_set_caps (inbuf, caps);
294
295   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
296
297   caps2 = gst_caps_from_string (CAPS_32khz);
298   gst_pad_set_caps (mysrcpad, caps2);
299
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) {
303     indata[i] = -1.0;
304     indata[i + 1] = 1.0;
305   }
306   gst_buffer_set_caps (inbuf, caps2);
307
308   /* Should work fine because the caps changed in a compatible way */
309   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
310
311   gst_caps_unref (caps2);
312
313   caps2 = gst_caps_from_string (CAPS_48khz_3CH);
314   gst_pad_set_caps (mysrcpad, caps2);
315
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) {
319     indata[i] = -1.0;
320     indata[i + 1] = 1.0;
321     indata[i + 2] = 0.0;
322   }
323   gst_buffer_set_caps (inbuf, caps2);
324
325   /* Should break because the caps changed in an incompatible way */
326   fail_if (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
327
328   fail_unless (gst_element_set_state (deinterleave,
329           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
330
331   for (i = 0; i < nsinkpads; i++)
332     g_object_unref (mysinkpads[i]);
333   g_free (mysinkpads);
334   mysinkpads = NULL;
335
336   g_object_unref (deinterleave);
337   g_object_unref (bus);
338   gst_caps_unref (caps);
339   gst_caps_unref (caps2);
340 }
341
342 GST_END_TEST;
343
344
345 #define SAMPLES_PER_BUFFER  10
346 #define NUM_CHANNELS        8
347 #define SAMPLE_RATE         44100
348
349 static guint pads_created;
350
351 static void
352 set_channel_positions (GstCaps * caps, int channels,
353     GstAudioChannelPosition * channelpositions)
354 {
355   GValue chanpos = { 0 };
356   GValue pos = { 0 };
357   GstStructure *structure = gst_caps_get_structure (caps, 0);
358   int c;
359
360   g_value_init (&chanpos, GST_TYPE_ARRAY);
361   g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
362
363   for (c = 0; c < channels; c++) {
364     g_value_set_enum (&pos, channelpositions[c]);
365     gst_value_array_append_value (&chanpos, &pos);
366   }
367   g_value_unset (&pos);
368
369   gst_structure_set_value (structure, "channel-positions", &chanpos);
370   g_value_unset (&chanpos);
371 }
372
373 static void
374 src_handoff_float32_8ch (GstElement * src, GstBuffer * buf, GstPad * pad,
375     gpointer user_data)
376 {
377   GstAudioChannelPosition layout[NUM_CHANNELS];
378   GstCaps *caps;
379   gfloat *data;
380   guint size, i, c;
381
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);
388
389   for (i = 0; i < NUM_CHANNELS; ++i)
390     layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
391
392   set_channel_positions (caps, NUM_CHANNELS, layout);
393
394   size = sizeof (gfloat) * SAMPLES_PER_BUFFER * NUM_CHANNELS;
395   data = (gfloat *) g_malloc (size);
396
397   GST_BUFFER_MALLOCDATA (buf) = (guint8 *) data;
398   GST_BUFFER_DATA (buf) = (guint8 *) data;
399   GST_BUFFER_SIZE (buf) = size;
400
401   GST_BUFFER_OFFSET (buf) = 0;
402   GST_BUFFER_TIMESTAMP (buf) = 0;
403
404   GST_BUFFER_CAPS (buf) = caps;
405
406   for (i = 0; i < SAMPLES_PER_BUFFER; ++i) {
407     for (c = 0; c < NUM_CHANNELS; ++c) {
408       *data = (gfloat) ((i * NUM_CHANNELS) + c);
409       ++data;
410     }
411   }
412 }
413
414 static gboolean
415 float_buffer_check_probe (GstPad * pad, GstBuffer * buf, gpointer userdata)
416 {
417   gfloat *data;
418   guint padnum, numpads;
419   guint num, i;
420   GstCaps *caps;
421   GstStructure *s;
422   GstAudioChannelPosition *pos;
423   gint channels;
424
425   fail_unless_equals_int (sscanf (GST_PAD_NAME (pad), "src%u", &padnum), 1);
426
427   numpads = pads_created;
428
429   /* Check caps */
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);
438   g_free (pos);
439
440   data = (gfloat *) GST_BUFFER_DATA (buf);
441   num = GST_BUFFER_SIZE (buf) / sizeof (gfloat);
442
443   /* Check buffer content */
444   for (i = 0; i < num; ++i) {
445     guint val, rest;
446
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);
455   }
456
457   return TRUE;                  /* don't drop data */
458 }
459
460 static void
461 pad_added_setup_data_check_float32_8ch_cb (GstElement * deinterleave,
462     GstPad * pad, GstElement * pipeline)
463 {
464   GstElement *queue, *sink;
465   GstPad *sinkpad;
466
467   queue = gst_element_factory_make ("queue", NULL);
468   fail_unless (queue != NULL);
469
470   sink = gst_element_factory_make ("fakesink", NULL);
471   fail_unless (sink != NULL);
472
473   gst_bin_add_many (GST_BIN (pipeline), queue, sink, NULL);
474   fail_unless (gst_element_link_many (queue, sink, NULL));
475
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);
479
480   gst_pad_add_buffer_probe (pad, G_CALLBACK (float_buffer_check_probe), NULL);
481
482   gst_element_set_state (sink, GST_STATE_PLAYING);
483   gst_element_set_state (queue, GST_STATE_PLAYING);
484
485   GST_LOG ("new pad: %s", GST_PAD_NAME (pad));
486   ++pads_created;
487 }
488
489 static GstElement *
490 make_fake_src_8chans_float32 (void)
491 {
492   GstElement *src;
493
494   src = gst_element_factory_make ("fakesrc", "src");
495   fail_unless (src != NULL, "failed to create fakesrc element");
496
497   g_object_set (src, "num-buffers", 1, NULL);
498   g_object_set (src, "signal-handoffs", TRUE, NULL);
499
500   g_signal_connect (src, "handoff", G_CALLBACK (src_handoff_float32_8ch), NULL);
501
502   return src;
503 }
504
505 GST_START_TEST (test_8_channels_float32)
506 {
507   GstElement *pipeline, *src, *deinterleave;
508   GstMessage *msg;
509
510   pipeline = (GstElement *) gst_pipeline_new ("pipeline");
511   fail_unless (pipeline != NULL, "failed to create pipeline");
512
513   src = make_fake_src_8chans_float32 ();
514
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);
518
519   gst_bin_add_many (GST_BIN (pipeline), src, deinterleave, NULL);
520
521   fail_unless (gst_element_link (src, deinterleave),
522       "failed to link src <=> deinterleave");
523
524   g_signal_connect (deinterleave, "pad-added",
525       G_CALLBACK (pad_added_setup_data_check_float32_8ch_cb), pipeline);
526
527   pads_created = 0;
528
529   gst_element_set_state (pipeline, GST_STATE_PLAYING);
530
531   msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
532   gst_message_unref (msg);
533
534   fail_unless_equals_int (pads_created, NUM_CHANNELS);
535
536   gst_element_set_state (pipeline, GST_STATE_NULL);
537   gst_object_unref (pipeline);
538 }
539
540 GST_END_TEST;
541
542 static Suite *
543 deinterleave_suite (void)
544 {
545   Suite *s = suite_create ("deinterleave");
546   TCase *tc_chain = tcase_create ("general");
547
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);
555
556   return s;
557 }
558
559 GST_CHECK_MAIN (deinterleave);