Add threadsafe replacement functions for getting internal links of an element. Deprec...
authorOlivier Crete <tester@tester.ca>
Mon, 1 Sep 2008 10:42:04 +0000 (10:42 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 1 Sep 2008 10:42:04 +0000 (10:42 +0000)
Original commit message from CVS:
Based on patch by: Olivier Crete <tester at tester dot ca>
* docs/gst/gstreamer-sections.txt:
* win32/common/libgstreamer.def:
* gst/gstpad.c: (gst_pad_init),
(gst_pad_set_iterate_internal_links_function),
(int_link_iter_data_free), (iterate_pad),
(gst_pad_iterate_internal_links_default),
(gst_pad_iterate_internal_links), (gst_pad_get_internal_links):
* gst/gstpad.h:
Add threadsafe replacement functions for getting internal links of an
element. Deprecate the old internal links functions.
API:GstPad::gst_pad_set_iterate_internal_links_function()
API:GstPad::GstPadIterIntLinkFunction
API:GstPad::gst_pad_iterate_internal_links()
API:GstPad::gst_pad_iterate_internal_links_default()
* gst/gstghostpad.c: (gst_proxy_pad_do_iterate_internal_links),
(gst_proxy_pad_init):
Implement threadsafe internal links.
* tests/check/elements/tee.c: (GST_START_TEST), (tee_suite):
Unit test for internal links on tee. See #549504.

ChangeLog
docs/gst/gstreamer-sections.txt
gst/gstghostpad.c
gst/gstpad.c
gst/gstpad.h
tests/check/elements/tee.c
win32/common/libgstreamer.def

index 821206e..8bfab44 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2008-09-01  Wim Taymans  <wim.taymans@collabora.co.uk>
+
+       Based on patch by: Olivier Crete <tester at tester dot ca>
+
+       * docs/gst/gstreamer-sections.txt:
+       * win32/common/libgstreamer.def:
+       * gst/gstpad.c: (gst_pad_init),
+       (gst_pad_set_iterate_internal_links_function),
+       (int_link_iter_data_free), (iterate_pad),
+       (gst_pad_iterate_internal_links_default),
+       (gst_pad_iterate_internal_links), (gst_pad_get_internal_links):
+       * gst/gstpad.h:
+       Add threadsafe replacement functions for getting internal links of an
+       element. Deprecate the old internal links functions.
+       API:GstPad::gst_pad_set_iterate_internal_links_function()
+       API:GstPad::GstPadIterIntLinkFunction
+       API:GstPad::gst_pad_iterate_internal_links()
+       API:GstPad::gst_pad_iterate_internal_links_default()
+
+       * gst/gstghostpad.c: (gst_proxy_pad_do_iterate_internal_links),
+       (gst_proxy_pad_init):
+       Implement threadsafe internal links.
+
+       * tests/check/elements/tee.c: (GST_START_TEST), (tee_suite):
+       Unit test for internal links on tee. See #549504.
+
 2008-08-30  Edward Hervey  <edward.hervey@collabora.co.uk>
 
        * tests/check/Makefile.am:
index 97b74a6..71cf495 100644 (file)
@@ -1338,10 +1338,16 @@ GstPadQueryTypeFunction
 gst_pad_get_query_types
 gst_pad_get_query_types_default
 
+gst_pad_set_iterate_internal_links_function
+GstPadIterIntLinkFunction
+gst_pad_iterate_internal_links
+gst_pad_iterate_internal_links_default
+
 gst_pad_set_internal_link_function
 GstPadIntLinkFunction
 gst_pad_get_internal_links
 gst_pad_get_internal_links_default
+
 gst_pad_load_and_link
 
 gst_pad_dispatcher
@@ -1433,6 +1439,7 @@ GST_PAD_FIXATECAPSFUNC
 GST_PAD_GETCAPSFUNC
 GST_PAD_GETRANGEFUNC
 GST_PAD_INTLINKFUNC
+GST_PAD_ITERINTLINKFUNC
 GST_PAD_IS_FLUSHING
 GST_PAD_LINKFUNC
 GST_PAD_QUERYFUNC
index 2aba5d2..e727cec 100644 (file)
@@ -172,6 +172,20 @@ gst_proxy_pad_do_internal_link (GstPad * pad)
   return res;
 }
 
