gst/gstpad.c (_gst_real_pad_fixate_accumulator): s/pointer/boxed/.
authorAndy Wingo <wingo@pobox.com>
Thu, 5 Feb 2004 13:51:26 +0000 (13:51 +0000)
committerAndy Wingo <wingo@pobox.com>
Thu, 5 Feb 2004 13:51:26 +0000 (13:51 +0000)
Original commit message from CVS:
2004-02-05  Andy Wingo  <wingo@pobox.com>

* gst/gstpad.c (_gst_real_pad_fixate_accumulator):
s/pointer/boxed/.

* gst/gstmarshal.list (VOID:BOXED, BOXED:BOXED): New marshallers.

* gst/gstpad.c (gst_real_pad_class_init): Use a BOXED:BOXED
marshaller for ::fixate, and VOID:BOXED for ::caps-nego-failed,
with the type=GST_TYPE_CAPS. This allows language bindings to know
what kind of data they're dealing with.

* gst/gstcaps.c (_gst_caps_value_init): GBoxed values initialize
to NULL when g_value_init is called. GstCaps, which rolls its own
type implementation, now does the same instead of allocating empty
caps.
(_gst_caps_initialize, _gst_caps_collect_value,
_gst_caps_lcopy_value): Provide collect_value and lcopy_value type
table methods. This allows G_VALUE_COLLECT to work.

2004-02-05  Andy Wingo  <wingo@pobox.com>

* configure.ac:
* testsuite/Makefile.am (SUBDIRS):
* testsuite/ghostpads/Makefile.am:
* testsuite/ghostpads/ghostpads.c: A new test for ghost pads.

* gst/gstpad.c (gst_pad_add_ghost_pad, gst_pad_remove_ghost_pad):
These two routines are the only ones that set
GST_GPAD_REALPAD(gpad), the ghost pad list, and the ghost pad's
pad template. They should be made static, depending on ABI needs.
(gst_real_pad_dispose): Handle the case of ghost pads without a
parent. Assert after dealing with ghost pads that the ghost pad
list is empty.
(gst_ghost_pad_class_init): New property added, ::real-pad. Can be
set after creation.
(gst_ghost_pad_dispose): Set ::real-pad to NULL.
(gst_ghost_pad_set_property, gst_ghost_pad_get_property): New
functions. set_property will call add_ghost_pad/remove_ghost_pad
as appropriate.
(gst_ghost_pad_new): All the work is offloaded to g_object_new.

* gst/gstelement.c (gst_element_add_pad): Handle ghost pads as well.
(gst_element_add_ghost_pad): Remove code duplicated from _add_pad.
(gst_element_remove_pad): Handle ghost pads as well.
(gst_element_remove_ghost_pad): Deprecated (could be removed,
depending on API-stability needs).

2004-02-05  Andy Wingo  <wingo@pobox.com>

* gst/gstbin.[ch]: (gst_bin_get_by_interface): GTypes are scalars,
of course they're const

13 files changed:
configure.ac
gst/gstbin.c
gst/gstbin.h
gst/gstcaps.c
gst/gstelement.c
gst/gstmarshal.list
gst/gstpad.c
tests/old/testsuite/Makefile.am
tests/old/testsuite/ghostpads/Makefile.am [new file with mode: 0644]
tests/old/testsuite/ghostpads/ghostpads.c [new file with mode: 0644]
testsuite/Makefile.am
testsuite/ghostpads/Makefile.am [new file with mode: 0644]
testsuite/ghostpads/ghostpads.c [new file with mode: 0644]

index b75fed8..bd5d061 100644 (file)
@@ -642,6 +642,7 @@ testsuite/clock/Makefile
 testsuite/debug/Makefile
 testsuite/dynparams/Makefile
 testsuite/elements/Makefile
+testsuite/ghostpads/Makefile
 testsuite/indexers/Makefile
 testsuite/parse/Makefile
 testsuite/plugin/Makefile
index c01778d..c2a2012 100644 (file)
@@ -906,7 +906,7 @@ gst_bin_get_list (GstBin * bin)
  * Returns: An element inside the bin implementing the interface.
  */
 GstElement *
