+2008-12-17 Alessandro Decina <alessandro.decina@collabora.co.uk>
+
+ * 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 <sebastian.droege@collabora.co.uk>
* gst/gstutils.c: (gst_element_found_tags_for_pad):
-Subproject commit 2c4d28a75c26e572b94a967901254caff83d85c4
+Subproject commit 5dc8ae302733ce1aae5b1aaa613ce77a8ae4b3d9
xmlNodePtr parent);
#endif
+static void on_src_target_notify (GstPad * target,
+ GParamSpec * unused, GstGhostPad * pad);
+
static void
gst_proxy_pad_class_init (GstProxyPadClass * klass)
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);
}
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)
{
GST_GHOST_PAD_PRIVATE (pad) = G_TYPE_INSTANCE_GET_PRIVATE (pad,
{
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);
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);
/* 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))
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");
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)
{
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;
}