+static GstIterator *
+gst_proxy_pad_do_iterate_internal_links (GstPad * pad)
+{
+  GstIterator *res = NULL;
+  GstPad *target = gst_proxy_pad_get_target (pad);
+
+  if (target) {
+    res = gst_pad_iterate_internal_links (target);
+    gst_object_unref (target);
+  }
+
+  return res;
+}
+
 static GstFlowReturn
 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
     GstCaps * caps, GstBuffer ** buf)
@@ -415,6 +429,8 @@ gst_proxy_pad_init (GstProxyPad * ppad)
   gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
   gst_pad_set_internal_link_function (pad,
       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
+  gst_pad_set_iterate_internal_links_function (pad,
+      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_iterate_internal_links));
 
   gst_pad_set_getcaps_function (pad,
       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
index b8e2405..dad0115 100644 (file)
@@ -347,6 +347,9 @@ gst_pad_init (GstPad * pad)
   GST_PAD_QUERYFUNC (pad) = GST_DEBUG_FUNCPTR (gst_pad_query_default);
   GST_PAD_INTLINKFUNC (pad) =
       GST_DEBUG_FUNCPTR (gst_pad_get_internal_links_default);
+  GST_PAD_ITERINTLINKFUNC (pad) =
+      GST_DEBUG_FUNCPTR (gst_pad_iterate_internal_links_default);
+
   GST_PAD_ACCEPTCAPSFUNC (pad) = GST_DEBUG_FUNCPTR (gst_pad_acceptcaps_default);
 
   pad->do_buffer_signals = 0;
@@ -1345,12 +1348,35 @@ gst_pad_get_query_types_default (GstPad * pad)
 }
 
 /**
+ * gst_pad_set_iterate_internal_links_function:
+ * @pad: a #GstPad of either direction.
+ * @iterintlink: the #GstPadIterIntLinkFunction to set.
+ *
+ * Sets the given internal link iterator function for the pad.
+ *
+ * Since: 0.10.21
+ */
+void
+gst_pad_set_iterate_internal_links_function (GstPad * pad,
+    GstPadIterIntLinkFunction iterintlink)
+{
+  g_return_if_fail (GST_IS_PAD (pad));
+
+  GST_PAD_ITERINTLINKFUNC (pad) = iterintlink;
+  GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "internal link iterator set to %s",
+      GST_DEBUG_FUNCPTR_NAME (iterintlink));
+}
+
+/**
  * gst_pad_set_internal_link_function:
  * @pad: a #GstPad of either direction.
  * @intlink: the #GstPadIntLinkFunction to set.
  *
  * Sets the given internal link function for the pad.
+ *
+ * Deprecated: Use the thread-safe gst_pad_set_iterate_internal_links_function()
  */
+#ifndef GST_REMOVE_DEPRECATED
 void
 gst_pad_set_internal_link_function (GstPad * pad, GstPadIntLinkFunction intlink)
 {
@@ -1360,6 +1386,7 @@ gst_pad_set_internal_link_function (GstPad * pad, GstPadIntLinkFunction intlink)
   GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "internal link set to %s",
       GST_DEBUG_FUNCPTR_NAME (intlink));
 }