-gst_bin_get_by_interface (GstBin *bin, const GType interface)
+gst_bin_get_by_interface (GstBin *bin, GType interface)
 {
   GList *walk;
   
@@ -942,7 +942,7 @@ gst_bin_get_by_interface (GstBin *bin, const GType interface)
  * Returns: An element inside the bin implementing the interface.
  */
 GList *
-gst_bin_get_all_by_interface (GstBin *bin, const GType interface)
+gst_bin_get_all_by_interface (GstBin *bin, GType interface)
 {
   GList *walk, *ret = NULL;
     
index 2e08b75..60cdbf6 100644 (file)
@@ -103,8 +103,8 @@ GstElement* gst_bin_get_by_name             (GstBin *bin, const gchar *name);
 GstElement*    gst_bin_get_by_name_recurse_up  (GstBin *bin, const gchar *name);
 G_CONST_RETURN GList*
                gst_bin_get_list                (GstBin *bin);
-GstElement*    gst_bin_get_by_interface        (GstBin *bin, const GType interface);
-GList *                gst_bin_get_all_by_interface    (GstBin *bin, const GType interface);
+GstElement*    gst_bin_get_by_interface        (GstBin *bin, GType interface);
+GList *                gst_bin_get_all_by_interface    (GstBin *bin, GType interface);
 
 gboolean       gst_bin_iterate                 (GstBin *bin);
 
index 676c835..3aa92c1 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 #include <string.h>
 
+#include <gobject/gvaluecollector.h>
 #include <gst/gst.h>
 
 #define CAPS_POISON(caps) G_STMT_START{ \
@@ -46,6 +47,14 @@ static void _gst_caps_value_init (GValue *value);
 static void _gst_caps_value_free (GValue *value);
 static void _gst_caps_value_copy (const GValue *src, GValue *dest);
 static gpointer _gst_caps_value_peek_pointer (const GValue *value);
+static gchar* _gst_caps_collect_value (GValue      *value,
+                                       guint        n_collect_values,
+                                       GTypeCValue *collect_values,
+                                       guint        collect_flags);
+static gchar* _gst_caps_lcopy_value (const GValue *value,
+                                     guint         n_collect_values,
+                                     GTypeCValue  *collect_values,
+                                     guint         collect_flags);
 static gboolean _gst_caps_from_string_inplace (GstCaps *caps,
     const gchar *string);
 
@@ -59,10 +68,10 @@ void _gst_caps_initialize (void)
     _gst_caps_value_free,
     _gst_caps_value_copy,
     _gst_caps_value_peek_pointer,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
+    "p",
+    _gst_caps_collect_value,
+    "p",
+    _gst_caps_lcopy_value,
   };
   static const GTypeInfo caps2_info = {
     0,
@@ -1134,7 +1143,7 @@ static void _gst_caps_transform_to_string (const GValue *src_value,
 
 static void _gst_caps_value_init (GValue *value)
 {
-  value->data[0].v_pointer = gst_caps_new_empty();
+  value->data[0].v_pointer = NULL;
 }
 
 static void _gst_caps_value_free (GValue *value)
@@ -1159,6 +1168,49 @@ static gpointer _gst_caps_value_peek_pointer (const GValue *value)
   return value->data[0].v_pointer;
 }
 
+/* adapted from gboxed.c */
+static gchar*
+_gst_caps_collect_value (GValue      *value,
+                         guint        n_collect_values,
+                         GTypeCValue *collect_values,
+                         guint        collect_flags)
+{
+  if (!collect_values[0].v_pointer)
+    value->data[0].v_pointer = NULL;
+  else
+    if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
+      {
+        value->data[0].v_pointer = collect_values[0].v_pointer;
+        value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
+      }
+    else
+      value->data[0].v_pointer = gst_caps_copy (collect_values[0].v_pointer);
+
+  return NULL;
+}
+
+static gchar*
+_gst_caps_lcopy_value (const GValue *value,
+                       guint         n_collect_values,
+                       GTypeCValue  *collect_values,
+                       guint         collect_flags)
+{
+  GstCaps **boxed_p = collect_values[0].v_pointer;
+
+  if (!boxed_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                            G_VALUE_TYPE_NAME (value));
+
+  if (!value->data[0].v_pointer)
+    *boxed_p = NULL;
+  else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
+    *boxed_p = value->data[0].v_pointer;
+  else
+    *boxed_p = gst_caps_copy (value->data[0].v_pointer);
+
+  return NULL;
+}
+
 /* fixate utility functions */
 
 gboolean gst_caps_structure_fixate_field_nearest_int (GstStructure *structure,
index f73ca65..e2918d1 100644 (file)
@@ -1056,7 +1056,8 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
   g_return_if_fail (GST_IS_ELEMENT (element));
   g_return_if_fail (GST_IS_PAD (pad));
 
-  /* first check to make sure the pad's parent is already set */
+  /* first check to make sure the pad hasn't already been added to another
+   * element */
   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
 
   /* then check to see if there's already a pad by that name here */
@@ -1070,10 +1071,18 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
   /* add it to the list */
   element->pads = g_list_append (element->pads, pad);
   element->numpads++;
-  if (gst_pad_get_direction (pad) == GST_PAD_SRC)
+
+  switch (gst_pad_get_direction (pad)) {
+  case GST_PAD_SRC:
     element->numsrcpads++;
-  else
+    break;
+  case GST_PAD_SINK:
     element->numsinkpads++;
+    break;
+  default:
+    /* can happen for ghost pads */
+    break;
+  }
 
   /* activate element when we are playing */
   if (GST_STATE (element) == GST_STATE_PLAYING)
@@ -1084,6 +1093,36 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
 }
 
 /**
+ * gst_element_add_ghost_pad:
+ * @element: a #GstElement to add the ghost pad to.
+ * @pad: the #GstPad from which the new ghost pad will be created.
+ * @name: the name of the new ghost pad, or NULL to assign a unique name
+ * automatically.
+ *
+ * Creates a ghost pad from the given pad, and adds it to the list of pads
+ * for this element.
+ * 
+ * Returns: the added ghost #GstPad, or NULL on error.
+ */
+GstPad *
+gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
+{
+  GstPad *ghostpad;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+
+  /* then check to see if there's already a pad by that name here */
+  g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
+
+  ghostpad = gst_ghost_pad_new (name, pad);
+
+  gst_element_add_pad (element, ghostpad);
+       
+  return ghostpad;
+}
+
+/**
  * gst_element_remove_pad:
  * @element: a #GstElement to remove pad from.
  * @pad: the #GstPad to remove from the element.
@@ -1100,22 +1139,29 @@ gst_element_remove_pad (GstElement *element, GstPad *pad)
 
   g_return_if_fail (GST_PAD_PARENT (pad) == element);
 
-  /* check to see if the pad is still linked */
-  /* FIXME: what if someone calls _remove_pad instead of 
-    _remove_ghost_pad? */
   if (GST_IS_REAL_PAD (pad)) {
+    /* unlink if necessary */
     if (GST_RPAD_PEER (pad) != NULL) {
       gst_pad_unlink (pad, GST_PAD (GST_RPAD_PEER (pad)));
     }
+  } else if (GST_IS_GHOST_PAD (pad)) {
+    g_object_set (pad, "real-pad", NULL, NULL);
   }
   
   /* remove it from the list */
   element->pads = g_list_remove (element->pads, pad);
   element->numpads--;
-  if (gst_pad_get_direction (pad) == GST_PAD_SRC)
+  switch (gst_pad_get_direction (pad)) {
+  case GST_PAD_SRC:
     element->numsrcpads--;
-  else
+    break;
+  case GST_PAD_SINK:
     element->numsinkpads--;
+    break;
+  default:
+    /* can happen for ghost pads */
+    break;
+  }
 
   g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
 
@@ -1123,56 +1169,12 @@ gst_element_remove_pad (GstElement *element, GstPad *pad)
 }
 
 /**
- * gst_element_add_ghost_pad:
- * @element: a #GstElement to add the ghost pad to.
- * @pad: the #GstPad from which the new ghost pad will be created.
- * @name: the name of the new ghost pad.
- *
- * Creates a ghost pad from the given pad, and adds it to the list of pads
- * for this element.
- * 
- * Returns: the added ghost #GstPad, or NULL, if no ghost pad was created.
- */
-GstPad *
-gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
-{
-  GstPad *ghostpad;
-
-  g_return_val_if_fail (element != NULL, NULL);
-  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
-  g_return_val_if_fail (pad != NULL, NULL);
-  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
-
-  /* then check to see if there's already a pad by that name here */
-  g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
-
-  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, 
-             "creating new ghost pad called %s, from pad %s:%s",
-             name, GST_DEBUG_PAD_NAME(pad));
-  ghostpad = gst_ghost_pad_new (name, pad);
-
-  /* add it to the list */
-  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
-            name, GST_ELEMENT_NAME (element));
-  element->pads = g_list_append (element->pads, ghostpad);
-  element->numpads++;
-  /* set the parent of the ghostpad */
-  gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
-
-  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
-
-  /* emit the NEW_GHOST_PAD signal */
-  g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
-       
-  return ghostpad;
-}
-
-/**
  * gst_element_remove_ghost_pad:
  * @element: a #GstElement to remove the ghost pad from.
  * @pad: ghost #GstPad to remove.
  *
- * Removes a ghost pad from an element.
+ * Removes a ghost pad from an element. Deprecated, use gst_element_remove_pad
+ * instead.
  */
 void
 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
