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.
This commit is contained in:
Olivier Crete 2008-09-01 10:42:04 +00:00 committed by Wim Taymans
parent 1639fb5905
commit 68037404b8
7 changed files with 372 additions and 4 deletions

View file

@ -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:

View 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

View 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));

View 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;
@ -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)

View file

@ -309,10 +309,27 @@ typedef gboolean (*GstPadCheckGetRangeFunction) (GstPad *pad);
*
* 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.
*
* 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*

View 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;
}

View 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