From c0a2c5839e9325d8343b56ff73bd4ba9e63bbeae Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Wed, 17 Dec 2008 16:16:45 +0000 Subject: [PATCH] In a source ghostpad, when caps are changed in the target pad, the change needs to be reflected in the ghostpad. Original commit message from CVS: * gst/gstghostpad.c: * tests/check/gst/gstghostpad.c: In a source ghostpad, when caps are changed in the target pad, the change needs to be reflected in the ghostpad. Fixes #564863. --- ChangeLog | 8 +++++ common | 2 +- gst/gstghostpad.c | 63 ++++++++++++++++++++++++++--------- tests/check/gst/gstghostpad.c | 60 +++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index ce4cd60f90..a9daa56cd0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-12-17 Alessandro Decina + + * gst/gstghostpad.c: + * tests/check/gst/gstghostpad.c: + In a source ghostpad, when caps are changed in the target pad, the + change needs to be reflected in the ghostpad. + Fixes #564863. + 2008-12-17 Sebastian Dröge * gst/gstutils.c: (gst_element_found_tags_for_pad): diff --git a/common b/common index 2c4d28a75c..5dc8ae3027 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 2c4d28a75c26e572b94a967901254caff83d85c4 +Subproject commit 5dc8ae302733ce1aae5b1aaa613ce77a8ae4b3d9 diff --git a/gst/gstghostpad.c b/gst/gstghostpad.c index 2d6e496ddf..961e3a6736 100644 --- a/gst/gstghostpad.c +++ b/gst/gstghostpad.c @@ -80,6 +80,9 @@ static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent); #endif +static void on_src_target_notify (GstPad * target, + GParamSpec * unused, GstGhostPad * pad); + static void gst_proxy_pad_class_init (GstProxyPadClass * klass) @@ -322,9 +325,9 @@ gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target) GST_LOG_OBJECT (pad, "clearing target"); /* clear old target */ - if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) { + if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) gst_object_unref (oldtarget); - } + /* set and ref new target if any */ if (target) GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target); @@ -684,6 +687,23 @@ on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad) gst_caps_unref (caps); } +static void +on_src_target_notify (GstPad * target, GParamSpec * unused, GstGhostPad * pad) +{ + GstCaps *caps; + + g_object_get (target, "caps", &caps, NULL); + + GST_OBJECT_LOCK (pad); + gst_caps_replace (&(GST_PAD_CAPS (pad)), caps); + GST_OBJECT_UNLOCK (pad); + + g_object_notify (G_OBJECT (pad), "caps"); + if (caps) + gst_caps_unref (caps); + +} + static void gst_ghost_pad_init (GstGhostPad * pad) { @@ -701,12 +721,26 @@ gst_ghost_pad_dispose (GObject * object) { GstPad *pad; GstPad *internal; - GstPad *intpeer; + GstPad *peer; pad = GST_PAD (object); GST_DEBUG_OBJECT (pad, "dispose"); + gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL); + + /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to + * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */ + peer = gst_pad_get_peer (pad); + if (peer) { + if (GST_PAD_IS_SRC (pad)) + gst_pad_unlink (pad, peer); + else + gst_pad_unlink (peer, pad); + + gst_object_unref (peer); + } + GST_PROXY_LOCK (pad); internal = GST_PROXY_PAD_INTERNAL (pad); @@ -716,21 +750,10 @@ gst_ghost_pad_dispose (GObject * object) g_signal_handler_disconnect (internal, GST_GHOST_PAD_PRIVATE (pad)->notify_id); - intpeer = gst_pad_get_peer (internal); - if (intpeer) { - if (GST_PAD_IS_SRC (internal)) - gst_pad_unlink (internal, intpeer); - else - gst_pad_unlink (intpeer, internal); - - gst_object_unref (intpeer); - } - - GST_PROXY_PAD_INTERNAL (internal) = NULL; - /* disposes of the internal pad, since the ghostpad is the only possible object * that has a refcount on the internal pad. */ gst_object_unparent (GST_OBJECT_CAST (internal)); + GST_PROXY_PAD_INTERNAL (pad) = NULL; GST_PROXY_UNLOCK (pad); @@ -1089,6 +1112,11 @@ gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget) /* clear old target */ if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) { + if (GST_PAD_IS_SRC (oldtarget)) { + g_signal_handlers_disconnect_by_func (oldtarget, + on_src_target_notify, gpad); + } + /* if we have an internal pad, unlink */ if (internal) { if (GST_PAD_IS_SRC (internal)) @@ -1101,6 +1129,11 @@ gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget) result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget); if (result && newtarget) { + if (GST_PAD_IS_SRC (newtarget)) { + g_signal_connect (newtarget, "notify::caps", + G_CALLBACK (on_src_target_notify), gpad); + } + /* and link to internal pad */ GST_DEBUG_OBJECT (gpad, "connecting internal pad to target"); diff --git a/tests/check/gst/gstghostpad.c b/tests/check/gst/gstghostpad.c index 577cc49954..ed39268e0a 100644 --- a/tests/check/gst/gstghostpad.c +++ b/tests/check/gst/gstghostpad.c @@ -668,6 +668,65 @@ GST_START_TEST (test_ghost_pads_new_no_target_from_template) GST_END_TEST; +static void +ghost_notify_caps (GObject * object, GParamSpec * pspec, gpointer * user_data) +{ + (*(gint *) user_data)++; +} + +GST_START_TEST (test_ghost_pads_forward_setcaps) +{ + GstCaps *templ_caps, *caps1, *caps2; + GstPadTemplate *src_template, *sink_template; + GstPad *src, *ghost, *sink; + gint notify_counter = 0; + + templ_caps = gst_caps_from_string ("meh; muh"); + src_template = gst_pad_template_new ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, templ_caps); + sink_template = gst_pad_template_new ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, templ_caps); + gst_caps_unref (templ_caps); + + src = gst_pad_new_from_template (src_template, "src"); + sink = gst_pad_new_from_template (sink_template, "sink"); + + /* ghost source pad */ + ghost = gst_ghost_pad_new ("ghostsrc", src); + g_signal_connect (ghost, "notify::caps", + G_CALLBACK (ghost_notify_caps), ¬ify_counter); + fail_unless (gst_pad_link (ghost, sink) == GST_PAD_LINK_OK); + + caps1 = gst_caps_from_string ("meh"); + fail_unless (gst_pad_set_caps (src, caps1)); + caps2 = GST_PAD_CAPS (ghost); + fail_unless (gst_caps_is_equal (caps1, caps2)); + fail_unless_equals_int (notify_counter, 1); + + gst_object_unref (ghost); + gst_caps_unref (caps1); + + /* ghost sink pad */ + notify_counter = 0; + ghost = gst_ghost_pad_new ("ghostsink", sink); + g_signal_connect (ghost, "notify::caps", + G_CALLBACK (ghost_notify_caps), ¬ify_counter); + fail_unless (gst_pad_link (src, ghost) == GST_PAD_LINK_OK); + + caps1 = gst_caps_from_string ("muh"); + fail_unless (gst_pad_set_caps (ghost, caps1)); + caps2 = GST_PAD_CAPS (sink); + fail_unless (gst_caps_is_equal (caps1, caps2)); + fail_unless_equals_int (notify_counter, 1); + + gst_object_unref (src); + gst_object_unref (sink); + gst_object_unref (src_template); + gst_object_unref (sink_template); +} + +GST_END_TEST; + static Suite * gst_ghost_pad_suite (void) { @@ -686,6 +745,7 @@ gst_ghost_pad_suite (void) tcase_add_test (tc_chain, test_ghost_pads_probes); 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); return s; }