@@ -1180,15 +1182,10 @@ gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
   g_return_if_fail (GST_IS_ELEMENT (element));
   g_return_if_fail (GST_IS_GHOST_PAD (pad));
 
-  /* FIXME this is redundant?
-   * wingo 10-july-2001: I don't think so, you have to actually remove the pad
-   * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
-   * the real pad's ghost pad list
-   */
-  gst_object_ref (GST_OBJECT (pad));
+  g_warning ("gst_element_remove_ghost_pad is deprecated.\n"
+             "Use gst_element_remove_pad instead.");
+
   gst_element_remove_pad (element, pad);
-  gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
-  gst_object_unref (GST_OBJECT (pad));
 }
 
 
index 48fff87..0f033ad 100644 (file)
@@ -16,3 +16,5 @@ VOID:UINT,POINTER
 BOOLEAN:VOID
 BOOLEAN:POINTER
 POINTER:POINTER
+BOXED:BOXED
+VOID:BOXED
index 0fb5331..2c21841 100644 (file)
@@ -183,8 +183,8 @@ gst_real_pad_class_init (GstRealPadClass *klass)
   gst_real_pad_signals[REAL_CAPS_NEGO_FAILED] =
     g_signal_new ("caps_nego_failed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GstRealPadClass, caps_nego_failed), NULL, NULL,
-                  gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-                  G_TYPE_POINTER);
+                  gst_marshal_VOID__BOXED, G_TYPE_NONE, 1,
+                  GST_TYPE_CAPS);
   gst_real_pad_signals[REAL_LINKED] =
     g_signal_new ("linked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GstRealPadClass, linked), NULL, NULL,
@@ -199,11 +199,9 @@ gst_real_pad_class_init (GstRealPadClass *klass)
     g_signal_new ("fixate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GstRealPadClass, appfixatefunc), 
                  _gst_real_pad_fixate_accumulator, NULL,
-                 gst_marshal_POINTER__POINTER, G_TYPE_POINTER, 1,
-                  G_TYPE_POINTER);
+                 gst_marshal_BOXED__BOXED, GST_TYPE_CAPS, 1,
+                  GST_TYPE_CAPS);
 
