1 /* GStreamer unit tests for the streamiddemux
2 *
3 * Copyright 2013 LGE Corporation.
4 * @author: Hoonhee Lee <hoonhee.lee@lge.com>
5 * @author: Jeongseok Kim <jeongseok.kim@lge.com>
6 * @author: Wonchul Lee <wonchul86.lee@lge.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <gst/check/gstcheck.h>
28 #include <stdlib.h>
29
30 #define NUM_SUBSTREAMS 100
31 #define NUM_BUFFER 1000
32
33 static GstPad *active_srcpad;
34
35 struct TestData
36 {
37 GstElement *demux;
38 GstPad *mysrc, *mysink[NUM_SUBSTREAMS];
39 GstPad *demuxsink, *demuxsrc[NUM_SUBSTREAMS];
40 gint srcpad_cnt;
41 GstCaps *mycaps;
42 GstCaps *caps[NUM_SUBSTREAMS];
43 GstSegment segment[NUM_SUBSTREAMS];
44 gchar *stream_ids[NUM_SUBSTREAMS];
45 };
46
47 static void
set_active_srcpad(struct TestData * td)48 set_active_srcpad (struct TestData *td)
49 {
50 if (active_srcpad)
51 gst_object_unref (active_srcpad);
52
53 g_object_get (td->demux, "active-pad", &active_srcpad, NULL);
54 }
55
56 static void
release_test_objects(struct TestData * td)57 release_test_objects (struct TestData *td)
58 {
59 fail_unless (gst_element_set_state (td->demux, GST_STATE_NULL) ==
60 GST_STATE_CHANGE_SUCCESS);
61
62 gst_object_unref (td->demuxsink);
63
64 gst_caps_unref (td->mycaps);
65
66 if (active_srcpad) {
67 gst_object_unref (active_srcpad);
68 active_srcpad = NULL;
69 }
70 gst_object_unref (td->demux);
71 }
72
73 static void
src_pad_added_cb(GstElement * demux,GstPad * pad,struct TestData * td)74 src_pad_added_cb (GstElement * demux, GstPad * pad, struct TestData *td)
75 {
76 if (td->srcpad_cnt < NUM_SUBSTREAMS) {
77 td->demuxsrc[td->srcpad_cnt] = pad;
78 fail_unless (gst_pad_link (pad,
79 td->mysink[td->srcpad_cnt++]) == GST_PAD_LINK_OK);
80 }
81 }
82
83 static void
setup_test_objects(struct TestData * td)84 setup_test_objects (struct TestData *td)
85 {
86 td->mycaps = gst_caps_new_empty_simple ("test/test");
87 td->srcpad_cnt = 0;
88
89 td->demux = gst_element_factory_make ("streamiddemux", NULL);
90 fail_unless (td->demux != NULL);
91 g_signal_connect (td->demux, "pad-added", G_CALLBACK (src_pad_added_cb), td);
92 td->demuxsink = gst_element_get_static_pad (td->demux, "sink");
93 fail_unless (td->demuxsink != NULL);
94
95 fail_unless (gst_element_set_state (td->demux, GST_STATE_PLAYING) ==
96 GST_STATE_CHANGE_SUCCESS);
97 }
98
99 static GstFlowReturn
chain_ok(GstPad * pad,GstObject * parent,GstBuffer * buffer)100 chain_ok (GstPad * pad, GstObject * parent, GstBuffer * buffer)
101 {
102 GstPad *peer_pad = NULL;
103 gchar *pad_stream_id, *active_srcpad_stream_id;
104
105 peer_pad = gst_pad_get_peer (active_srcpad);
106 pad_stream_id = gst_pad_get_stream_id (pad);
107 active_srcpad_stream_id = gst_pad_get_stream_id (active_srcpad);
108 fail_unless (pad == peer_pad);
109 fail_unless (g_strcmp0 (pad_stream_id, active_srcpad_stream_id) == 0);
110
111 g_free (pad_stream_id);
112 g_free (active_srcpad_stream_id);
113 gst_object_unref (peer_pad);
114 gst_buffer_unref (buffer);
115
116 return GST_FLOW_OK;
117 }
118
GST_START_TEST(test_simple_create_destroy)119 GST_START_TEST (test_simple_create_destroy)
120 {
121 GstElement *demux;
122
123 demux = gst_element_factory_make ("streamiddemux", NULL);
124 gst_object_unref (demux);
125 }
126
127 GST_END_TEST;
128
GST_START_TEST(test_streamiddemux_with_stream_start)129 GST_START_TEST (test_streamiddemux_with_stream_start)
130 {
131 struct TestData td;
132
133 setup_test_objects (&td);
134
135 GST_DEBUG ("Creating mysink");
136 td.mysink[0] = gst_pad_new ("mysink0", GST_PAD_SINK);
137 gst_pad_set_active (td.mysink[0], TRUE);
138
139 GST_DEBUG ("Creating mysrc");
140 td.mysrc = gst_pad_new ("mysrc", GST_PAD_SRC);
141 fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (td.mysrc, td.demuxsink)));
142 gst_pad_set_active (td.mysrc, TRUE);
143
144 GST_DEBUG ("Pushing stream-start event");
145 fail_unless (gst_pad_push_event (td.mysrc,
146 gst_event_new_stream_start ("test0")));
147
148 g_object_get (td.demux, "active-pad", &active_srcpad, NULL);
149 fail_unless (active_srcpad != NULL, "Failed to generate a srcpad");
150 fail_unless (td.srcpad_cnt == 1, "pad-added signal has not emitted");
151
152 GST_DEBUG ("Releasing mysink and mysrc");
153 gst_pad_set_active (td.mysink[0], FALSE);
154 gst_pad_set_active (td.mysrc, FALSE);
155
156 gst_object_unref (td.mysink[0]);
157 gst_object_unref (td.mysrc);
158
159 GST_DEBUG ("Releasing streamiddemux");
160 release_test_objects (&td);
161 }
162
163 GST_END_TEST;
164
GST_START_TEST(test_streamiddemux_without_stream_start)165 GST_START_TEST (test_streamiddemux_without_stream_start)
166 {
167 struct TestData td;
168 GstSegment segment;
169
170 setup_test_objects (&td);
171
172 GST_DEBUG ("Creating mysink");
173 td.mysink[0] = gst_pad_new ("mysink0", GST_PAD_SINK);
174 gst_pad_set_active (td.mysink[0], TRUE);
175
176 GST_DEBUG ("Creating mysrc");
177 td.mysrc = gst_pad_new ("mysrc", GST_PAD_SRC);
178 fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (td.mysrc, td.demuxsink)));
179 gst_pad_set_active (td.mysrc, TRUE);
180
181 GST_DEBUG ("Pushing caps and segment event without stream-start");
182 fail_unless (gst_pad_push_event (td.mysrc, gst_event_new_caps (td.mycaps)));
183 gst_segment_init (&segment, GST_FORMAT_BYTES);
184 fail_unless (gst_pad_push_event (td.mysrc, gst_event_new_segment (&segment)));
185
186 g_object_get (td.demux, "active-pad", &active_srcpad, NULL);
187 fail_unless (active_srcpad == NULL, "srcpad has created unexpectedly");
188 fail_unless (td.srcpad_cnt == 0, "pad-added signal is emitted unexpectedly");
189
190 GST_DEBUG ("Releasing mysink and mysrc");
191 gst_pad_set_active (td.mysink[0], FALSE);
192 gst_pad_set_active (td.mysrc, FALSE);
193
194 gst_object_unref (td.mysink[0]);
195 gst_object_unref (td.mysrc);
196
197 GST_DEBUG ("Releasing streamiddemux");
198 release_test_objects (&td);
199 }
200
201 GST_END_TEST;
202
GST_START_TEST(test_streamiddemux_simple)203 GST_START_TEST (test_streamiddemux_simple)
204 {
205 struct TestData td;
206
207 setup_test_objects (&td);
208
209 GST_DEBUG ("Creating mysink");
210 td.mysink[0] = gst_pad_new ("mysink0", GST_PAD_SINK);
211 td.mysink[0]->chaindata = &td;
212 gst_pad_set_chain_function (td.mysink[0], chain_ok);
213 gst_pad_set_active (td.mysink[0], TRUE);
214
215 td.mysink[1] = gst_pad_new ("mysink1", GST_PAD_SINK);
216 td.mysink[1]->chaindata = &td;
217 gst_pad_set_chain_function (td.mysink[1], chain_ok);
218 gst_pad_set_active (td.mysink[1], TRUE);
219
220 GST_DEBUG ("Creating mysrc");
221 td.mysrc = gst_pad_new ("mysrc", GST_PAD_SRC);
222 fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (td.mysrc, td.demuxsink)));
223 gst_pad_set_active (td.mysrc, TRUE);
224
225 GST_DEBUG ("Pushing stream-start, caps and segment event");
226 gst_check_setup_events_with_stream_id (td.mysrc, td.demux, td.mycaps,
227 GST_FORMAT_BYTES, "test0");
228 set_active_srcpad (&td);
229 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
230
231 gst_check_setup_events_with_stream_id (td.mysrc, td.demux, td.mycaps,
232 GST_FORMAT_BYTES, "test1");
233 set_active_srcpad (&td);
234 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
235
236 GST_DEBUG ("Pushing buffer");
237 fail_unless (gst_pad_push_event (td.mysrc,
238 gst_event_new_stream_start ("test0")));
239 set_active_srcpad (&td);
240 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
241 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
242
243 fail_unless (gst_pad_push_event (td.mysrc,
244 gst_event_new_stream_start ("test1")));
245 set_active_srcpad (&td);
246 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
247 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
248
249 GST_DEBUG ("Releasing mysink and mysrc");
250 gst_pad_set_active (td.mysink[0], FALSE);
251 gst_pad_set_active (td.mysink[1], FALSE);
252 gst_pad_set_active (td.mysrc, FALSE);
253
254 gst_object_unref (td.mysink[0]);
255 gst_object_unref (td.mysink[1]);
256 gst_object_unref (td.mysrc);
257
258 GST_DEBUG ("Releasing streamiddemux");
259 release_test_objects (&td);
260 }
261
262 GST_END_TEST;
263
264 GList *expected[NUM_SUBSTREAMS];
265
266 static gboolean
sink_event_func(GstPad * pad,GstObject * parent,GstEvent * event)267 sink_event_func (GstPad * pad, GstObject * parent, GstEvent * event)
268 {
269 GList **expected = GST_PAD_ELEMENT_PRIVATE (pad), *l;
270 GstEvent *exp;
271
272 switch (GST_EVENT_TYPE (event)) {
273 case GST_EVENT_CAPS:{
274 GstCaps *recvcaps, *expectcaps;
275
276 l = g_list_first (*expected);
277 exp = GST_EVENT (l->data);
278
279 gst_event_parse_caps (event, &recvcaps);
280 gst_event_parse_caps (exp, &expectcaps);
281
282 fail_unless (gst_caps_is_equal (recvcaps, expectcaps));
283 break;
284 }
285 case GST_EVENT_SEGMENT:{
286 const GstSegment *recvseg, *expectseg;
287
288 l = g_list_last (*expected);
289 exp = GST_EVENT (l->data);
290
291 gst_event_parse_segment (event, &recvseg);
292 gst_event_parse_segment (exp, &expectseg);
293
294 fail_unless_equals_uint64 (recvseg->position, expectseg->position);
295 break;
296 }
297 default:
298 break;
299 }
300
301 return gst_pad_event_default (pad, parent, event);
302 }
303
GST_START_TEST(test_streamiddemux_num_buffers)304 GST_START_TEST (test_streamiddemux_num_buffers)
305 {
306 struct TestData td;
307 gint buffer_cnt = 0;
308 gint stream_cnt = 0;
309 GstEvent *event;
310
311 setup_test_objects (&td);
312
313 GST_DEBUG ("Creating mysink");
314 for (stream_cnt = 0; stream_cnt < NUM_SUBSTREAMS; ++stream_cnt) {
315 gchar *name;
316 name = g_strdup_printf ("mysink%d", stream_cnt);
317 td.mysink[stream_cnt] = gst_pad_new (name, GST_PAD_SINK);
318 g_free (name);
319 gst_pad_set_chain_function (td.mysink[stream_cnt], chain_ok);
320 gst_pad_set_event_function (td.mysink[stream_cnt], sink_event_func);
321 gst_pad_set_active (td.mysink[stream_cnt], TRUE);
322 GST_PAD_ELEMENT_PRIVATE (td.mysink[stream_cnt]) = &expected[stream_cnt];
323 }
324
325 GST_DEBUG ("Creating mysrc");
326 td.mysrc = gst_pad_new ("mysrc", GST_PAD_SRC);
327 fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (td.mysrc, td.demuxsink)));
328 gst_pad_set_active (td.mysrc, TRUE);
329
330 GST_DEBUG ("Creating caps");
331 for (stream_cnt = 0; stream_cnt < NUM_SUBSTREAMS; ++stream_cnt) {
332 gchar *caps_name;
333 caps_name = g_strdup_printf ("test/test%d", stream_cnt);
334 td.caps[stream_cnt] = gst_caps_new_empty_simple (caps_name);
335
336 g_free (caps_name);
337 }
338
339 GST_DEBUG ("Creating segment");
340 for (stream_cnt = 0; stream_cnt < NUM_SUBSTREAMS; ++stream_cnt) {
341 gst_segment_init (&td.segment[stream_cnt], GST_FORMAT_BYTES);
342 td.segment[stream_cnt].position = stream_cnt * GST_SECOND;
343 }
344
345 GST_DEBUG ("Pushing stream-start, caps and segment event");
346 for (stream_cnt = 0; stream_cnt < NUM_SUBSTREAMS; ++stream_cnt) {
347 gchar *name;
348 name = g_strdup_printf ("test%d", stream_cnt);
349
350 fail_unless (gst_pad_push_event (td.mysrc,
351 gst_event_new_stream_start (name)));
352
353 event = gst_event_new_caps (td.caps[stream_cnt]);
354 expected[stream_cnt] =
355 g_list_append (expected[stream_cnt], gst_event_ref (event));
356 fail_unless (gst_pad_push_event (td.mysrc, event));
357
358 event = gst_event_new_segment (&td.segment[stream_cnt]);
359 expected[stream_cnt] =
360 g_list_append (expected[stream_cnt], gst_event_ref (event));
361 fail_unless (gst_pad_push_event (td.mysrc, event));
362
363 g_free (name);
364 set_active_srcpad (&td);
365
366 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
367 }
368
369 GST_DEBUG ("Pushing buffers to random srcpad");
370 for (buffer_cnt = 0; buffer_cnt < NUM_BUFFER; ++buffer_cnt) {
371 gchar *name;
372 gint active_stream = rand () % NUM_SUBSTREAMS;
373 name = g_strdup_printf ("test%d", active_stream);
374
375 fail_unless (gst_pad_push_event (td.mysrc,
376 gst_event_new_stream_start (name)));
377 fail_unless (gst_pad_push_event (td.mysrc,
378 gst_event_new_caps (td.caps[active_stream])));
379 fail_unless (gst_pad_push_event (td.mysrc,
380 gst_event_new_segment (&td.segment[active_stream])));
381
382 g_free (name);
383 set_active_srcpad (&td);
384
385 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
386 }
387
388 for (stream_cnt = 0; stream_cnt < NUM_SUBSTREAMS; ++stream_cnt)
389 gst_caps_unref (td.caps[stream_cnt]);
390
391 GST_DEBUG ("Releasing mysink and mysrc");
392 for (stream_cnt = 0; stream_cnt < NUM_SUBSTREAMS; ++stream_cnt) {
393 gst_pad_set_active (td.mysink[stream_cnt], FALSE);
394 }
395 gst_pad_set_active (td.mysrc, FALSE);
396
397 for (stream_cnt = 0; stream_cnt < NUM_SUBSTREAMS; ++stream_cnt) {
398 gst_object_unref (td.mysink[stream_cnt]);
399
400 g_list_free_full (expected[stream_cnt], (GDestroyNotify) gst_event_unref);
401 }
402 gst_object_unref (td.mysrc);
403
404 GST_DEBUG ("Releasing streamiddemux");
405 release_test_objects (&td);
406 }
407
408 GST_END_TEST;
409
410 guint num_eos = 0;
411 guint num_flush_start = 0;
412 guint num_flush_stop = 0;
413
414 static gboolean
event_func(GstPad * pad,GstObject * parent,GstEvent * event)415 event_func (GstPad * pad, GstObject * parent, GstEvent * event)
416 {
417 switch (GST_EVENT_TYPE (event)) {
418 case GST_EVENT_STREAM_START:
419 ++num_flush_start;
420 break;
421 case GST_EVENT_FLUSH_STOP:
422 ++num_flush_stop;
423 break;
424 case GST_EVENT_EOS:
425 ++num_eos;
426 break;
427 default:
428 break;
429 }
430
431 return gst_pad_event_default (pad, parent, event);
432 }
433
GST_START_TEST(test_streamiddemux_eos)434 GST_START_TEST (test_streamiddemux_eos)
435 {
436 struct TestData td;
437
438 setup_test_objects (&td);
439
440 num_eos = 0;
441
442 GST_DEBUG ("Creating mysink");
443 td.mysink[0] = gst_pad_new ("mysink0", GST_PAD_SINK);
444 gst_pad_set_chain_function (td.mysink[0], chain_ok);
445 gst_pad_set_event_function (td.mysink[0], event_func);
446 gst_pad_set_active (td.mysink[0], TRUE);
447
448 td.mysink[1] = gst_pad_new ("mysink1", GST_PAD_SINK);
449 gst_pad_set_chain_function (td.mysink[1], chain_ok);
450 gst_pad_set_event_function (td.mysink[1], event_func);
451 gst_pad_set_active (td.mysink[1], TRUE);
452
453 GST_DEBUG ("Creating mysrc");
454 td.mysrc = gst_pad_new ("mysrc", GST_PAD_SRC);
455 fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (td.mysrc, td.demuxsink)));
456 gst_pad_set_active (td.mysrc, TRUE);
457
458 GST_DEBUG ("Pushing stream-start, caps and segment event");
459 gst_check_setup_events_with_stream_id (td.mysrc, td.demux, td.mycaps,
460 GST_FORMAT_BYTES, "test0");
461 set_active_srcpad (&td);
462 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
463
464 gst_check_setup_events_with_stream_id (td.mysrc, td.demux, td.mycaps,
465 GST_FORMAT_BYTES, "test1");
466 set_active_srcpad (&td);
467 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_OK);
468
469 GST_DEBUG ("Pushing flush event");
470 fail_unless (gst_pad_push_event (td.mysrc, gst_event_new_flush_start ()));
471 fail_unless (num_flush_start == 2,
472 "Failed to send flush-start event to all pads internally linked");
473 fail_unless (gst_pad_push_event (td.mysrc, gst_event_new_flush_stop (TRUE)));
474 fail_unless (num_flush_stop == 2,
475 "Failed to send flush-stop event to all pads internally linked");
476
477 GST_DEBUG ("Pushing eos event");
478 fail_unless (gst_pad_push_event (td.mysrc, gst_event_new_eos ()));
479 fail_unless (num_eos == 2,
480 "Failed to send eos event to all pads internally linked");
481
482 fail_unless (gst_pad_push (td.mysrc, gst_buffer_new ()) == GST_FLOW_EOS);
483
484 GST_DEBUG ("Releasing mysink and mysrc");
485 gst_pad_set_active (td.mysink[0], FALSE);
486 gst_pad_set_active (td.mysink[1], FALSE);
487 gst_pad_set_active (td.mysrc, FALSE);
488
489 gst_object_unref (td.mysink[0]);
490 gst_object_unref (td.mysink[1]);
491 gst_object_unref (td.mysrc);
492
493 GST_DEBUG ("Releasing streamiddemux");
494 release_test_objects (&td);
495 }
496
497 GST_END_TEST;
498
499 static Suite *
streamiddemux_suite(void)500 streamiddemux_suite (void)
501 {
502 Suite *s = suite_create ("streamiddemux");
503 TCase *tc_chain;
504
505 tc_chain = tcase_create ("streamiddemux simple");
506 tcase_add_test (tc_chain, test_simple_create_destroy);
507 tcase_add_test (tc_chain, test_streamiddemux_with_stream_start);
508 tcase_add_test (tc_chain, test_streamiddemux_without_stream_start);
509 tcase_add_test (tc_chain, test_streamiddemux_simple);
510 tcase_add_test (tc_chain, test_streamiddemux_num_buffers);
511 tcase_add_test (tc_chain, test_streamiddemux_eos);
512 suite_add_tcase (s, tc_chain);
513
514 return s;
515 }
516
517 GST_CHECK_MAIN (streamiddemux);
518