+#endif /* GST_REMOVE_DEPRECATED */
 
 /**
  * gst_pad_set_link_function:
@@ -2892,6 +2919,148 @@ gst_pad_alloc_buffer_and_set_caps (GstPad * pad, guint64 offset, gint size,
   return gst_pad_alloc_buffer_full (pad, offset, size, caps, buf, TRUE);
 }
 
+
+#ifndef GST_REMOVE_DEPRECATED
+typedef struct
+{
+  GList *list;
+  guint32 cookie;
+} IntLinkIterData;
+
+static void
+int_link_iter_data_free (IntLinkIterData * data)
+{
+  g_list_free (data->list);
+  g_free (data);
+}
+#endif
+
+static GstIteratorItem
+iterate_pad (GstIterator * it, GstPad * pad)
+{
+  gst_object_ref (pad);
+  return GST_ITERATOR_ITEM_PASS;
+}
+
+/**
+ * gst_pad_iterate_internal_links_default:
+ * @pad: the #GstPad to get the internal links of.
+ *
+ * Iterate the list of pads to which the given pad is linked to inside of
+ * the parent element.
+ * This is the default handler, and thus returns an iterator of all of the
+ * pads inside the parent element with opposite direction.
+ *
+ * The caller must free this iterator after use with gst_iterator_free().
+ *
+ * Returns: a #GstIterator of #GstPad, or NULL if @pad has no parent. Unref each
+ * returned pad with gst_object_unref().
+ *
+ * Since: 0.10.21
+ */
+GstIterator *
+gst_pad_iterate_internal_links_default (GstPad * pad)
+{
+  GstIterator *res;
+  GstElement *parent = NULL;
+  GList **padlist;
+  guint32 *cookie;
+  gpointer owner;
+  GstIteratorDisposeFunction dispose;
+
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+
+#ifndef GST_REMOVE_DEPRECATED
+  /* when we get here, the default handler for the iterate links is called,
+   * which means that the user has not installed a custom one. We first check if
+   * there is maybe a custom legacy function we can call. */
+  if (GST_PAD_INTLINKFUNC (pad) &&
+      GST_PAD_INTLINKFUNC (pad) != gst_pad_get_internal_links_default) {
+    IntLinkIterData *data;
+
+    /* make an iterator for the list. We can't protect the list with a
+     * cookie. If we would take the cookie of the parent element, we need to
+     * have a parent, which is not required for GST_PAD_INTLINKFUNC(). We could
+     * cache the per-pad list and invalidate the list when a new call to
+     * INTLINKFUNC() returned a different list but then this would only work if
+     * two concurrent iterators were used and the last iterator would still be
+     * thread-unsafe. Just don't use this method anymore. */
+    data = g_new0 (IntLinkIterData, 1);
+    data->list = GST_PAD_INTLINKFUNC (pad) (pad);
+    data->cookie = 0;
+
+    GST_WARNING_OBJECT (pad, "Making unsafe iterator");
+
+    cookie = &data->cookie;
+    padlist = &data->list;
+    owner = data;
+    dispose = (GstIteratorDisposeFunction) int_link_iter_data_free;
+  } else
+#endif
+  {
+    GST_OBJECT_LOCK (pad);
+    parent = GST_PAD_PARENT (pad);
+    if (!parent || !GST_IS_ELEMENT (parent))
+      goto no_parent;
+
+    gst_object_ref (parent);
+    GST_OBJECT_UNLOCK (pad);
+
+    if (pad->direction == GST_PAD_SRC)
+      padlist = &parent->sinkpads;
+    else
+      padlist = &parent->srcpads;
+
+    GST_DEBUG_OBJECT (pad, "Making iterator");
+
+    cookie = &parent->pads_cookie;
+    owner = parent;
+    dispose = (GstIteratorDisposeFunction) gst_object_unref;
+  }
+
+  res = gst_iterator_new_list (GST_TYPE_PAD,
+      GST_OBJECT_GET_LOCK (parent),
+      cookie, padlist, owner, (GstIteratorItemFunction) iterate_pad, dispose);
+
+  return res;
+
+  /* ERRORS */
+no_parent:
+  {
+    GST_OBJECT_UNLOCK (pad);
+    GST_DEBUG_OBJECT (pad, "no parent element");
+    return NULL;
+  }
+}
+
+/**
+ * gst_pad_iterate_internal_links:
+ * @pad: the GstPad to get the internal links of.
+ *
+ * Gets an iterator for the pads to which the given pad is linked to inside
+ * of the parent element.
+ *
+ * Each #GstPad element yielded by the iterator will have its refcount increased,
+ * so unref after use.
+ *
+ * Returns: a new #GstIterator of #GstPad or %NULL when the pad does not have an
+ * iterator function configured. Use gst_iterator_free() after usage.
+ *
+ * Since: 0.10.21
+ */
+GstIterator *
+gst_pad_iterate_internal_links (GstPad * pad)
+{
+  GstIterator *res = NULL;
+
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+
+  if (GST_PAD_ITERINTLINKFUNC (pad))
+    res = GST_PAD_ITERINTLINKFUNC (pad) (pad);
+
+  return res;
+}
+
 /**
  * gst_pad_get_internal_links_default:
  * @pad: the #GstPad to get the internal links of.
@@ -2906,7 +3075,11 @@ gst_pad_alloc_buffer_and_set_caps (GstPad * pad, guint64 offset, gint size,
  * Returns: a newly allocated #GList of pads, or NULL if the pad has no parent.
  *
  * Not MT safe.
+ *
+ * Deprecated: use the thread-safe gst_pad_iterate_internal_links() functions
+ * instead.
  */
+#ifndef GST_REMOVE_DEPRECATED
 GList *
 gst_pad_get_internal_links_default (GstPad * pad)
 {
@@ -2947,6 +3120,7 @@ no_parent:
     return NULL;
   }
 }