-/*  gtk_object_add_arg_type ("GstRealPad::active", G_TYPE_BOOLEAN, */
-/*                           GTK_ARG_READWRITE, REAL_ARG_ACTIVE); */
   g_object_class_install_property (G_OBJECT_CLASS (klass), REAL_ARG_ACTIVE,
     g_param_spec_boolean ("active", "Active", "Whether the pad is active.",
                           TRUE, G_PARAM_READWRITE));
@@ -221,7 +219,7 @@ static gboolean
 _gst_real_pad_fixate_accumulator (GSignalInvocationHint *ihint,
     GValue *return_accu, const GValue *handler_return, gpointer dummy)
 {
-  if (g_value_get_pointer (handler_return)) {
+  if (g_value_get_boxed (handler_return)) {
     g_value_copy (handler_return, return_accu);
     /* stop emission if something was returned */
     return FALSE;
@@ -400,7 +398,10 @@ gst_pad_get_direction (GstPad *pad)
 {
   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN);
 
-  return GST_PAD_DIRECTION (pad);
+  if (GST_IS_REAL_PAD (pad))
+    return GST_PAD_DIRECTION (pad);
+  else
+    return GST_PAD_UNKNOWN;
 }
 
 /**
@@ -1837,12 +1838,18 @@ gst_pad_add_ghost_pad (GstPad *pad,
   g_return_if_fail (ghostpad != NULL);
   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
 
-  realpad = GST_PAD_REALIZE (pad);
+  /* if we're ghosting a ghost pad, drill down to find the real pad */
+  realpad = (GstRealPad*)pad;
+  while (GST_IS_GHOST_PAD (realpad))
+    realpad = GST_GPAD_REALPAD (realpad);
+  g_return_if_fail (GST_IS_REAL_PAD (realpad));
 
+  /* will ref the pad template */
+  GST_GPAD_REALPAD (ghostpad) = realpad;
   realpad->ghostpads = g_list_prepend (realpad->ghostpads, ghostpad);
+  gst_pad_set_pad_template (GST_PAD (ghostpad), GST_PAD_PAD_TEMPLATE (pad));
 }
 
-
 /**
  * gst_pad_remove_ghost_pad:
  * @pad: a #GstPad to remove the ghost pad from.
@@ -1861,6 +1868,7 @@ gst_pad_remove_ghost_pad (GstPad *pad,
   realpad = GST_PAD_REALIZE (pad);
   g_return_if_fail (GST_GPAD_REALPAD (ghostpad) == realpad);
 
+  gst_pad_set_pad_template (GST_PAD (ghostpad), NULL);
   realpad->ghostpads = g_list_remove (realpad->ghostpads, ghostpad);
   GST_GPAD_REALPAD (ghostpad) = NULL;
 }
@@ -2441,8 +2449,8 @@ gst_pad_get_caps (GstPad *pad)
  *
  * Gets the template capabilities of this pad.
  *
- * Returns: the template #GstCaps of this pad, unref the caps
- * if you no longer need it.
+ * Returns: the #GstCaps of this pad template. If you intend to keep a reference
+ * on the caps, make a copy (see gst_caps_copy ()).
  */
 const GstCaps*
 gst_pad_get_pad_template_caps (GstPad *pad)
@@ -2470,8 +2478,8 @@ gst_pad_get_pad_template_caps (GstPad *pad)
  *
  * Gets the capability with the given name from this pad template.
  *
- * Returns: the #GstCaps, or NULL if not found or in case of an error. unref 
- * the caps if you no longer need it.
+ * Returns: the #GstCaps of this pad template, or NULL if not found. If you
+ * intend to keep a reference on the caps, make a copy (see gst_caps_copy ()).
  */
 const GstCaps*
 gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
@@ -2497,7 +2505,7 @@ gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
  * Checks if two pads have compatible capabilities.
  *
  * Returns: TRUE if they are compatible or if the capabilities
- * could not be checked
+ * could not be checked.
  */
 gboolean
 gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
@@ -2684,6 +2692,9 @@ gst_real_pad_dispose (GObject *object)
   /* No linked pad can ever be disposed.
    * It has to have a parent to be linked 
    * and a parent would hold a reference */
+  /* FIXME: what about if g_object_dispose is explicitly called on the pad? Is
+     that legal? otherwise we could assert GST_OBJECT_PARENT (pad) == NULL as
+     well... */
   g_assert (GST_PAD_PEER (pad) == NULL);
 
   GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "dispose %s:%s", GST_DEBUG_PAD_NAME(pad));
