make %u in all request pad templates
[platform/upstream/gst-plugins-good.git] / tests / check / elements / matroskamux.c
1 /* GStreamer
2  *
3  * unit test for matroskamux
4  *
5  * Copyright (C) <2005> Michal Benes <michal.benes@xeris.cz>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <unistd.h>
24
25 #include <gst/check/gstcheck.h>
26 #include <gst/base/gstadapter.h>
27
28 /* For ease of programming we use globals to keep refs for our floating
29  * src and sink pads we create; otherwise we always have to do get_pad,
30  * get_peer, and then remove references in every test function */
31 GstPad *mysrcpad, *mysinkpad;
32
33 #define AC3_CAPS_STRING "audio/x-ac3, " \
34                         "channels = (int) 1, " \
35                         "rate = (int) 8000"
36 #define VORBIS_CAPS_STRING "audio/x-vorbis, " \
37                            "channels = (int) 1, " \
38                            "rate = (int) 8000, " \
39                            "streamheader=(buffer)<10, 2020, 303030>"
40
41 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
42     GST_PAD_SINK,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS ("video/x-matroska"));
45 static GstStaticPadTemplate srcvorbistemplate = GST_STATIC_PAD_TEMPLATE ("src",
46     GST_PAD_SRC,
47     GST_PAD_ALWAYS,
48     GST_STATIC_CAPS (VORBIS_CAPS_STRING));
49
50 static GstStaticPadTemplate srcac3template = GST_STATIC_PAD_TEMPLATE ("src",
51     GST_PAD_SRC,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS (AC3_CAPS_STRING));
54
55
56 static GstPad *
57 setup_src_pad (GstElement * element,
58     GstStaticPadTemplate * template, GstCaps * caps)
59 {
60   GstPad *srcpad, *sinkpad;
61
62   GST_DEBUG_OBJECT (element, "setting up sending pad");
63   /* sending pad */
64   srcpad = gst_pad_new_from_static_template (template, "src");
65   fail_if (srcpad == NULL, "Could not create a srcpad");
66   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
67   gst_pad_set_active (srcpad, TRUE);
68
69   if (!(sinkpad = gst_element_get_static_pad (element, "audio_%u")))
70     sinkpad = gst_element_get_request_pad (element, "audio_%u");
71   fail_if (sinkpad == NULL, "Could not get sink pad from %s",
72       GST_ELEMENT_NAME (element));
73   /* references are owned by: 1) us, 2) matroskamux, 3) collect pads */
74   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
75   if (caps)
76     fail_unless (gst_pad_set_caps (srcpad, caps));
77   fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
78       "Could not link source and %s sink pads", GST_ELEMENT_NAME (element));
79   gst_object_unref (sinkpad);   /* because we got it higher up */
80
81   /* references are owned by: 1) matroskamux, 2) collect pads */
82   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
83
84   return srcpad;
85 }
86
87 static void
88 teardown_src_pad (GstElement * element)
89 {
90   GstPad *srcpad, *sinkpad;
91
92   /* clean up floating src pad */
93   if (!(sinkpad = gst_element_get_static_pad (element, "audio_0")))
94     sinkpad = gst_element_get_request_pad (element, "audio_0");
95   /* references are owned by: 1) us, 2) matroskamux, 3) collect pads */
96   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
97   srcpad = gst_pad_get_peer (sinkpad);
98
99   gst_pad_unlink (srcpad, sinkpad);
100
101   /* references are owned by: 1) us, 2) matroskamux, 3) collect pads */
102   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 3);
103   gst_object_unref (sinkpad);
104   /* one more ref is held by element itself */
105
106   /* pad refs held by both creator and this function (through _get_peer) */
107   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
108   gst_object_unref (srcpad);
109   gst_object_unref (srcpad);
110 }
111
112 static GstPad *
113 setup_sink_pad (GstElement * element, GstStaticPadTemplate * template,
114     GstCaps * caps)
115 {
116   GstPad *srcpad, *sinkpad;
117
118   GST_DEBUG_OBJECT (element, "setting up receiving pad");
119   /* receiving pad */
120   sinkpad = gst_pad_new_from_static_template (template, "sink");
121
122   fail_if (sinkpad == NULL, "Could not create a sinkpad");
123   gst_pad_set_active (sinkpad, TRUE);
124
125   srcpad = gst_element_get_static_pad (element, "src");
126   fail_if (srcpad == NULL, "Could not get source pad from %s",
127       GST_ELEMENT_NAME (element));
128   if (caps)
129     fail_unless (gst_pad_set_caps (sinkpad, caps));
130   gst_pad_set_chain_function (sinkpad, gst_check_chain_func);
131
132   fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
133       "Could not link %s source and sink pads", GST_ELEMENT_NAME (element));
134   gst_object_unref (srcpad);    /* because we got it higher up */
135   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
136
137   return sinkpad;
138 }
139
140 static void
141 teardown_sink_pad (GstElement * element)
142 {
143   GstPad *srcpad, *sinkpad;
144
145   /* clean up floating sink pad */
146   srcpad = gst_element_get_static_pad (element, "src");
147   sinkpad = gst_pad_get_peer (srcpad);
148   gst_pad_unlink (srcpad, sinkpad);
149
150   /* pad refs held by both creator and this function (through _get_pad) */
151   ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 3);
152   gst_object_unref (srcpad);
153   /* one more ref is held by element itself */
154
155   /* pad refs held by both creator and this function (through _get_peer) */
156   ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
157   gst_object_unref (sinkpad);
158   gst_object_unref (sinkpad);
159 }
160
161
162 static GstElement *
163 setup_matroskamux (GstStaticPadTemplate * srctemplate)
164 {
165   GstElement *matroskamux;
166
167   GST_DEBUG ("setup_matroskamux");
168   matroskamux = gst_check_setup_element ("matroskamux");
169   g_object_set (matroskamux, "version", 1, NULL);
170   mysrcpad = setup_src_pad (matroskamux, srctemplate, NULL);
171   mysinkpad = setup_sink_pad (matroskamux, &sinktemplate, NULL);
172
173   return matroskamux;
174 }
175
176 static void
177 cleanup_matroskamux (GstElement * matroskamux)
178 {
179   GST_DEBUG ("cleanup_matroskamux");
180   gst_element_set_state (matroskamux, GST_STATE_NULL);
181
182   teardown_src_pad (matroskamux);
183   teardown_sink_pad (matroskamux);
184   gst_check_teardown_element (matroskamux);
185 }
186
187 static void
188 check_buffer_data (GstBuffer * buffer, void *data, size_t data_size)
189 {
190   fail_unless (GST_BUFFER_SIZE (buffer) == data_size);
191   fail_unless (memcmp (data, GST_BUFFER_DATA (buffer), data_size) == 0);
192 }
193
194 GST_START_TEST (test_ebml_header)
195 {
196   GstElement *matroskamux;
197   GstBuffer *inbuffer, *outbuffer;
198   GstAdapter *adapter;
199   int num_buffers;
200   int i;
201   gint available;
202   guint8 data[] =
203       { 0x1a, 0x45, 0xdf, 0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
204     0x42, 0x82, 0x89, 0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x00,
205     0x42, 0x87, 0x81, 0x01,
206     0x42, 0x85, 0x81, 0x01
207   };
208
209   matroskamux = setup_matroskamux (&srcac3template);
210   fail_unless (gst_element_set_state (matroskamux,
211           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
212       "could not set to playing");
213
214   inbuffer = gst_buffer_new_and_alloc (1);
215   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
216   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
217   num_buffers = g_list_length (buffers);
218   fail_unless (num_buffers >= 1,
219       "expected at least 5 buffers, but got only %d", num_buffers);
220
221   adapter = gst_adapter_new ();
222   for (i = 0; i < num_buffers; ++i) {
223     outbuffer = GST_BUFFER (buffers->data);
224     fail_if (outbuffer == NULL);
225     buffers = g_list_remove (buffers, outbuffer);
226
227     ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
228
229     gst_adapter_push (adapter, outbuffer);
230   }
231
232   available = gst_adapter_available (adapter);
233   fail_unless (available >= sizeof (data));
234   outbuffer = gst_adapter_take_buffer (adapter, sizeof (data));
235   g_object_unref (adapter);
236
237   check_buffer_data (outbuffer, data, sizeof (data));
238   gst_buffer_unref (outbuffer);
239
240   cleanup_matroskamux (matroskamux);
241   g_list_free (buffers);
242   buffers = NULL;
243 }
244
245 GST_END_TEST;
246
247
248 GST_START_TEST (test_vorbis_header)
249 {
250   GstElement *matroskamux;
251   GstBuffer *inbuffer, *outbuffer;
252   GstCaps *caps;
253   int num_buffers;
254   int i;
255   gboolean vorbis_header_found = FALSE;
256   guint8 data[12] =
257       { 0x63, 0xa2, 0x89, 0x02, 0x01, 0x02, 0x10, 0x20, 0x20, 0x30, 0x30,
258     0x30
259   };
260
261   matroskamux = setup_matroskamux (&srcvorbistemplate);
262   fail_unless (gst_element_set_state (matroskamux,
263           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
264       "could not set to playing");
265
266   inbuffer = gst_buffer_new_and_alloc (1);
267   caps = gst_caps_from_string (VORBIS_CAPS_STRING);
268   gst_buffer_set_caps (inbuffer, caps);
269   gst_caps_unref (caps);
270   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
271
272   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
273   num_buffers = g_list_length (buffers);
274
275   for (i = 0; i < num_buffers; ++i) {
276     gint j;
277
278     outbuffer = GST_BUFFER (buffers->data);
279     fail_if (outbuffer == NULL);
280     buffers = g_list_remove (buffers, outbuffer);
281
282     if (!vorbis_header_found && GST_BUFFER_SIZE (outbuffer) >= sizeof (data)) {
283       for (j = 0; j <= GST_BUFFER_SIZE (outbuffer) - sizeof (data); j++) {
284         if (memcmp (GST_BUFFER_DATA (outbuffer) + j, data, sizeof (data)) == 0) {
285           vorbis_header_found = TRUE;
286           break;
287         }
288       }
289     }
290
291     ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
292     gst_buffer_unref (outbuffer);
293     outbuffer = NULL;
294   }
295
296   fail_unless (vorbis_header_found);
297
298   cleanup_matroskamux (matroskamux);
299   g_list_free (buffers);
300   buffers = NULL;
301 }
302
303 GST_END_TEST;
304
305
306 GST_START_TEST (test_block_group)
307 {
308   GstElement *matroskamux;
309   GstBuffer *inbuffer, *outbuffer;
310   GstCaps *caps;
311   int num_buffers;
312   int i;
313   guint8 data0[] = { 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
314     0xa1, 0x85,
315     0x81, 0x00, 0x01, 0x00
316   };
317   guint8 data1[] = { 0x42 };
318
319   matroskamux = setup_matroskamux (&srcac3template);
320   fail_unless (gst_element_set_state (matroskamux,
321           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
322       "could not set to playing");
323
324   /* Generate the header */
325   inbuffer = gst_buffer_new_and_alloc (1);
326   GST_BUFFER_TIMESTAMP (inbuffer) = 0;
327   caps = gst_caps_from_string (AC3_CAPS_STRING);
328   gst_buffer_set_caps (inbuffer, caps);
329   gst_caps_unref (caps);
330   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
331
332   fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
333   num_buffers = g_list_length (buffers);
334
335   for (i = 0; i < num_buffers; ++i) {
336     outbuffer = GST_BUFFER (buffers->data);
337     fail_if (outbuffer == NULL);
338     buffers = g_list_remove (buffers, outbuffer);
339
340     ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
341     gst_buffer_unref (outbuffer);
342     outbuffer = NULL;
343   }
344
345   g_list_free (buffers);
346   buffers = NULL;
347
348   /* Now push a buffer */
349   inbuffer = gst_buffer_new_and_alloc (1);
350   GST_BUFFER_DATA (inbuffer)[0] = 0x42;
351   GST_BUFFER_TIMESTAMP (inbuffer) = 1000000;
352   caps = gst_caps_from_string (AC3_CAPS_STRING);
353   gst_buffer_set_caps (inbuffer, caps);
354   gst_caps_unref (caps);
355   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
356
357   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
358   num_buffers = g_list_length (buffers);
359   fail_unless (num_buffers >= 2);
360
361   for (i = 0; i < num_buffers; ++i) {
362     outbuffer = GST_BUFFER (buffers->data);
363     fail_if (outbuffer == NULL);
364     buffers = g_list_remove (buffers, outbuffer);
365
366     switch (i) {
367       case 0:
368         check_buffer_data (outbuffer, data0, sizeof (data0));
369         break;
370       case 1:
371         check_buffer_data (outbuffer, data1, sizeof (data1));
372         break;
373       default:
374         break;
375     }
376
377     ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
378     gst_buffer_unref (outbuffer);
379     outbuffer = NULL;
380   }
381
382   g_list_free (buffers);
383   buffers = NULL;
384
385   cleanup_matroskamux (matroskamux);
386 }
387
388 GST_END_TEST;
389
390 GST_START_TEST (test_reset)
391 {
392   GstElement *matroskamux;
393   GstBuffer *inbuffer;
394   GstBuffer *outbuffer;
395   int num_buffers;
396   int i;
397
398   matroskamux = setup_matroskamux (&srcac3template);
399   fail_unless (gst_element_set_state (matroskamux,
400           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
401       "could not set to playing");
402
403   inbuffer = gst_buffer_new_and_alloc (1);
404   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
405   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
406   num_buffers = g_list_length (buffers);
407   fail_unless (num_buffers >= 1,
408       "expected at least 1 buffer, but got only %d", num_buffers);
409
410   fail_unless (gst_element_set_state (matroskamux,
411           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
412
413   fail_unless (gst_element_set_state (matroskamux,
414           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
415       "could not set to playing");
416
417   inbuffer = gst_buffer_new_and_alloc (1);
418   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
419   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
420   num_buffers = g_list_length (buffers);
421   fail_unless (num_buffers >= 2,
422       "expected at least 2 buffers, but got only %d", num_buffers);
423
424   for (i = 0; i < num_buffers; ++i) {
425     outbuffer = GST_BUFFER (buffers->data);
426     fail_if (outbuffer == NULL);
427     buffers = g_list_remove (buffers, outbuffer);
428
429     ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
430     gst_buffer_unref (outbuffer);
431   }
432
433   cleanup_matroskamux (matroskamux);
434   g_list_free (buffers);
435   buffers = NULL;
436 }
437
438 GST_END_TEST;
439
440 static Suite *
441 matroskamux_suite (void)
442 {
443   Suite *s = suite_create ("matroskamux");
444   TCase *tc_chain = tcase_create ("general");
445
446   suite_add_tcase (s, tc_chain);
447   tcase_add_test (tc_chain, test_ebml_header);
448   tcase_add_test (tc_chain, test_vorbis_header);
449   tcase_add_test (tc_chain, test_block_group);
450   tcase_add_test (tc_chain, test_reset);
451
452   return s;
453 }
454
455 int
456 main (int argc, char **argv)
457 {
458   int nf;
459
460   Suite *s = matroskamux_suite ();
461   SRunner *sr = srunner_create (s);
462
463   gst_check_init (&argc, &argv);
464
465   srunner_run_all (sr, CK_NORMAL);
466   nf = srunner_ntests_failed (sr);
467   srunner_free (sr);
468
469   return nf;
470 }