+#endif /* GST_REMOVE_DEPRECATED */
 
 /**
  * gst_pad_get_internal_links:
@@ -2959,7 +3133,10 @@ no_parent:
  * Returns: a newly allocated #GList of pads.
  *
  * Not MT safe.
+ * 
+ * Deprecated: Use the thread-safe gst_pad_iterate_internal_links() instead.
  */
+#ifndef GST_REMOVE_DEPRECATED
 GList *
 gst_pad_get_internal_links (GstPad * pad)
 {
@@ -2967,12 +3144,14 @@ gst_pad_get_internal_links (GstPad * pad)
 
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
+  GST_WARNING_OBJECT (pad, "Calling unsafe internal links");
+
   if (GST_PAD_INTLINKFUNC (pad))
     res = GST_PAD_INTLINKFUNC (pad) (pad);
 
   return res;
 }
-
+#endif /* GST_REMOVE_DEPRECATED */
 
 static gboolean
 gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event)
index 9879bee..50da287 100644 (file)
@@ -308,11 +308,28 @@ typedef gboolean          (*GstPadCheckGetRangeFunction)  (GstPad *pad);
  * The signature of the internal pad link function.
  *
  * Returns: a newly allocated #GList of pads that are linked to the given pad on
- *  the inside of the parent element.
- *  The caller must call g_list_free() on it after use.
+ * the inside of the parent element.
+ *
+ * The caller must call g_list_free() on it after use.
+ *
+ * Deprecated: use the threadsafe #GstPadIterIntLinkFunction instead.
  */
 typedef GList*                 (*GstPadIntLinkFunction)        (GstPad *pad);
 
+/**
+ * GstPadIterIntLinkFunction:
+ * @pad: The #GstPad to query.
+ *
+ * The signature of the internal pad link iterator function.
+ *
+ * Returns: a new #GstIterator that will iterate over all pads that are
+ * linked to the given pad on the inside of the parent element.
+ *
+ * the caller must call gst_iterator_free() after usage.
+ *
+ * Since 0.10.21
+ */
+typedef GstIterator*           (*GstPadIterIntLinkFunction)    (GstPad *pad);
 
 /* generic query function */
 /**
@@ -540,6 +557,7 @@ typedef struct _GstPadTemplate GstPadTemplate;
  * @bufferallocfunc: function to allocate a buffer for this pad
  * @do_buffer_signals: counter counting installed buffer signals
  * @do_event_signals: counter counting installed event signals
+ * @iterintlinkfunc: get the internal links iterator of this pad
  *
  * The #GstPad structure. Use the functions to update the variables.
  */