@@ -2697,16 +2708,23 @@ gst_real_pad_dispose (GObject *object)
     while (ghostpads) {
       GstPad *ghostpad = GST_PAD (ghostpads->data);
 
-      if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad))){
-        GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "removing ghost pad from element '%s'", 
-                  GST_OBJECT_NAME (GST_OBJECT_PARENT (ghostpad)));
+      if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad))) {
+        GstElement *parent = GST_ELEMENT (GST_OBJECT_PARENT (ghostpad));
 
-        gst_element_remove_ghost_pad (GST_ELEMENT (GST_OBJECT_PARENT (ghostpad)), GST_PAD (ghostpad));
+        GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "removing ghost pad from element '%s'", 
+                       GST_OBJECT_NAME (parent));
+        gst_element_remove_pad (parent, ghostpad);
+      } else {
+        /* handle the case where we have some floating ghost pad that was never
+           added to an element */
+        g_object_set (ghostpad, "real-pad", NULL, NULL);
       }
       ghostpads = g_list_next (ghostpads);
     }
     g_list_free (orig);
-    g_list_free (GST_REAL_PAD(pad)->ghostpads);
+    /* as the ghost pads are removed, they remove themselves from ->ghostpads.
+       So it should be empty now. Let's assert that. */
+    g_assert (GST_REAL_PAD(pad)->ghostpads == NULL);
   }
 
   if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))) {
@@ -3239,8 +3257,8 @@ gst_pad_template_new (const gchar *name_template,
  *
  * Gets the capabilities of the pad template.
  *
- * Returns: the #GstCaps of the pad template. unref the caps
- * after use.
+ * Returns: the #GstCaps of the pad template. If you need to keep a reference to
+ * the caps, make a copy (see gst_caps_copy ()).
  */
 const GstCaps*
 gst_pad_template_get_caps (GstPadTemplate *templ)
@@ -3285,9 +3303,19 @@ GType _gst_ghost_pad_type = 0;
 static void     gst_ghost_pad_class_init        (GstGhostPadClass *klass);
 static void     gst_ghost_pad_init              (GstGhostPad *pad);
 static void     gst_ghost_pad_dispose          (GObject *object);
+static void    gst_ghost_pad_get_property      (GObject* object, guint prop_id, 
+                                                 GValue* value, GParamSpec* pspec);
+static void    gst_ghost_pad_set_property      (GObject* object, guint prop_id, 
+                                                 const GValue* value, GParamSpec* pspec);
 
 static GstPad *ghost_pad_parent_class = NULL;
 /* static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 }; */
+enum 
+{
+  GPAD_ARG_0,
+  GPAD_ARG_REAL_PAD
+  /* fill me */
+};
 
 GType
 gst_ghost_pad_get_type (void) 
@@ -3317,6 +3345,12 @@ gst_ghost_pad_class_init (GstGhostPadClass *klass)
   ghost_pad_parent_class = g_type_class_ref (GST_TYPE_PAD);
 
   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
+  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_set_property);
+  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ghost_pad_get_property);
+
+  g_object_class_install_property (gobject_class, GPAD_ARG_REAL_PAD,
+    g_param_spec_object ("real-pad", "Real pad", "The real pad for the ghost pad",
+                         GST_TYPE_PAD, G_PARAM_READWRITE));
 }
 
 static void
