• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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