@@ -607,8 +625,12 @@ struct _GstPad {
   gint                          do_buffer_signals;
   gint                          do_event_signals;
 
+  /* ABI added */
+  /* iterate internal links */
+  GstPadIterIntLinkFunction     iterintlinkfunc;
+
   /*< private >*/
-  gpointer _gst_reserved[GST_PADDING];
+  gpointer _gst_reserved[GST_PADDING - 1];
 };
 
 struct _GstPadClass {
@@ -645,6 +667,7 @@ struct _GstPadClass {
 #define GST_PAD_QUERYTYPEFUNC(pad)     (GST_PAD_CAST(pad)->querytypefunc)
 #define GST_PAD_QUERYFUNC(pad)         (GST_PAD_CAST(pad)->queryfunc)
 #define GST_PAD_INTLINKFUNC(pad)       (GST_PAD_CAST(pad)->intlinkfunc)
+#define GST_PAD_ITERINTLINKFUNC(pad)    (GST_PAD_CAST(pad)->iterintlinkfunc)
 
 #define GST_PAD_PEER(pad)              (GST_PAD_CAST(pad)->peer)
 #define GST_PAD_LINKFUNC(pad)          (GST_PAD_CAST(pad)->linkfunc)
@@ -865,6 +888,12 @@ void                       gst_pad_set_internal_link_function      (GstPad *pad, GstPadIntLinkFunction in
 GList*                 gst_pad_get_internal_links              (GstPad *pad);
 GList*                 gst_pad_get_internal_links_default      (GstPad *pad);
 
+void                    gst_pad_set_iterate_internal_links_function (GstPad * pad,
+                                                                 GstPadIterIntLinkFunction iterintlink);
+GstIterator *           gst_pad_iterate_internal_links          (GstPad * pad);
+GstIterator *           gst_pad_iterate_internal_links_default  (GstPad * pad);
+
+
 /* generic query function */
 void                   gst_pad_set_query_type_function         (GstPad *pad, GstPadQueryTypeFunction type_func);
 G_CONST_RETURN GstQueryType*
index bc017dd..d62a975 100644 (file)
@@ -345,6 +345,113 @@ GST_START_TEST (test_release_while_second_buffer_alloc)
 
 GST_END_TEST;
 
+/* Check the internal pads of tee */
+GST_START_TEST (test_internal_links)
+{
+  GstElement *tee;
+  GstPad *sinkpad, *srcpad1, *srcpad2;
+  GstIterator *it;
+  GstIteratorResult res;
+  gpointer val1, val2;
+
+  tee = gst_check_setup_element ("tee");
+
+  sinkpad = gst_element_get_static_pad (tee, "sink");
+  fail_unless (sinkpad != NULL);
+  it = gst_pad_iterate_internal_links (sinkpad);
+  fail_unless (it != NULL);
+
+  /* iterator should not return anything */
+  val1 = NULL;
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_DONE);
+  fail_unless (val1 == NULL);
+
+  srcpad1 = gst_element_get_request_pad (tee, "src%d");
+  fail_unless (srcpad1 != NULL);
+
+  /* iterator should resync */
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_RESYNC);
+  fail_unless (val1 == NULL);
+  gst_iterator_resync (it);
+
+  /* we should get something now */
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_OK);
+  fail_unless (GST_PAD_CAST (val1) == srcpad1);
+
+  gst_object_unref (val1);
+
+  val1 = NULL;
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_DONE);
+  fail_unless (val1 == NULL);
+
+  srcpad2 = gst_element_get_request_pad (tee, "src%d");
+  fail_unless (srcpad2 != NULL);
+
+  /* iterator should resync */
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_RESYNC);
+  fail_unless (val1 == NULL);
+  gst_iterator_resync (it);
+
+  /* we should get one of the 2 pads now */
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_OK);
+  fail_unless (GST_PAD_CAST (val1) == srcpad1
+      || GST_PAD_CAST (val1) == srcpad2);
+
+  /* and the other */
+  res = gst_iterator_next (it, &val2);
+  fail_unless (res == GST_ITERATOR_OK);
+  fail_unless (GST_PAD_CAST (val2) == srcpad1
+      || GST_PAD_CAST (val2) == srcpad2);
+  fail_unless (val1 != val2);
+  gst_object_unref (val1);
+  gst_object_unref (val2);
+
+  val1 = NULL;
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_DONE);
+  fail_unless (val1 == NULL);
+
+  gst_iterator_free (it);
+
+  /* get an iterator for the other direction */
+  it = gst_pad_iterate_internal_links (srcpad1);
+  fail_unless (it != NULL);
+
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_OK);
+  fail_unless (GST_PAD_CAST (val1) == sinkpad);
+  gst_object_unref (val1);
+
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_DONE);
+  gst_iterator_free (it);
+
+  it = gst_pad_iterate_internal_links (srcpad2);
+  fail_unless (it != NULL);
+
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_OK);
+  fail_unless (GST_PAD_CAST (val1) == sinkpad);
+  gst_object_unref (val1);
+
+  res = gst_iterator_next (it, &val1);
+  fail_unless (res == GST_ITERATOR_DONE);
+
+  gst_iterator_free (it);
+  gst_object_unref (srcpad1);
+  gst_object_unref (srcpad2);
+  gst_object_unref (sinkpad);
+  gst_object_unref (tee);
+}
+
+GST_END_TEST;
+
 static Suite *
 tee_suite (void)
 {
@@ -356,6 +463,7 @@ tee_suite (void)
   tcase_add_test (tc_chain, test_stress);
   tcase_add_test (tc_chain, test_release_while_buffer_alloc);
   tcase_add_test (tc_chain, test_release_while_second_buffer_alloc);
+  tcase_add_test (tc_chain, test_internal_links);
 
   return s;
 }
index af8e36e..2f55dbb 100644 (file)
@@ -546,6 +546,8 @@ EXPORTS
        gst_pad_is_blocked
        gst_pad_is_blocking
        gst_pad_is_linked
+        gst_pad_iterate_internal_links
+        gst_pad_iterate_internal_links_default
        gst_pad_link
        gst_pad_link_return_get_type
        gst_pad_load_and_link
@@ -591,6 +593,7 @@ EXPORTS
        gst_pad_set_getcaps_function
        gst_pad_set_getrange_function
        gst_pad_set_internal_link_function
+       gst_pad_set_iterate_internal_links_function
        gst_pad_set_link_function
        gst_pad_set_query_function
        gst_pad_set_query_type_function