|
1 /* GStreamer |
|
2 * |
|
3 * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org> |
|
4 * |
|
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. |
|
9 * |
|
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. |
|
14 * |
|
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. |
|
19 */ |
|
20 |
|
21 #include "config.h" |
|
22 #include <string.h> |
|
23 #include <unistd.h> |
|
24 |
|
25 #include <gst/check/gstcheck.h> |
|
26 #include <gst/dataprotocol/dataprotocol.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 static GstPad *mysrcpad, *mysinkpad, *myshsinkpad; |
|
32 |
|
33 #define AUDIO_CAPS_TEMPLATE_STRING \ |
|
34 "audio/x-raw-int, " \ |
|
35 "rate = (int) [ 1, MAX ], " \ |
|
36 "channels = (int) [ 1, 8 ], " \ |
|
37 "endianness = (int) BYTE_ORDER, " \ |
|
38 "width = (int) {8, 16}, " \ |
|
39 "depth = (int) {8, 16}, " \ |
|
40 "signed = (boolean) true" |
|
41 |
|
42 #define AUDIO_CAPS_STRING \ |
|
43 "audio/x-raw-int, " \ |
|
44 "rate = (int) 1000, " \ |
|
45 "channels = (int) 2, " \ |
|
46 "endianness = (int) BYTE_ORDER, " \ |
|
47 "width = (int) 16, " \ |
|
48 "depth = (int) 16, " \ |
|
49 "signed = (boolean) true" |
|
50 |
|
51 |
|
52 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", |
|
53 GST_PAD_SINK, |
|
54 GST_PAD_ALWAYS, |
|
55 GST_STATIC_CAPS (AUDIO_CAPS_TEMPLATE_STRING) |
|
56 ); |
|
57 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", |
|
58 GST_PAD_SRC, |
|
59 GST_PAD_ALWAYS, |
|
60 GST_STATIC_CAPS ("application/x-gdp") |
|
61 ); |
|
62 |
|
63 /* takes over reference for outcaps */ |
|
64 static GstElement * |
|
65 setup_gdpdepay (void) |
|
66 { |
|
67 GstElement *gdpdepay; |
|
68 |
|
69 GST_DEBUG ("setup_gdpdepay"); |
|
70 gdpdepay = gst_check_setup_element ("gdpdepay"); |
|
71 mysrcpad = gst_check_setup_src_pad (gdpdepay, &srctemplate, NULL); |
|
72 mysinkpad = gst_check_setup_sink_pad (gdpdepay, &sinktemplate, NULL); |
|
73 gst_pad_set_active (mysrcpad, TRUE); |
|
74 gst_pad_set_active (mysinkpad, TRUE); |
|
75 |
|
76 return gdpdepay; |
|
77 } |
|
78 |
|
79 static void |
|
80 cleanup_gdpdepay (GstElement * gdpdepay) |
|
81 { |
|
82 GST_DEBUG ("cleanup_gdpdepay"); |
|
83 |
|
84 gst_pad_set_active (mysrcpad, FALSE); |
|
85 if (mysinkpad) |
|
86 gst_pad_set_active (mysinkpad, FALSE); |
|
87 if (myshsinkpad) |
|
88 gst_pad_set_active (myshsinkpad, FALSE); |
|
89 gst_check_teardown_src_pad (gdpdepay); |
|
90 gst_check_teardown_sink_pad (gdpdepay); |
|
91 gst_check_teardown_element (gdpdepay); |
|
92 mysinkpad = NULL; |
|
93 myshsinkpad = NULL; |
|
94 } |
|
95 |
|
96 static void |
|
97 gdpdepay_push_per_byte (gchar * reason, guint8 * bytes, guint length) |
|
98 { |
|
99 int i; |
|
100 GstBuffer *inbuffer; |
|
101 |
|
102 for (i = 0; i < length; ++i) { |
|
103 inbuffer = gst_buffer_new_and_alloc (1); |
|
104 GST_BUFFER_DATA (inbuffer)[0] = bytes[i]; |
|
105 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK, |
|
106 "%s: failed pushing byte buffer", reason); |
|
107 } |
|
108 } |
|
109 |
|
110 GST_START_TEST (test_audio_per_byte) |
|
111 { |
|
112 GstCaps *caps; |
|
113 GstPad *srcpad; |
|
114 GstElement *gdpdepay; |
|
115 GstBuffer *buffer, *outbuffer; |
|
116 guint8 *header, *payload; |
|
117 guint len; |
|
118 GstDPPacketizer *pk; |
|
119 |
|
120 pk = gst_dp_packetizer_new (GST_DP_VERSION_1_0); |
|
121 |
|
122 gdpdepay = setup_gdpdepay (); |
|
123 srcpad = gst_element_get_pad (gdpdepay, "src"); |
|
124 |
|
125 fail_unless (gst_element_set_state (gdpdepay, |
|
126 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, |
|
127 "could not set to playing"); |
|
128 |
|
129 caps = gst_pad_get_caps (srcpad); |
|
130 fail_unless (gst_caps_is_any (caps)); |
|
131 gst_caps_unref (caps); |
|
132 fail_if (gst_pad_get_negotiated_caps (srcpad)); |
|
133 |
|
134 /* create caps and buffer packets and push them */ |
|
135 caps = gst_caps_from_string (AUDIO_CAPS_STRING); |
|
136 fail_unless (pk->packet_from_caps (caps, 0, &len, &header, &payload)); |
|
137 gst_caps_unref (caps); |
|
138 gdpdepay_push_per_byte ("caps header", header, len); |
|
139 fail_unless_equals_int (g_list_length (buffers), 0); |
|
140 gdpdepay_push_per_byte ("caps payload", payload, |
|
141 gst_dp_header_payload_length (header)); |
|
142 fail_unless_equals_int (g_list_length (buffers), 0); |
|
143 caps = gst_pad_get_caps (srcpad); |
|
144 fail_if (gst_caps_is_any (caps)); |
|
145 gst_caps_unref (caps); |
|
146 |
|
147 g_free (header); |
|
148 g_free (payload); |
|
149 |
|
150 buffer = gst_buffer_new_and_alloc (4); |
|
151 memcpy (GST_BUFFER_DATA (buffer), "f00d", 4); |
|
152 GST_BUFFER_TIMESTAMP (buffer) = GST_SECOND; |
|
153 GST_BUFFER_DURATION (buffer) = GST_SECOND / 10; |
|
154 fail_unless (pk->header_from_buffer (buffer, 0, &len, &header)); |
|
155 gdpdepay_push_per_byte ("buffer header", header, len); |
|
156 fail_unless_equals_int (g_list_length (buffers), 0); |
|
157 gdpdepay_push_per_byte ("buffer payload", GST_BUFFER_DATA (buffer), |
|
158 gst_dp_header_payload_length (header)); |
|
159 g_free (header); |
|
160 gst_buffer_unref (buffer); |
|
161 |
|
162 fail_unless_equals_int (g_list_length (buffers), 1); |
|
163 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); |
|
164 fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer), GST_SECOND); |
|
165 fail_unless_equals_uint64 (GST_BUFFER_DURATION (outbuffer), GST_SECOND / 10); |
|
166 |
|
167 buffers = g_list_remove (buffers, outbuffer); |
|
168 gst_buffer_unref (outbuffer); |
|
169 |
|
170 fail_unless (gst_element_set_state (gdpdepay, |
|
171 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); |
|
172 |
|
173 ASSERT_OBJECT_REFCOUNT (gdpdepay, "gdpdepay", 1); |
|
174 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL); |
|
175 g_list_free (buffers); |
|
176 buffers = NULL; |
|
177 gst_object_unref (srcpad); |
|
178 cleanup_gdpdepay (gdpdepay); |
|
179 |
|
180 gst_dp_packetizer_free (pk); |
|
181 } |
|
182 |
|
183 GST_END_TEST; |
|
184 |
|
185 GST_START_TEST (test_audio_in_one_buffer) |
|
186 { |
|
187 GstCaps *caps; |
|
188 GstPad *srcpad; |
|
189 GstElement *gdpdepay; |
|
190 GstBuffer *buffer, *inbuffer; |
|
191 guint8 *caps_header, *caps_payload, *buf_header; |
|
192 guint header_len, payload_len; |
|
193 guint i; |
|
194 GstDPPacketizer *pk; |
|
195 |
|
196 pk = gst_dp_packetizer_new (GST_DP_VERSION_1_0); |
|
197 |
|
198 gdpdepay = setup_gdpdepay (); |
|
199 srcpad = gst_element_get_pad (gdpdepay, "src"); |
|
200 |
|
201 fail_unless (gst_element_set_state (gdpdepay, |
|
202 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, |
|
203 "could not set to playing"); |
|
204 |
|
205 /* make sure no caps are set yet */ |
|
206 caps = gst_pad_get_caps (srcpad); |
|
207 fail_unless (gst_caps_is_any (caps)); |
|
208 gst_caps_unref (caps); |
|
209 fail_if (gst_pad_get_negotiated_caps (srcpad)); |
|
210 |
|
211 /* create caps and buffer packets and push them as one buffer */ |
|
212 caps = gst_caps_from_string (AUDIO_CAPS_STRING); |
|
213 fail_unless (pk->packet_from_caps (caps, 0, &header_len, &caps_header, |
|
214 &caps_payload)); |
|
215 |
|
216 buffer = gst_buffer_new_and_alloc (4); |
|
217 memcpy (GST_BUFFER_DATA (buffer), "f00d", 4); |
|
218 fail_unless (pk->header_from_buffer (buffer, 0, &header_len, &buf_header)); |
|
219 |
|
220 payload_len = gst_dp_header_payload_length (caps_header); |
|
221 |
|
222 inbuffer = gst_buffer_new_and_alloc (2 * GST_DP_HEADER_LENGTH + |
|
223 payload_len + GST_BUFFER_SIZE (buffer)); |
|
224 memcpy (GST_BUFFER_DATA (inbuffer), caps_header, GST_DP_HEADER_LENGTH); |
|
225 i = GST_DP_HEADER_LENGTH; |
|
226 memcpy (GST_BUFFER_DATA (inbuffer) + i, caps_payload, payload_len); |
|
227 i += payload_len; |
|
228 memcpy (GST_BUFFER_DATA (inbuffer) + i, buf_header, GST_DP_HEADER_LENGTH); |
|
229 i += GST_DP_HEADER_LENGTH; |
|
230 memcpy (GST_BUFFER_DATA (inbuffer) + i, GST_BUFFER_DATA (buffer), |
|
231 GST_BUFFER_SIZE (buffer)); |
|
232 |
|
233 gst_caps_unref (caps); |
|
234 gst_buffer_unref (buffer); |
|
235 |
|
236 g_free (caps_header); |
|
237 g_free (caps_payload); |
|
238 g_free (buf_header); |
|
239 |
|
240 /* now push it */ |
|
241 gst_pad_push (mysrcpad, inbuffer); |
|
242 |
|
243 /* the buffer is still queued */ |
|
244 fail_unless_equals_int (g_list_length (buffers), 1); |
|
245 |
|
246 fail_unless (gst_element_set_state (gdpdepay, |
|
247 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); |
|
248 |
|
249 gst_object_unref (srcpad); |
|
250 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL); |
|
251 g_list_free (buffers); |
|
252 buffers = NULL; |
|
253 ASSERT_OBJECT_REFCOUNT (gdpdepay, "gdpdepay", 1); |
|
254 cleanup_gdpdepay (gdpdepay); |
|
255 |
|
256 gst_dp_packetizer_free (pk); |
|
257 } |
|
258 |
|
259 GST_END_TEST; |
|
260 |
|
261 static GstStaticPadTemplate shsinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", |
|
262 GST_PAD_SINK, |
|
263 GST_PAD_ALWAYS, |
|
264 GST_STATIC_CAPS ("application/x-gst-test-streamheader") |
|
265 ); |
|
266 |
|
267 static GstElement * |
|
268 setup_gdpdepay_streamheader (void) |
|
269 { |
|
270 GstElement *gdpdepay; |
|
271 |
|
272 GST_DEBUG ("setup_gdpdepay"); |
|
273 gdpdepay = gst_check_setup_element ("gdpdepay"); |
|
274 mysrcpad = gst_check_setup_src_pad (gdpdepay, &srctemplate, NULL); |
|
275 myshsinkpad = gst_check_setup_sink_pad (gdpdepay, &shsinktemplate, NULL); |
|
276 gst_pad_set_active (mysrcpad, TRUE); |
|
277 gst_pad_set_active (myshsinkpad, TRUE); |
|
278 |
|
279 return gdpdepay; |
|
280 } |
|
281 |
|
282 #ifndef HAVE_CPU_PPC64 /* Test known to fail on PPC64. See #348114 */ |
|
283 |
|
284 /* this tests deserialization of a GDP stream where the serialized caps |
|
285 * have a streamheader set */ |
|
286 GST_START_TEST (test_streamheader) |
|
287 { |
|
288 GstCaps *caps, *padcaps; |
|
289 GstPad *srcpad; |
|
290 GstElement *gdpdepay; |
|
291 GstBuffer *buffer, *inbuffer, *outbuffer, *shbuffer; |
|
292 guint8 *caps_header, *caps_payload, *buf_header; |
|
293 guint header_len, payload_len; |
|
294 guint i; |
|
295 GstStructure *structure; |
|
296 GValue array = { 0 }; |
|
297 GValue value = { 0 }; |
|
298 GstDPPacketizer *pk; |
|
299 |
|
300 pk = gst_dp_packetizer_new (GST_DP_VERSION_1_0); |
|
301 |
|
302 gdpdepay = setup_gdpdepay_streamheader (); |
|
303 srcpad = gst_element_get_pad (gdpdepay, "src"); |
|
304 ASSERT_OBJECT_REFCOUNT (gdpdepay, "gdpdepay", 1); |
|
305 |
|
306 fail_unless (gst_element_set_state (gdpdepay, |
|
307 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, |
|
308 "could not set to playing"); |
|
309 |
|
310 /* make sure no caps are set yet */ |
|
311 caps = gst_pad_get_caps (srcpad); |
|
312 fail_unless (gst_caps_is_any (caps)); |
|
313 gst_caps_unref (caps); |
|
314 fail_if (gst_pad_get_negotiated_caps (srcpad)); |
|
315 |
|
316 /* create a streamheader buffer and the caps containing it */ |
|
317 caps = gst_caps_from_string ("application/x-gst-test-streamheader"); |
|
318 structure = gst_caps_get_structure (caps, 0); |
|
319 buffer = gst_buffer_new_and_alloc (4); |
|
320 memcpy (GST_BUFFER_DATA (buffer), "f00d", 4); |
|
321 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS); |
|
322 g_value_init (&array, GST_TYPE_ARRAY); |
|
323 g_value_init (&value, GST_TYPE_BUFFER); |
|
324 shbuffer = gst_buffer_copy (buffer); |
|
325 gst_value_set_buffer (&value, shbuffer); |
|
326 gst_buffer_unref (shbuffer); |
|
327 gst_value_array_append_value (&array, &value); |
|
328 g_value_unset (&value); |
|
329 gst_structure_set_value (structure, "streamheader", &array); |
|
330 g_value_unset (&array); |
|
331 |
|
332 gst_buffer_set_caps (buffer, caps); |
|
333 |
|
334 /* create GDP packets for the caps and the buffer, and put them in one |
|
335 * GDP buffer */ |
|
336 fail_unless (pk->packet_from_caps (caps, 0, &header_len, &caps_header, |
|
337 &caps_payload)); |
|
338 |
|
339 fail_unless (pk->header_from_buffer (buffer, 0, &header_len, &buf_header)); |
|
340 |
|
341 payload_len = gst_dp_header_payload_length (caps_header); |
|
342 |
|
343 inbuffer = gst_buffer_new_and_alloc (2 * GST_DP_HEADER_LENGTH + |
|
344 payload_len + GST_BUFFER_SIZE (buffer)); |
|
345 memcpy (GST_BUFFER_DATA (inbuffer), caps_header, GST_DP_HEADER_LENGTH); |
|
346 i = GST_DP_HEADER_LENGTH; |
|
347 memcpy (GST_BUFFER_DATA (inbuffer) + i, caps_payload, payload_len); |
|
348 i += payload_len; |
|
349 memcpy (GST_BUFFER_DATA (inbuffer) + i, buf_header, GST_DP_HEADER_LENGTH); |
|
350 i += GST_DP_HEADER_LENGTH; |
|
351 memcpy (GST_BUFFER_DATA (inbuffer) + i, GST_BUFFER_DATA (buffer), |
|
352 GST_BUFFER_SIZE (buffer)); |
|
353 |
|
354 gst_caps_unref (caps); |
|
355 gst_buffer_unref (buffer); |
|
356 |
|
357 g_free (caps_header); |
|
358 g_free (caps_payload); |
|
359 g_free (buf_header); |
|
360 |
|
361 /* now push it */ |
|
362 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); |
|
363 gst_pad_push (mysrcpad, inbuffer); |
|
364 |
|
365 /* our only output buffer is the streamheader buffer */ |
|
366 fail_unless_equals_int (g_list_length (buffers), 1); |
|
367 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); |
|
368 buffers = g_list_remove (buffers, outbuffer); |
|
369 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); |
|
370 fail_unless (GST_BUFFER_FLAG_IS_SET (outbuffer, GST_BUFFER_FLAG_IN_CAPS)); |
|
371 |
|
372 padcaps = gst_pad_get_negotiated_caps (myshsinkpad); |
|
373 caps = gst_buffer_get_caps (outbuffer); |
|
374 fail_if (caps == NULL); |
|
375 fail_if (padcaps == NULL); |
|
376 GST_DEBUG ("caps: %" GST_PTR_FORMAT ", padcaps: %" GST_PTR_FORMAT, caps, |
|
377 padcaps); |
|
378 fail_unless (gst_caps_is_equal (padcaps, caps)); |
|
379 |
|
380 /* FIXME: get streamheader, compare data with buffer */ |
|
381 gst_buffer_unref (outbuffer); |
|
382 gst_caps_unref (padcaps); |
|
383 gst_caps_unref (caps); |
|
384 |
|
385 /* clean up */ |
|
386 fail_unless (gst_element_set_state (gdpdepay, |
|
387 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); |
|
388 |
|
389 gst_object_unref (srcpad); |
|
390 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL); |
|
391 g_list_free (buffers); |
|
392 buffers = NULL; |
|
393 ASSERT_OBJECT_REFCOUNT (gdpdepay, "gdpdepay", 1); |
|
394 cleanup_gdpdepay (gdpdepay); |
|
395 |
|
396 gst_dp_packetizer_free (pk); |
|
397 } |
|
398 |
|
399 GST_END_TEST; |
|
400 |
|
401 #endif /* ifndef HAVE_CPU_PPC64 */ |
|
402 |
|
403 static Suite * |
|
404 gdpdepay_suite (void) |
|
405 { |
|
406 Suite *s = suite_create ("gdpdepay"); |
|
407 TCase *tc_chain = tcase_create ("general"); |
|
408 |
|
409 suite_add_tcase (s, tc_chain); |
|
410 tcase_add_test (tc_chain, test_audio_per_byte); |
|
411 tcase_add_test (tc_chain, test_audio_in_one_buffer); |
|
412 #ifndef HAVE_CPU_PPC64 /* Test known to fail on PPC64. See #348114 */ |
|
413 tcase_add_test (tc_chain, test_streamheader); |
|
414 #endif |
|
415 return s; |
|
416 } |
|
417 |
|
418 int |
|
419 main (int argc, char **argv) |
|
420 { |
|
421 int nf; |
|
422 |
|
423 Suite *s = gdpdepay_suite (); |
|
424 SRunner *sr = srunner_create (s); |
|
425 |
|
426 gst_check_init (&argc, &argv); |
|
427 |
|
428 srunner_run_all (sr, CK_NORMAL); |
|
429 nf = srunner_ntests_failed (sr); |
|
430 srunner_free (sr); |
|
431 |
|
432 return nf; |
|
433 } |