From ae76b3d60626e495a3227df613803a4c6b6b4101 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 21 Jan 2009 12:21:49 +0100 Subject: [PATCH] do not call the unlink function on the target pad when the ghostpad is unlinked. Add some unit tests for this behaviour. Fixes #566936. --- gst/gstghostpad.c | 10 -- tests/check/gst/gstghostpad.c | 207 +++++++++++++++++++++++++++++++++- 2 files changed, 203 insertions(+), 14 deletions(-) diff --git a/gst/gstghostpad.c b/gst/gstghostpad.c index 33cda52c5f..58f1ea4975 100644 --- a/gst/gstghostpad.c +++ b/gst/gstghostpad.c @@ -652,23 +652,14 @@ link_failed: static void gst_ghost_pad_do_unlink (GstPad * pad) { - GstPad *target; GstPad *internal; - target = gst_proxy_pad_get_target (pad); internal = GST_PROXY_PAD_INTERNAL (pad); GST_DEBUG_OBJECT (pad, "unlinking ghostpad"); /* The target of the internal pad is no longer valid */ gst_proxy_pad_set_target (internal, NULL); - - if (target) { - if (GST_PAD_UNLINKFUNC (target)) - GST_PAD_UNLINKFUNC (target) (target); - - gst_object_unref (target); - } } static void @@ -821,7 +812,6 @@ gst_ghost_pad_construct (GstGhostPad * gpad) gst_pad_set_unlink_function (pad, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink)); - /* INTERNAL PAD, it always exists and is child of the ghostpad */ otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC; if (templ) { diff --git a/tests/check/gst/gstghostpad.c b/tests/check/gst/gstghostpad.c index 8a265fc2d8..25a0baa4e6 100644 --- a/tests/check/gst/gstghostpad.c +++ b/tests/check/gst/gstghostpad.c @@ -554,9 +554,7 @@ GST_END_TEST; GST_START_TEST (test_ghost_pads_new_from_template) { GstPad *sinkpad, *ghostpad; - GstPadTemplate *padtempl, *ghosttempl; - GstCaps *padcaps, *ghostcaps, *newcaps; GstCaps *copypadcaps; @@ -607,9 +605,7 @@ GST_END_TEST; GST_START_TEST (test_ghost_pads_new_no_target_from_template) { GstPad *sinkpad, *ghostpad; - GstPadTemplate *padtempl, *ghosttempl; - GstCaps *padcaps, *ghostcaps, *newcaps; GstCaps *copypadcaps, *copyghostcaps; @@ -767,7 +763,208 @@ GST_START_TEST (test_ghost_pads_forward_setcaps) gst_object_unref (src_template); gst_object_unref (sink_template); } +GST_END_TEST; +static gint linked_count1; +static gint unlinked_count1; +static gint linked_count2; +static gint unlinked_count2; + +static GstPadLinkReturn +pad_linked1 (GstPad *pad, GstPad *peer) +{ + linked_count1++; + + return GST_PAD_LINK_OK; +} +static void +pad_unlinked1 (GstPad *pad) +{ + unlinked_count1++; +} +static GstPadLinkReturn +pad_linked2 (GstPad *pad, GstPad *peer) +{ + linked_count2++; + + return GST_PAD_LINK_OK; +} +static void +pad_unlinked2 (GstPad *pad) +{ + unlinked_count2++; +} + +GST_START_TEST (test_ghost_pads_sink_link_unlink) +{ + GstCaps *padcaps; + GstPad *srcpad, *sinkpad, *ghostpad; + GstPadTemplate *srctempl, *sinktempl; + GstPadLinkReturn ret; + gboolean res; + + padcaps = gst_caps_from_string ("some/caps"); + fail_unless (padcaps != NULL); + + srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC, + GST_PAD_ALWAYS, padcaps); + sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK, + GST_PAD_ALWAYS, padcaps); + gst_caps_unref (padcaps); + + srcpad = gst_pad_new_from_template (srctempl, "src"); + fail_unless (srcpad != NULL); + sinkpad = gst_pad_new_from_template (sinktempl, "sink"); + fail_unless (sinkpad != NULL); + + /* set up link/unlink functions for the pad */ + linked_count1 = unlinked_count1 = 0; + gst_pad_set_link_function (sinkpad, pad_linked1); + gst_pad_set_unlink_function (sinkpad, pad_unlinked1); + linked_count2 = unlinked_count2 = 0; + gst_pad_set_link_function (srcpad, pad_linked2); + gst_pad_set_unlink_function (srcpad, pad_unlinked2); + + /* this should trigger a link from the internal pad to the sinkpad */ + ghostpad = gst_ghost_pad_new ("ghostpad", sinkpad); + fail_unless (ghostpad != NULL); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 0); + fail_unless (unlinked_count2 == 0); + + /* this should not trigger anything because we are not directly + * linking/unlinking the sink pad. */ + ret = gst_pad_link (srcpad, ghostpad); + fail_unless (ret == GST_PAD_LINK_OK); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 0); + + res = gst_pad_unlink (srcpad, ghostpad); + fail_unless (res == TRUE); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 1); + + /* this should trigger the unlink */ + res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL); + fail_unless (res == TRUE); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 1); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 1); + + gst_object_unref (ghostpad); + gst_object_unref (sinkpad); + gst_object_unref (srcpad); + gst_object_unref (srctempl); + gst_object_unref (sinktempl); +} +GST_END_TEST; + +GST_START_TEST (test_ghost_pads_src_link_unlink) +{ + GstCaps *padcaps; + GstPad *srcpad, *sinkpad, *ghostpad, *dummy; + GstPadTemplate *srctempl, *sinktempl; + GstPadLinkReturn ret; + gboolean res; + + padcaps = gst_caps_from_string ("some/caps"); + fail_unless (padcaps != NULL); + + srctempl = gst_pad_template_new ("srctempl", GST_PAD_SRC, + GST_PAD_ALWAYS, padcaps); + sinktempl = gst_pad_template_new ("sinktempl", GST_PAD_SINK, + GST_PAD_ALWAYS, padcaps); + gst_caps_unref (padcaps); + + srcpad = gst_pad_new_from_template (srctempl, "src"); + fail_unless (srcpad != NULL); + sinkpad = gst_pad_new_from_template (sinktempl, "sink"); + fail_unless (sinkpad != NULL); + + /* set up link/unlink functions for the pad */ + linked_count1 = unlinked_count1 = 0; + gst_pad_set_link_function (srcpad, pad_linked1); + gst_pad_set_unlink_function (srcpad, pad_unlinked1); + linked_count2 = unlinked_count2 = 0; + gst_pad_set_link_function (sinkpad, pad_linked2); + gst_pad_set_unlink_function (sinkpad, pad_unlinked2); + + /* this should trigger a link from the internal pad to the srcpad */ + ghostpad = gst_ghost_pad_new ("ghostpad", srcpad); + fail_unless (ghostpad != NULL); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 0); + fail_unless (unlinked_count2 == 0); + + /* this should fail with a critial */ + ASSERT_CRITICAL (dummy = gst_ghost_pad_new ("ghostpad", srcpad)); + fail_unless (dummy == NULL); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 0); + fail_unless (unlinked_count2 == 0); + + /* this should not trigger anything because we are not directly + * linking/unlinking the src pad. */ + ret = gst_pad_link (ghostpad, sinkpad); + fail_unless (ret == GST_PAD_LINK_OK); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 0); + + /* this link should fail because we are already linked. Let's make sure the + * link functions are not called */ + ret = gst_pad_link (ghostpad, sinkpad); + fail_unless (ret == GST_PAD_LINK_WAS_LINKED); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 0); + + res = gst_pad_unlink (ghostpad, sinkpad); + fail_unless (res == TRUE); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 1); + + res = gst_pad_unlink (ghostpad, sinkpad); + fail_unless (res == FALSE); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 0); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 1); + + /* this should trigger the unlink function */ + res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), NULL); + fail_unless (res == TRUE); + fail_unless (linked_count1 == 1); + fail_unless (unlinked_count1 == 1); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 1); + + /* and this the link function again */ + res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghostpad), srcpad); + fail_unless (res == TRUE); + fail_unless (linked_count1 == 2); + fail_unless (unlinked_count1 == 1); + fail_unless (linked_count2 == 1); + fail_unless (unlinked_count2 == 1); + + gst_object_unref (ghostpad); + gst_object_unref (sinkpad); + gst_object_unref (srcpad); + gst_object_unref (srctempl); + gst_object_unref (sinktempl); +} GST_END_TEST; static Suite * @@ -789,6 +986,8 @@ gst_ghost_pad_suite (void) tcase_add_test (tc_chain, test_ghost_pads_new_from_template); tcase_add_test (tc_chain, test_ghost_pads_new_no_target_from_template); tcase_add_test (tc_chain, test_ghost_pads_forward_setcaps); + tcase_add_test (tc_chain, test_ghost_pads_sink_link_unlink); + tcase_add_test (tc_chain, test_ghost_pads_src_link_unlink); return s; }