Commit 68037404 authored by Olivier Crete's avatar Olivier Crete Committed by Wim Taymans
Browse files

Add threadsafe replacement functions for getting internal links of an element....

Add threadsafe replacement functions for getting internal links of an element. Deprecate the old internal links funct...

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.
parent 1639fb59
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:
......@@ -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
......
......@@ -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));
......
......@@ -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;
......@@ -1344,13 +1347,36 @@ gst_pad_get_query_types_default (GstPad * pad)
return result;
}
/**
* 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)
......
......@@ -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*
......
......@@ -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;
}
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment