3 * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
24 #include <gst/check/gstcheck.h>
25 #include <gst/dataprotocol/dataprotocol.h>
27 gboolean have_eos = FALSE;
29 /* For ease of programming we use globals to keep refs for our floating
30 * src and sink pads we create; otherwise we always have to do get_pad,
31 * get_peer, and then remove references in every test function */
32 GstPad *mysrcpad, *myshsrcpad, *mysinkpad;
34 #define AUDIO_CAPS_TEMPLATE_STRING \
36 "rate = (int) [ 1, MAX ], " \
37 "channels = (int) [ 1, 8 ], " \
38 "endianness = (int) BYTE_ORDER, " \
39 "width = (int) {8, 16}, " \
40 "depth = (int) {8, 16}, " \
41 "signed = (boolean) true"
43 #define AUDIO_CAPS_STRING \
45 "rate = (int) 1000, " \
46 "channels = (int) 2, " \
47 "endianness = (int) BYTE_ORDER, " \
48 "width = (int) 16, " \
49 "depth = (int) 16, " \
50 "signed = (boolean) true"
53 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
56 GST_STATIC_CAPS ("application/x-gdp")
58 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
61 GST_STATIC_CAPS (AUDIO_CAPS_TEMPLATE_STRING)
64 /* takes over reference for outcaps */
70 GST_DEBUG ("setup_gdppay");
71 gdppay = gst_check_setup_element ("gdppay");
72 mysrcpad = gst_check_setup_src_pad (gdppay, &srctemplate, NULL);
73 mysinkpad = gst_check_setup_sink_pad (gdppay, &sinktemplate, NULL);
74 gst_pad_set_active (mysrcpad, TRUE);
75 gst_pad_set_active (mysinkpad, TRUE);
81 cleanup_gdppay (GstElement * gdppay)
83 GST_DEBUG ("cleanup_gdppay");
85 gst_pad_set_active (mysrcpad, FALSE);
86 gst_pad_set_active (mysinkpad, FALSE);
87 gst_check_teardown_src_pad (gdppay);
88 gst_check_teardown_sink_pad (gdppay);
89 gst_check_teardown_element (gdppay);
92 GST_START_TEST (test_audio)
96 GstBuffer *inbuffer, *outbuffer;
101 gdppay = setup_gdppay ();
103 fail_unless (gst_element_set_state (gdppay,
104 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
105 "could not set to playing");
107 GST_DEBUG ("new segment");
109 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_SECOND, 0);
110 fail_unless (gst_pad_push_event (mysrcpad, event));
112 /* no buffer should be pushed yet, waiting for caps */
113 fail_unless_equals_int (g_list_length (buffers), 0);
115 GST_DEBUG ("first buffer");
116 inbuffer = gst_buffer_new_and_alloc (4);
117 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
118 gst_buffer_set_caps (inbuffer, caps);
119 caps_string = gst_caps_to_string (caps);
121 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
123 /* pushing gives away my reference */
124 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
126 /* we should have three buffers now */
127 fail_unless_equals_int (g_list_length (buffers), 3);
129 /* first buffer is the serialized new_segment event;
130 * the element also holds a ref to it */
131 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
132 buffers = g_list_remove (buffers, outbuffer);
133 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
134 gst_buffer_unref (outbuffer);
136 /* second buffer is the serialized caps;
137 * the element also holds a ref to it */
138 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
139 buffers = g_list_remove (buffers, outbuffer);
140 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
141 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
142 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
143 gst_buffer_unref (outbuffer);
145 /* the third buffer is the GDP buffer for our pushed buffer */
146 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
147 buffers = g_list_remove (buffers, outbuffer);
148 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
149 length = GST_DP_HEADER_LENGTH + 4;
150 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
151 gst_buffer_unref (outbuffer);
154 GST_DEBUG ("second buffer");
155 inbuffer = gst_buffer_new_and_alloc (4);
156 gst_buffer_set_caps (inbuffer, caps);
158 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
160 /* pushing gives away my reference */
161 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
163 fail_unless_equals_int (g_list_length (buffers), 1);
164 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
165 buffers = g_list_remove (buffers, outbuffer);
166 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
168 /* the third output buffer is data */
169 length = GST_DP_HEADER_LENGTH + 4;
170 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
171 gst_buffer_unref (outbuffer);
173 /* a third buffer without caps set explicitly; should work */
174 GST_DEBUG ("Creating third buffer, no caps set");
175 inbuffer = gst_buffer_new_and_alloc (4);
177 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
179 /* pushing gives away my reference */
180 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
182 fail_unless_equals_int (g_list_length (buffers), 1);
183 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
184 buffers = g_list_remove (buffers, outbuffer);
185 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
187 /* the fourth output buffer is data */
188 length = GST_DP_HEADER_LENGTH + 4;
189 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
190 gst_buffer_unref (outbuffer);
193 fail_unless (gst_element_set_state (gdppay,
194 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
196 gst_caps_unref (caps);
197 g_free (caps_string);
198 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
199 g_list_free (buffers);
201 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
202 gst_object_unref (gdppay);
207 static GstStaticPadTemplate shsrctemplate = GST_STATIC_PAD_TEMPLATE ("src",
210 GST_STATIC_CAPS ("application/x-gst-test-streamheader")
215 setup_gdppay_streamheader ()
219 GST_DEBUG ("setup_gdppay");
220 gdppay = gst_check_setup_element ("gdppay");
221 myshsrcpad = gst_check_setup_src_pad (gdppay, &shsrctemplate, NULL);
222 mysinkpad = gst_check_setup_sink_pad (gdppay, &sinktemplate, NULL);
227 /* this test serializes a stream that already has a streamheader of its own.
228 * the streamheader should then be serialized and put on the GDP stream's
230 GST_START_TEST (test_streamheader)
232 GstCaps *caps, *sinkcaps;
234 GstBuffer *inbuffer, *outbuffer, *shbuffer;
238 GstStructure *structure;
239 GValue array = { 0 };
240 GValue value = { 0 };
245 gdppay = setup_gdppay_streamheader ();
247 fail_unless (gst_element_set_state (gdppay,
248 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
249 "could not set to playing");
251 GST_DEBUG ("new segment");
253 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_SECOND, 0);
254 fail_unless (gst_pad_push_event (myshsrcpad, event));
256 /* no buffer should be pushed yet, still waiting for caps */
257 fail_unless_equals_int (g_list_length (buffers), 0);
259 GST_DEBUG ("first buffer");
260 inbuffer = gst_buffer_new_and_alloc (4);
261 memcpy (GST_BUFFER_DATA (inbuffer), "head", 4);
262 caps = gst_caps_from_string ("application/x-gst-test-streamheader");
263 structure = gst_caps_get_structure (caps, 0);
264 GST_BUFFER_FLAG_SET (inbuffer, GST_BUFFER_FLAG_IN_CAPS);
265 g_value_init (&array, GST_TYPE_ARRAY);
266 g_value_init (&value, GST_TYPE_BUFFER);
267 shbuffer = gst_buffer_copy (inbuffer);
268 gst_value_set_buffer (&value, shbuffer);
269 gst_buffer_unref (shbuffer);
270 gst_value_array_append_value (&array, &value);
271 g_value_unset (&value);
272 gst_structure_set_value (structure, "streamheader", &array);
273 g_value_unset (&array);
274 caps_string = gst_caps_to_string (caps);
276 gst_buffer_set_caps (inbuffer, caps);
277 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
279 /* pushing gives away my reference */
280 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
282 /* we should have three buffers now */
283 fail_unless_equals_int (g_list_length (buffers), 3);
285 /* our sink pad should now have GDP caps with a streamheader that includes
286 * GDP wrappings of our streamheader */
287 sinkcaps = gst_pad_get_negotiated_caps (mysinkpad);
288 structure = gst_caps_get_structure (sinkcaps, 0);
289 fail_unless_equals_string ((gchar *) gst_structure_get_name (structure),
290 "application/x-gdp");
291 fail_unless (gst_structure_has_field (structure, "streamheader"));
292 sh = gst_structure_get_value (structure, "streamheader");
293 fail_unless (G_VALUE_TYPE (sh) == GST_TYPE_ARRAY);
294 shbuffers = g_value_peek_pointer (sh);
295 /* a serialized new_segment, a serialized caps, and serialization of our
296 * incoming streamheader */
297 fail_unless_equals_int (shbuffers->len, 3);
299 gst_caps_unref (sinkcaps);
301 /* first buffer is the serialized new_segment event;
302 * the element also holds a ref to it */
303 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
304 buffers = g_list_remove (buffers, outbuffer);
305 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
306 gst_buffer_unref (outbuffer);
308 /* second buffer is the serialized caps;
309 * the element also holds a ref to it */
310 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
311 buffers = g_list_remove (buffers, outbuffer);
312 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
313 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
314 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
315 gst_buffer_unref (outbuffer);
317 /* the third buffer is the GDP buffer for our pushed buffer */
318 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
319 buffers = g_list_remove (buffers, outbuffer);
320 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
321 length = GST_DP_HEADER_LENGTH + 4;
322 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
323 gst_buffer_unref (outbuffer);
326 GST_DEBUG ("second buffer");
327 inbuffer = gst_buffer_new_and_alloc (4);
328 gst_buffer_set_caps (inbuffer, caps);
330 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
332 /* pushing gives away my reference */
333 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
335 fail_unless_equals_int (g_list_length (buffers), 1);
336 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
337 buffers = g_list_remove (buffers, outbuffer);
338 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
340 /* the third output buffer is data */
341 length = GST_DP_HEADER_LENGTH + 4;
342 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
343 gst_buffer_unref (outbuffer);
345 /* a third buffer without caps set explicitly; should work */
346 GST_DEBUG ("Creating third buffer, no caps set");
347 inbuffer = gst_buffer_new_and_alloc (4);
349 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
351 /* pushing gives away my reference */
352 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
354 fail_unless_equals_int (g_list_length (buffers), 1);
355 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
356 buffers = g_list_remove (buffers, outbuffer);
357 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
359 /* the fourth output buffer is data */
360 length = GST_DP_HEADER_LENGTH + 4;
361 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
362 gst_buffer_unref (outbuffer);
365 fail_unless (gst_element_set_state (gdppay,
366 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
368 gst_caps_unref (caps);
369 g_free (caps_string);
370 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
371 g_list_free (buffers);
373 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
374 gst_object_unref (gdppay);
380 GST_START_TEST (test_first_no_caps)
385 gdppay = setup_gdppay ();
387 fail_unless (gst_element_set_state (gdppay,
388 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
389 "could not set to playing");
391 GST_DEBUG ("first buffer");
392 inbuffer = gst_buffer_new_and_alloc (4);
393 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
395 /* pushing should trigger an error */
396 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_NOT_NEGOTIATED);
398 fail_unless_equals_int (g_list_length (buffers), 0);
400 fail_unless (gst_element_set_state (gdppay,
401 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
403 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
404 g_list_free (buffers);
406 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
407 gst_object_unref (gdppay);
412 /* element should still work if no new_segment is sent before the first
414 GST_START_TEST (test_first_no_new_segment)
420 gdppay = setup_gdppay ();
422 fail_unless (gst_element_set_state (gdppay,
423 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
424 "could not set to playing");
426 GST_DEBUG ("first buffer");
427 inbuffer = gst_buffer_new_and_alloc (4);
428 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
429 gst_buffer_set_caps (inbuffer, caps);
431 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
433 /* pushing gives away my reference */
434 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
436 /* we should have three buffers now;
437 * one for an "invented" new segment, one for GDP caps, and one with our
439 fail_unless_equals_int (g_list_length (buffers), 3);
441 fail_unless (gst_element_set_state (gdppay,
442 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
444 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
445 g_list_free (buffers);
447 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
448 gst_object_unref (gdppay);
453 GST_START_TEST (test_crc)
457 GstBuffer *inbuffer, *outbuffer;
461 guint16 crc_calculated, crc_read;
463 gdppay = setup_gdppay ();
464 g_object_set (gdppay, "crc-header", TRUE, NULL);
466 fail_unless (gst_element_set_state (gdppay,
467 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
468 "could not set to playing");
470 GST_DEBUG ("new segment");
472 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_SECOND, 0);
473 fail_unless (gst_pad_push_event (mysrcpad, event));
475 /* no buffer should be pushed yet, waiting for caps */
476 fail_unless_equals_int (g_list_length (buffers), 0);
478 GST_DEBUG ("first buffer");
479 inbuffer = gst_buffer_new_and_alloc (4);
480 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
481 gst_buffer_set_caps (inbuffer, caps);
482 caps_string = gst_caps_to_string (caps);
484 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
486 /* pushing gives away my reference */
487 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
489 /* we should have three buffers now */
490 fail_unless_equals_int (g_list_length (buffers), 3);
492 /* first buffer is the serialized new_segment event;
493 * the element also holds a ref to it */
494 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
495 buffers = g_list_remove (buffers, outbuffer);
496 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
498 /* verify the header checksum */
499 /* CRC's start at 58 in the header */
500 crc_calculated = gst_dp_crc (GST_BUFFER_DATA (outbuffer), 58);
501 crc_read = GST_READ_UINT16_BE (GST_BUFFER_DATA (outbuffer) + 58);
502 fail_unless_equals_int (crc_calculated, crc_read);
504 /* change a byte in the header and verify that the checksum now fails */
505 GST_BUFFER_DATA (outbuffer)[0] = 0xff;
506 crc_calculated = gst_dp_crc (GST_BUFFER_DATA (outbuffer), 58);
507 fail_if (crc_calculated == crc_read,
508 "Introducing a byte error in the header should make the checksum fail");
510 gst_buffer_unref (outbuffer);
512 /* second buffer is the serialized caps;
513 * the element also holds a ref to it */
514 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
515 buffers = g_list_remove (buffers, outbuffer);
516 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
517 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
518 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
519 gst_buffer_unref (outbuffer);
521 /* the third buffer is the GDP buffer for our pushed buffer */
522 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
523 buffers = g_list_remove (buffers, outbuffer);
524 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
525 length = GST_DP_HEADER_LENGTH + 4;
526 fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
527 gst_buffer_unref (outbuffer);
529 fail_unless (gst_element_set_state (gdppay,
530 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
532 gst_caps_unref (caps);
533 g_free (caps_string);
534 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
535 g_list_free (buffers);
537 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
538 gst_object_unref (gdppay);
547 Suite *s = suite_create ("gdppay");
548 TCase *tc_chain = tcase_create ("general");
550 suite_add_tcase (s, tc_chain);
551 tcase_add_test (tc_chain, test_audio);
552 tcase_add_test (tc_chain, test_first_no_caps);
553 tcase_add_test (tc_chain, test_first_no_new_segment);
554 tcase_add_test (tc_chain, test_streamheader);
555 tcase_add_test (tc_chain, test_crc);
561 main (int argc, char **argv)
565 Suite *s = gdppay_suite ();
566 SRunner *sr = srunner_create (s);
568 gst_check_init (&argc, &argv);
570 srunner_run_all (sr, CK_NORMAL);
571 nf = srunner_ntests_failed (sr);