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 /* Refcount should be unchanged, targets are now decuced using peer pad */
110 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
111 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
112 gst_object_unref (srcpad);
113 gst_object_unref (sinkpad);
115 /* now remove the sink from the bin */
116 gst_bin_remove (GST_BIN (b2), sink);
118 srcpad = gst_element_get_static_pad (src, "src");
119 /* pad is still linked to ghostpad */
120 fail_if (!gst_pad_is_linked (srcpad));
121 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
122 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
123 gst_object_unref (srcpad);
124 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
127 /* now unlink the pads */
128 gst_pad_unlink (srcpad, sinkpad);
129 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); /* we dropped our ref */
130 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
132 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
133 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
134 /* remove b2 from b1 */
135 gst_bin_remove (GST_BIN (b1), b2);
137 /* flush the message, dropping the b1 refcount to 1 */
138 gst_element_set_state (b1, GST_STATE_READY);
139 gst_element_set_state (b1, GST_STATE_NULL);
140 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
141 gst_object_unref (b1);
148 /* test if a ghost pad without a target can be linked and
149 * unlinked. An untargeted ghostpad has a default ANY caps unless there
150 * is a padtemplate that says something else.
152 GST_START_TEST (test_ghost_pads_notarget)
154 GstElement *b1, *b2, *sink;
155 GstPad *srcpad, *sinkpad, *peer;
156 GstPadLinkReturn ret;
161 b1 = gst_element_factory_make ("pipeline", NULL);
163 /* make sure all messages are discarded */
164 bus = gst_pipeline_get_bus (GST_PIPELINE (b1));
165 gst_bus_set_flushing (bus, TRUE);
166 gst_object_unref (bus);
168 b2 = gst_element_factory_make ("bin", NULL);
169 sink = gst_element_factory_make ("fakesink", NULL);
171 fail_unless (gst_bin_add (GST_BIN (b1), sink));
172 fail_unless (gst_bin_add (GST_BIN (b1), b2));
174 srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
175 fail_unless (srcpad != NULL);
176 sinkpad = gst_element_get_static_pad (sink, "sink");
177 fail_unless (sinkpad != NULL);
179 ret = gst_pad_link (srcpad, sinkpad);
180 fail_unless (ret == GST_PAD_LINK_OK);
182 /* check if the peers are ok */
183 peer = gst_pad_get_peer (srcpad);
184 fail_unless (peer == sinkpad);
185 gst_object_unref (peer);
187 peer = gst_pad_get_peer (sinkpad);
188 fail_unless (peer == srcpad);
189 gst_object_unref (peer);
191 /* check caps, untargetted pad should return ANY or the padtemplate caps
192 * when it was created from a template */
193 caps = gst_pad_query_caps (srcpad, NULL);
194 fail_unless (gst_caps_is_any (caps));
195 gst_caps_unref (caps);
198 bret = gst_pad_unlink (srcpad, sinkpad);
199 fail_unless (bret == TRUE);
202 gst_object_unref (srcpad);
203 gst_object_unref (sinkpad);
204 gst_object_unref (b1);
209 /* Test that removing the target of a ghostpad properly sets the target of the
210 * ghostpad to NULL */
211 GST_START_TEST (test_remove_target)
213 GstElement *b1, *b2, *src, *sink;
214 GstPad *sinkpad, *ghost, *target;
216 b1 = gst_element_factory_make ("pipeline", NULL);
217 b2 = gst_element_factory_make ("bin", NULL);
218 src = gst_element_factory_make ("fakesrc", NULL);
219 sink = gst_element_factory_make ("fakesink", NULL);
220 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
222 fail_unless (gst_bin_add (GST_BIN (b2), sink));
223 fail_unless (gst_bin_add (GST_BIN (b1), src));
224 fail_unless (gst_bin_add (GST_BIN (b1), b2));
225 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
227 sinkpad = gst_element_get_static_pad (sink, "sink");
228 gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
230 ghost = gst_element_get_static_pad (b2, "sink");
232 target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
233 fail_unless (target == sinkpad);
234 gst_object_unref (target);
235 gst_object_unref (sinkpad);
237 gst_bin_remove (GST_BIN (b2), sink);
239 target = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost));
240 fail_unless (target == NULL);
242 gst_object_unref (b1);
243 gst_object_unref (ghost);
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", 2); /* parent */
365 ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2); /* parent */
366 ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2); /* parent */
367 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 2); /* parent */
369 ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2); /* parent */
370 ASSERT_OBJECT_REFCOUNT (isink, "isink", 2); /* parent */
371 ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
372 ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 2); /* parent */
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 GstPadProbeReturn
482 block_callback (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
484 BlockData *block_data = (BlockData *) user_data;
486 g_mutex_lock (&block_data->mutex);
487 GST_DEBUG ("blocked\n");
488 g_cond_signal (&block_data->cond);
489 g_mutex_unlock (&block_data->mutex);
491 return GST_PAD_PROBE_OK;
494 GST_START_TEST (test_ghost_pads_block)
501 BlockData block_data;
503 pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
505 srcbin = GST_BIN (gst_bin_new ("srcbin"));
506 gst_bin_add (pipeline, GST_ELEMENT (srcbin));
508 src = gst_element_factory_make ("fakesrc", "src");
509 gst_bin_add (srcbin, src);
510 srcpad = gst_element_get_static_pad (src, "src");
511 srcghost = gst_ghost_pad_new ("src", srcpad);
512 gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
513 gst_object_unref (srcpad);
515 g_mutex_init (&block_data.mutex);
516 g_cond_init (&block_data.cond);
518 g_mutex_lock (&block_data.mutex);
519 gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
521 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
523 g_cond_wait (&block_data.cond, &block_data.mutex);
524 g_mutex_unlock (&block_data.mutex);
525 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
527 g_mutex_clear (&block_data.mutex);
528 g_cond_clear (&block_data.cond);
530 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
531 gst_object_unref (pipeline);
536 GST_START_TEST (test_ghost_pads_probes)
543 BlockData block_data;
545 pipeline = GST_BIN (gst_pipeline_new ("pipeline"));
547 srcbin = GST_BIN (gst_bin_new ("srcbin"));
548 gst_bin_add (pipeline, GST_ELEMENT (srcbin));
550 src = gst_element_factory_make ("fakesrc", "src");
551 gst_bin_add (srcbin, src);
552 srcpad = gst_element_get_static_pad (src, "src");
553 srcghost = gst_ghost_pad_new ("src", srcpad);
554 gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
555 gst_object_unref (srcpad);
557 g_mutex_init (&block_data.mutex);
558 g_cond_init (&block_data.cond);
560 g_mutex_lock (&block_data.mutex);
561 gst_pad_add_probe (srcghost, GST_PAD_PROBE_TYPE_BLOCK, block_callback,
563 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
565 g_cond_wait (&block_data.cond, &block_data.mutex);
566 g_mutex_unlock (&block_data.mutex);
567 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
569 g_mutex_clear (&block_data.mutex);
570 g_cond_clear (&block_data.cond);
572 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
573 gst_object_unref (pipeline);
578 GST_START_TEST (test_ghost_pads_new_from_template)
580 GstPad *sinkpad, *ghostpad;
581 GstPadTemplate *padtempl, *ghosttempl;
582 GstCaps *padcaps, *ghostcaps, *newcaps;
584 padcaps = gst_caps_from_string ("some/caps");
585 fail_unless (padcaps != NULL);
586 ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
587 fail_unless (ghostcaps != NULL);
589 padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
590 GST_PAD_ALWAYS, padcaps);
591 fail_unless (padtempl != NULL);
592 ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
593 GST_PAD_ALWAYS, ghostcaps);
595 sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
596 fail_unless (sinkpad != NULL);
598 ghostpad = gst_ghost_pad_new_from_template ("ghostpad", sinkpad, ghosttempl);
599 fail_unless (ghostpad != NULL);
601 /* check template is properly set */
602 fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
604 /* check ghostpad caps are from the sinkpad */
605 newcaps = gst_pad_query_caps (ghostpad, NULL);
606 fail_unless (newcaps != NULL);
607 fail_unless (gst_caps_is_equal (newcaps, padcaps));
608 gst_caps_unref (newcaps);
609 gst_caps_unref (padcaps);
610 gst_caps_unref (ghostcaps);
612 gst_object_unref (sinkpad);
613 gst_object_unref (ghostpad);
615 gst_object_unref (padtempl);
616 gst_object_unref (ghosttempl);
621 GST_START_TEST (test_ghost_pads_new_no_target_from_template)
623 GstPad *sinkpad, *ghostpad;
624 GstPadTemplate *padtempl, *ghosttempl;
625 GstCaps *padcaps, *ghostcaps, *newcaps;
627 padcaps = gst_caps_from_string ("some/caps");
628 fail_unless (padcaps != NULL);
629 ghostcaps = gst_caps_from_string ("some/caps;some/other-caps");
630 fail_unless (ghostcaps != NULL);
632 padtempl = gst_pad_template_new ("padtempl", GST_PAD_SINK,
633 GST_PAD_ALWAYS, padcaps);
634 fail_unless (padtempl != NULL);
635 ghosttempl = gst_pad_template_new ("ghosttempl", GST_PAD_SINK,
636 GST_PAD_ALWAYS, ghostcaps);
638 sinkpad = gst_pad_new_from_template (padtempl, "sinkpad");
639 fail_unless (sinkpad != NULL);
641 ghostpad = gst_ghost_pad_new_no_target_from_template ("ghostpad", ghosttempl);
642 fail_unless (ghostpad != NULL);
644 /* check template is properly set */
645 fail_unless (GST_PAD_PAD_TEMPLATE (ghostpad) == ghosttempl);
647 /* check ghostpad caps are from the ghostpad template */
648 newcaps = gst_pad_query_caps (ghostpad, NULL);
649 fail_unless (newcaps != NULL);
650 fail_unless (gst_caps_is_equal (newcaps, ghostcaps));
651 gst_caps_unref (newcaps);
653 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
655 /* check ghostpad caps are now from the target pad */
656 newcaps = gst_pad_query_caps (ghostpad, NULL);
657 fail_unless (newcaps != NULL);
658 fail_unless (gst_caps_is_equal (newcaps, padcaps));
659 gst_caps_unref (newcaps);
661 gst_object_unref (sinkpad);
662 gst_object_unref (ghostpad);
664 gst_object_unref (padtempl);
665 gst_object_unref (ghosttempl);
667 gst_caps_unref (padcaps);
668 gst_caps_unref (ghostcaps);
674 ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data)
676 GST_DEBUG ("caps notify called");
677 (*(gint *) user_data)++;
680 GST_START_TEST (test_ghost_pads_forward_setcaps)
682 GstCaps *templ_caps, *caps1, *caps2;
683 GstPadTemplate *src_template, *sink_template;
684 GstPad *src, *ghost, *sink;
685 gint notify_counter = 0;
687 templ_caps = gst_caps_from_string ("meh; muh");
688 src_template = gst_pad_template_new ("src", GST_PAD_SRC,
689 GST_PAD_ALWAYS, templ_caps);
690 gst_caps_unref (templ_caps);
692 templ_caps = gst_caps_from_string ("muh; meh");
693 sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
694 GST_PAD_ALWAYS, templ_caps);
695 gst_caps_unref (templ_caps);
697 src = gst_pad_new_from_template (src_template, "src");
698 sink = gst_pad_new_from_template (sink_template, "sink");
700 /* ghost source pad, setting caps on the source influences the caps of the
702 ghost = gst_ghost_pad_new ("ghostsrc", src);
703 g_signal_connect (ghost, "notify::caps",
704 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
705 fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
707 /* Activate pads for caps forwarding/setting to work */
708 gst_pad_set_active (src, TRUE);
709 gst_pad_set_active (ghost, TRUE);
711 caps1 = gst_caps_from_string ("meh");
712 fail_unless (gst_pad_set_caps (src, caps1));
713 caps2 = gst_pad_get_current_caps (ghost);
714 fail_unless (gst_caps_is_equal (caps1, caps2));
715 fail_unless_equals_int (notify_counter, 1);
717 gst_object_unref (ghost);
718 gst_caps_unref (caps1);
719 gst_caps_unref (caps2);
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);
763 gst_caps_unref (caps2);
765 /* clear caps on pads */
766 gst_pad_set_active (src, FALSE);
767 gst_pad_set_active (src, TRUE);
768 gst_pad_set_active (sink, FALSE);
769 gst_pad_set_active (sink, TRUE);
771 /* sink pad 2, setting caps just on the target pad should not influence the caps
772 * on the ghostpad. */
774 ghost = gst_ghost_pad_new ("ghostsink", sink);
775 fail_unless (gst_pad_get_current_caps (ghost) == NULL);
776 g_signal_connect (ghost, "notify::caps",
777 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
778 fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
780 gst_pad_set_active (ghost, TRUE);
782 caps1 = gst_caps_from_string ("muh");
783 fail_unless (gst_pad_set_caps (sink, caps1));
784 caps2 = gst_pad_get_current_caps (ghost);
785 fail_unless (caps2 == NULL);
786 fail_unless_equals_int (notify_counter, 0);
788 gst_object_unref (ghost);
789 gst_caps_unref (caps1);
791 gst_object_unref (src);
792 gst_object_unref (sink);
793 gst_object_unref (src_template);
794 gst_object_unref (sink_template);
799 static gint linked_count1;
800 static gint unlinked_count1;
801 static gint linked_count2;
802 static gint unlinked_count2;
804 static GstPadLinkReturn
805 pad_linked1 (GstPad * pad, GstObject * parent, GstPad * peer)
809 return GST_PAD_LINK_OK;
813 pad_unlinked1 (GstPad * pad, GstObject * parent)
818 static GstPadLinkReturn
819 pad_linked2 (GstPad * pad, GstObject * parent, GstPad * peer)
823 return GST_PAD_LINK_OK;
827 pad_unlinked2 (GstPad * pad, GstObject * parent)
832 GST_START_TEST (test_ghost_pads_sink_link_unlink)
835 GstPad *srcpad, *sinkpad, *ghostpad;
836 GstPadTemplate *srctempl, *sinktempl;
837 GstPadLinkReturn ret;
840 padcaps = gst_caps_from_string ("some/caps");
841 fail_unless (padcaps != NULL);
842 srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
843 GST_PAD_ALWAYS, padcaps);
844 gst_caps_unref (padcaps);
846 padcaps = gst_caps_from_string ("some/caps");
847 fail_unless (padcaps != NULL);
848 sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
849 GST_PAD_ALWAYS, padcaps);
850 gst_caps_unref (padcaps);
852 srcpad = gst_pad_new_from_template (srctempl, "src");
853 fail_unless (srcpad != NULL);
854 sinkpad = gst_pad_new_from_template (sinktempl, "sink");
855 fail_unless (sinkpad != NULL);
857 /* set up link/unlink functions for the pad */
858 linked_count1 = unlinked_count1 = 0;
859 gst_pad_set_link_function (sinkpad, pad_linked1);
860 gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
861 linked_count2 = unlinked_count2 = 0;
862 gst_pad_set_link_function (srcpad, pad_linked2);
863 gst_pad_set_unlink_function (srcpad, pad_unlinked2);
865 /* this should trigger a link from the internal pad to the sinkpad */
866 ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
867 fail_unless (ghostpad != NULL);
868 fail_unless (linked_count1 == 1);
869 fail_unless (unlinked_count1 == 0);
870 fail_unless (linked_count2 == 0);
871 fail_unless (unlinked_count2 == 0);
873 /* this should not trigger anything because we are not directly
874 * linking/unlinking the sink pad. */
875 ret = gst_pad_link (srcpad, ghostpad);
876 fail_unless (ret == GST_PAD_LINK_OK);
877 fail_unless (linked_count1 == 1);
878 fail_unless (unlinked_count1 == 0);
879 fail_unless (linked_count2 == 1);
880 fail_unless (unlinked_count2 == 0);
882 res = gst_pad_unlink (srcpad, ghostpad);
883 fail_unless (res == TRUE);
884 fail_unless (linked_count1 == 1);
885 fail_unless (unlinked_count1 == 0);
886 fail_unless (linked_count2 == 1);
887 fail_unless (unlinked_count2 == 1);
889 /* this should trigger the unlink */
890 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
891 fail_unless (res == TRUE);
892 fail_unless (linked_count1 == 1);
893 fail_unless (unlinked_count1 == 1);
894 fail_unless (linked_count2 == 1);
895 fail_unless (unlinked_count2 == 1);
897 gst_object_unref (ghostpad);
898 gst_object_unref (sinkpad);
899 gst_object_unref (srcpad);
900 gst_object_unref (srctempl);
901 gst_object_unref (sinktempl);
906 GST_START_TEST (test_ghost_pads_src_link_unlink)
909 GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
910 GstPadTemplate *srctempl, *sinktempl;
911 GstPadLinkReturn ret;
914 padcaps = gst_caps_from_string ("some/caps");
915 fail_unless (padcaps != NULL);
916 srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
917 GST_PAD_ALWAYS, padcaps);
918 gst_caps_unref (padcaps);
920 padcaps = gst_caps_from_string ("some/caps");
921 fail_unless (padcaps != NULL);
922 sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
923 GST_PAD_ALWAYS, padcaps);
924 gst_caps_unref (padcaps);
926 srcpad = gst_pad_new_from_template (srctempl, "src");
927 fail_unless (srcpad != NULL);
928 sinkpad = gst_pad_new_from_template (sinktempl, "sink");
929 fail_unless (sinkpad != NULL);
931 /* set up link/unlink functions for the pad */
932 linked_count1 = unlinked_count1 = 0;
933 gst_pad_set_link_function (srcpad, pad_linked1);
934 gst_pad_set_unlink_function (srcpad, pad_unlinked1);
935 linked_count2 = unlinked_count2 = 0;
936 gst_pad_set_link_function (sinkpad, pad_linked2);
937 gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
939 /* this should trigger a link from the internal pad to the srcpad */
940 ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
941 fail_unless (ghostpad != NULL);
942 fail_unless (linked_count1 == 1);
943 fail_unless (unlinked_count1 == 0);
944 fail_unless (linked_count2 == 0);
945 fail_unless (unlinked_count2 == 0);
947 /* this should fail with a critial */
948 ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
949 fail_unless (dummy == NULL);
950 fail_unless (linked_count1 == 1);
951 fail_unless (unlinked_count1 == 0);
952 fail_unless (linked_count2 == 0);
953 fail_unless (unlinked_count2 == 0);
955 /* this should not trigger anything because we are not directly
956 * linking/unlinking the src pad. */
957 ret = gst_pad_link (ghostpad, sinkpad);
958 fail_unless (ret == GST_PAD_LINK_OK);
959 fail_unless (linked_count1 == 1);
960 fail_unless (unlinked_count1 == 0);
961 fail_unless (linked_count2 == 1);
962 fail_unless (unlinked_count2 == 0);
964 /* this link should fail because we are already linked. Let's make sure the
965 * link functions are not called */
966 ret = gst_pad_link (ghostpad, sinkpad);
967 fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
968 fail_unless (linked_count1 == 1);
969 fail_unless (unlinked_count1 == 0);
970 fail_unless (linked_count2 == 1);
971 fail_unless (unlinked_count2 == 0);
973 res = gst_pad_unlink (ghostpad, sinkpad);
974 fail_unless (res == TRUE);
975 fail_unless (linked_count1 == 1);
976 fail_unless (unlinked_count1 == 0);
977 fail_unless (linked_count2 == 1);
978 fail_unless (unlinked_count2 == 1);
980 res = gst_pad_unlink (ghostpad, sinkpad);
981 fail_unless (res == FALSE);
982 fail_unless (linked_count1 == 1);
983 fail_unless (unlinked_count1 == 0);
984 fail_unless (linked_count2 == 1);
985 fail_unless (unlinked_count2 == 1);
987 /* this should trigger the unlink function */
988 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
989 fail_unless (res == TRUE);
990 fail_unless (linked_count1 == 1);
991 fail_unless (unlinked_count1 == 1);
992 fail_unless (linked_count2 == 1);
993 fail_unless (unlinked_count2 == 1);
995 /* and this the link function again */
996 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
997 fail_unless (res == TRUE);
998 fail_unless (linked_count1 == 2);
999 fail_unless (unlinked_count1 == 1);
1000 fail_unless (linked_count2 == 1);
1001 fail_unless (unlinked_count2 == 1);
1003 gst_object_unref (ghostpad);
1004 gst_object_unref (sinkpad);
1005 gst_object_unref (srcpad);
1006 gst_object_unref (srctempl);
1007 gst_object_unref (sinktempl);
1012 GST_START_TEST (test_ghost_pads_change_when_linked)
1014 GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1015 GstPad *sinkpad, *ghostpad;
1018 b1 = gst_element_factory_make ("pipeline", NULL);
1019 b2 = gst_element_factory_make ("bin", NULL);
1020 src = gst_element_factory_make ("fakesrc", NULL);
1021 fmt = gst_element_factory_make ("capsfilter", NULL);
1022 sink1 = gst_element_factory_make ("fakesink", NULL);
1023 sink2 = gst_element_factory_make ("fakesink", NULL);
1025 gst_bin_add (GST_BIN (b2), sink1);
1026 gst_bin_add (GST_BIN (b2), sink2);
1027 gst_bin_add (GST_BIN (b1), src);
1028 gst_bin_add (GST_BIN (b1), fmt);
1029 gst_bin_add (GST_BIN (b1), b2);
1031 caps = gst_caps_from_string ("audio/x-raw, format=S16LE, channels=1");
1032 g_object_set (fmt, "caps", caps, NULL);
1033 gst_caps_unref (caps);
1035 /* create the ghostpad as a sink-pad for bin 2 */
1036 ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1037 gst_element_add_pad (b2, ghostpad);
1039 sinkpad = gst_element_get_static_pad (sink1, "sink");
1040 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1041 gst_object_unref (sinkpad);
1043 fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1045 /* set different target after ghostpad is linked */
1046 sinkpad = gst_element_get_static_pad (sink2, "sink");
1047 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1048 gst_object_unref (sinkpad);
1051 gst_object_unref (b1);
1056 /* test that setting a ghostpad proxy pad as ghostpad target automatically set
1057 * both ghostpad targets.
1059 * fakesrc ! ( ) ! fakesink
1062 GST_START_TEST (test_ghost_pads_internal_link)
1064 GstElement *pipeline, *src, *bin, *sink;
1065 GstPad *sinkpad, *srcpad, *target;
1066 GstProxyPad *proxypad;
1068 pipeline = gst_element_factory_make ("pipeline", NULL);
1069 bin = gst_element_factory_make ("bin", NULL);
1070 src = gst_element_factory_make ("fakesrc", NULL);
1071 sink = gst_element_factory_make ("fakesink", NULL);
1073 gst_bin_add (GST_BIN (pipeline), src);
1074 gst_bin_add (GST_BIN (pipeline), bin);
1075 gst_bin_add (GST_BIN (pipeline), sink);
1077 /* create the sink ghostpad */
1078 sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1079 proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1080 gst_element_add_pad (bin, sinkpad);
1082 /* create the src ghostpad and link it to sink proxypad */
1083 srcpad = gst_ghost_pad_new ("src", GST_PAD (proxypad));
1084 gst_object_unref (proxypad);
1085 gst_element_add_pad (bin, srcpad);
1087 fail_unless (gst_element_link_many (src, bin, sink, NULL));
1089 /* Check that both targets are set, and point to each other */
1090 target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkpad));
1091 fail_if (target == NULL);
1092 proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (srcpad));
1093 fail_unless (target == GST_PAD (proxypad));
1094 gst_object_unref (target);
1095 gst_object_unref (proxypad);
1097 target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
1098 fail_if (target == NULL);
1099 proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1100 fail_unless (target == GST_PAD (proxypad));
1101 gst_object_unref (target);
1102 gst_object_unref (proxypad);
1105 gst_object_unref (pipeline);
1110 /* Test that remove a ghostpad that has something flowing through it does not
1118 static GstPadProbeReturn
1119 remove_ghostpad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer data)
1121 gst_pad_set_active (ghostsrc, FALSE);
1122 gst_pad_set_active (ghostsink, FALSE);
1123 gst_element_remove_pad (bin, ghostsrc);
1124 gst_element_remove_pad (bin, ghostsink);
1126 return GST_PAD_PROBE_DROP;
1129 GST_START_TEST (test_ghost_pads_remove_while_playing)
1134 bin = gst_bin_new (NULL);
1135 gst_element_set_state (bin, GST_STATE_PLAYING);
1136 sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
1138 ghostsrc = gst_ghost_pad_new_no_target ("ghostsrc", GST_PAD_SRC);
1139 sinkpad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ghostsrc)));
1140 ghostsink = gst_ghost_pad_new ("ghostsink", sinkpad);
1141 gst_object_unref (sinkpad);
1142 gst_pad_set_active (ghostsrc, TRUE);
1143 gst_pad_set_active (ghostsink, TRUE);
1144 gst_element_add_pad (bin, ghostsrc);
1145 gst_element_add_pad (bin, ghostsink);
1147 srcpad = gst_pad_new ("srcpad", GST_PAD_SRC);
1148 gst_pad_set_active (srcpad, TRUE);
1149 gst_pad_link (srcpad, ghostsink);
1151 gst_pad_add_probe (ghostsrc, GST_PAD_PROBE_TYPE_BUFFER,
1152 remove_ghostpad_probe_cb, NULL, NULL);
1154 g_assert (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
1156 gst_pad_set_active (srcpad, FALSE);
1157 gst_element_set_state (bin, GST_STATE_NULL);
1158 gst_object_unref (bin);
1159 gst_object_unref (srcpad);
1165 gst_ghost_pad_suite (void)
1167 Suite *s = suite_create ("GstGhostPad");
1169 TCase *tc_chain = tcase_create ("ghost pad tests");
1171 suite_add_tcase (s, tc_chain);
1172 tcase_add_test (tc_chain, test_remove1);
1173 tcase_add_test (tc_chain, test_remove2);
1174 tcase_add_test (tc_chain, test_remove_target);
1175 tcase_add_test (tc_chain, test_link);
1176 tcase_add_test (tc_chain, test_ghost_pads);
1177 tcase_add_test (tc_chain, test_ghost_pads_bin);
1178 tcase_add_test (tc_chain, test_ghost_pads_notarget);
1179 tcase_add_test (tc_chain, test_ghost_pads_block);
1180 tcase_add_test (tc_chain, test_ghost_pads_probes);
1181 tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1182 tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1183 tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1184 tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1185 tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1186 tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1187 tcase_add_test (tc_chain, test_ghost_pads_internal_link);
1188 tcase_add_test (tc_chain, test_ghost_pads_remove_while_playing);
1193 GST_CHECK_MAIN (gst_ghost_pad);