In a source ghostpad, when caps are changed in the target pad, the change needs to...
authorAlessandro Decina <alessandro.d@gmail.com>
Wed, 17 Dec 2008 16:16:45 +0000 (16:16 +0000)
committerAlessandro Decina <alessandro.d@gmail.com>
Wed, 17 Dec 2008 16:16:45 +0000 (16:16 +0000)
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
common
gst/gstghostpad.c
tests/check/gst/gstghostpad.c

index ce4cd60..a9daa56 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+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):
diff --git a/common b/common
index 2c4d28a..5dc8ae3 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 2c4d28a75c26e572b94a967901254caff83d85c4
+Subproject commit 5dc8ae302733ce1aae5b1aaa613ce77a8ae4b3d9
index 2d6e496..961e3a6 100644 (file)
@@ -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);
@@ -685,6 +688,23 @@ on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
 }
 
 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,
@@ -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");
 
index 577cc49..ed39268 100644 (file)
@@ -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), &notify_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), &notify_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;
 }