do not call the unlink function on the target pad when the ghostpad

is unlinked.
Add some unit tests for this behaviour.
Fixes #566936.
This commit is contained in:
Wim Taymans 2009-01-21 12:21:49 +01:00 committed by Wim Taymans
parent 044b46ec98
commit ae76b3d606
2 changed files with 203 additions and 14 deletions

View file

@ -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) {

View file

@ -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;
}