3 * unit test for autoconvert element
4 * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
27 #include <gst/check/gstcheck.h>
28 #include <gst/insertbin/gstinsertbin.h>
30 GstStaticPadTemplate sinkpad_template = GST_STATIC_PAD_TEMPLATE ("sink", /* the name of the pad */
31 GST_PAD_SINK, /* the direction of the pad */
32 GST_PAD_ALWAYS, /* when this pad will be present */
33 GST_STATIC_CAPS ( /* the capabilities of the padtemplate */
37 GstStaticPadTemplate srcpad_template = GST_STATIC_PAD_TEMPLATE ("src", /* the name of the pad */
38 GST_PAD_SRC, /* the direction of the pad */
39 GST_PAD_ALWAYS, /* when this pad will be present */
40 GST_STATIC_CAPS ( /* the capabilities of the padtemplate */
49 GThread *push_thread = NULL;
50 GThread *streaming_thread = NULL;
51 gulong block_probe_id = 0;
52 gboolean is_blocked = FALSE;
55 success_cb (GstInsertBin * insertbin, GstElement * element, gboolean success,
58 fail_unless (g_thread_self () == push_thread);
59 fail_unless (success == TRUE);
60 fail_unless (GST_IS_ELEMENT (insertbin));
61 fail_unless (GST_IS_ELEMENT (element));
66 fail_cb (GstInsertBin * insertbin, GstElement * element, gboolean success,
69 fail_unless (GST_IS_ELEMENT (insertbin));
70 fail_unless (GST_IS_ELEMENT (element));
71 fail_unless (success == FALSE);
76 * This is a macro so the line number of any error is more useful
78 #define push_buffer(srcpad, count) \
80 fail_unless (cb_count == 0); \
81 gst_pad_push (srcpad, gst_buffer_new ()); \
82 fail_unless (g_list_length (buffers) == 1); \
83 gst_check_drop_buffers (); \
84 fail_unless (cb_count == (count)); \
88 #define check_reset_cb_count(count) \
90 fail_unless (cb_count == (count)); \
95 thread_push_buffer (gpointer data)
99 gst_pad_push (pad, gst_buffer_new ());
103 static GstPadProbeReturn
104 got_buffer_block (GstPad * pad, GstPadProbeInfo * info, gpointer data)
106 g_mutex_lock (&lock);
108 g_cond_broadcast (&cond);
109 g_mutex_unlock (&lock);
111 return GST_PAD_PROBE_OK;
114 #define block_thread() \
116 fail_unless (cb_count == 0); \
117 fail_unless (block_probe_id == 0); \
118 fail_unless (is_blocked == FALSE); \
119 fail_unless (push_thread == NULL); \
120 block_probe_id = gst_pad_add_probe (sinkpad, \
121 GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER, \
122 got_buffer_block, NULL, NULL); \
123 push_thread = g_thread_new ("push block", thread_push_buffer, srcpad); \
124 fail_unless (push_thread != NULL); \
125 g_mutex_lock (&lock); \
126 while (is_blocked == FALSE) \
127 g_cond_wait (&cond, &lock); \
128 g_mutex_unlock (&lock); \
131 #define unblock_thread() \
133 fail_unless (cb_count == 0); \
134 fail_unless (push_thread != NULL); \
135 fail_unless (is_blocked == TRUE); \
136 fail_unless (block_probe_id != 0); \
137 gst_pad_remove_probe (sinkpad, block_probe_id); \
138 g_thread_join (push_thread); \
139 fail_unless (g_list_length (buffers) == 1); \
140 gst_check_drop_buffers (); \
141 block_probe_id = 0; \
142 push_thread = NULL; \
143 is_blocked = FALSE; \
146 GST_START_TEST (test_insertbin_simple)
148 GstElement *insertbin;
157 g_mutex_init (&lock);
160 insertbin = gst_insert_bin_new (NULL);
161 fail_unless (insertbin != NULL);
162 ASSERT_OBJECT_REFCOUNT (insertbin, insertbin, 1);
163 srcpad = gst_check_setup_src_pad (insertbin, &srcpad_template);
164 sinkpad = gst_check_setup_sink_pad (insertbin, &sinkpad_template);
166 g_assert (srcpad && sinkpad);
168 ASSERT_CRITICAL (gst_insert_bin_append (GST_INSERT_BIN (insertbin), NULL,
170 ASSERT_CRITICAL (gst_insert_bin_append (GST_INSERT_BIN (insertbin), NULL,
172 fail_unless (cb_count == 0);
174 /* insertbin is stopped and pads are idle, should be called immediately
175 * from this same thread */
176 push_thread = g_thread_self ();
177 elem = gst_element_factory_make ("identity", NULL);
178 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem, success_cb, NULL);
179 check_reset_cb_count (1);
181 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem, success_cb, NULL);
182 check_reset_cb_count (1);
184 fail_unless (gst_pad_set_active (srcpad, TRUE));
185 fail_unless (gst_pad_set_active (sinkpad, TRUE));
186 fail_unless (gst_element_set_state (insertbin,
187 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
189 caps = gst_caps_new_empty_simple ("video/test");
190 gst_check_setup_events (srcpad, insertbin, caps, GST_FORMAT_BYTES);
191 gst_caps_unref (caps);
193 fail_unless (cb_count == 0);
194 fail_unless (buffers == NULL);
196 push_thread = g_thread_self ();
197 push_buffer (srcpad, 0);
199 /* now the pad should be active, the change should come from the
200 * 'streaming thread' */
203 elem = gst_element_factory_make ("identity", NULL);
204 gst_insert_bin_prepend (GST_INSERT_BIN (insertbin), elem, success_cb, NULL);
206 check_reset_cb_count (1);
208 /* can't add the same element twice */
210 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem, fail_cb, NULL);
211 check_reset_cb_count (1);
213 push_buffer (srcpad, 0);
215 /* remove the element */
217 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem, success_cb, NULL);
219 check_reset_cb_count (1);
220 push_buffer (srcpad, 0);
222 /* try adding multiple elements, one at a time */
224 elem = gst_element_factory_make ("identity", NULL);
225 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem, success_cb, NULL);
227 check_reset_cb_count (1);
228 push_buffer (srcpad, 0);
231 elem2 = gst_element_factory_make ("identity", NULL);
232 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem2, success_cb, NULL);
234 check_reset_cb_count (1);
235 push_buffer (srcpad, 0);
238 elem3 = gst_element_factory_make ("identity", NULL);
239 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem3, success_cb, NULL);
241 check_reset_cb_count (1);
242 push_buffer (srcpad, 0);
245 elem4 = gst_element_factory_make ("identity", NULL);
246 gst_insert_bin_prepend (GST_INSERT_BIN (insertbin), elem4, success_cb, NULL);
248 check_reset_cb_count (1);
249 push_buffer (srcpad, 0);
251 /* remove 2 of those elements at once */
253 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem3, success_cb, NULL);
254 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem2, success_cb, NULL);
256 check_reset_cb_count (2);
257 push_buffer (srcpad, 0);
259 /* add another 2 elements at once */
261 elem2 = gst_element_factory_make ("identity", NULL);
262 elem3 = gst_element_factory_make ("identity", NULL);
263 gst_insert_bin_insert_after (GST_INSERT_BIN (insertbin), elem2, elem,
265 gst_insert_bin_insert_before (GST_INSERT_BIN (insertbin), elem3, elem4,
268 check_reset_cb_count (2);
269 push_buffer (srcpad, 0);
271 /* remove 2 elements */
273 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem3, success_cb, NULL);
274 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem2, success_cb, NULL);
276 check_reset_cb_count (2);
277 push_buffer (srcpad, 0);
281 elem2 = gst_element_factory_make ("identity", NULL);
282 elem3 = gst_element_factory_make ("identity", NULL);
283 gst_insert_bin_insert_before (GST_INSERT_BIN (insertbin), elem3, elem4,
285 gst_insert_bin_insert_after (GST_INSERT_BIN (insertbin), elem2, elem,
288 check_reset_cb_count (2);
289 push_buffer (srcpad, 0);
291 /* try to add an element that has no pads */
293 elem = gst_bin_new (NULL);
294 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem, fail_cb, NULL);
295 check_reset_cb_count (1);
298 /* try to add an element that has a parent */
300 elem = gst_bin_new (NULL);
301 elem2 = gst_element_factory_make ("identity", NULL);
302 gst_bin_add (GST_BIN (elem), elem2);
303 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem2, fail_cb, NULL);
304 check_reset_cb_count (1);
305 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem2, fail_cb, NULL);
306 check_reset_cb_count (1);
308 gst_object_unref (elem);
309 push_buffer (srcpad, 0);
311 /* when removing an element insertbin will look at the pending operations list
312 * and check if that element is pending and remove it before adding.
313 * So we check that the callback count hapenned before the end, and it
314 * also happens from this same main thread. So we need to store the
315 * streaming thread to restore it after the check */
316 elem = gst_element_factory_make ("identity", NULL);
317 elem2 = gst_element_factory_make ("identity", NULL);
319 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem, success_cb, NULL);
320 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem2, success_cb, NULL);
321 streaming_thread = push_thread;
322 push_thread = g_thread_self ();
323 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem2, success_cb, NULL);
324 push_thread = streaming_thread;
325 check_reset_cb_count (2);
327 check_reset_cb_count (1);
328 push_buffer (srcpad, 0);
330 /* fail when trying to add an element before another that isn't in
333 elem = gst_element_factory_make ("identity", NULL);
334 elem2 = gst_element_factory_make ("identity", NULL);
335 gst_insert_bin_insert_before (GST_INSERT_BIN (insertbin), elem, elem2,
337 check_reset_cb_count (1);
339 push_buffer (srcpad, 0);
340 gst_object_unref (elem2);
342 fail_unless (gst_element_set_state (insertbin,
343 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
344 gst_pad_set_active (srcpad, FALSE);
345 gst_pad_set_active (sinkpad, FALSE);
348 push_thread = g_thread_self ();
349 elem = gst_element_factory_make ("identity", NULL);
350 gst_insert_bin_remove (GST_INSERT_BIN (insertbin), elem, fail_cb, NULL);
351 check_reset_cb_count (1);
353 gst_insert_bin_append (GST_INSERT_BIN (insertbin), elem, success_cb, NULL);
354 check_reset_cb_count (1);
356 gst_check_teardown_sink_pad (insertbin);
357 gst_check_teardown_src_pad (insertbin);
358 gst_check_teardown_element (insertbin);
360 fail_unless (cb_count == 0);
362 g_mutex_clear (&lock);
363 g_cond_clear (&cond);
370 insert_bin_suite (void)
372 Suite *s = suite_create ("insertbin");
373 TCase *tc_basic = tcase_create ("general");
375 suite_add_tcase (s, tc_basic);
376 tcase_add_test (tc_basic, test_insertbin_simple);
382 GST_CHECK_MAIN (insert_bin);