2 * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
4 * gstghostpad.c: Unit test for GstGhostPad
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.
22 #include <gst/check/gstcheck.h>
24 /* test if removing a bin also cleans up the ghostpads
26 GST_START_TEST (test_remove1)
28 GstElement *b1, *b2, *src, *sink;
29 GstPad *srcpad, *sinkpad;
32 b1 = gst_element_factory_make ("pipeline", NULL);
33 b2 = gst_element_factory_make ("bin", NULL);
34 src = gst_element_factory_make ("fakesrc", NULL);
35 sink = gst_element_factory_make ("fakesink", NULL);
36 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
37 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
39 fail_unless (gst_bin_add (GST_BIN (b2), sink));
40 fail_unless (gst_bin_add (GST_BIN (b1), src));
41 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
42 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
43 fail_unless (gst_bin_add (GST_BIN (b1), b2));
44 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
45 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
47 sinkpad = gst_element_get_static_pad (sink, "sink");
48 gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
49 gst_object_unref (sinkpad);
51 srcpad = gst_element_get_static_pad (src, "src");
52 /* get the ghostpad */
53 sinkpad = gst_element_get_static_pad (b2, "sink");
55 ret = gst_pad_link (srcpad, sinkpad);
56 fail_unless (ret == GST_PAD_LINK_OK);
57 gst_object_unref (srcpad);
58 gst_object_unref (sinkpad);
60 /* now remove the bin with the ghostpad, b2 is disposed now. */
61 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
62 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
63 gst_bin_remove (GST_BIN (b1), b2);
65 srcpad = gst_element_get_static_pad (src, "src");
66 /* pad cannot be linked now */
67 fail_if (gst_pad_is_linked (srcpad));
68 gst_object_unref (srcpad);
70 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
71 gst_object_unref (b1);
76 /* test if removing a bin also cleans up the ghostpads
78 GST_START_TEST (test_remove2)
80 GstElement *b1, *b2, *src, *sink;
81 GstPad *srcpad, *sinkpad;
84 b1 = gst_element_factory_make ("pipeline", NULL);
85 b2 = gst_element_factory_make ("bin", NULL);
86 src = gst_element_factory_make ("fakesrc", NULL);
87 sink = gst_element_factory_make ("fakesink", NULL);
88 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
90 fail_unless (gst_bin_add (GST_BIN (b2), sink));
91 fail_unless (gst_bin_add (GST_BIN (b1), src));
92 fail_unless (gst_bin_add (GST_BIN (b1), b2));
93 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
95 sinkpad = gst_element_get_static_pad (sink, "sink");
96 gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
97 gst_object_unref (sinkpad);
99 srcpad = gst_element_get_static_pad (src, "src");
100 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); /* since we got one */
101 /* get the ghostpad */
102 sinkpad = gst_element_get_static_pad (b2, "sink");
103 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); /* since we got one */
105 GST_DEBUG ("linking srcpad and sinkpad");
106 ret = gst_pad_link (srcpad, sinkpad);
107 GST_DEBUG ("linked srcpad and sinkpad");
108 fail_unless (ret == GST_PAD_LINK_OK);
109 /* the linking causes a proxypad to be created for srcpad,
110 * to which sinkpad gets linked. This proxypad has a ref to srcpad */
111 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 3);
112 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
113 gst_object_unref (srcpad);
114 gst_object_unref (sinkpad);
116 /* now remove the sink from the bin */
117 gst_bin_remove (GST_BIN (b2), sink);
119 srcpad = gst_element_get_static_pad (src, "src");
120 /* pad is still linked to ghostpad */
121 fail_if (!gst_pad_is_linked (srcpad));
122 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
123 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 3);
124 gst_object_unref (srcpad);
125 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
128 /* now unlink the pads */
129 gst_pad_unlink (srcpad, sinkpad);
130 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); /* proxy has dropped ref */
131 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
133 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
134 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
135 /* remove b2 from b1 */
136 gst_bin_remove (GST_BIN (b1), b2);
138 /* flush the message, dropping the b1 refcount to 1 */
139 gst_element_set_state (b1, GST_STATE_READY);
140 gst_element_set_state (b1, GST_STATE_NULL);
141 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
142 gst_object_unref (b1);
149 /* test if a ghost pad without a target can be linked and
150 * unlinked. An untargeted ghostpad has a default ANY caps unless there
151 * is a padtemplate that says something else.
153 GST_START_TEST (test_ghost_pads_notarget)
155 GstElement *b1, *b2, *sink;
156 GstPad *srcpad, *sinkpad, *peer;
157 GstPadLinkReturn ret;
162 b1 = gst_element_factory_make ("pipeline", NULL);
164 /* make sure all messages are discarded */
165 bus = gst_pipeline_get_bus (GST_PIPELINE (b1));
166 gst_bus_set_flushing (bus, TRUE);
167 gst_object_unref (bus);
169 b2 = gst_element_factory_make ("bin", NULL);
170 sink = gst_element_factory_make ("fakesink", NULL);
172 fail_unless (gst_bin_add (GST_BIN (b1), sink));
173 fail_unless (gst_bin_add (GST_BIN (b1), b2));
175 srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
176 fail_unless (srcpad != NULL);
177 sinkpad = gst_element_get_static_pad (sink, "sink");
178 fail_unless (sinkpad != NULL);
180 ret = gst_pad_link (srcpad, sinkpad);
181 fail_unless (ret == GST_PAD_LINK_OK);
183 /* check if the peers are ok */
184 peer = gst_pad_get_peer (srcpad);
185 fail_unless (peer == sinkpad);
186 gst_object_unref (peer);
188 peer = gst_pad_get_peer (sinkpad);
189 fail_unless (peer == srcpad);
190 gst_object_unref (peer);
192 /* check caps, untargetted pad should return ANY or the padtemplate caps
193 * when it was created from a template */
194 caps = gst_pad_get_caps (srcpad, NULL);
195 fail_unless (gst_caps_is_any (caps));
196 gst_caps_unref (caps);
199 bret = gst_pad_unlink (srcpad, sinkpad);
200 fail_unless (bret == TRUE);
203 gst_object_unref (srcpad);
204 gst_object_unref (sinkpad);
205 gst_object_unref (b1);
210 /* Test that removing the target of a ghostpad properly sets the target of the
211 * ghostpad to NULL */
212 GST_START_TEST (test_remove_target)
214 GstElement *b1, *b2, *src, *sink;
215 GstPad *sinkpad, *ghost, *target;
217 b1 = gst_element_factory_make ("pipeline", NULL);
218 b2 = gst_element_factory_make ("bin", NULL);
219 src = gst_element_factory_make ("fakesrc", NULL);
220 sink = gst_element_factory_make ("fakesink", NULL);
221 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
223 fail_unless (gst_bin_add (GST_BIN (b2), sink));
224 fail_unless (gst_bin_add (GST_BIN (b1), src));
225 fail_unless (gst_bin_add (GST_BIN (b1), b2));
226 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
228 sinkpad = gst_element_get_static_pad (sink, "sink");
229 gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
231 ghost = gst_element_get_static_pad (b2, "sink");
233 target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
234 fail_unless (target == sinkpad);
235 gst_object_unref (target);
236 gst_object_unref (sinkpad);
238 gst_bin_remove (GST_BIN (b2), sink);
240 target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
241 fail_unless (target == NULL);
243 gst_object_unref (b1);
249 /* test if linking fails over different bins using a pipeline
252 * fakesrc num_buffers=10 ! ( fakesink )
255 GST_START_TEST (test_link)
257 GstElement *b1, *b2, *src, *sink;
258 GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp;
259 GstPadLinkReturn ret;
261 b1 = gst_element_factory_make ("pipeline", NULL);
262 b2 = gst_element_factory_make ("bin", NULL);
263 src = gst_element_factory_make ("fakesrc", NULL);
264 sink = gst_element_factory_make ("fakesink", NULL);
266 fail_unless (gst_bin_add (GST_BIN (b2), sink));
267 fail_unless (gst_bin_add (GST_BIN (b1), src));
268 fail_unless (gst_bin_add (GST_BIN (b1), b2));
270 srcpad = gst_element_get_static_pad (src, "src");
271 fail_unless (srcpad != NULL);
272 sinkpad = gst_element_get_static_pad (sink, "sink");
273 fail_unless (sinkpad != NULL);
275 /* linking in different hierarchies should fail */
276 ret = gst_pad_link (srcpad, sinkpad);
277 fail_unless (ret == GST_PAD_LINK_WRONG_HIERARCHY);
279 /* now setup a ghostpad */
280 gpad = gst_ghost_pad_new ("sink", sinkpad);
282 /* Check if the internal pads are set correctly */
283 ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
284 fail_unless (ppad == GST_PAD_PEER (sinkpad));
285 tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad)));
286 fail_unless (tmp == gpad);
287 gst_object_unref (tmp);
288 gst_object_unref (ppad);
289 gst_object_unref (sinkpad);
290 /* need to ref as _add_pad takes ownership */
291 gst_object_ref (gpad);
292 gst_element_add_pad (b2, gpad);
294 /* our new sinkpad */
297 /* and linking should work now */
298 ret = gst_pad_link (srcpad, sinkpad);
299 fail_unless (ret == GST_PAD_LINK_OK);
301 /* flush the message, dropping the b1 refcount to 1 */
302 gst_element_set_state (b1, GST_STATE_READY);
303 gst_element_set_state (b1, GST_STATE_NULL);
304 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
306 gst_object_unref (srcpad);
307 gst_object_unref (sinkpad);
308 gst_object_unref (b1);
313 /* test if ghostpads are created automagically when using
314 * gst_element_link_pads.
316 * fakesrc num_buffers=10 ! ( identity ) ! fakesink
318 GST_START_TEST (test_ghost_pads)
320 GstElement *b1, *b2, *src, *i1, *sink;
321 GstPad *gsink, *gsrc, *gisrc, *gisink, *isink, *isrc, *fsrc, *fsink;
322 GstStateChangeReturn ret;
324 b1 = gst_element_factory_make ("pipeline", NULL);
325 b2 = gst_element_factory_make ("bin", NULL);
326 src = gst_element_factory_make ("fakesrc", NULL);
327 g_object_set (src, "num-buffers", (int) 10, NULL);
328 i1 = gst_element_factory_make ("identity", NULL);
329 sink = gst_element_factory_make ("fakesink", NULL);
331 fail_unless (gst_bin_add (GST_BIN (b2), i1));
332 fail_unless (gst_bin_add (GST_BIN (b1), src));
333 fail_unless (gst_bin_add (GST_BIN (b1), b2));
334 fail_unless (gst_bin_add (GST_BIN (b1), sink));
335 fail_unless (gst_element_link_pads (src, NULL, i1, NULL));
336 fail_unless (gst_element_link_pads (i1, NULL, sink, NULL));
337 GST_OBJECT_LOCK (b2);
338 fail_unless (b2->numsinkpads == 1);
339 fail_unless (GST_IS_GHOST_PAD (b2->sinkpads->data));
340 fail_unless (b2->numsrcpads == 1);
341 fail_unless (GST_IS_GHOST_PAD (b2->srcpads->data));
342 GST_OBJECT_UNLOCK (b2);
344 fsrc = gst_element_get_static_pad (src, "src");
345 fail_unless (fsrc != NULL);
346 gsink = GST_PAD (gst_object_ref (b2->sinkpads->data));
347 fail_unless (gsink != NULL);
348 gsrc = GST_PAD (gst_object_ref (b2->srcpads->data));
349 fail_unless (gsrc != NULL);
350 fsink = gst_element_get_static_pad (sink, "sink");
351 fail_unless (fsink != NULL);
353 isink = gst_element_get_static_pad (i1, "sink");
354 fail_unless (isink != NULL);
355 isrc = gst_element_get_static_pad (i1, "src");
356 fail_unless (isrc != NULL);
357 gisrc = gst_pad_get_peer (isink);
358 fail_unless (gisrc != NULL);
359 gisink = gst_pad_get_peer (isrc);
360 fail_unless (gisink != NULL);
362 /* all objects above have one refcount owned by us as well */
364 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 3); /* parent and gisrc */
365 ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2); /* parent */
366 ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2); /* parent */
367 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 3); /* parent and gisink */
369 ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2); /* parent */
370 ASSERT_OBJECT_REFCOUNT (isink, "isink", 3); /* parent and gsink */
371 ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
372 ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 3); /* parent and gsrc */
374 ret = gst_element_set_state (b1, GST_STATE_PLAYING);
375 ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
376 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
378 ret = gst_element_set_state (b1, GST_STATE_NULL);
379 ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
380 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
382 gst_object_unref (b1);
383 /* unreffing the bin will unref all elements, which will unlink and unparent
386 /* wait for thread to settle down */
387 while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 1)
390 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
391 ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
392 ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
393 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
395 ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2); /* gsink */
396 ASSERT_OBJECT_REFCOUNT (isink, "isink", 1); /* gsink */
397 ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
398 ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1); /* gsrc */
400 gst_object_unref (gsink);
401 ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
402 ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
403 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
404 gst_object_unref (gisrc);
405 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
407 gst_object_unref (gsrc);
408 ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
409 ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
410 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
411 gst_object_unref (gisink);
412 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
414 gst_object_unref (fsrc);
415 gst_object_unref (isrc);
416 gst_object_unref (isink);
417 gst_object_unref (fsink);
422 GST_START_TEST (test_ghost_pads_bin)
429 GstPad *srcpad, *srcghost, *target;
430 GstPad *sinkpad, *sinkghost;
432 pipeline = GST_BIN (gst_pipeline_new ("pipe"));
433 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
435 srcbin = GST_BIN (gst_bin_new ("srcbin"));
436 gst_bin_add (pipeline, GST_ELEMENT (srcbin));
437 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
439 sinkbin = GST_BIN (gst_bin_new ("sinkbin"));
440 gst_bin_add (pipeline, GST_ELEMENT (sinkbin));
441 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
443 src = gst_element_factory_make ("fakesrc", "src");
444 gst_bin_add (srcbin, src);
445 srcpad = gst_element_get_static_pad (src, "src");
446 srcghost = gst_ghost_pad_new ("src", srcpad);
447 gst_object_unref (srcpad);
448 gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
450 sink = gst_element_factory_make ("fakesink", "sink");
451 gst_bin_add (sinkbin, sink);
452 sinkpad = gst_element_get_static_pad (sink, "sink");
453 sinkghost = gst_ghost_pad_new ("sink", sinkpad);
454 gst_object_unref (sinkpad);
455 gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost);
457 gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin));
459 fail_unless (GST_PAD_PEER (srcghost) != NULL);
460 fail_unless (GST_PAD_PEER (sinkghost) != NULL);
461 target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcghost));
462 fail_unless (GST_PAD_PEER (target) != NULL);
463 gst_object_unref (target);
464 target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkghost));
465 fail_unless (GST_PAD_PEER (target) != NULL);
466 gst_object_unref (target);
468 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
470 gst_object_unref (pipeline);
481 static GstProbeReturn
482 block_callback (GstPad * pad, GstProbeType type, gpointer type_data,
485 BlockData *block_data = (BlockData *) user_data;
487 g_mutex_lock (block_data->mutex);
488 GST_DEBUG ("blocked\n");
489 g_cond_signal (block_data->cond);
490 g_mutex_unlock (block_data->mutex);
495 GST_START_TEST (test_ghost_pads_block)
502 BlockData block_data;
504 pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
506 srcbin = GST_BIN (gst_bin_new ("srcbin"));
507 gst_bin_add (pipeline, GST_ELEMENT (srcbin));
509 src = gst_element_factory_make ("fakesrc", "src");
510 gst_bin_add (srcbin, src);
511 srcpad = gst_element_get_static_pad (src, "src");
512 srcghost = gst_ghost_pad_new ("src", srcpad);
513 gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
514 gst_object_unref (srcpad);
516 block_data.mutex = g_mutex_new ();
517 block_data.cond = g_cond_new ();
519 g_mutex_lock (block_data.mutex);
520 gst_pad_add_probe (srcghost, GST_PROBE_TYPE_BLOCK, block_callback,
522 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
524 g_cond_wait (block_data.cond, block_data.mutex);
525 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
526 g_mutex_unlock (block_data.mutex);
528 g_mutex_free (block_data.mutex);
529 g_cond_free (block_data.cond);
531 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
532 gst_object_unref (pipeline);
537 GST_START_TEST (test_ghost_pads_probes)
544 BlockData block_data;
546 pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
548 srcbin = GST_BIN (gst_bin_new ("srcbin"));
549 gst_bin_add (pipeline, GST_ELEMENT (srcbin));
551 src = gst_element_factory_make ("fakesrc", "src");
552 gst_bin_add (srcbin, src);
553 srcpad = gst_element_get_static_pad (src, "src");
554 srcghost = gst_ghost_pad_new ("src", srcpad);
555 gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
556 gst_object_unref (srcpad);
558 block_data.mutex = g_mutex_new ();
559 block_data.cond = g_cond_new ();
561 g_mutex_lock (block_data.mutex);
562 gst_pad_add_probe (srcghost, GST_PROBE_TYPE_BLOCK, block_callback,
564 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
566 g_cond_wait (block_data.cond, block_data.mutex);
567 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
568 g_mutex_unlock (block_data.mutex);
570 g_mutex_free (block_data.mutex);
571 g_cond_free (block_data.cond);
573 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
574 gst_object_unref (pipeline);
579 GST_START_TEST (test_ghost_pads_new_from_template)
581 GstPad *sinkpad, *ghostpad;
582 GstPadTemplate *padtempl, *ghosttempl;
583 GstCaps *padcaps, *ghostcaps, *newcaps;
585 padcaps = gst_caps_from_string ("some/caps");
586 fail_unless (padcaps != NULL);
587 ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
588 fail_unless (ghostcaps != NULL);
590 padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
591 GST_PAD_ALWAYS, padcaps);
592 fail_unless (padtempl != NULL);
593 ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
594 GST_PAD_ALWAYS, ghostcaps);
596 sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
597 fail_unless (sinkpad != NULL);
599 ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
600 fail_unless (ghostpad != NULL);
602 /* check template is properly set */
603 fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
605 /* check ghostpad caps are from the sinkpad */
606 newcaps = gst_pad_get_caps (ghostpad, NULL);
607 fail_unless (newcaps != NULL);
608 fail_unless (gst_caps_is_equal (newcaps, padcaps));
609 gst_caps_unref (newcaps);
610 gst_caps_unref (padcaps);
611 gst_caps_unref (ghostcaps);
613 gst_object_unref (sinkpad);
614 gst_object_unref (ghostpad);
616 gst_object_unref (padtempl);
617 gst_object_unref (ghosttempl);
622 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
624 GstPad *sinkpad, *ghostpad;
625 GstPadTemplate *padtempl, *ghosttempl;
626 GstCaps *padcaps, *ghostcaps, *newcaps;
628 padcaps = gst_caps_from_string ("some/caps");
629 fail_unless (padcaps != NULL);
630 ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
631 fail_unless (ghostcaps != NULL);
633 padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
634 GST_PAD_ALWAYS, padcaps);
635 fail_unless (padtempl != NULL);
636 ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
637 GST_PAD_ALWAYS, ghostcaps);
639 sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
640 fail_unless (sinkpad != NULL);
642 ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
643 fail_unless (ghostpad != NULL);
645 /* check template is properly set */
646 fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
648 /* check ghostpad caps are from the ghostpad template */
649 newcaps = gst_pad_get_caps (ghostpad, NULL);
650 fail_unless (newcaps != NULL);
651 fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
652 gst_caps_unref (newcaps);
654 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
656 /* check ghostpad caps are now from the target pad */
657 newcaps = gst_pad_get_caps (ghostpad, NULL);
658 fail_unless (newcaps != NULL);
659 fail_unless (gst_caps_is_equal (newcaps, padcaps));
660 gst_caps_unref (newcaps);
662 gst_object_unref (sinkpad);
663 gst_object_unref (ghostpad);
665 gst_object_unref (padtempl);
666 gst_object_unref (ghosttempl);
668 gst_caps_unref (padcaps);
669 gst_caps_unref (ghostcaps);
675 ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data)
677 GST_DEBUG ("caps notify called");
678 (*(gint *) user_data)++;
681 GST_START_TEST (test_ghost_pads_forward_setcaps)
683 GstCaps *templ_caps, *caps1, *caps2;
684 GstPadTemplate *src_template, *sink_template;
685 GstPad *src, *ghost, *sink;
686 gint notify_counter = 0;
688 templ_caps = gst_caps_from_string ("meh; muh");
689 src_template = gst_pad_template_new ("src", GST_PAD_SRC,
690 GST_PAD_ALWAYS, templ_caps);
691 gst_caps_unref (templ_caps);
693 templ_caps = gst_caps_from_string ("muh; meh");
694 sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
695 GST_PAD_ALWAYS, templ_caps);
696 gst_caps_unref (templ_caps);
698 src = gst_pad_new_from_template (src_template, "src");
699 sink = gst_pad_new_from_template (sink_template, "sink");
701 /* ghost source pad, setting caps on the source influences the caps of the
703 ghost = gst_ghost_pad_new ("ghostsrc", src);
704 g_signal_connect (ghost, "notify::caps",
705 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
706 fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
708 /* Activate pads for caps forwarding/setting to work */
709 gst_pad_set_active (src, TRUE);
710 gst_pad_set_active (ghost, TRUE);
712 caps1 = gst_caps_from_string ("meh");
713 fail_unless (gst_pad_set_caps (src, caps1));
714 caps2 = gst_pad_get_current_caps (ghost);
715 fail_unless (gst_caps_is_equal (caps1, caps2));
716 fail_unless_equals_int (notify_counter, 1);
718 gst_object_unref (ghost);
719 gst_caps_unref (caps1);
721 /* source 2, setting the caps on the ghostpad does not influence the caps of
724 ghost = gst_ghost_pad_new ("ghostsrc", src);
725 g_signal_connect (ghost, "notify::caps",
726 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
727 fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
729 gst_pad_set_active (ghost, TRUE);
730 gst_pad_set_active (sink, TRUE);
732 caps1 = gst_caps_from_string ("meh");
733 fail_unless (gst_pad_set_caps (ghost, caps1));
735 caps2 = gst_pad_get_current_caps (src);
736 fail_unless (caps2 == NULL);
738 fail_unless_equals_int (notify_counter, 1);
740 gst_object_unref (ghost);
741 gst_caps_unref (caps1);
744 /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
747 ghost = gst_ghost_pad_new ("ghostsink", sink);
748 g_signal_connect (ghost, "notify::caps",
749 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
750 fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
752 gst_pad_set_active (src, TRUE);
753 gst_pad_set_active (ghost, TRUE);
755 caps1 = gst_caps_from_string ("muh");
756 fail_unless (gst_pad_set_caps (ghost, caps1));
757 caps2 = gst_pad_get_current_caps (sink);
758 fail_unless (gst_caps_is_equal (caps1, caps2));
759 fail_unless_equals_int (notify_counter, 1);
761 gst_object_unref (ghost);
762 gst_caps_unref (caps1);
764 /* clear caps on pads */
765 gst_pad_set_active (src, FALSE);
766 gst_pad_set_active (src, TRUE);
767 gst_pad_set_active (sink, FALSE);
768 gst_pad_set_active (sink, TRUE);
770 /* sink pad 2, setting caps just on the target pad should not influence the caps
771 * on the ghostpad. */
773 ghost = gst_ghost_pad_new ("ghostsink", sink);
774 fail_unless (gst_pad_get_current_caps (ghost) == NULL);
775 g_signal_connect (ghost, "notify::caps",
776 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
777 fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
779 gst_pad_set_active (ghost, TRUE);
781 caps1 = gst_caps_from_string ("muh");
782 fail_unless (gst_pad_set_caps (sink, caps1));
783 caps2 = gst_pad_get_current_caps (ghost);
784 fail_unless (caps2 == NULL);
785 fail_unless_equals_int (notify_counter, 0);
787 gst_object_unref (ghost);
788 gst_caps_unref (caps1);
790 gst_object_unref (src);
791 gst_object_unref (sink);
792 gst_object_unref (src_template);
793 gst_object_unref (sink_template);
798 static gint linked_count1;
799 static gint unlinked_count1;
800 static gint linked_count2;
801 static gint unlinked_count2;
803 static GstPadLinkReturn
804 pad_linked1 (GstPad * pad, GstPad * peer)
808 return GST_PAD_LINK_OK;
812 pad_unlinked1 (GstPad * pad)
817 static GstPadLinkReturn
818 pad_linked2 (GstPad * pad, GstPad * peer)
822 return GST_PAD_LINK_OK;
826 pad_unlinked2 (GstPad * pad)
831 GST_START_TEST (test_ghost_pads_sink_link_unlink)
834 GstPad *srcpad, *sinkpad, *ghostpad;
835 GstPadTemplate *srctempl, *sinktempl;
836 GstPadLinkReturn ret;
839 padcaps = gst_caps_from_string ("some/caps");
840 fail_unless (padcaps != NULL);
841 srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
842 GST_PAD_ALWAYS, padcaps);
843 gst_caps_unref (padcaps);
845 padcaps = gst_caps_from_string ("some/caps");
846 fail_unless (padcaps != NULL);
847 sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
848 GST_PAD_ALWAYS, padcaps);
849 gst_caps_unref (padcaps);
851 srcpad = gst_pad_new_from_template (srctempl, "src");
852 fail_unless (srcpad != NULL);
853 sinkpad = gst_pad_new_from_template (sinktempl, "sink");
854 fail_unless (sinkpad != NULL);
856 /* set up link/unlink functions for the pad */
857 linked_count1 = unlinked_count1 = 0;
858 gst_pad_set_link_function (sinkpad, pad_linked1);
859 gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
860 linked_count2 = unlinked_count2 = 0;
861 gst_pad_set_link_function (srcpad, pad_linked2);
862 gst_pad_set_unlink_function (srcpad, pad_unlinked2);
864 /* this should trigger a link from the internal pad to the sinkpad */
865 ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
866 fail_unless (ghostpad != NULL);
867 fail_unless (linked_count1 == 1);
868 fail_unless (unlinked_count1 == 0);
869 fail_unless (linked_count2 == 0);
870 fail_unless (unlinked_count2 == 0);
872 /* this should not trigger anything because we are not directly
873 * linking/unlinking the sink pad. */
874 ret = gst_pad_link (srcpad, ghostpad);
875 fail_unless (ret == GST_PAD_LINK_OK);
876 fail_unless (linked_count1 == 1);
877 fail_unless (unlinked_count1 == 0);
878 fail_unless (linked_count2 == 1);
879 fail_unless (unlinked_count2 == 0);
881 res = gst_pad_unlink (srcpad, ghostpad);
882 fail_unless (res == TRUE);
883 fail_unless (linked_count1 == 1);
884 fail_unless (unlinked_count1 == 0);
885 fail_unless (linked_count2 == 1);
886 fail_unless (unlinked_count2 == 1);
888 /* this should trigger the unlink */
889 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
890 fail_unless (res == TRUE);
891 fail_unless (linked_count1 == 1);
892 fail_unless (unlinked_count1 == 1);
893 fail_unless (linked_count2 == 1);
894 fail_unless (unlinked_count2 == 1);
896 gst_object_unref (ghostpad);
897 gst_object_unref (sinkpad);
898 gst_object_unref (srcpad);
899 gst_object_unref (srctempl);
900 gst_object_unref (sinktempl);
905 GST_START_TEST (test_ghost_pads_src_link_unlink)
908 GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
909 GstPadTemplate *srctempl, *sinktempl;
910 GstPadLinkReturn ret;
913 padcaps = gst_caps_from_string ("some/caps");
914 fail_unless (padcaps != NULL);
915 srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
916 GST_PAD_ALWAYS, padcaps);
917 gst_caps_unref (padcaps);
919 padcaps = gst_caps_from_string ("some/caps");
920 fail_unless (padcaps != NULL);
921 sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
922 GST_PAD_ALWAYS, padcaps);
923 gst_caps_unref (padcaps);
925 srcpad = gst_pad_new_from_template (srctempl, "src");
926 fail_unless (srcpad != NULL);
927 sinkpad = gst_pad_new_from_template (sinktempl, "sink");
928 fail_unless (sinkpad != NULL);
930 /* set up link/unlink functions for the pad */
931 linked_count1 = unlinked_count1 = 0;
932 gst_pad_set_link_function (srcpad, pad_linked1);
933 gst_pad_set_unlink_function (srcpad, pad_unlinked1);
934 linked_count2 = unlinked_count2 = 0;
935 gst_pad_set_link_function (sinkpad, pad_linked2);
936 gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
938 /* this should trigger a link from the internal pad to the srcpad */
939 ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
940 fail_unless (ghostpad != NULL);
941 fail_unless (linked_count1 == 1);
942 fail_unless (unlinked_count1 == 0);
943 fail_unless (linked_count2 == 0);
944 fail_unless (unlinked_count2 == 0);
946 /* this should fail with a critial */
947 ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
948 fail_unless (dummy == NULL);
949 fail_unless (linked_count1 == 1);
950 fail_unless (unlinked_count1 == 0);
951 fail_unless (linked_count2 == 0);
952 fail_unless (unlinked_count2 == 0);
954 /* this should not trigger anything because we are not directly
955 * linking/unlinking the src pad. */
956 ret = gst_pad_link (ghostpad, sinkpad);
957 fail_unless (ret == GST_PAD_LINK_OK);
958 fail_unless (linked_count1 == 1);
959 fail_unless (unlinked_count1 == 0);
960 fail_unless (linked_count2 == 1);
961 fail_unless (unlinked_count2 == 0);
963 /* this link should fail because we are already linked. Let's make sure the
964 * link functions are not called */
965 ret = gst_pad_link (ghostpad, sinkpad);
966 fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
967 fail_unless (linked_count1 == 1);
968 fail_unless (unlinked_count1 == 0);
969 fail_unless (linked_count2 == 1);
970 fail_unless (unlinked_count2 == 0);
972 res = gst_pad_unlink (ghostpad, sinkpad);
973 fail_unless (res == TRUE);
974 fail_unless (linked_count1 == 1);
975 fail_unless (unlinked_count1 == 0);
976 fail_unless (linked_count2 == 1);
977 fail_unless (unlinked_count2 == 1);
979 res = gst_pad_unlink (ghostpad, sinkpad);
980 fail_unless (res == FALSE);
981 fail_unless (linked_count1 == 1);
982 fail_unless (unlinked_count1 == 0);
983 fail_unless (linked_count2 == 1);
984 fail_unless (unlinked_count2 == 1);
986 /* this should trigger the unlink function */
987 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
988 fail_unless (res == TRUE);
989 fail_unless (linked_count1 == 1);
990 fail_unless (unlinked_count1 == 1);
991 fail_unless (linked_count2 == 1);
992 fail_unless (unlinked_count2 == 1);
994 /* and this the link function again */
995 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
996 fail_unless (res == TRUE);
997 fail_unless (linked_count1 == 2);
998 fail_unless (unlinked_count1 == 1);
999 fail_unless (linked_count2 == 1);
1000 fail_unless (unlinked_count2 == 1);
1002 gst_object_unref (ghostpad);
1003 gst_object_unref (sinkpad);
1004 gst_object_unref (srcpad);
1005 gst_object_unref (srctempl);
1006 gst_object_unref (sinktempl);
1011 GST_START_TEST (test_ghost_pads_change_when_linked)
1013 GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1014 GstPad *sinkpad, *ghostpad;
1017 b1 = gst_element_factory_make ("pipeline", NULL);
1018 b2 = gst_element_factory_make ("bin", NULL);
1019 src = gst_element_factory_make ("fakesrc", NULL);
1020 fmt = gst_element_factory_make ("capsfilter", NULL);
1021 sink1 = gst_element_factory_make ("fakesink", NULL);
1022 sink2 = gst_element_factory_make ("fakesink", NULL);
1024 gst_bin_add (GST_BIN (b2), sink1);
1025 gst_bin_add (GST_BIN (b2), sink2);
1026 gst_bin_add (GST_BIN (b1), src);
1027 gst_bin_add (GST_BIN (b1), fmt);
1028 gst_bin_add (GST_BIN (b1), b2);
1030 caps = gst_caps_from_string ("audio/x-raw-int, width=16, channels=1");
1031 g_object_set (fmt, "caps", caps, NULL);
1032 gst_caps_unref (caps);
1034 /* create the ghostpad as a sink-pad for bin 2 */
1035 ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1036 gst_element_add_pad (b2, ghostpad);
1038 sinkpad = gst_element_get_static_pad (sink1, "sink");
1039 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1040 gst_object_unref (sinkpad);
1042 fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1044 /* set different target after ghostpad is linked */
1045 sinkpad = gst_element_get_static_pad (sink2, "sink");
1046 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1047 gst_object_unref (sinkpad);
1050 gst_object_unref (b1);
1057 gst_ghost_pad_suite (void)
1059 Suite *s = suite_create ("GstGhostPad");
1061 TCase *tc_chain = tcase_create ("ghost pad tests");
1063 suite_add_tcase (s, tc_chain);
1064 tcase_add_test (tc_chain, test_remove1);
1065 tcase_add_test (tc_chain, test_remove2);
1066 tcase_add_test (tc_chain, test_remove_target);
1067 tcase_add_test (tc_chain, test_link);
1068 tcase_add_test (tc_chain, test_ghost_pads);
1069 tcase_add_test (tc_chain, test_ghost_pads_bin);
1070 tcase_add_test (tc_chain, test_ghost_pads_notarget);
1071 tcase_add_test (tc_chain, test_ghost_pads_block);
1072 tcase_add_test (tc_chain, test_ghost_pads_probes);
1073 tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1074 tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1075 tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1076 tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1077 tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1078 tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1083 GST_CHECK_MAIN (gst_ghost_pad);