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., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include <gst/check/gstcheck.h>
23 #include <gst/check/gstharness.h>
25 /* test if removing a bin also cleans up the ghostpads
27 GST_START_TEST (test_remove1)
29 GstElement *b1, *b2, *src, *sink;
30 GstPad *srcpad, *sinkpad;
33 b1 = gst_element_factory_make ("pipeline", NULL);
34 b2 = gst_element_factory_make ("bin", NULL);
35 src = gst_element_factory_make ("fakesrc", NULL);
36 sink = gst_element_factory_make ("fakesink", NULL);
37 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
38 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
40 fail_unless (gst_bin_add (GST_BIN (b2), sink));
41 fail_unless (gst_bin_add (GST_BIN (b1), src));
42 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
43 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
44 fail_unless (gst_bin_add (GST_BIN (b1), b2));
45 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
46 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
48 sinkpad = gst_element_get_static_pad (sink, "sink");
49 gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
50 gst_object_unref (sinkpad);
52 srcpad = gst_element_get_static_pad (src, "src");
53 /* get the ghostpad */
54 sinkpad = gst_element_get_static_pad (b2, "sink");
56 ret = gst_pad_link (srcpad, sinkpad);
57 fail_unless (ret == GST_PAD_LINK_OK);
58 gst_object_unref (srcpad);
59 gst_object_unref (sinkpad);
61 /* now remove the bin with the ghostpad, b2 is disposed now. */
62 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
63 ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
64 gst_bin_remove (GST_BIN (b1), b2);
66 srcpad = gst_element_get_static_pad (src, "src");
67 /* pad cannot be linked now */
68 fail_if (gst_pad_is_linked (srcpad));
69 gst_object_unref (srcpad);
71 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
72 gst_object_unref (b1);
77 /* test if removing a bin also cleans up the ghostpads
79 GST_START_TEST (test_remove2)
81 GstElement *b1, *b2, *src, *sink;
82 GstPad *srcpad, *sinkpad;
85 b1 = gst_element_factory_make ("pipeline", NULL);
86 b2 = gst_element_factory_make ("bin", NULL);
87 src = gst_element_factory_make ("fakesrc", NULL);
88 sink = gst_element_factory_make ("fakesink", NULL);
89 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
91 fail_unless (gst_bin_add (GST_BIN (b2), sink));
92 fail_unless (gst_bin_add (GST_BIN (b1), src));
93 fail_unless (gst_bin_add (GST_BIN (b1), b2));
94 ASSERT_OBJECT_REFCOUNT (src, "src", 1);
96 sinkpad = gst_element_get_static_pad (sink, "sink");
97 gst_element_add_pad (b2, gst_ghost_pad_new ("sink", sinkpad));
98 gst_object_unref (sinkpad);
100 srcpad = gst_element_get_static_pad (src, "src");
101 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2); /* since we got one */
102 /* get the ghostpad */
103 sinkpad = gst_element_get_static_pad (b2, "sink");
104 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2); /* since we got one */
106 GST_DEBUG ("linking srcpad and sinkpad");
107 ret = gst_pad_link (srcpad, sinkpad);
108 GST_DEBUG ("linked srcpad and sinkpad");
109 fail_unless (ret == GST_PAD_LINK_OK);
110 /* Refcount should be unchanged, targets are now decuced using peer pad */
111 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
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", 2);
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); /* we dropped our 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_query_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);
244 gst_object_unref (ghost);
250 /* test if linking fails over different bins using a pipeline
253 * fakesrc num_buffers=10 ! ( fakesink )
256 GST_START_TEST (test_link)
258 GstElement *b1, *b2, *src, *sink;
259 GstPad *srcpad, *sinkpad, *gpad, *ppad, *tmp;
260 GstPadLinkReturn ret;
262 b1 = gst_element_factory_make ("pipeline", NULL);
263 b2 = gst_element_factory_make ("bin", NULL);
264 src = gst_element_factory_make ("fakesrc", NULL);
265 sink = gst_element_factory_make ("fakesink", NULL);
267 fail_unless (gst_bin_add (GST_BIN (b2), sink));
268 fail_unless (gst_bin_add (GST_BIN (b1), src));
269 fail_unless (gst_bin_add (GST_BIN (b1), b2));
271 srcpad = gst_element_get_static_pad (src, "src");
272 fail_unless (srcpad != NULL);
273 sinkpad = gst_element_get_static_pad (sink, "sink");
274 fail_unless (sinkpad != NULL);
276 /* linking in different hierarchies should fail */
277 ret = gst_pad_link (srcpad, sinkpad);
278 fail_unless (ret == GST_PAD_LINK_WRONG_HIERARCHY);
280 /* now setup a ghostpad */
281 gpad = gst_ghost_pad_new ("sink", sinkpad);
283 /* Check if the internal pads are set correctly */
284 ppad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
285 fail_unless (ppad == GST_PAD_PEER (sinkpad));
286 tmp = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ppad)));
287 fail_unless (tmp == gpad);
288 gst_object_unref (tmp);
289 gst_object_unref (ppad);
290 gst_object_unref (sinkpad);
291 /* need to ref as _add_pad takes ownership */
292 gst_object_ref (gpad);
293 gst_element_add_pad (b2, gpad);
295 /* our new sinkpad */
298 /* and linking should work now */
299 ret = gst_pad_link (srcpad, sinkpad);
300 fail_unless (ret == GST_PAD_LINK_OK);
302 /* flush the message, dropping the b1 refcount to 1 */
303 gst_element_set_state (b1, GST_STATE_READY);
304 gst_element_set_state (b1, GST_STATE_NULL);
305 ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 1);
307 gst_object_unref (srcpad);
308 gst_object_unref (sinkpad);
309 gst_object_unref (b1);
314 /* test if ghostpads are created automagically when using
315 * gst_element_link_pads.
317 * fakesrc num_buffers=10 ! ( identity ) ! fakesink
319 GST_START_TEST (test_ghost_pads)
321 GstElement *b1, *b2, *src, *i1, *sink;
322 GstPad *gsink, *gsrc, *gisrc, *gisink, *isink, *isrc, *fsrc, *fsink;
323 GstStateChangeReturn ret;
325 b1 = gst_element_factory_make ("pipeline", NULL);
326 b2 = gst_element_factory_make ("bin", NULL);
327 src = gst_element_factory_make ("fakesrc", NULL);
328 g_object_set (src, "num-buffers", (int) 10, NULL);
329 i1 = gst_element_factory_make ("identity", NULL);
330 sink = gst_element_factory_make ("fakesink", NULL);
332 fail_unless (gst_bin_add (GST_BIN (b2), i1));
333 fail_unless (gst_bin_add (GST_BIN (b1), src));
334 fail_unless (gst_bin_add (GST_BIN (b1), b2));
335 fail_unless (gst_bin_add (GST_BIN (b1), sink));
336 fail_unless (gst_element_link_pads (src, NULL, i1, NULL));
337 fail_unless (gst_element_link_pads (i1, NULL, sink, NULL));
338 GST_OBJECT_LOCK (b2);
339 fail_unless (b2->numsinkpads == 1);
340 fail_unless (GST_IS_GHOST_PAD (b2->sinkpads->data));
341 fail_unless (b2->numsrcpads == 1);
342 fail_unless (GST_IS_GHOST_PAD (b2->srcpads->data));
343 GST_OBJECT_UNLOCK (b2);
345 fsrc = gst_element_get_static_pad (src, "src");
346 fail_unless (fsrc != NULL);
347 gsink = GST_PAD (gst_object_ref (b2->sinkpads->data));
348 fail_unless (gsink != NULL);
349 gsrc = GST_PAD (gst_object_ref (b2->srcpads->data));
350 fail_unless (gsrc != NULL);
351 fsink = gst_element_get_static_pad (sink, "sink");
352 fail_unless (fsink != NULL);
354 isink = gst_element_get_static_pad (i1, "sink");
355 fail_unless (isink != NULL);
356 isrc = gst_element_get_static_pad (i1, "src");
357 fail_unless (isrc != NULL);
358 gisrc = gst_pad_get_peer (isink);
359 fail_unless (gisrc != NULL);
360 gisink = gst_pad_get_peer (isrc);
361 fail_unless (gisink != NULL);
363 /* all objects above have one refcount owned by us as well */
365 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 2); /* parent */
366 ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 2); /* parent */
367 ASSERT_OBJECT_REFCOUNT (gsrc, "gsrc", 2); /* parent */
368 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 2); /* parent */
370 ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2); /* parent */
371 ASSERT_OBJECT_REFCOUNT (isink, "isink", 2); /* parent */
372 ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* parent */
373 ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 2); /* parent */
375 ret = gst_element_set_state (b1, GST_STATE_PLAYING);
376 ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
377 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
379 ret = gst_element_set_state (b1, GST_STATE_NULL);
380 ret = gst_element_get_state (b1, NULL, NULL, GST_CLOCK_TIME_NONE);
381 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
383 gst_object_unref (b1);
384 /* unreffing the bin will unref all elements, which will unlink and unparent
387 /* wait for thread to settle down */
388 while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 1)
391 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
392 ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
393 ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
394 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
396 ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2); /* gsink */
397 ASSERT_OBJECT_REFCOUNT (isink, "isink", 1); /* gsink */
398 ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
399 ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1); /* gsrc */
401 gst_object_unref (gsink);
402 ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
403 ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
404 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
405 gst_object_unref (gisrc);
406 ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
408 gst_object_unref (gsrc);
409 ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
410 ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
411 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
412 gst_object_unref (gisink);
413 ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
415 gst_object_unref (fsrc);
416 gst_object_unref (isrc);
417 gst_object_unref (isink);
418 gst_object_unref (fsink);
423 GST_START_TEST (test_ghost_pads_bin)
430 GstPad *srcpad, *srcghost, *target;
431 GstPad *sinkpad, *sinkghost;
433 pipeline = GST_BIN (gst_pipeline_new ("pipe"));
434 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
436 srcbin = GST_BIN (gst_bin_new ("srcbin"));
437 gst_bin_add (pipeline, GST_ELEMENT (srcbin));
438 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
440 sinkbin = GST_BIN (gst_bin_new ("sinkbin"));
441 gst_bin_add (pipeline, GST_ELEMENT (sinkbin));
442 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
444 src = gst_element_factory_make ("fakesrc", "src");
445 gst_bin_add (srcbin, src);
446 srcpad = gst_element_get_static_pad (src, "src");
447 srcghost = gst_ghost_pad_new ("src", srcpad);
448 gst_object_unref (srcpad);
449 gst_element_add_pad (GST_ELEMENT (srcbin), srcghost);
451 sink = gst_element_factory_make ("fakesink", "sink");
452 gst_bin_add (sinkbin, sink);
453 sinkpad = gst_element_get_static_pad (sink, "sink");
454 sinkghost = gst_ghost_pad_new ("sink", sinkpad);
455 gst_object_unref (sinkpad);
456 gst_element_add_pad (GST_ELEMENT (sinkbin), sinkghost);
458 gst_element_link (GST_ELEMENT (srcbin), GST_ELEMENT (sinkbin));
460 fail_unless (GST_PAD_PEER (srcghost) != NULL);
461 fail_unless (GST_PAD_PEER (sinkghost) != NULL);
462 target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcghost));
463 fail_unless (GST_PAD_PEER (target) != NULL);
464 gst_object_unref (target);
465 target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkghost));
466 fail_unless (GST_PAD_PEER (target) != NULL);
467 gst_object_unref (target);
469 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
471 gst_object_unref (pipeline);
482 static GstPadProbeReturn
483 block_callback (GstPad * pad, GstPadProbeInfo * info, gpointer user_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);
492 return GST_PAD_PROBE_OK;
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 g_mutex_init (&block_data.mutex);
517 g_cond_init (&block_data.cond);
519 g_mutex_lock (&block_data.mutex);
520 gst_pad_add_probe (srcghost, GST_PAD_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 g_mutex_unlock (&block_data.mutex);
526 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
528 g_mutex_clear (&block_data.mutex);
529 g_cond_clear (&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 g_mutex_init (&block_data.mutex);
559 g_cond_init (&block_data.cond);
561 g_mutex_lock (&block_data.mutex);
562 gst_pad_add_probe (srcghost, GST_PAD_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 g_mutex_unlock (&block_data.mutex);
568 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
570 g_mutex_clear (&block_data.mutex);
571 g_cond_clear (&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_query_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_query_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_query_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);
720 gst_caps_unref (caps2);
722 /* source 2, setting the caps on the ghostpad does not influence the caps of
725 ghost = gst_ghost_pad_new ("ghostsrc", src);
726 g_signal_connect (ghost, "notify::caps",
727 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
728 fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK);
730 gst_pad_set_active (ghost, TRUE);
731 gst_pad_set_active (sink, TRUE);
733 caps1 = gst_caps_from_string ("meh");
734 fail_unless (gst_pad_set_caps (ghost, caps1));
736 caps2 = gst_pad_get_current_caps (src);
737 fail_unless (caps2 == NULL);
739 fail_unless_equals_int (notify_counter, 1);
741 gst_object_unref (ghost);
742 gst_caps_unref (caps1);
745 /* ghost sink pad. Setting caps on the ghostpad will also set those caps on
748 ghost = gst_ghost_pad_new ("ghostsink", sink);
749 g_signal_connect (ghost, "notify::caps",
750 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
751 fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
753 gst_pad_set_active (src, TRUE);
754 gst_pad_set_active (ghost, TRUE);
756 caps1 = gst_caps_from_string ("muh");
757 fail_unless (gst_pad_set_caps (ghost, caps1));
758 caps2 = gst_pad_get_current_caps (sink);
759 fail_unless (gst_caps_is_equal (caps1, caps2));
760 fail_unless_equals_int (notify_counter, 1);
762 gst_object_unref (ghost);
763 gst_caps_unref (caps1);
764 gst_caps_unref (caps2);
766 /* clear caps on pads */
767 gst_pad_set_active (src, FALSE);
768 gst_pad_set_active (src, TRUE);
769 gst_pad_set_active (sink, FALSE);
770 gst_pad_set_active (sink, TRUE);
772 /* sink pad 2, setting caps just on the target pad should not influence the caps
773 * on the ghostpad. */
775 ghost = gst_ghost_pad_new ("ghostsink", sink);
776 fail_unless (gst_pad_get_current_caps (ghost) == NULL);
777 g_signal_connect (ghost, "notify::caps",
778 G_CALLBACK (ghost_notify_caps), ¬ify_counter);
779 fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK);
781 gst_pad_set_active (ghost, TRUE);
783 caps1 = gst_caps_from_string ("muh");
784 fail_unless (gst_pad_set_caps (sink, caps1));
785 caps2 = gst_pad_get_current_caps (ghost);
786 fail_unless (caps2 == NULL);
787 fail_unless_equals_int (notify_counter, 0);
789 gst_object_unref (ghost);
790 gst_caps_unref (caps1);
792 gst_object_unref (src);
793 gst_object_unref (sink);
794 gst_object_unref (src_template);
795 gst_object_unref (sink_template);
800 static gint linked_count1;
801 static gint unlinked_count1;
802 static gint linked_count2;
803 static gint unlinked_count2;
805 static GstPadLinkReturn
806 pad_linked1 (GstPad * pad, GstObject * parent, GstPad * peer)
810 return GST_PAD_LINK_OK;
814 pad_unlinked1 (GstPad * pad, GstObject * parent)
819 static GstPadLinkReturn
820 pad_linked2 (GstPad * pad, GstObject * parent, GstPad * peer)
824 return GST_PAD_LINK_OK;
828 pad_unlinked2 (GstPad * pad, GstObject * parent)
833 GST_START_TEST (test_ghost_pads_sink_link_unlink)
836 GstPad *srcpad, *sinkpad, *ghostpad;
837 GstPadTemplate *srctempl, *sinktempl;
838 GstPadLinkReturn ret;
841 padcaps = gst_caps_from_string ("some/caps");
842 fail_unless (padcaps != NULL);
843 srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
844 GST_PAD_ALWAYS, padcaps);
845 gst_caps_unref (padcaps);
847 padcaps = gst_caps_from_string ("some/caps");
848 fail_unless (padcaps != NULL);
849 sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
850 GST_PAD_ALWAYS, padcaps);
851 gst_caps_unref (padcaps);
853 srcpad = gst_pad_new_from_template (srctempl, "src");
854 fail_unless (srcpad != NULL);
855 sinkpad = gst_pad_new_from_template (sinktempl, "sink");
856 fail_unless (sinkpad != NULL);
858 /* set up link/unlink functions for the pad */
859 linked_count1 = unlinked_count1 = 0;
860 gst_pad_set_link_function (sinkpad, pad_linked1);
861 gst_pad_set_unlink_function (sinkpad, pad_unlinked1);
862 linked_count2 = unlinked_count2 = 0;
863 gst_pad_set_link_function (srcpad, pad_linked2);
864 gst_pad_set_unlink_function (srcpad, pad_unlinked2);
866 /* this should trigger a link from the internal pad to the sinkpad */
867 ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad);
868 fail_unless (ghostpad != NULL);
869 fail_unless (linked_count1 == 1);
870 fail_unless (unlinked_count1 == 0);
871 fail_unless (linked_count2 == 0);
872 fail_unless (unlinked_count2 == 0);
874 /* this should not trigger anything because we are not directly
875 * linking/unlinking the sink pad. */
876 ret = gst_pad_link (srcpad, ghostpad);
877 fail_unless (ret == GST_PAD_LINK_OK);
878 fail_unless (linked_count1 == 1);
879 fail_unless (unlinked_count1 == 0);
880 fail_unless (linked_count2 == 1);
881 fail_unless (unlinked_count2 == 0);
883 res = gst_pad_unlink (srcpad, ghostpad);
884 fail_unless (res == TRUE);
885 fail_unless (linked_count1 == 1);
886 fail_unless (unlinked_count1 == 0);
887 fail_unless (linked_count2 == 1);
888 fail_unless (unlinked_count2 == 1);
890 /* this should trigger the unlink */
891 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
892 fail_unless (res == TRUE);
893 fail_unless (linked_count1 == 1);
894 fail_unless (unlinked_count1 == 1);
895 fail_unless (linked_count2 == 1);
896 fail_unless (unlinked_count2 == 1);
898 gst_object_unref (ghostpad);
899 gst_object_unref (sinkpad);
900 gst_object_unref (srcpad);
901 gst_object_unref (srctempl);
902 gst_object_unref (sinktempl);
907 GST_START_TEST (test_ghost_pads_src_link_unlink)
910 GstPad *srcpad, *sinkpad, *ghostpad, *dummy;
911 GstPadTemplate *srctempl, *sinktempl;
912 GstPadLinkReturn ret;
915 padcaps = gst_caps_from_string ("some/caps");
916 fail_unless (padcaps != NULL);
917 srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC,
918 GST_PAD_ALWAYS, padcaps);
919 gst_caps_unref (padcaps);
921 padcaps = gst_caps_from_string ("some/caps");
922 fail_unless (padcaps != NULL);
923 sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK,
924 GST_PAD_ALWAYS, padcaps);
925 gst_caps_unref (padcaps);
927 srcpad = gst_pad_new_from_template (srctempl, "src");
928 fail_unless (srcpad != NULL);
929 sinkpad = gst_pad_new_from_template (sinktempl, "sink");
930 fail_unless (sinkpad != NULL);
932 /* set up link/unlink functions for the pad */
933 linked_count1 = unlinked_count1 = 0;
934 gst_pad_set_link_function (srcpad, pad_linked1);
935 gst_pad_set_unlink_function (srcpad, pad_unlinked1);
936 linked_count2 = unlinked_count2 = 0;
937 gst_pad_set_link_function (sinkpad, pad_linked2);
938 gst_pad_set_unlink_function (sinkpad, pad_unlinked2);
940 /* this should trigger a link from the internal pad to the srcpad */
941 ghostpad = gst_ghost_pad_new ("ghostpad", srcpad);
942 fail_unless (ghostpad != NULL);
943 fail_unless (linked_count1 == 1);
944 fail_unless (unlinked_count1 == 0);
945 fail_unless (linked_count2 == 0);
946 fail_unless (unlinked_count2 == 0);
948 /* this should fail with a critial */
949 ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad));
950 fail_unless (dummy == NULL);
951 fail_unless (linked_count1 == 1);
952 fail_unless (unlinked_count1 == 0);
953 fail_unless (linked_count2 == 0);
954 fail_unless (unlinked_count2 == 0);
956 /* this should not trigger anything because we are not directly
957 * linking/unlinking the src pad. */
958 ret = gst_pad_link (ghostpad, sinkpad);
959 fail_unless (ret == GST_PAD_LINK_OK);
960 fail_unless (linked_count1 == 1);
961 fail_unless (unlinked_count1 == 0);
962 fail_unless (linked_count2 == 1);
963 fail_unless (unlinked_count2 == 0);
965 /* this link should fail because we are already linked. Let's make sure the
966 * link functions are not called */
967 ret = gst_pad_link (ghostpad, sinkpad);
968 fail_unless (ret == GST_PAD_LINK_WAS_LINKED);
969 fail_unless (linked_count1 == 1);
970 fail_unless (unlinked_count1 == 0);
971 fail_unless (linked_count2 == 1);
972 fail_unless (unlinked_count2 == 0);
974 res = gst_pad_unlink (ghostpad, sinkpad);
975 fail_unless (res == TRUE);
976 fail_unless (linked_count1 == 1);
977 fail_unless (unlinked_count1 == 0);
978 fail_unless (linked_count2 == 1);
979 fail_unless (unlinked_count2 == 1);
981 res = gst_pad_unlink (ghostpad, sinkpad);
982 fail_unless (res == FALSE);
983 fail_unless (linked_count1 == 1);
984 fail_unless (unlinked_count1 == 0);
985 fail_unless (linked_count2 == 1);
986 fail_unless (unlinked_count2 == 1);
988 /* this should trigger the unlink function */
989 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
990 fail_unless (res == TRUE);
991 fail_unless (linked_count1 == 1);
992 fail_unless (unlinked_count1 == 1);
993 fail_unless (linked_count2 == 1);
994 fail_unless (unlinked_count2 == 1);
996 /* and this the link function again */
997 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad);
998 fail_unless (res == TRUE);
999 fail_unless (linked_count1 == 2);
1000 fail_unless (unlinked_count1 == 1);
1001 fail_unless (linked_count2 == 1);
1002 fail_unless (unlinked_count2 == 1);
1004 gst_object_unref (ghostpad);
1005 gst_object_unref (sinkpad);
1006 gst_object_unref (srcpad);
1007 gst_object_unref (srctempl);
1008 gst_object_unref (sinktempl);
1013 GST_START_TEST (test_ghost_pads_change_when_linked)
1015 GstElement *b1, *b2, *src, *fmt, *sink1, *sink2;
1016 GstPad *sinkpad, *ghostpad;
1019 b1 = gst_element_factory_make ("pipeline", NULL);
1020 b2 = gst_element_factory_make ("bin", NULL);
1021 src = gst_element_factory_make ("fakesrc", NULL);
1022 fmt = gst_element_factory_make ("capsfilter", NULL);
1023 sink1 = gst_element_factory_make ("fakesink", NULL);
1024 sink2 = gst_element_factory_make ("fakesink", NULL);
1026 gst_bin_add (GST_BIN (b2), sink1);
1027 gst_bin_add (GST_BIN (b2), sink2);
1028 gst_bin_add (GST_BIN (b1), src);
1029 gst_bin_add (GST_BIN (b1), fmt);
1030 gst_bin_add (GST_BIN (b1), b2);
1032 caps = gst_caps_from_string ("audio/x-raw, format=S16LE, channels=1");
1033 g_object_set (fmt, "caps", caps, NULL);
1034 gst_caps_unref (caps);
1036 /* create the ghostpad as a sink-pad for bin 2 */
1037 ghostpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1038 gst_element_add_pad (b2, ghostpad);
1040 sinkpad = gst_element_get_static_pad (sink1, "sink");
1041 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1042 gst_object_unref (sinkpad);
1044 fail_unless (gst_element_link_many (src, fmt, b2, NULL));
1046 /* set different target after ghostpad is linked */
1047 sinkpad = gst_element_get_static_pad (sink2, "sink");
1048 fail_unless (gst_ghost_pad_set_target ((GstGhostPad *) ghostpad, sinkpad));
1049 gst_object_unref (sinkpad);
1052 gst_object_unref (b1);
1057 /* test that setting a ghostpad proxy pad as ghostpad target automatically set
1058 * both ghostpad targets.
1060 * fakesrc ! ( ) ! fakesink
1063 GST_START_TEST (test_ghost_pads_internal_link)
1065 GstElement *pipeline, *src, *bin, *sink;
1066 GstPad *sinkpad, *srcpad, *target;
1067 GstProxyPad *proxypad;
1069 pipeline = gst_element_factory_make ("pipeline", NULL);
1070 bin = gst_element_factory_make ("bin", NULL);
1071 src = gst_element_factory_make ("fakesrc", NULL);
1072 sink = gst_element_factory_make ("fakesink", NULL);
1074 gst_bin_add (GST_BIN (pipeline), src);
1075 gst_bin_add (GST_BIN (pipeline), bin);
1076 gst_bin_add (GST_BIN (pipeline), sink);
1078 /* create the sink ghostpad */
1079 sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1080 proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1081 gst_element_add_pad (bin, sinkpad);
1083 /* create the src ghostpad and link it to sink proxypad */
1084 srcpad = gst_ghost_pad_new ("src", GST_PAD (proxypad));
1085 gst_object_unref (proxypad);
1086 gst_element_add_pad (bin, srcpad);
1088 fail_unless (gst_element_link_many (src, bin, sink, NULL));
1090 /* Check that both targets are set, and point to each other */
1091 target = gst_ghost_pad_get_target (GST_GHOST_PAD (sinkpad));
1092 fail_if (target == NULL);
1093 proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (srcpad));
1094 fail_unless (target == GST_PAD (proxypad));
1095 gst_object_unref (target);
1096 gst_object_unref (proxypad);
1098 target = gst_ghost_pad_get_target (GST_GHOST_PAD (srcpad));
1099 fail_if (target == NULL);
1100 proxypad = gst_proxy_pad_get_internal (GST_PROXY_PAD (sinkpad));
1101 fail_unless (target == GST_PAD (proxypad));
1102 gst_object_unref (target);
1103 gst_object_unref (proxypad);
1106 gst_object_unref (pipeline);
1111 /* Test that remove a ghostpad that has something flowing through it does not
1119 static GstPadProbeReturn
1120 remove_ghostpad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer data)
1122 gst_pad_set_active (ghostsrc, FALSE);
1123 gst_pad_set_active (ghostsink, FALSE);
1124 gst_element_remove_pad (bin, ghostsrc);
1125 gst_element_remove_pad (bin, ghostsink);
1127 return GST_PAD_PROBE_DROP;
1130 GST_START_TEST (test_ghost_pads_remove_while_playing)
1136 bin = gst_bin_new (NULL);
1137 gst_element_set_state (bin, GST_STATE_PLAYING);
1139 ghostsrc = gst_ghost_pad_new_no_target ("ghostsrc", GST_PAD_SRC);
1140 sinkpad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (ghostsrc)));
1141 ghostsink = gst_ghost_pad_new ("ghostsink", sinkpad);
1142 gst_object_unref (sinkpad);
1143 gst_pad_set_active (ghostsrc, TRUE);
1144 gst_pad_set_active (ghostsink, TRUE);
1145 gst_element_add_pad (bin, ghostsrc);
1146 gst_element_add_pad (bin, ghostsink);
1148 srcpad = gst_pad_new ("srcpad", GST_PAD_SRC);
1149 gst_pad_set_active (srcpad, TRUE);
1150 gst_pad_link (srcpad, ghostsink);
1152 gst_segment_init (&segment, GST_FORMAT_BYTES);
1153 fail_unless (gst_pad_push_event (srcpad,
1154 gst_event_new_stream_start ("test")) == TRUE);
1155 fail_unless (gst_pad_push_event (srcpad,
1156 gst_event_new_segment (&segment)) == TRUE);
1158 gst_pad_add_probe (ghostsrc, GST_PAD_PROBE_TYPE_BUFFER,
1159 remove_ghostpad_probe_cb, NULL, NULL);
1161 g_assert (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
1163 gst_pad_set_active (srcpad, FALSE);
1164 gst_element_set_state (bin, GST_STATE_NULL);
1165 gst_object_unref (bin);
1166 gst_object_unref (srcpad);
1172 GST_START_TEST (test_activate_src)
1179 b = gst_bin_new (NULL);
1180 src = gst_element_factory_make ("fakesrc", NULL);
1181 g_object_set (src, "sync", TRUE, NULL);
1182 gst_bin_add (GST_BIN (b), src);
1184 srcpad = gst_element_get_static_pad (src, "src");
1185 gst_element_add_pad (b, gst_ghost_pad_new ("src", srcpad));
1186 gst_object_unref (srcpad);
1188 h = gst_harness_new_with_element (b, NULL, "src");
1189 gst_harness_play (h);
1191 gst_harness_crank_single_clock_wait (h);
1192 gst_buffer_unref (gst_harness_pull (h));
1194 gst_object_unref (b);
1195 gst_harness_teardown (h);
1200 GST_START_TEST (test_activate_sink_and_src)
1204 GstElement *element;
1208 b = gst_bin_new (NULL);
1209 element = gst_element_factory_make ("identity", NULL);
1210 gst_bin_add (GST_BIN (b), element);
1212 sinkpad = gst_element_get_static_pad (element, "sink");
1213 gst_element_add_pad (b, gst_ghost_pad_new ("sink", sinkpad));
1214 gst_object_unref (sinkpad);
1216 srcpad = gst_element_get_static_pad (element, "src");
1217 gst_element_add_pad (b, gst_ghost_pad_new ("src", srcpad));
1218 gst_object_unref (srcpad);
1220 h = gst_harness_new_with_element (b, "sink", "src");
1221 gst_harness_set_src_caps_str (h, "mycaps");
1223 gst_harness_push (h, gst_buffer_new ());
1224 gst_buffer_unref (gst_harness_pull (h));
1226 gst_object_unref (b);
1227 gst_harness_teardown (h);
1232 GST_START_TEST (test_activate_src_pull_mode)
1237 GstPad *internalpad;
1240 b = gst_bin_new (NULL);
1241 src = gst_element_factory_make ("fakesrc", NULL);
1242 gst_bin_add (GST_BIN (b), src);
1244 srcpad = gst_element_get_static_pad (src, "src");
1245 ghost = gst_ghost_pad_new ("src", srcpad);
1246 gst_element_add_pad (b, ghost);
1248 internalpad = (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) ghost);
1250 fail_if (GST_PAD_IS_ACTIVE (ghost));
1251 fail_if (GST_PAD_IS_ACTIVE (internalpad));
1252 fail_if (GST_PAD_IS_ACTIVE (srcpad));
1253 fail_unless (gst_pad_activate_mode (ghost, GST_PAD_MODE_PULL, TRUE));
1254 fail_unless (GST_PAD_IS_ACTIVE (ghost));
1255 fail_unless (GST_PAD_IS_ACTIVE (internalpad));
1256 fail_unless (GST_PAD_IS_ACTIVE (srcpad));
1258 gst_object_unref (internalpad);
1259 gst_object_unref (srcpad);
1260 gst_object_unref (b);
1265 GST_START_TEST (test_activate_sink_switch_mode)
1267 GstElement *pipeline;
1268 GstElement *b, *src, *identity;
1269 GstPad *srcpad, *sinkpad, *internalpad, *ghost;
1271 pipeline = gst_pipeline_new (NULL);
1272 b = gst_bin_new (NULL);
1273 gst_bin_add (GST_BIN (pipeline), b);
1274 src = gst_element_factory_make ("fakesrc", NULL);
1275 gst_bin_add (GST_BIN (pipeline), src);
1276 identity = gst_element_factory_make ("identity", NULL);
1277 gst_bin_add (GST_BIN (b), identity);
1279 sinkpad = gst_element_get_static_pad (identity, "sink");
1280 ghost = gst_ghost_pad_new ("sink", sinkpad);
1281 gst_element_add_pad (b, ghost);
1282 srcpad = gst_element_get_static_pad (src, "src");
1283 gst_pad_link (srcpad, ghost);
1285 internalpad = (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) ghost);
1287 /* We start with no active pads */
1288 fail_if (GST_PAD_IS_ACTIVE (ghost));
1289 fail_if (GST_PAD_IS_ACTIVE (internalpad));
1290 fail_if (GST_PAD_IS_ACTIVE (sinkpad));
1291 fail_if (GST_PAD_IS_ACTIVE (srcpad));
1293 GST_DEBUG ("Activating pads in push mode");
1294 /* Let's first try to activate everything in push-mode, for this we need
1295 * to go on every exposed pad */
1296 fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE));
1297 fail_unless (gst_pad_activate_mode (ghost, GST_PAD_MODE_PUSH, TRUE));
1298 fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE));
1300 GST_DEBUG ("Checking pads are all activated properly");
1301 /* Let's check all pads are now active, including internal ones */
1302 fail_unless (GST_PAD_MODE (ghost) == GST_PAD_MODE_PUSH);
1303 fail_unless (GST_PAD_MODE (internalpad) == GST_PAD_MODE_PUSH);
1304 fail_unless (GST_PAD_MODE (srcpad) == GST_PAD_MODE_PUSH);
1305 fail_unless (GST_PAD_MODE (sinkpad) == GST_PAD_MODE_PUSH);
1307 /* Now simulate a scheduling reconfiguration (PUSH=>PULL) */
1308 fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE));
1310 /* All pads should have switched modes */
1311 fail_unless (GST_PAD_MODE (ghost) == GST_PAD_MODE_PULL);
1312 fail_unless (GST_PAD_MODE (srcpad) == GST_PAD_MODE_PULL);
1313 fail_unless (GST_PAD_MODE (sinkpad) == GST_PAD_MODE_PULL);
1314 fail_unless (GST_PAD_MODE (internalpad) == GST_PAD_MODE_PULL);
1316 gst_object_unref (internalpad);
1317 gst_object_unref (srcpad);
1318 gst_object_unref (sinkpad);
1319 gst_object_unref (pipeline);
1324 static gboolean thread_running;
1327 send_query_to_pad_func (GstPad * pad)
1329 GstQuery *query = gst_query_new_latency ();
1331 while (thread_running) {
1332 gst_pad_peer_query (pad, query);
1336 gst_query_unref (query);
1340 GST_START_TEST (test_stress_upstream_queries_while_tearing_down)
1342 GThread *query_thread;
1344 GstPad *pad = gst_pad_new ("sink", GST_PAD_SINK);
1345 gst_pad_set_active (pad, TRUE);
1347 thread_running = TRUE;
1348 query_thread = g_thread_new ("queries",
1349 (GThreadFunc) send_query_to_pad_func, pad);
1351 for (i = 0; i < 1000; i++) {
1352 GstPad *ghostpad = gst_ghost_pad_new ("ghost-sink", pad);
1353 gst_pad_set_active (ghostpad, TRUE);
1357 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL);
1358 gst_pad_set_active (pad, FALSE);
1359 gst_object_unref (ghostpad);
1362 thread_running = FALSE;
1363 g_thread_join (query_thread);
1365 gst_object_unref (pad);
1370 GST_START_TEST (test_deactivate_already_deactive_with_no_parent)
1372 /* This simulates the behavior where a ghostpad is released while
1373 * deactivating (for instance because of a state change).
1374 * gst_pad_activate_mode() may be be called from
1375 * gst_ghost_pad_internal_activate_push_default() on a pad that is already
1376 * deactivate and unparented. The call chain is really like somethink like
1378 * gst_pad_activate_mode(ghostpad)
1380 * -> gst_pad_activate_mode(proxypad)
1382 * -> gst_pad_activate_mode(ghostpad)
1384 GstElement *bin = gst_bin_new ("testbin");
1385 GstPad *pad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
1386 gst_object_ref (pad);
1388 /* We need to add/remove pad because that will update the pad's flags */
1389 fail_unless (gst_element_add_pad (bin, pad));
1390 fail_unless (gst_element_remove_pad (bin, pad));
1392 /* Setting a pad that's already deactive to deactive should not fail. */
1393 fail_if (gst_pad_is_active (pad));
1394 fail_unless (gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, FALSE));
1396 gst_object_unref (bin);
1397 gst_object_unref (pad);
1403 gst_ghost_pad_suite (void)
1405 Suite *s = suite_create ("GstGhostPad");
1407 TCase *tc_chain = tcase_create ("ghost pad tests");
1409 suite_add_tcase (s, tc_chain);
1410 tcase_add_test (tc_chain, test_remove1);
1411 tcase_add_test (tc_chain, test_remove2);
1412 tcase_add_test (tc_chain, test_remove_target);
1413 tcase_add_test (tc_chain, test_link);
1414 tcase_add_test (tc_chain, test_ghost_pads);
1415 tcase_add_test (tc_chain, test_ghost_pads_bin);
1416 tcase_add_test (tc_chain, test_ghost_pads_notarget);
1417 tcase_add_test (tc_chain, test_ghost_pads_block);
1418 tcase_add_test (tc_chain, test_ghost_pads_probes);
1419 tcase_add_test (tc_chain, test_ghost_pads_new_from_template);
1420 tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template);
1421 tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps);
1422 tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink);
1423 tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink);
1424 tcase_add_test (tc_chain, test_ghost_pads_change_when_linked);
1425 tcase_add_test (tc_chain, test_ghost_pads_internal_link);
1426 tcase_add_test (tc_chain, test_ghost_pads_remove_while_playing);
1428 tcase_add_test (tc_chain, test_activate_src);
1429 tcase_add_test (tc_chain, test_activate_sink_and_src);
1430 tcase_add_test (tc_chain, test_activate_src_pull_mode);
1431 tcase_add_test (tc_chain, test_activate_sink_switch_mode);
1432 tcase_add_test (tc_chain, test_deactivate_already_deactive_with_no_parent);
1433 tcase_add_test (tc_chain, test_stress_upstream_queries_while_tearing_down);
1438 GST_CHECK_MAIN (gst_ghost_pad);