@@ -3324,17 +3358,59 @@ gst_ghost_pad_init (GstGhostPad *pad)
 {
   /* zeroed by glib */
 }
+
 static void
 gst_ghost_pad_dispose (GObject *object)
 {
-  GstGhostPad *pad = GST_GHOST_PAD (object);
-
-  if (pad->realpad)
-    gst_pad_remove_ghost_pad((GstPad *) pad->realpad, (GstPad *) pad);
+  g_object_set (object, "real-pad", NULL, NULL);
 
   G_OBJECT_CLASS (ghost_pad_parent_class)->dispose (object);
 }
 
+static void
+gst_ghost_pad_set_property (GObject* object, guint prop_id, 
+                            const GValue* value, GParamSpec* pspec)
+{
+  GstPad *ghostpad = (GstPad*)object;
+  GstPad *oldrealpad = (GstPad*)GST_GPAD_REALPAD (ghostpad);
+  GstPad *realpad = NULL;
+           
+  switch (prop_id) {
+    case GPAD_ARG_REAL_PAD:
+      realpad = g_value_get_object (value);
+      
+      if (oldrealpad) {
+        if (realpad == oldrealpad)
+          return;
+        else
+          gst_pad_remove_ghost_pad (oldrealpad, ghostpad);
+      }
+      
+      if (realpad)
+        gst_pad_add_ghost_pad (realpad, ghostpad);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_ghost_pad_get_property (GObject* object, guint prop_id, 
+                            GValue* value, GParamSpec* pspec)
+{
+  switch (prop_id) {
+    case GPAD_ARG_REAL_PAD:
+      g_value_set_object (value, GST_GPAD_REALPAD (object));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
 /**
  * gst_ghost_pad_new:
  * @name: the name of the new ghost pad.
@@ -3342,40 +3418,28 @@ gst_ghost_pad_dispose (GObject *object)
  *
  * Creates a new ghost pad associated with the given pad, and names it with
  * the given name.  If name is NULL, a guaranteed unique name (across all
- * ghost pads) will be assigned (most likely of the form ghostpad%d).
+ * ghost pads) will be assigned.
  *
  * Returns: a new ghost #GstPad, or NULL in case of an error.
  */
-
 GstPad*
 gst_ghost_pad_new (const gchar *name,
                    GstPad *pad)
 {
-  GstGhostPad *ghostpad;
-  GstRealPad *realpad;
+  GstPad *gpad;
 
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  ghostpad = g_object_new (gst_ghost_pad_get_type () ,NULL);
-  gst_pad_set_name (GST_PAD (ghostpad), name);
-
-  realpad = (GstRealPad *) pad;
-
-  while (!GST_IS_REAL_PAD (realpad)) {
-    realpad = GST_PAD_REALIZE (realpad);
-  }
-  GST_GPAD_REALPAD (ghostpad) = realpad;
-  gst_pad_set_pad_template (GST_PAD (ghostpad), GST_PAD_PAD_TEMPLATE (pad));
-
-  /* add ourselves to the real pad's list of ghostpads */
-  gst_pad_add_ghost_pad (pad, GST_PAD (ghostpad));
-
-  /* FIXME need to ref the real pad here... ? */
+  gpad = g_object_new (GST_TYPE_GHOST_PAD,
+                       "name", name,
+                       "real-pad", pad,
+                       NULL);
 
-  GST_CAT_DEBUG (GST_CAT_PADS, "created ghost pad \"%s\"", 
-             gst_pad_get_name (GST_PAD (ghostpad)));
+  GST_CAT_DEBUG (GST_CAT_PADS, "created ghost pad \"%s\" for pad %s:%s", 
+                 GST_OBJECT_NAME (gpad),
+                 GST_DEBUG_PAD_NAME (pad));
 
-  return GST_PAD (ghostpad);
+  return gpad;
 }
 
 /**
index 0d0d2d3..75ddff7 100644 (file)
@@ -13,12 +13,12 @@ else
 GST_DEBUG_DIRS = debug
 endif
 
-SUBDIRS = bins bytestream cleanup dynparams \
+SUBDIRS = bins bytestream cleanup dynparams ghostpads \
        caps plugin elements clock refcounting tags threads \
        indexers debug $(GST_PARSE_DIRS) $(GST_DEBUG_DIRS)
 
 DIST_SUBDIRS = bins bytestream caps cleanup clock dynparams elements indexers \
-               plugin refcounting tags threads parse debug
+               plugin refcounting tags threads parse debug ghostpads
 
 tests_pass = test_gst_init
 tests_fail = 
diff --git a/tests/old/testsuite/ghostpads/Makefile.am b/tests/old/testsuite/ghostpads/Makefile.am
new file mode 100644 (file)
index 0000000..c66c40b
--- /dev/null
@@ -0,0 +1,7 @@
+include ../Rules
+
+tests_pass = ghostpads
+tests_fail = 
+
+ghostpads_SOURCES = ghostpads.c
+
diff --git a/tests/old/testsuite/ghostpads/ghostpads.c b/tests/old/testsuite/ghostpads/ghostpads.c
new file mode 100644 (file)
index 0000000..27c0aff
--- /dev/null
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) 2004 Andy Wingo <wingo at pobox.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/gst.h>
+
+gint
+main (gint argc, gchar *argv[]) 
+{
+  GstElement *pipeline, *bin;
+  GstElement *fakesrc, *fakesink, *identity;
+  GstPad *sink, *src, *real = (GstPad*)0xdeadbeef;
+
+  gst_init (&argc, &argv);
+
+  pipeline = gst_element_factory_make ("pipeline", NULL);
+  bin = gst_element_factory_make ("bin", NULL);
+  fakesrc = gst_element_factory_make ("fakesrc", NULL);
+  fakesink = gst_element_factory_make ("fakesink", NULL);
+  identity = gst_element_factory_make ("identity", NULL);
+  
+  gst_bin_add_many (GST_BIN (pipeline), fakesrc, bin, fakesink, NULL);
+  gst_bin_add (GST_BIN (bin), identity);
+  
+  sink = gst_element_add_ghost_pad (bin,
+                                    gst_element_get_pad (identity, "sink"),
+                                    "sink");
+  src = gst_element_add_ghost_pad (bin,
+                                   gst_element_get_pad (identity, "src"),
+                                   "src");
+
+  gst_element_link_many (fakesrc, bin, fakesink);
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  
+  if (!gst_bin_iterate (GST_BIN (pipeline)))
+    g_assert_not_reached ();
+  
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  /* test the cleanup */
+  gst_object_ref (GST_OBJECT (sink));
+  gst_object_unref ((GstObject*)pipeline);
+  g_object_get (sink, "real-pad", &real, NULL);
+  g_assert (real == NULL);
+  g_assert (G_OBJECT (sink)->ref_count == 1);
+  gst_object_unref (GST_OBJECT (sink));
+  
+  return 0;
+}
index 0d0d2d3..75ddff7 100644 (file)
@@ -13,12 +13,12 @@ else
 GST_DEBUG_DIRS = debug
 endif
 
-SUBDIRS = bins bytestream cleanup dynparams \
+SUBDIRS = bins bytestream cleanup dynparams ghostpads \
        caps plugin elements clock refcounting tags threads \
        indexers debug $(GST_PARSE_DIRS) $(GST_DEBUG_DIRS)
 
 DIST_SUBDIRS = bins bytestream caps cleanup clock dynparams elements indexers \
-               plugin refcounting tags threads parse debug
+               plugin refcounting tags threads parse debug ghostpads
 
 tests_pass = test_gst_init
 tests_fail = 
diff --git a/testsuite/ghostpads/Makefile.am b/testsuite/ghostpads/Makefile.am
new file mode 100644 (file)
index 0000000..c66c40b
--- /dev/null
@@ -0,0 +1,7 @@
+include ../Rules
+
+tests_pass = ghostpads
+tests_fail = 
+
+ghostpads_SOURCES = ghostpads.c
+
diff --git a/testsuite/ghostpads/ghostpads.c b/testsuite/ghostpads/ghostpads.c
new file mode 100644 (file)
index 0000000..27c0aff
--- /dev/null
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) 2004 Andy Wingo <wingo at pobox.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/gst.h>
+
+gint
+main (gint argc, gchar *argv[]) 
+{
+  GstElement *pipeline, *bin;
+  GstElement *fakesrc, *fakesink, *identity;
+  GstPad *sink, *src, *real = (GstPad*)0xdeadbeef;
+
+  gst_init (&argc, &argv);
+
+  pipeline = gst_element_factory_make ("pipeline", NULL);
+  bin = gst_element_factory_make ("bin", NULL);
+  fakesrc = gst_element_factory_make ("fakesrc", NULL);
+  fakesink = gst_element_factory_make ("fakesink", NULL);
+  identity = gst_element_factory_make ("identity", NULL);
+  
+  gst_bin_add_many (GST_BIN (pipeline), fakesrc, bin, fakesink, NULL);
+  gst_bin_add (GST_BIN (bin), identity);
+  
+  sink = gst_element_add_ghost_pad (bin,
+                                    gst_element_get_pad (identity, "sink"),
+                                    "sink");
+  src = gst_element_add_ghost_pad (bin,
+                                   gst_element_get_pad (identity, "src"),
+                                   "src");
+
+  gst_element_link_many (fakesrc, bin, fakesink);
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  
+  if (!gst_bin_iterate (GST_BIN (pipeline)))
+    g_assert_not_reached ();
+  
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  /* test the cleanup */
+  gst_object_ref (GST_OBJECT (sink));
+  gst_object_unref ((GstObject*)pipeline);
+  g_object_get (sink, "real-pad", &real, NULL);
+  g_assert (real == NULL);
+  g_assert (G_OBJECT (sink)->ref_count == 1);
+  gst_object_unref (GST_OBJECT (sink));
+  
+  return 0;
+}