gst/gstelement.c (gst_element_dispose): Protect against multiple invocations.

Original commit message from CVS:
2004-02-24  Andy Wingo  <wingo@pobox.com>

* gst/gstelement.c (gst_element_dispose): Protect against multiple
invocations.

* gst/schedulers/gstoptimalscheduler.c
I added a mess of prototypes at the top of the file by way of
documentation. Some of the operations on chains and groups were
re-organized.

(create_group): Added a type argument so if the group is enabled,
the setup_group_scheduler knows what to do.
(group_elements): Added a type argument here, too, to be passed on
to create_group.
(group_element_set_enabled): If an unlinked PLAYING element is
added to a bin, we have to create a new group to hold the element,
and this function will be called before the group is added to the
chain. Thus we have a valid case for group->chain==NULL. Instead
of calling chain_group_set_enabled, just set the flag on the group
(the chain's status will be set when the group is added to it).
(gst_opt_scheduler_state_transition, chain_group_set_enabled):
Setup the group scheduler when the group is enabled, not
specifically when an element goes PAUSED->PLAYING. This means
PLAYING elements can be added, linked, and scheduled into a
PLAYING pipeline, as was intended.
(add_to_group): Don't ref the group twice. I don't know when this
double-ref got in here. Removing it has the potential to cause
segfaults if other parts of the scheduler are buggy. If you find
that the scheduler is segfaulting for you, put in an extra ref
here and see if that hacks over the underlying issue. Of course,
then find out what code is unreffing a group it doesn't own...
(create_group): Make the extra refcount floating, and remove it
after adding the element. This means that...
(unref_group): Destroy when the refcount reaches 0, not 1, like
every other refcounted object in the known universe.
(remove_from_group): When a group becomes empty, set it to be not
active, and remove it from its chain. Don't unref it again,
there's no floating reference any more.
(destroy_group): We have to remove the group from the chain in
remove_from_group (rather than here) to break refcounting cycles
(the chain always has a ref on the group). So assert that
group->chain==NULL.
(ref_group_by_count): Removed, it was commented out anyway.
(merge_chains): Use the remove_from_chain and add_to_chain
primitives to do the reparenting, instead of rolling our own
implementation.
(add_to_chain): The first non-disabled group in the chain's group
list will be the entry point for the chain. Because buffers can
accumulate in loop elements' peer bufpens, we preferentially
schedule loop groups before get groups to avoid unnecessary
execution of get-based groups when the bufpens are already full.
(gst_opt_scheduler_schedule_run_queue): Debug fixes.
(get_group_schedule_function): Ditto.
(loop_group_schedule_function): Ditto.
(gst_opt_scheduler_loop_wrapper): Ditto.
(gst_opt_scheduler_iterate): Ditto.

I understand the opt scheduler now, yippee!

* gst/gstpad.c: All throughout, added FIXMEs to look at for 0.9.
(gst_pad_get_name, gst_pad_set_chain_function)
(gst_pad_set_get_function, gst_pad_set_event_function)
(gst_pad_set_event_mask_function, gst_pad_get_event_masks)
(gst_pad_get_event_masks_default, gst_pad_set_convert_function)
(gst_pad_set_query_function, gst_pad_get_query_types)
(gst_pad_get_query_types_default)
(gst_pad_set_internal_link_function)
(gst_pad_set_formats_function, gst_pad_set_link_function)
(gst_pad_set_fixate_function, gst_pad_set_getcaps_function)
(gst_pad_set_bufferalloc_function, gst_pad_unlink)
(gst_pad_renegotiate, gst_pad_set_parent, gst_pad_get_parent)
(gst_pad_add_ghost_pad, gst_pad_proxy_getcaps)
(gst_pad_proxy_pad_link, gst_pad_proxy_fixate)
(gst_pad_get_pad_template_caps, gst_pad_check_compatibility)
(gst_pad_get_peer, gst_pad_get_allowed_caps)
(gst_pad_alloc_buffer, gst_pad_push, gst_pad_pull)
(gst_pad_selectv, gst_pad_select, gst_pad_template_get_caps)
(gst_pad_event_default_dispatch, gst_pad_event_default)
(gst_pad_dispatcher, gst_pad_send_event, gst_pad_convert_default)
(gst_pad_convert, gst_pad_query_default, gst_pad_query)
(gst_pad_get_formats_default, gst_pad_get_formats): Better
argument checks, and some doc fixes.

(gst_pad_custom_new_from_template): Um, does anyone
use these functions? Actually make a custom pad instead of a
normal one.
(gst_pad_try_set_caps): Transpose some checks.
(gst_pad_try_set_caps_nonfixed): Same, and use a macro to check if
the pad is in negotiation.
(gst_pad_try_relink_filtered): Use pad_link_prepare.

* gst/gstelement.c: Remove prototypes also defined in gstclock.h.

* gst/gstelement.h:
* gst/gstclock.h: Un-deprecate the old clocking API, as discussed
on the list.
This commit is contained in:
Andy Wingo 2004-02-25 13:16:12 +00:00
parent 79f5d87041
commit 3f5a8814d5
8 changed files with 615 additions and 388 deletions

View file

@ -1,3 +1,100 @@
2004-02-24 Andy Wingo <wingo@pobox.com>
* gst/gstelement.c (gst_element_dispose): Protect against multiple
invocations.
* gst/schedulers/gstoptimalscheduler.c
I added a mess of prototypes at the top of the file by way of
documentation. Some of the operations on chains and groups were
re-organized.
(create_group): Added a type argument so if the group is enabled,
the setup_group_scheduler knows what to do.
(group_elements): Added a type argument here, too, to be passed on
to create_group.
(group_element_set_enabled): If an unlinked PLAYING element is
added to a bin, we have to create a new group to hold the element,
and this function will be called before the group is added to the
chain. Thus we have a valid case for group->chain==NULL. Instead
of calling chain_group_set_enabled, just set the flag on the group
(the chain's status will be set when the group is added to it).
(gst_opt_scheduler_state_transition, chain_group_set_enabled):
Setup the group scheduler when the group is enabled, not
specifically when an element goes PAUSED->PLAYING. This means
PLAYING elements can be added, linked, and scheduled into a
PLAYING pipeline, as was intended.
(add_to_group): Don't ref the group twice. I don't know when this
double-ref got in here. Removing it has the potential to cause
segfaults if other parts of the scheduler are buggy. If you find
that the scheduler is segfaulting for you, put in an extra ref
here and see if that hacks over the underlying issue. Of course,
then find out what code is unreffing a group it doesn't own...
(create_group): Make the extra refcount floating, and remove it
after adding the element. This means that...
(unref_group): Destroy when the refcount reaches 0, not 1, like
every other refcounted object in the known universe.
(remove_from_group): When a group becomes empty, set it to be not
active, and remove it from its chain. Don't unref it again,
there's no floating reference any more.
(destroy_group): We have to remove the group from the chain in
remove_from_group (rather than here) to break refcounting cycles
(the chain always has a ref on the group). So assert that
group->chain==NULL.
(ref_group_by_count): Removed, it was commented out anyway.
(merge_chains): Use the remove_from_chain and add_to_chain
primitives to do the reparenting, instead of rolling our own
implementation.
(add_to_chain): The first non-disabled group in the chain's group
list will be the entry point for the chain. Because buffers can
accumulate in loop elements' peer bufpens, we preferentially
schedule loop groups before get groups to avoid unnecessary
execution of get-based groups when the bufpens are already full.
(gst_opt_scheduler_schedule_run_queue): Debug fixes.
(get_group_schedule_function): Ditto.
(loop_group_schedule_function): Ditto.
(gst_opt_scheduler_loop_wrapper): Ditto.
(gst_opt_scheduler_iterate): Ditto.
I understand the opt scheduler now, yippee!
* gst/gstpad.c: All throughout, added FIXMEs to look at for 0.9.
(gst_pad_get_name, gst_pad_set_chain_function)
(gst_pad_set_get_function, gst_pad_set_event_function)
(gst_pad_set_event_mask_function, gst_pad_get_event_masks)
(gst_pad_get_event_masks_default, gst_pad_set_convert_function)
(gst_pad_set_query_function, gst_pad_get_query_types)
(gst_pad_get_query_types_default)
(gst_pad_set_internal_link_function)
(gst_pad_set_formats_function, gst_pad_set_link_function)
(gst_pad_set_fixate_function, gst_pad_set_getcaps_function)
(gst_pad_set_bufferalloc_function, gst_pad_unlink)
(gst_pad_renegotiate, gst_pad_set_parent, gst_pad_get_parent)
(gst_pad_add_ghost_pad, gst_pad_proxy_getcaps)
(gst_pad_proxy_pad_link, gst_pad_proxy_fixate)
(gst_pad_get_pad_template_caps, gst_pad_check_compatibility)
(gst_pad_get_peer, gst_pad_get_allowed_caps)
(gst_pad_alloc_buffer, gst_pad_push, gst_pad_pull)
(gst_pad_selectv, gst_pad_select, gst_pad_template_get_caps)
(gst_pad_event_default_dispatch, gst_pad_event_default)
(gst_pad_dispatcher, gst_pad_send_event, gst_pad_convert_default)
(gst_pad_convert, gst_pad_query_default, gst_pad_query)
(gst_pad_get_formats_default, gst_pad_get_formats): Better
argument checks, and some doc fixes.
(gst_pad_custom_new_from_template): Um, does anyone
use these functions? Actually make a custom pad instead of a
normal one.
(gst_pad_try_set_caps): Transpose some checks.
(gst_pad_try_set_caps_nonfixed): Same, and use a macro to check if
the pad is in negotiation.
(gst_pad_try_relink_filtered): Use pad_link_prepare.
* gst/gstelement.c: Remove prototypes also defined in gstclock.h.
* gst/gstelement.h:
* gst/gstclock.h: Un-deprecate the old clocking API, as discussed
on the list.
2004-02-24 Thomas Vander Stichele <thomas at apestaart dot org>
* gst/gstbin.c: (gst_bin_add):

View file

@ -116,7 +116,7 @@ U gst-template/gst-app/src/Makefile.am
<para>
First we will examine the code you would be likely to place in a header
file (although since the interface to the code is entirely defined by the
pluging system, and doesn't depend on reading a header file, this is not
plugin system, and doesn't depend on reading a header file, this is not
crucial.)
The code here can be found in

View file

@ -0,0 +1,62 @@
-*- outline -*-
* Creating Elements Without Factories
** The purpose of factories
On a typical GStreamer system, there are approximately 6.022*10^23
plugins. GStreamer knows about all of them because of the registry. The
goal is to avoid initializing each one of them, when maybe for your
application you only need one or two.
The problem becomes, how do you create an instance of the plugin? The
normal way to instantiate a class is via g_object_new (TYPE, ARGS...).
In the case that the plugin isn't loaded, you don't know its type, and
can't even get it from the type name.
Element factories exist to solve this problem by associating names (like
"sinesrc" or "identity") with certain types that are provided by the
plugin. Then when the user asks for "sinesrc", the appropriate plugin is
loaded, its types are initialized, and then gst_element_factory_create
creates the object for you.
** Why not factories?
To review, factories (1) allow plugins to remain unloaded if not
necessary, and (2) make it easy to create elements.
If you are writing an application that has custom elements (as is the
case with most serious applications), you will probably have the plugin
loaded up already, and you will have access to the type of the element.
To muck about creating a plugin for the app, registering the element
with the plugin, and then creating it with the element factory API
actually takes more work than the normal way.
** g_object_new
So you want to avoid factories. To create objects with a simple
g_object_new call is our strategy. However, to preserve the same
semantics as gst_element_factory_create, we need to know what else is
needed to initialize a GStreamer element.
The other things that gst_element_factory_create does are as follows:
*** Sets the ->elementfactory member on the element class
Note that anything trying to get the factory won't work (e.g.
gst_element_get_factory). Thankfully this is less of a problem after the
0.7 plugin system changes.
*** Initializes the name of the element
To do this ourselves, we either call gst_object_set_name, or when we
set the "name" property when creating the object.
** Summary
To create a GStreamer element when you know the type, you can just use
g_object_new (get_type_of_my_element (),
"name", the_name_you_want_possibly_null,
... any other properties ...
NULL);

View file

@ -163,27 +163,21 @@ struct _GstClockClass {
GType gst_clock_get_type (void);
#ifndef GST_DISABLE_DEPRECATED
gdouble gst_clock_set_speed (GstClock *clock, gdouble speed);
gdouble gst_clock_get_speed (GstClock *clock);
#endif
guint64 gst_clock_set_resolution (GstClock *clock, guint64 resolution);
guint64 gst_clock_get_resolution (GstClock *clock);
#ifndef GST_DISABLE_DEPRECATED
void gst_clock_set_active (GstClock *clock, gboolean active);
gboolean gst_clock_is_active (GstClock *clock);
void gst_clock_reset (GstClock *clock);
gboolean gst_clock_handle_discont (GstClock *clock, guint64 time);
#endif
GstClockTime gst_clock_get_time (GstClock *clock);
GstClockTime gst_clock_get_event_time (GstClock *clock);
/* FIXME: deprecate? */
#ifndef GST_DISABLE_DEPRECATED
GstClockID gst_clock_get_next_id (GstClock *clock);
/* creating IDs that can be used to get notifications */
@ -203,7 +197,6 @@ GstClockReturn gst_clock_id_wait_async (GstClockID id,
void gst_clock_id_unschedule (GstClockID id);
void gst_clock_id_unlock (GstClockID id);
void gst_clock_id_free (GstClockID id);
#endif
G_END_DECLS

View file

@ -835,9 +835,6 @@ gst_element_get_time (GstElement *element)
}
}
GstClockID gst_clock_new_single_shot_id (GstClock *clock,
GstClockTime time);
void gst_clock_id_free (GstClockID id);
/**
* gst_element_wait:
* @element: element that should wait
@ -2961,8 +2958,10 @@ gst_element_dispose (GObject *object)
element->numsrcpads = 0;
element->numsinkpads = 0;
element->numpads = 0;
g_mutex_free (element->state_mutex);
g_cond_free (element->state_cond);
if (element->state_mutex)
g_mutex_free (element->state_mutex);
if (element->state_cond)
g_cond_free (element->state_cond);
if (element->prop_value_queue)
g_async_queue_unref (element->prop_value_queue);

View file

@ -287,10 +287,8 @@ gboolean gst_element_requires_clock (GstElement *element);
gboolean gst_element_provides_clock (GstElement *element);
GstClock* gst_element_get_clock (GstElement *element);
void gst_element_set_clock (GstElement *element, GstClock *clock);
#ifndef GST_DISABLE_DEPRECATED
GstClockReturn gst_element_clock_wait (GstElement *element,
GstClockID id, GstClockTimeDiff *jitter);
#endif
GstClockTime gst_element_get_time (GstElement *element);
gboolean gst_element_wait (GstElement *element, GstClockTime timestamp);
void gst_element_set_time (GstElement *element, GstClockTime time);

View file

@ -353,9 +353,9 @@ gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ,
{
GstPad *pad;
g_return_val_if_fail (templ != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
pad = gst_pad_new (name, templ->direction);
pad = gst_pad_custom_new (type, name, templ->direction);
gst_pad_set_pad_template (pad, templ);
return pad;
@ -379,6 +379,7 @@ gst_pad_new_from_template (GstPadTemplate *templ, const gchar *name)
templ, name);
}
/* FIXME 0.9: GST_PAD_UNKNOWN needs to die! */
/**
* gst_pad_get_direction:
* @pad: a #GstPad to get the direction of.
@ -465,6 +466,7 @@ gst_pad_set_name (GstPad *pad, const gchar *name)
gst_object_set_name (GST_OBJECT (pad), name);
}
/* FIXME 0.9: This function must die */
/**
* gst_pad_get_name:
* @pad: a #GstPad to get the name of.
@ -477,7 +479,6 @@ gst_pad_set_name (GstPad *pad, const gchar *name)
const gchar*
gst_pad_get_name (GstPad *pad)
{
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
return GST_OBJECT_NAME (pad);
@ -485,15 +486,15 @@ gst_pad_get_name (GstPad *pad)
/**
* gst_pad_set_chain_function:
* @pad: a #GstPad to set the chain function for.
* @pad: a real sink #GstPad.
* @chain: the #GstPadChainFunction to set.
*
* Sets the given chain function for the pad.
* Sets the given chain function for the pad. The chain function is called to
* process a #GstData input buffer.
*/
void
gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
g_return_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK);
@ -504,16 +505,17 @@ gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain)
/**
* gst_pad_set_get_function:
* @pad: a #GstPad to set the get function for.
* @pad: a real source #GstPad.
* @get: the #GstPadGetFunction to set.
*
* Sets the given get function for the pad.
* Sets the given get function for the pad. The get function is called to
* produce a new #GstData to start the processing pipeline. Get functions cannot
* return %NULL.
*/
void
gst_pad_set_get_function (GstPad *pad,
GstPadGetFunction get)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
g_return_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SRC);
@ -525,7 +527,7 @@ gst_pad_set_get_function (GstPad *pad,
/**
* gst_pad_set_event_function:
* @pad: a #GstPad to set the event handler for.
* @pad: a real source #GstPad.
* @event: the #GstPadEventFunction to set.
*
* Sets the given event handler for the pad.
@ -545,7 +547,7 @@ gst_pad_set_event_function (GstPad *pad,
/**
* gst_pad_set_event_mask_function:
* @pad: a #GstPad to set the event mask function for.
* @pad: a real #GstPad of either direction.
* @mask_func: the #GstPadEventMaskFunction to set.
*
* Sets the given event mask function for the pad.
@ -564,7 +566,7 @@ gst_pad_set_event_mask_function (GstPad *pad,
/**
* gst_pad_get_event_masks:
* @pad: a #GstPad to get the event mask for.
* @pad: a #GstPad.
*
* Gets the array of eventmasks from the given pad.
*
@ -576,8 +578,7 @@ gst_pad_get_event_masks (GstPad *pad)
{
GstRealPad *rpad;
if (pad == NULL)
return FALSE;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
rpad = GST_PAD_REALIZE (pad);
@ -599,7 +600,7 @@ gst_pad_get_event_masks_dispatcher (GstPad *pad, const GstEventMask **data)
/**
* gst_pad_get_event_masks_default:
* @pad: a #GstPad to get the event mask for.
* @pad: a #GstPad.
*
* Invokes the default event masks dispatcher on the pad.
*
@ -611,6 +612,8 @@ gst_pad_get_event_masks_default (GstPad *pad)
{
GstEventMask *result = NULL;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
gst_pad_dispatcher (pad, (GstPadDispatcherFunction)
gst_pad_get_event_masks_dispatcher, &result);
@ -619,7 +622,7 @@ gst_pad_get_event_masks_default (GstPad *pad)
/**
* gst_pad_set_convert_function:
* @pad: a #GstPad to set the convert function for.
* @pad: a real #GstPad of either direction.
* @convert: the #GstPadConvertFunction to set.
*
* Sets the given convert function for the pad.
@ -628,7 +631,6 @@ void
gst_pad_set_convert_function (GstPad *pad,
GstPadConvertFunction convert)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_CONVERTFUNC (pad) = convert;
@ -639,7 +641,7 @@ gst_pad_set_convert_function (GstPad *pad,
/**
* gst_pad_set_query_function:
* @pad: the #GstPad to set the query function for.
* @pad: a real #GstPad of either direction.
* @query: the #GstPadQueryFunction to set.
*
* Set the given query function for the pad.
@ -647,7 +649,6 @@ gst_pad_set_convert_function (GstPad *pad,
void
gst_pad_set_query_function (GstPad *pad, GstPadQueryFunction query)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_QUERYFUNC (pad) = query;
@ -658,7 +659,7 @@ gst_pad_set_query_function (GstPad *pad, GstPadQueryFunction query)
/**
* gst_pad_set_query_type_function:
* @pad: the #GstPad to set the query type function for.
* @pad: a real #GstPad of either direction.
* @type_func: the #GstPadQueryTypeFunction to set.
*
* Set the given query type function for the pad.
@ -666,7 +667,6 @@ gst_pad_set_query_function (GstPad *pad, GstPadQueryFunction query)
void
gst_pad_set_query_type_function (GstPad *pad, GstPadQueryTypeFunction type_func)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_QUERYTYPEFUNC (pad) = type_func;
@ -677,7 +677,7 @@ gst_pad_set_query_type_function (GstPad *pad, GstPadQueryTypeFunction type_func)
/**
* gst_pad_get_query_types:
* @pad: the #GstPad to query
* @pad: a #GstPad.
*
* Get an array of supported queries that can be performed
* on this pad.
@ -689,12 +689,11 @@ gst_pad_get_query_types (GstPad *pad)
{
GstRealPad *rpad;
if (pad == NULL)
return FALSE;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
rpad = GST_PAD_REALIZE (pad);
g_return_val_if_fail (rpad, FALSE);
g_return_val_if_fail (rpad, NULL);
if (GST_RPAD_QUERYTYPEFUNC (rpad))
return GST_RPAD_QUERYTYPEFUNC (rpad) (GST_PAD (pad));
@ -712,7 +711,7 @@ gst_pad_get_query_types_dispatcher (GstPad *pad, const GstQueryType **data)
/**
* gst_pad_get_query_types_default:
* @pad: the #GstPad to query
* @pad: a #GstPad.
*
* Invoke the default dispatcher for the query types on
* the pad.
@ -725,6 +724,8 @@ gst_pad_get_query_types_default (GstPad *pad)
{
GstQueryType *result = NULL;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
gst_pad_dispatcher (pad, (GstPadDispatcherFunction)
gst_pad_get_query_types_dispatcher, &result);
@ -733,7 +734,7 @@ gst_pad_get_query_types_default (GstPad *pad)
/**
* gst_pad_set_internal_link_function:
* @pad: a #GstPad to set the internal link function for.
* @pad: a real #GstPad of either direction.
* @intlink: the #GstPadIntLinkFunction to set.
*
* Sets the given internal link function for the pad.
@ -742,7 +743,6 @@ void
gst_pad_set_internal_link_function (GstPad *pad,
GstPadIntLinkFunction intlink)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_INTLINKFUNC (pad) = intlink;
@ -752,7 +752,7 @@ gst_pad_set_internal_link_function (GstPad *pad,
/**
* gst_pad_set_formats_function:
* @pad: the #GstPad to set the formats function for.
* @pad: a real #GstPad of either direction.
* @formats: the #GstPadFormatsFunction to set.
*
* Sets the given formats function for the pad.
@ -760,7 +760,6 @@ gst_pad_set_internal_link_function (GstPad *pad,
void
gst_pad_set_formats_function (GstPad *pad, GstPadFormatsFunction formats)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_FORMATSFUNC (pad) = formats;
@ -770,7 +769,7 @@ gst_pad_set_formats_function (GstPad *pad, GstPadFormatsFunction formats)
/**
* gst_pad_set_link_function:
* @pad: a #GstPad to set the link function for.
* @pad: a real #GstPad.
* @link: the #GstPadLinkFunction to set.
*
* Sets the given link function for the pad. It will be called when the pad is
@ -797,9 +796,8 @@ gst_pad_set_formats_function (GstPad *pad, GstPadFormatsFunction formats)
*/
void
gst_pad_set_link_function (GstPad *pad,
GstPadLinkFunction link)
GstPadLinkFunction link)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_LINKFUNC (pad) = link;
@ -809,7 +807,7 @@ gst_pad_set_link_function (GstPad *pad,
/**
* gst_pad_set_unlink_function:
* @pad: a #GstPad to set the unlink function for.
* @pad: a real #GstPad.
* @unlink: the #GstPadUnlinkFunction to set.
*
* Sets the given unlink function for the pad. It will be called
@ -819,7 +817,6 @@ void
gst_pad_set_unlink_function (GstPad *pad,
GstPadUnlinkFunction unlink)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_UNLINKFUNC (pad) = unlink;
@ -829,7 +826,7 @@ gst_pad_set_unlink_function (GstPad *pad,
/**
* gst_pad_set_fixate_function:
* @pad: a #GstPad to set the fixate function for.
* @pad: a real #GstPad.
* @fixate: the #GstPadFixateFunction to set.
*
* Sets the given fixate function for the pad. Its job is to narrow down the
@ -845,7 +842,6 @@ gst_pad_set_unlink_function (GstPad *pad,
void
gst_pad_set_fixate_function (GstPad *pad, GstPadFixateFunction fixate)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_FIXATEFUNC (pad) = fixate;
@ -855,7 +851,7 @@ gst_pad_set_fixate_function (GstPad *pad, GstPadFixateFunction fixate)
/**
* gst_pad_set_getcaps_function:
* @pad: a #GstPad to set the getcaps function for.
* @pad: a real #GstPad.
* @getcaps: the #GstPadGetCapsFunction to set.
*
* Sets the given getcaps function for the pad. @getcaps should return the
@ -882,7 +878,6 @@ void
gst_pad_set_getcaps_function (GstPad *pad,
GstPadGetCapsFunction getcaps)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_GETCAPSFUNC (pad) = getcaps;
@ -892,7 +887,7 @@ gst_pad_set_getcaps_function (GstPad *pad,
/**
* gst_pad_set_bufferalloc_function:
* @pad: a #GstPad to set the bufferalloc function for.
* @pad: a real sink #GstPad.
* @bufalloc: the #GstPadBufferAllocFunction to set.
*
* Sets the given bufferalloc function for the pad. Note that the
@ -902,7 +897,6 @@ void
gst_pad_set_bufferalloc_function (GstPad *pad,
GstPadBufferAllocFunction bufalloc)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_REAL_PAD (pad));
g_return_if_fail (GST_PAD_IS_SINK (pad));
@ -911,6 +905,8 @@ gst_pad_set_bufferalloc_function (GstPad *pad,
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (bufalloc));
}
/* FIXME 0.9: Do we actually want to allow the case where src and sink are
switched? */
/**
* gst_pad_unlink:
* @srcpad: the source #GstPad to unlink.
@ -921,22 +917,18 @@ gst_pad_set_bufferalloc_function (GstPad *pad,
*/
void
gst_pad_unlink (GstPad *srcpad,
GstPad *sinkpad)
GstPad *sinkpad)
{
GstRealPad *realsrc, *realsink;
GstScheduler *src_sched, *sink_sched;
/* generic checks */
g_return_if_fail (srcpad != NULL);
g_return_if_fail (GST_IS_PAD (srcpad));
g_return_if_fail (sinkpad != NULL);
g_return_if_fail (GST_IS_PAD (sinkpad));
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "unlinking %s:%s(%p) and %s:%s(%p)",
GST_DEBUG_PAD_NAME (srcpad), srcpad,
GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
/* now we need to deal with the real/ghost stuff */
realsrc = GST_PAD_REALIZE (srcpad);
realsink = GST_PAD_REALIZE (sinkpad);
@ -1352,9 +1344,7 @@ gst_pad_renegotiate (GstPad *pad)
{
GstPadLink *link;
g_return_val_if_fail (pad != NULL, GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_PAD_LINK_SRC (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_PAD_LINK_SINK (pad), GST_PAD_LINK_REFUSED);
@ -1400,7 +1390,6 @@ gst_pad_try_set_caps (GstPad *pad, const GstCaps *caps)
GstPadLink *oldlink;
GstPadLinkReturn ret;
g_return_val_if_fail (pad != NULL, GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (!GST_PAD_IS_NEGOTIATING (pad), GST_PAD_LINK_REFUSED);
@ -1421,15 +1410,15 @@ gst_pad_try_set_caps (GstPad *pad, const GstCaps *caps)
return GST_PAD_LINK_OK;
}
g_return_val_if_fail (GST_PAD_LINK_SRC (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_PAD_LINK_SINK (pad), GST_PAD_LINK_REFUSED);
/* if the desired caps are already there, it's trivially ok */
if (GST_PAD_CAPS (pad) && gst_caps_is_equal_fixed (caps,
GST_PAD_CAPS (pad))) {
return GST_PAD_LINK_OK;
}
g_return_val_if_fail (GST_PAD_LINK_SRC (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_PAD_LINK_SINK (pad), GST_PAD_LINK_REFUSED);
link = gst_pad_link_new ();
link->srcpad = GST_PAD_LINK_SRC (pad);
@ -1461,7 +1450,7 @@ gst_pad_try_set_caps (GstPad *pad, const GstCaps *caps)
/**
* gst_pad_try_set_caps_nonfixed:
* @pad: a #GstPad
* @pad: a real #GstPad
* @caps: #GstCaps to set on @pad
*
* Like gst_pad_try_set_caps(), but allows non-fixed caps.
@ -1475,16 +1464,17 @@ gst_pad_try_set_caps_nonfixed (GstPad *pad, const GstCaps *caps)
GstPadLink *oldlink;
GstPadLinkReturn ret;
g_return_val_if_fail (pad != NULL, GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (!GST_FLAG_IS_SET (pad, GST_PAD_NEGOTIATING),
GST_PAD_LINK_REFUSED);
g_return_val_if_fail (!GST_PAD_IS_NEGOTIATING (pad), GST_PAD_LINK_REFUSED);
/* we allow setting caps on non-linked pads. It's ignored */
if (!GST_PAD_PEER (pad)) {
return GST_PAD_LINK_OK;
}
g_return_val_if_fail (GST_PAD_LINK_SRC (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_PAD_LINK_SINK (pad), GST_PAD_LINK_REFUSED);
/* if the link is already negotiated and the caps are compatible
* with what we're setting, it's trivially OK. */
if (GST_PAD_CAPS (pad)) {
@ -1497,9 +1487,6 @@ gst_pad_try_set_caps_nonfixed (GstPad *pad, const GstCaps *caps)
gst_caps_free (intersection);
}
g_return_val_if_fail (GST_PAD_LINK_SRC (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_PAD_LINK_SINK (pad), GST_PAD_LINK_REFUSED);
link = gst_pad_link_new ();
link->srcpad = GST_PAD_LINK_SRC (pad);
@ -1565,6 +1552,11 @@ gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad,
realsrc = GST_PAD_REALIZE (srcpad);
realsink = GST_PAD_REALIZE (sinkpad);
g_return_val_if_fail (GST_RPAD_PEER (realsrc) == NULL, NULL);
g_return_val_if_fail (GST_RPAD_PEER (realsink) == NULL, NULL);
g_return_val_if_fail (GST_PAD_PARENT (realsrc) != NULL, NULL);
g_return_val_if_fail (GST_PAD_PARENT (realsink) != NULL, NULL);
if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
GST_CAT_INFO (GST_CAT_PADS, "*actually* linking %s:%s and %s:%s",
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
@ -1665,7 +1657,7 @@ gst_pad_can_link (GstPad *srcpad, GstPad *sinkpad)
*/
gboolean
gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad,
const GstCaps *filtercaps)
const GstCaps *filtercaps)
{
GstRealPad *realsrc, *realsink;
GstScheduler *src_sched, *sink_sched;
@ -1792,6 +1784,7 @@ gst_pad_link (GstPad *srcpad, GstPad *sinkpad)
return gst_pad_link_filtered (srcpad, sinkpad, NULL);
}
/* FIXME 0.9: Remove this */
/**
* gst_pad_set_parent:
* @pad: a #GstPad to set the parent of.
@ -1803,16 +1796,14 @@ gst_pad_link (GstPad *srcpad, GstPad *sinkpad)
void
gst_pad_set_parent (GstPad *pad, GstElement *parent)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
g_return_if_fail (parent != NULL);
g_return_if_fail (GST_IS_OBJECT (parent));
g_return_if_fail ((gpointer) pad != (gpointer) parent);
g_return_if_fail (GST_IS_ELEMENT (parent));
gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (parent));
}
/* FIXME 0.9: Remove this */
/**
* gst_pad_get_parent:
* @pad: the #GstPad to get the parent of.
@ -1841,13 +1832,15 @@ gst_pad_set_pad_template (GstPad *pad, GstPadTemplate *templ)
if (templ)
g_signal_emit (G_OBJECT (templ), gst_pad_template_signals[TEMPL_PAD_CREATED], 0, pad);
}
/**
* gst_pad_get_pad_template:
* @pad: a #GstPad to get the pad template of.
* @pad: a #GstPad.
*
* Gets the pad template object of this pad.
* Gets the template for @pad.
*
* Returns: the #GstPadTemplate from which this pad was instantiated.
* Returns: the #GstPadTemplate from which this pad was instantiated, or %NULL
* if this pad has no template.
*/
GstPadTemplate*
gst_pad_get_pad_template (GstPad *pad)
@ -1867,7 +1860,8 @@ gst_pad_get_pad_template (GstPad *pad)
* is taken. For decoupled pads, the scheduler of the peer
* parent is taken.
*
* Returns: the #GstScheduler of the pad.
* Returns: the #GstScheduler of the pad, or %NULL if there is no parent or the
* parent is not yet in a managing bin.
*/
GstScheduler*
gst_pad_get_scheduler (GstPad *pad)
@ -1907,12 +1901,12 @@ gst_pad_get_scheduler (GstPad *pad)
GstElement*
gst_pad_get_real_parent (GstPad *pad)
{
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
return GST_PAD_PARENT (GST_PAD (GST_PAD_REALIZE (pad)));
}
/* FIXME 0.9: Make static. */
/**
* gst_pad_add_ghost_pad:
* @pad: a #GstPad to attach the ghost pad to.
@ -1927,9 +1921,7 @@ gst_pad_add_ghost_pad (GstPad *pad,
{
GstRealPad *realpad;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (ghostpad != NULL);
g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
/* if we're ghosting a ghost pad, drill down to find the real pad */
@ -1944,6 +1936,7 @@ gst_pad_add_ghost_pad (GstPad *pad,
gst_pad_set_pad_template (GST_PAD (ghostpad), GST_PAD_PAD_TEMPLATE (pad));
}
/* FIXME 0.9: Make static. */
/**
* gst_pad_remove_ghost_pad:
* @pad: a #GstPad to remove the ghost pad from.
@ -1978,7 +1971,6 @@ gst_pad_remove_ghost_pad (GstPad *pad,
GList*
gst_pad_get_ghost_pad_list (GstPad *pad)
{
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
return GST_PAD_REALIZE(pad)->ghostpads;
@ -2110,57 +2102,23 @@ gst_pad_unnegotiate (GstPad *pad)
*/
gboolean
gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
const GstCaps *filtercaps)
const GstCaps *filtercaps)
{
GstRealPad *realsrc, *realsink;
GstPadLink *link;
/* generic checks */
g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
GST_INFO ("trying to relink %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT
" with filtercaps %" GST_PTR_FORMAT, srcpad, sinkpad);
GST_CAT_INFO (GST_CAT_PADS, "trying to relink %s:%s and %s:%s with filtercaps %" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), filtercaps);
/* now we need to deal with the real/ghost stuff */
realsrc = GST_PAD_REALIZE (srcpad);
realsink = GST_PAD_REALIZE (sinkpad);
g_return_val_if_fail (realsrc != NULL, FALSE);
g_return_val_if_fail (realsink != NULL, FALSE);
g_return_val_if_fail (GST_RPAD_PEER (realsrc) == realsink, FALSE);
g_assert (realsrc == GST_RPAD_PEER (realsink));
if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
GST_CAT_INFO (GST_CAT_PADS, "*actually* linking %s:%s and %s:%s",
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
}
link = gst_pad_link_prepare (srcpad, sinkpad, filtercaps);
if (!link) return FALSE;
link = gst_pad_link_new ();
if (GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) {
link->srcpad = GST_PAD (realsrc);
link->sinkpad = GST_PAD (realsink);
} else {
link->srcpad = GST_PAD (realsink);
link->sinkpad = GST_PAD (realsrc);
}
if (GST_RPAD_DIRECTION (link->srcpad) != GST_PAD_SRC) {
GST_CAT_INFO (GST_CAT_PADS, "Real src pad %s:%s is not a source pad, failed",
GST_DEBUG_PAD_NAME (link->srcpad));
gst_pad_link_free (link);
return FALSE;
}
if (GST_RPAD_DIRECTION (link->sinkpad) != GST_PAD_SINK) {
GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s is not a sink pad, failed",
GST_DEBUG_PAD_NAME (link->sinkpad));
if (GST_RPAD_PEER (link->srcpad) != (GstRealPad*)link->sinkpad) {
g_warning ("Pads %s:%s and %s:%s were never linked",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
gst_pad_link_free (link);
return FALSE;
}
link->srccaps = gst_pad_get_caps (link->srcpad);
link->sinkcaps = gst_pad_get_caps (link->sinkpad);
if (filtercaps) link->filtercaps = gst_caps_copy (filtercaps);
if (GST_PAD_LINK_FAILED (gst_pad_link_try (link)))
return FALSE;
@ -2181,7 +2139,7 @@ gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
*/
gboolean
gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
const GstCaps *filtercaps)
const GstCaps *filtercaps)
{
if (gst_pad_try_relink_filtered (srcpad, sinkpad, filtercaps))
return TRUE;
@ -2210,6 +2168,8 @@ gst_pad_proxy_getcaps (GstPad *pad)
const GList *pads;
GstCaps *caps;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
GST_DEBUG ("proxying getcaps for %s:%s\n", GST_DEBUG_PAD_NAME (pad));
element = gst_pad_get_parent (pad);
@ -2241,7 +2201,7 @@ gst_pad_proxy_getcaps (GstPad *pad)
*
* Calls gst_pad_try_set_caps() for every other pad belonging to the
* same element as @pad. If gst_pad_try_set_caps() fails on any pad,
* the proxy link fails.
* the proxy link fails. May be used only during negotiation.
*
* Returns: GST_PAD_LINK_OK if sucessful
*/
@ -2252,6 +2212,9 @@ gst_pad_proxy_pad_link (GstPad *pad, const GstCaps *caps)
const GList *pads;
GstPadLinkReturn ret;
g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (caps != NULL, GST_PAD_LINK_REFUSED);
GST_DEBUG ("proxying pad link for %s:%s\n", GST_DEBUG_PAD_NAME (pad));
element = gst_pad_get_parent (pad);
@ -2290,6 +2253,9 @@ gst_pad_proxy_fixate (GstPad *pad, const GstCaps *caps)
const GList *pads;
const GstCaps *othercaps;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail (caps != NULL, NULL);
GST_DEBUG ("proxying fixate for %s:%s\n", GST_DEBUG_PAD_NAME (pad));
element = gst_pad_get_parent (pad);
@ -2550,7 +2516,6 @@ const GstCaps*
gst_pad_get_pad_template_caps (GstPad *pad)
{
static GstStaticCaps anycaps = GST_STATIC_CAPS ("ANY");
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
if (GST_PAD_PAD_TEMPLATE (pad))
@ -2558,6 +2523,7 @@ gst_pad_get_pad_template_caps (GstPad *pad)
#if 0
/* FIXME this should be enabled some day */
/* wingo: why? mail the list during 0.9 when you find this :) */
g_warning("pad %s:%s (%p) has no pad template\n",
GST_DEBUG_PAD_NAME (realpad), realpad);
#endif
@ -2565,6 +2531,8 @@ gst_pad_get_pad_template_caps (GstPad *pad)
return gst_static_caps_get(&anycaps);
}
/* FIXME 0.9: This function should probably die, or at least be renamed to
* get_caps_by_format. */
/**
* gst_pad_template_get_caps_by_name:
* @templ: a #GstPadTemplate to get the capabilities of.
@ -2591,12 +2559,14 @@ gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
return NULL;
}
/* FIXME 0.9: What good is this if it only works for already-negotiated pads? */
/**
* gst_pad_check_compatibility:
* @srcpad: the source #GstPad to check.
* @sinkpad: the sink #GstPad to check against.
*
* Checks if two pads have compatible capabilities.
* Checks if two pads have compatible capabilities. If neither one has yet been
* negotiated, returns TRUE for no good reason.
*
* Returns: TRUE if they are compatible or if the capabilities could not be
* checked, FALSE if the capabilities are not compatible.
@ -2604,9 +2574,7 @@ gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
gboolean
gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
{
g_return_val_if_fail (srcpad != NULL, FALSE);
g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
g_return_val_if_fail (sinkpad != NULL, FALSE);
g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
if (GST_PAD_CAPS (srcpad) && GST_PAD_CAPS (sinkpad)) {
@ -2631,14 +2599,13 @@ gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
* gst_pad_get_peer:
* @pad: a #GstPad to get the peer of.
*
* Gets the peer pad of @pad.
* Gets the peer of @pad.
*
* Returns: the peer #GstPad.
*/
GstPad*
gst_pad_get_peer (GstPad *pad)
{
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
return GST_PAD (GST_PAD_PEER (pad));
@ -2646,10 +2613,10 @@ gst_pad_get_peer (GstPad *pad)
/**
* gst_pad_get_allowed_caps:
* @pad: a #GstPad to get the allowed caps of.
* @pad: a real #GstPad.
*
* Gets the capabilities of the allowed media types that can
* flow through this pad. The caller must free the resulting caps.
* Gets the capabilities of the allowed media types that can flow through @pad.
* The caller must free the resulting caps.
*
* Returns: the allowed #GstCaps of the pad link. Free the caps when
* you no longer need it.
@ -2663,7 +2630,6 @@ gst_pad_get_allowed_caps (GstPad *pad)
GstCaps *icaps;
GstPadLink *link;
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_REAL_PAD (pad), NULL);
GST_CAT_DEBUG (GST_CAT_PROPERTIES, "get allowed caps of %s:%s",
@ -2717,12 +2683,14 @@ gst_pad_caps_change_notify (GstPad *pad)
gboolean
gst_pad_recover_caps_error (GstPad *pad, const GstCaps *allowed)
{
/* FIXME */
return FALSE;
}
/* FIXME 0.9: Is it so difficult to write SOURCE? */
/**
* gst_pad_alloc_buffer:
* @pad: a #GstPad to get the buffer from.
* @pad: a source #GstPad.
*
* Allocates a new, empty buffer optimized to push to pad @pad. This
* function only works if @pad is a src pad.
@ -2734,7 +2702,6 @@ gst_pad_alloc_buffer (GstPad *pad, guint64 offset, gint size)
{
GstRealPad *peer;
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
@ -2950,10 +2917,11 @@ gst_ghost_pad_save_thyself (GstPad *pad, xmlNodePtr parent)
/**
* gst_pad_push:
* @pad: a #GstPad to push the buffer out of.
* @pad: a source #GstPad.
* @data: the #GstData to push.
*
* Pushes a buffer or an event to the peer of @pad. @pad must be linked.
* Pushes a buffer or an event to the peer of @pad. @pad must be linked. May
* only be called by @pad's parent.
*/
void
gst_pad_push (GstPad *pad, GstData *data)
@ -3016,9 +2984,10 @@ gst_pad_push (GstPad *pad, GstData *data)
/**
* gst_pad_pull:
* @pad: a #GstPad to pull a buffer from.
* @pad: a sink #GstPad.
*
* Pulls an event or a buffer from the peer pad.
* Pulls an event or a buffer from the peer pad. May only be called by @pad's
* parent.
*
* Returns: a new #GstData from the peer pad.
*/
@ -3070,9 +3039,10 @@ restart:
/**
* gst_pad_selectv:
* @padlist: a #GList of pads.
* @padlist: a #GList of sink pads.
*
* Waits for a buffer on any of the list of pads.
* Waits for a buffer on any of the list of pads. Each #GstPad in @padlist must
* be owned by the calling code.
*
* Returns: the #GstPad that has a buffer available.
* Use #gst_pad_pull() to get the buffer.
@ -3087,9 +3057,10 @@ gst_pad_selectv (GList *padlist)
return pad;
}
/* FIXME 0.9: Don't allow the first pad to be NULL */
/**
* gst_pad_select:
* @pad: a first #GstPad to perform the select on.
* @pad: a first sink #GstPad to perform the select on.
* @...: A NULL-terminated list of more pads to select on.
*
* Waits for a buffer on the given set of pads.
@ -3342,7 +3313,7 @@ gst_pad_template_new (const gchar *name_template,
const GstCaps*
gst_pad_template_get_caps (GstPadTemplate *templ)
{
g_return_val_if_fail (templ != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
return GST_PAD_TEMPLATE_CAPS (templ);
}
@ -3595,13 +3566,15 @@ gst_pad_event_default_dispatch (GstPad *pad, GstElement *element,
{
GList *orig, *pads;
GST_INFO_OBJECT (pad, "Sending event %p to all internally linked pads", event);
orig = pads = gst_pad_get_internal_links (pad);
while (pads) {
GstPad *eventpad = GST_PAD (pads->data);
pads = g_list_next (pads);
/* for all pads in the opposite direction that are linked */
/* for all of the internally-linked pads that are actually linked */
if (GST_PAD_IS_LINKED (eventpad)) {
if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
/* increase the refcount */
@ -3628,7 +3601,11 @@ gst_pad_event_default_dispatch (GstPad *pad, GstElement *element,
* @pad: a #GstPad to call the default event handler on.
* @event: the #GstEvent to handle.
*
* Invokes the default event handler for the given pad.
* Invokes the default event handler for the given pad. End-of-stream and
* discontinuity events are handled specially, and then the event is sent to all
* pads internally linked to @pad. Note that if there are many possible sink
* pads that are internally linked to @pad, only one will be sent an event.
* Multi-sinkpad elements should implement custom event handlers.
*
* Returns: TRUE if the event was sent succesfully.
*/
@ -3638,7 +3615,7 @@ gst_pad_event_default (GstPad *pad, GstEvent *event)
GstElement *element;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (event, FALSE);
g_return_val_if_fail (event != NULL, FALSE);
element = GST_PAD_PARENT (pad);
@ -3695,7 +3672,7 @@ gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch,
GList *int_pads, *orig;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (data, FALSE);
g_return_val_if_fail (dispatch != NULL, FALSE);
orig = int_pads = gst_pad_get_internal_links (pad);
@ -3732,7 +3709,7 @@ gst_pad_send_event (GstPad *pad, GstEvent *event)
GstRealPad *rpad;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (event, FALSE);
g_return_val_if_fail (event != NULL, FALSE);
rpad = GST_PAD_REALIZE (pad);
@ -3790,8 +3767,8 @@ gst_pad_convert_default (GstPad *pad,
GstPadConvertData data;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (dest_format, FALSE);
g_return_val_if_fail (dest_value, FALSE);
g_return_val_if_fail (dest_format != NULL, FALSE);
g_return_val_if_fail (dest_value != NULL, FALSE);
data.src_format = src_format;
data.src_value = src_value;
@ -3822,8 +3799,8 @@ gst_pad_convert (GstPad *pad,
GstRealPad *rpad;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (dest_format, FALSE);
g_return_val_if_fail (dest_value, FALSE);
g_return_val_if_fail (dest_format != NULL, FALSE);
g_return_val_if_fail (dest_value != NULL, FALSE);
if (src_format == *dest_format) {
*dest_value = src_value;
@ -3871,8 +3848,8 @@ gst_pad_query_default (GstPad *pad, GstQueryType type,
GstPadQueryData data;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (format, FALSE);
g_return_val_if_fail (value, FALSE);
g_return_val_if_fail (format != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
data.type = type;
data.format = format;
@ -3904,8 +3881,8 @@ gst_pad_query (GstPad *pad, GstQueryType type,
GstRealPad *rpad;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (format, FALSE);
g_return_val_if_fail (value, FALSE);
g_return_val_if_fail (format != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
rpad = GST_PAD_REALIZE (pad);
@ -3938,6 +3915,8 @@ gst_pad_get_formats_default (GstPad *pad)
{
GstFormat *result = NULL;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
gst_pad_dispatcher (pad, (GstPadDispatcherFunction)
gst_pad_get_formats_dispatcher, &result);
@ -3957,7 +3936,7 @@ gst_pad_get_formats (GstPad *pad)
{
GstRealPad *rpad;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
rpad = GST_PAD_REALIZE (pad);

View file

@ -183,20 +183,81 @@ struct _GstOptSchedulerGroup {
};
/* some group operations */
/*
* A group is a set of elements through which data can flow without switching
* cothreads or without invoking the scheduler's run queue.
*/
static GstOptSchedulerGroup* ref_group (GstOptSchedulerGroup *group);
#ifndef USE_COTHREADS
/*
static GstOptSchedulerGroup* ref_group_by_count (GstOptSchedulerGroup *group, gint count);
*/
#endif
static GstOptSchedulerGroup* unref_group (GstOptSchedulerGroup *group);
static GstOptSchedulerGroup* create_group (GstOptSchedulerChain *chain,
GstElement *element,
GstOptSchedulerGroupType type);
static void destroy_group (GstOptSchedulerGroup *group);
static GstOptSchedulerGroup* add_to_group (GstOptSchedulerGroup *group,
GstElement *element);
static GstOptSchedulerGroup* remove_from_group (GstOptSchedulerGroup *group,
GstElement *element);
static GstOptSchedulerGroup* merge_groups (GstOptSchedulerGroup *group1,
GstOptSchedulerGroup *group2);
static void setup_group_scheduler (GstOptScheduler *osched,
GstOptSchedulerGroup *group);
static void destroy_group_scheduler (GstOptSchedulerGroup *group);
static void group_error_handler (GstOptSchedulerGroup *group);
static void group_element_set_enabled (GstOptSchedulerGroup *group,
GstElement *element, gboolean enabled);
GstElement *element,
gboolean enabled);
static gboolean schedule_group (GstOptSchedulerGroup *group);
/*
* A chain is a set of groups that are linked to each other.
*/
static void destroy_chain (GstOptSchedulerChain *chain);
static GstOptSchedulerChain* create_chain (GstOptScheduler *osched);
static GstOptSchedulerChain* ref_chain (GstOptSchedulerChain *chain);
static GstOptSchedulerChain* unref_chain (GstOptSchedulerChain *chain);
static GstOptSchedulerChain* add_to_chain (GstOptSchedulerChain *chain,
GstOptSchedulerGroup *group);
static GstOptSchedulerChain* remove_from_chain (GstOptSchedulerChain *chain,
GstOptSchedulerGroup *group);
static GstOptSchedulerChain* merge_chains (GstOptSchedulerChain *chain1,
GstOptSchedulerChain *chain2);
static void chain_recursively_migrate_group (GstOptSchedulerChain *chain,
GstOptSchedulerGroup *group);
static void chain_group_set_enabled (GstOptSchedulerChain *chain,
GstOptSchedulerGroup *group, gboolean enabled);
GstOptSchedulerGroup *group,
gboolean enabled);
static void schedule_chain (GstOptSchedulerChain *chain);
/*
* The schedule functions are the entry points for cothreads, or called directly
* by gst_opt_scheduler_schedule_run_queue
*/
static int get_group_schedule_function (int argc, char *argv[]);
static int loop_group_schedule_function (int argc, char *argv[]);
static int unknown_group_schedule_function (int argc, char *argv[]);
/*
* These wrappers are set on the pads as the chain handler (what happens when
* gst_pad_push is called) or get handler (for gst_pad_pull).
*/
static void gst_opt_scheduler_loop_wrapper (GstPad *sinkpad, GstData *data);
static GstData* gst_opt_scheduler_get_wrapper (GstPad *srcpad);
static void gst_opt_scheduler_chain_wrapper (GstPad *sinkpad, GstData *data);
/*
* Without cothreads, gst_pad_push or gst_pad_pull on a loop-based group will
* just queue the peer element on a list. We need to actually run the queue
* instead of relying on cothreads to do the switch for us.
*/
#ifndef USE_COTHREADS
static void gst_opt_scheduler_schedule_run_queue (GstOptScheduler *osched);
#endif
/*
* Scheduler private data for an element
*/
@ -212,13 +273,16 @@ struct _GstOptSchedulerCtx {
GstOptSchedulerCtxFlags flags; /* flags for this element */
};
/*
* Implementation of GstScheduler
*/
enum
{
ARG_0,
ARG_ITERATIONS,
ARG_MAX_RECURSION,
};
static void gst_opt_scheduler_class_init (GstOptSchedulerClass *klass);
static void gst_opt_scheduler_init (GstOptScheduler *scheduler);
@ -379,42 +443,6 @@ GST_PLUGIN_DEFINE (
);
static void
destroy_chain (GstOptSchedulerChain *chain)
{
GstOptScheduler *osched;
GST_LOG ( "destroy chain %p", chain);
g_assert (chain->num_groups == 0);
g_assert (chain->groups == NULL);
osched = chain->sched;
osched->chains = g_slist_remove (osched->chains, chain);
gst_object_unref (GST_OBJECT (osched));
g_free (chain);
}
static GstOptSchedulerChain*
create_chain (GstOptScheduler *osched)
{
GstOptSchedulerChain *chain;
chain = g_new0 (GstOptSchedulerChain, 1);
chain->sched = osched;
chain->refcount = 1;
chain->flags = GST_OPT_SCHEDULER_CHAIN_DISABLED;
gst_object_ref (GST_OBJECT (osched));
osched->chains = g_slist_prepend (osched->chains, chain);
GST_LOG ( "new chain %p", chain);
return chain;
}
static GstOptSchedulerChain*
ref_chain (GstOptSchedulerChain *chain)
{
@ -439,17 +467,63 @@ unref_chain (GstOptSchedulerChain *chain)
return chain;
}
static GstOptSchedulerChain*
create_chain (GstOptScheduler *osched)
{
GstOptSchedulerChain *chain;
chain = g_new0 (GstOptSchedulerChain, 1);
chain->sched = osched;
chain->refcount = 1;
chain->flags = GST_OPT_SCHEDULER_CHAIN_DISABLED;
gst_object_ref (GST_OBJECT (osched));
osched->chains = g_slist_prepend (osched->chains, chain);
GST_LOG ( "new chain %p", chain);
return chain;
}
static void
destroy_chain (GstOptSchedulerChain *chain)
{
GstOptScheduler *osched;
GST_LOG ( "destroy chain %p", chain);
g_assert (chain->num_groups == 0);
g_assert (chain->groups == NULL);
osched = chain->sched;
osched->chains = g_slist_remove (osched->chains, chain);
gst_object_unref (GST_OBJECT (osched));
g_free (chain);
}
static GstOptSchedulerChain*
add_to_chain (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group)
{
GST_LOG ( "adding group %p to chain %p", group, chain);
GST_LOG ("adding group %p to chain %p", group, chain);
g_assert (group->chain == NULL);
group = ref_group (group);
group->chain = ref_chain (chain);
chain->groups = g_slist_prepend (chain->groups, group);
/* The first non-disabled group in the chain's group list will be the entry
point for the chain. Because buffers can accumulate in loop elements' peer
bufpens, we preferentially schedule loop groups before get groups to avoid
unnecessary execution of get-based groups when the bufpens are already
full. */
if (group->type == GST_OPT_SCHEDULER_GROUP_LOOP)
chain->groups = g_slist_prepend (chain->groups, group);
else
chain->groups = g_slist_append (chain->groups, group);
chain->num_groups++;
if (GST_OPT_SCHEDULER_GROUP_IS_ENABLED (group)) {
@ -462,7 +536,7 @@ add_to_chain (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group)
static GstOptSchedulerChain*
remove_from_chain (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group)
{
GST_LOG ( "removing group %p from chain %p", group, chain);
GST_LOG ("removing group %p from chain %p", group, chain);
if (!chain)
return NULL;
@ -491,10 +565,17 @@ merge_chains (GstOptSchedulerChain *chain1, GstOptSchedulerChain *chain2)
GST_LOG ("merging chain %p and %p", chain1, chain2);
/* FIXME: document how chain2 can be NULL */
if (chain1 == chain2 || chain2 == NULL)
return chain1;
ref_chain (chain2);
/* switch if it's more efficient */
if (chain1->num_groups < chain2->num_groups) {
GstOptSchedulerChain *tmp = chain2;
chain2 = chain1;
chain1 = tmp;
}
walk = chain2->groups;
while (walk) {
GstOptSchedulerGroup *group = (GstOptSchedulerGroup *) walk->data;
@ -503,17 +584,15 @@ merge_chains (GstOptSchedulerChain *chain1, GstOptSchedulerChain *chain2)
GST_LOG ("reparenting group %p from chain %p to %p",
group, chain2, chain1);
group->chain = NULL;
chain2->num_groups--;
chain2 = unref_chain (chain2);
ref_group (group);
remove_from_chain (chain2, group);
add_to_chain (chain1, group);
group->chain = ref_chain (chain1);
chain1->groups = g_slist_prepend (chain1->groups, group);
chain1->num_groups++;
unref_group (group);
}
g_slist_free (chain2->groups);
chain2->groups = NULL;
unref_chain (chain2);
/* chain2 is now freed, if nothing else was referencing it before */
return chain1;
}
@ -521,8 +600,8 @@ merge_chains (GstOptSchedulerChain *chain1, GstOptSchedulerChain *chain2)
static void
chain_group_set_enabled (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group, gboolean enabled)
{
g_assert (chain != NULL);
g_assert (group != NULL);
g_assert (chain != NULL);
GST_LOG ("request to %d group %p in chain %p, have %d groups enabled out of %d",
enabled, group, chain, chain->num_enabled, chain->num_groups);
@ -539,6 +618,10 @@ chain_group_set_enabled (GstOptSchedulerChain *chain, GstOptSchedulerGroup *grou
GST_DEBUG ("enable group %p in chain %p, now %d groups enabled out of %d", group, chain,
chain->num_enabled, chain->num_groups);
/* OK to call even if the scheduler (cothread context / schedulerfunc) was
setup already -- will get destroyed when the group is destroyed */
setup_group_scheduler (chain->sched, group);
if (chain->num_enabled == chain->num_groups) {
GST_DEBUG ("enable chain %p", chain);
GST_OPT_SCHEDULER_CHAIN_ENABLE (chain);
@ -594,28 +677,13 @@ ref_group (GstOptSchedulerGroup *group)
return group;
}
#ifndef USE_COTHREADS
/* remove me
static GstOptSchedulerGroup*
ref_group_by_count (GstOptSchedulerGroup *group, gint count)
{
GST_LOG ("ref group %p %d->%d", group,
group->refcount, group->refcount+count);
group->refcount += count;
return group;
}
*/
#endif
static GstOptSchedulerGroup*
unref_group (GstOptSchedulerGroup *group)
{
GST_LOG ("unref group %p %d->%d", group,
group->refcount, group->refcount-1);
if (--group->refcount == 1) {
if (--group->refcount == 0) {
destroy_group (group);
group = NULL;
}
@ -623,6 +691,42 @@ unref_group (GstOptSchedulerGroup *group)
return group;
}
static GstOptSchedulerGroup*
create_group (GstOptSchedulerChain *chain, GstElement *element,
GstOptSchedulerGroupType type)
{
GstOptSchedulerGroup *group;
group = g_new0 (GstOptSchedulerGroup, 1);
GST_LOG ("new group %p", group);
group->refcount = 1; /* float... */
group->flags = GST_OPT_SCHEDULER_GROUP_DISABLED;
group->type = type;
add_to_group (group, element);
add_to_chain (chain, group);
group = unref_group (group); /* ...and sink. */
/* group's refcount is now 2 (one for the element, one for the chain) */
return group;
}
static void
destroy_group (GstOptSchedulerGroup *group)
{
GST_LOG ("destroy group %p", group);
g_assert (group != NULL);
g_assert (group->elements == NULL);
g_assert (group->chain == NULL);
if (group->flags & GST_OPT_SCHEDULER_GROUP_SCHEDULABLE)
destroy_group_scheduler (group);
g_free (group);
}
static GstOptSchedulerGroup*
add_to_group (GstOptSchedulerGroup *group, GstElement *element)
{
@ -639,6 +743,7 @@ add_to_group (GstOptSchedulerGroup *group, GstElement *element)
g_assert (GST_ELEMENT_SCHED_GROUP (element) == NULL);
/* Ref the group... */
GST_ELEMENT_SCHED_GROUP (element) = ref_group (group);
gst_object_ref (GST_OBJECT (element));
@ -649,28 +754,100 @@ add_to_group (GstOptSchedulerGroup *group, GstElement *element)
group_element_set_enabled (group, element, TRUE);
}
/* Ref the group... */
ref_group (group);
return group;
}
static GstOptSchedulerGroup*
create_group (GstOptSchedulerChain *chain, GstElement *element)
remove_from_group (GstOptSchedulerGroup *group, GstElement *element)
{
GstOptSchedulerGroup *group;
GST_DEBUG ("removing element \"%s\" from group %p", GST_ELEMENT_NAME (element), group);
group = g_new0 (GstOptSchedulerGroup, 1);
GST_LOG ("new group %p", group);
group->refcount = 1;
group->flags = GST_OPT_SCHEDULER_GROUP_DISABLED;
g_assert (group != NULL);
g_assert (element != NULL);
g_assert (GST_ELEMENT_SCHED_GROUP (element) == group);
group->elements = g_slist_remove (group->elements, element);
group->num_elements--;
/* if the element was an entry point in the group, clear the group's
* entry point */
if (group->entry == element) {
group->entry = NULL;
}
GST_ELEMENT_SCHED_GROUP (element) = NULL;
gst_object_unref (GST_OBJECT (element));
if (group->num_elements == 0) {
GST_LOG ("group %p is now empty", group);
/* don't know in what case group->chain would be NULL, but putting this here
in deference to 0.8 -- remove me in 0.9 */
if (group->chain) {
GST_LOG ("removing group %p from its chain", group);
chain_group_set_enabled (group->chain, group, FALSE);
remove_from_chain (group->chain, group);
}
}
group = unref_group (group);
add_to_group (group, element);
add_to_chain (chain, group);
return group;
}
/* FIXME need to check if the groups are of the same type -- otherwise need to
setup the scheduler again, if it is setup */
static GstOptSchedulerGroup*
merge_groups (GstOptSchedulerGroup *group1, GstOptSchedulerGroup *group2)
{
g_assert (group1 != NULL);
GST_DEBUG ("merging groups %p and %p", group1, group2);
if (group1 == group2 || group2 == NULL)
return group1;
while (group2 && group2->elements) {
GstElement *element = (GstElement *)group2->elements->data;
group2 = remove_from_group (group2, element);
add_to_group (group1, element);
}
return group1;
}
/* setup the scheduler context for a group. The right schedule function
* is selected based on the group type and cothreads are created if
* needed */
static void
setup_group_scheduler (GstOptScheduler *osched, GstOptSchedulerGroup *group)
{
GroupScheduleFunction wrapper;
wrapper = unknown_group_schedule_function;
/* figure out the wrapper function for this group */
if (group->type == GST_OPT_SCHEDULER_GROUP_GET)
wrapper = get_group_schedule_function;
else if (group->type == GST_OPT_SCHEDULER_GROUP_LOOP)
wrapper = loop_group_schedule_function;
#ifdef USE_COTHREADS
if (!(group->flags & GST_OPT_SCHEDULER_GROUP_SCHEDULABLE)) {
do_cothread_create (group->cothread, osched->context,
(cothread_func) wrapper, 0, (char **) group);
}
else {
do_cothread_setfunc (group->cothread, osched->context,
(cothread_func) wrapper, 0, (char **) group);
}
#else
group->schedulefunc = wrapper;
group->argc = 0;
group->argv = (char **) group;
#endif
group->flags |= GST_OPT_SCHEDULER_GROUP_SCHEDULABLE;
}
static void
destroy_group_scheduler (GstOptSchedulerGroup *group)
{
@ -693,71 +870,6 @@ destroy_group_scheduler (GstOptSchedulerGroup *group)
group->flags &= ~GST_OPT_SCHEDULER_GROUP_SCHEDULABLE;
}
static void
destroy_group (GstOptSchedulerGroup *group)
{
GST_LOG ("destroy group %p", group);
g_assert (group != NULL);
g_assert (group->elements == NULL);
remove_from_chain (group->chain, group);
if (group->flags & GST_OPT_SCHEDULER_GROUP_SCHEDULABLE)
destroy_group_scheduler (group);
g_free (group);
}
static GstOptSchedulerGroup*
remove_from_group (GstOptSchedulerGroup *group, GstElement *element)
{
GST_DEBUG ("removing element \"%s\" from group %p", GST_ELEMENT_NAME (element), group);
g_assert (group != NULL);
g_assert (element != NULL);
g_assert (GST_ELEMENT_SCHED_GROUP (element) == group);
group->elements = g_slist_remove (group->elements, element);
group->num_elements--;
/* if the element was an entry point in the group, clear the group's
* entry point */
if (group->entry == element) {
group->entry = NULL;
}
GST_ELEMENT_SCHED_GROUP (element) = NULL;
gst_object_unref (GST_OBJECT (element));
if (group->num_elements == 0) {
group = unref_group (group);
}
group = unref_group (group);
return group;
}
static GstOptSchedulerGroup*
merge_groups (GstOptSchedulerGroup *group1, GstOptSchedulerGroup *group2)
{
g_assert (group1 != NULL);
GST_DEBUG ("merging groups %p and %p", group1, group2);
if (group1 == group2 || group2 == NULL)
return group1;
while (group2 && group2->elements) {
GstElement *element = (GstElement *)group2->elements->data;
group2 = remove_from_group (group2, element);
add_to_group (group1, element);
}
return group1;
}
static void
group_error_handler (GstOptSchedulerGroup *group)
{
@ -779,6 +891,11 @@ group_element_set_enabled (GstOptSchedulerGroup *group, GstElement *element, gbo
GST_LOG ("request to %d element %s in group %p, have %d elements enabled out of %d",
enabled, GST_ELEMENT_NAME (element), group, group->num_enabled, group->num_elements);
/* Note that if an unlinked PLAYING element is added to a bin, we have to
create a new group to hold the element, and this function will be called
before the group is added to the chain. Thus we have a valid case for
group->chain==NULL. */
if (enabled) {
if (group->num_enabled < group->num_elements)
group->num_enabled++;
@ -787,8 +904,13 @@ group_element_set_enabled (GstOptSchedulerGroup *group, GstElement *element, gbo
GST_ELEMENT_NAME (element), group, group->num_enabled, group->num_elements);
if (group->num_enabled == group->num_elements) {
GST_LOG ("enable group %p", group);
chain_group_set_enabled (group->chain, group, TRUE);
if (!group->chain) {
GST_DEBUG ("enable chainless group %p", group);
GST_OPT_SCHEDULER_GROUP_ENABLE (group);
} else {
GST_LOG ("enable group %p", group);
chain_group_set_enabled (group->chain, group, TRUE);
}
}
}
else {
@ -799,8 +921,13 @@ group_element_set_enabled (GstOptSchedulerGroup *group, GstElement *element, gbo
GST_ELEMENT_NAME (element), group, group->num_enabled, group->num_elements);
if (group->num_enabled == 0) {
GST_LOG ("disable group %p", group);
chain_group_set_enabled (group->chain, group, FALSE);
if (!group->chain) {
GST_DEBUG ("disable chainless group %p", group);
GST_OPT_SCHEDULER_GROUP_DISABLE (group);
} else {
GST_LOG ("disable group %p", group);
chain_group_set_enabled (group->chain, group, FALSE);
}
}
}
}
@ -855,8 +982,11 @@ schedule_group (GstOptSchedulerGroup *group)
static void
gst_opt_scheduler_schedule_run_queue (GstOptScheduler *osched)
{
GST_LOG_OBJECT (osched, "entering scheduler run queue recursion %d %d",
osched->recursion, g_list_length (osched->runqueue));
GST_LOG_OBJECT (osched, "running queue: %d groups, recursed %d times",
g_list_length (osched->runqueue),
osched->recursion, g_list_length (osched->runqueue));
/* note that we have a ref on each group on the queue (unref after running) */
/* make sure we don't exceed max_recursion */
if (osched->recursion > osched->max_recursion) {
@ -872,7 +1002,7 @@ gst_opt_scheduler_schedule_run_queue (GstOptScheduler *osched)
group = (GstOptSchedulerGroup *) osched->runqueue->data;
/* runqueue hols refcount to group */
/* runqueue holds refcount to group */
osched->runqueue = g_list_remove (osched->runqueue, group);
GST_LOG_OBJECT (osched, "scheduling group %p", group);
@ -945,7 +1075,7 @@ get_group_schedule_function (int argc, char *argv[])
GstElement *entry = group->entry;
const GList *pads = gst_element_get_pad_list (entry);
GST_LOG ("get wrapper of group %p", group);
GST_LOG ("executing get-based group %p", group);
group->flags |= GST_OPT_SCHEDULER_GROUP_RUNNING;
@ -986,7 +1116,7 @@ loop_group_schedule_function (int argc, char *argv[])
GstOptSchedulerGroup *group = (GstOptSchedulerGroup *) argv;
GstElement *entry = group->entry;
GST_LOG ("loop wrapper of group %p", group);
GST_LOG ("executing loop-based group %p", group);
group->flags |= GST_OPT_SCHEDULER_GROUP_RUNNING;
@ -1024,26 +1154,31 @@ gst_opt_scheduler_loop_wrapper (GstPad *sinkpad, GstData *data)
{
GstOptSchedulerGroup *group;
GstOptScheduler *osched;
GST_LOG ("loop wrapper, putting buffer in bufpen");
GstRealPad *peer;
group = GST_ELEMENT_SCHED_GROUP (GST_PAD_PARENT (sinkpad));
osched = group->chain->sched;
peer = GST_RPAD_PEER (sinkpad);
GST_LOG ("chain handler for loop-based pad %" GST_PTR_FORMAT, sinkpad);
#ifdef USE_COTHREADS
if (GST_PAD_BUFLIST (GST_RPAD_PEER (sinkpad))) {
if (GST_PAD_BUFLIST (peer)) {
g_warning ("deadlock detected, disabling group %p", group);
group_error_handler (group);
}
else {
GST_PAD_BUFLIST (GST_RPAD_PEER (sinkpad)) = g_list_append (GST_PAD_BUFLIST (GST_RPAD_PEER (sinkpad)), data);
GST_LOG ("queueing data %p on %s:%s's bufpen", data,
GST_DEBUG_PAD_NAME (peer));
GST_PAD_BUFLIST (peer) = g_list_append (GST_PAD_BUFLIST (peer), data);
schedule_group (group);
}
#else
GST_PAD_BUFLIST (GST_RPAD_PEER (sinkpad)) = g_list_append (GST_PAD_BUFLIST (GST_RPAD_PEER (sinkpad)), data);
GST_LOG ("queueing data %p on %s:%s's bufpen", data,
GST_DEBUG_PAD_NAME (peer));
GST_PAD_BUFLIST (peer) = g_list_append (GST_PAD_BUFLIST (peer), data);
if (!(group->flags & GST_OPT_SCHEDULER_GROUP_RUNNING)) {
GST_LOG ("adding %p to runqueue", group);
GST_LOG ("adding group %p to runqueue", group);
if (!g_list_find (osched->runqueue, group))
{
ref_group (group);
@ -1052,8 +1187,8 @@ gst_opt_scheduler_loop_wrapper (GstPad *sinkpad, GstData *data)
}
#endif
GST_LOG ("after loop wrapper buflist %d",
g_list_length (GST_PAD_BUFLIST (GST_RPAD_PEER (sinkpad))));
GST_LOG ("%d buffers left on %s:%s's bufpen after chain handler",
g_list_length (GST_PAD_BUFLIST (peer)));
}
/* this function is called by a loop based element that performs a
@ -1067,15 +1202,14 @@ gst_opt_scheduler_get_wrapper (GstPad *srcpad)
GstOptScheduler *osched;
gboolean disabled;
GST_LOG ("get wrapper, removing buffer from bufpen");
GST_LOG ("get handler for %" GST_PTR_FORMAT, srcpad);
/* first try to grab a queued buffer */
if (GST_PAD_BUFLIST (srcpad)) {
data = GST_PAD_BUFLIST (srcpad)->data;
GST_PAD_BUFLIST (srcpad) = g_list_remove (GST_PAD_BUFLIST (srcpad), data);
GST_LOG ("get wrapper, returning queued data %d",
g_list_length (GST_PAD_BUFLIST (srcpad)));
GST_LOG ("returning popped queued data %p", data);
return data;
}
@ -1087,6 +1221,7 @@ gst_opt_scheduler_get_wrapper (GstPad *srcpad)
disabled = FALSE;
do {
GST_LOG ("scheduling upstream group %p to fill bufpen", group);
#ifdef USE_COTHREADS
schedule_group (group);
#else
@ -1099,9 +1234,9 @@ gst_opt_scheduler_get_wrapper (GstPad *srcpad)
osched->runqueue = g_list_append (osched->runqueue, group);
}
GST_LOG_OBJECT (osched, "recursing into scheduler group %p", group);
GST_LOG ("recursing into scheduler group %p", group);
gst_opt_scheduler_schedule_run_queue (osched);
GST_LOG_OBJECT (osched, "return from recurse group %p", group);
GST_LOG ("return from recurse group %p", group);
/* if the other group was disabled we might have to break out of the loop */
disabled = GST_OPT_SCHEDULER_GROUP_IS_DISABLED (group);
@ -1139,7 +1274,7 @@ gst_opt_scheduler_get_wrapper (GstPad *srcpad)
}
while (data == NULL);
GST_LOG ("get wrapper, returning data %p, queue length %d",
GST_LOG ("get handler, returning data %p, queue length %d",
data, g_list_length (GST_PAD_BUFLIST (srcpad)));
return data;
@ -1207,44 +1342,9 @@ gst_opt_scheduler_event_wrapper (GstPad *srcpad, GstEvent *event)
return GST_RPAD_EVENTFUNC (srcpad) (srcpad, event);
}
/* setup the scheduler context for a group. The right schedule function
* is selected based on the group type and cothreads are created if
* needed */
static void
setup_group_scheduler (GstOptScheduler *osched, GstOptSchedulerGroup *group)
{
GroupScheduleFunction wrapper;
wrapper = unknown_group_schedule_function;
/* figure out the wrapper function for this group */
if (group->type == GST_OPT_SCHEDULER_GROUP_GET)
wrapper = get_group_schedule_function;
else if (group->type == GST_OPT_SCHEDULER_GROUP_LOOP)
wrapper = loop_group_schedule_function;
#ifdef USE_COTHREADS
if (!(group->flags & GST_OPT_SCHEDULER_GROUP_SCHEDULABLE)) {
do_cothread_create (group->cothread, osched->context,
(cothread_func) wrapper, 0, (char **) group);
}
else {
do_cothread_setfunc (group->cothread, osched->context,
(cothread_func) wrapper, 0, (char **) group);
}
#else
group->schedulefunc = wrapper;
group->argc = 0;
group->argv = (char **) group;
#endif
group->flags |= GST_OPT_SCHEDULER_GROUP_SCHEDULABLE;
}
static GstElementStateReturn
gst_opt_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
{
GstOptScheduler *osched = GST_OPT_SCHEDULER (sched);
GstOptSchedulerGroup *group;
GstElementStateReturn res = GST_STATE_SUCCESS;
@ -1288,7 +1388,6 @@ gst_opt_scheduler_state_transition (GstScheduler *sched, GstElement *element, gi
}
/* else construct the scheduling context of this group and enable it */
else {
setup_group_scheduler (osched, group);
group_element_set_enabled (group, element, TRUE);
}
break;
@ -1340,7 +1439,8 @@ get_group (GstElement *element, GstOptSchedulerGroup **group)
* will also merge the chains.
*/
static GstOptSchedulerGroup*
group_elements (GstOptScheduler *osched, GstElement *element1, GstElement *element2)
group_elements (GstOptScheduler *osched, GstElement *element1, GstElement *element2,
GstOptSchedulerGroupType type)
{
GstOptSchedulerGroup *group1, *group2, *group = NULL;
@ -1356,7 +1456,7 @@ group_elements (GstOptScheduler *osched, GstElement *element1, GstElement *eleme
GST_ELEMENT_NAME (element1), GST_ELEMENT_NAME (element2));
chain = create_chain (osched);
group = create_group (chain, element1);
group = create_group (chain, element1, type);
add_to_group (group, element2);
}
/* the first element has a group */
@ -1548,9 +1648,8 @@ gst_opt_scheduler_add_element (GstScheduler *sched, GstElement *element)
chain = create_chain (osched);
group = create_group (chain, element);
group = create_group (chain, element, GST_OPT_SCHEDULER_GROUP_LOOP);
group->entry = element;
group->type = GST_OPT_SCHEDULER_GROUP_LOOP;
GST_LOG ("added element \"%s\" as loop based entry", GST_ELEMENT_NAME (element));
}
@ -1733,13 +1832,13 @@ gst_opt_scheduler_pad_link (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad
/* the two elements should be put into the same group,
* this also means that they are in the same chain automatically */
group = group_elements (osched, element1, element2);
group = group_elements (osched, element1, element2,
GST_OPT_SCHEDULER_GROUP_GET);
/* if there is not yet an entry in the group, select the source
* element as the entry point */
if (!group->entry) {
group->entry = element1;
group->type = GST_OPT_SCHEDULER_GROUP_GET;
GST_DEBUG ("setting \"%s\" as entry point of _get-based group %p",
GST_ELEMENT_NAME (element1), group);
@ -1759,7 +1858,7 @@ gst_opt_scheduler_pad_link (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad
* this also means that they are in the same chain automatically,
* in case of a loop-based element1, there will be a group for element1 and
* element2 will be added to it. */
group_elements (osched, element1, element2);
group_elements (osched, element1, element2, GST_OPT_SCHEDULER_GROUP_LOOP);
break;
case GST_OPT_GET_TO_LOOP:
GST_LOG ("get to loop based link");
@ -1770,7 +1869,7 @@ gst_opt_scheduler_pad_link (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad
* this also means that they are in the same chain automatically,
* element2 is loop-based so it already has a group where element1
* will be added to */
group_elements (osched, element1, element2);
group_elements (osched, element1, element2, GST_OPT_SCHEDULER_GROUP_LOOP);
break;
case GST_OPT_CHAIN_TO_LOOP:
case GST_OPT_LOOP_TO_LOOP:
@ -1796,7 +1895,8 @@ gst_opt_scheduler_pad_link (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad
/* create a new group for element1 as it cannot be merged into another group
* here. we create the group in the same chain as the loop-based element. */
GST_DEBUG ("creating new group for element %s", GST_ELEMENT_NAME (element1));
group1 = create_group (group2->chain, element1);
group1 = create_group (group2->chain, element1,
GST_OPT_SCHEDULER_GROUP_LOOP);
}
else {
/* both elements are already in a group, make sure they are added to
@ -2052,7 +2152,7 @@ gst_opt_scheduler_iterate (GstScheduler *sched)
osched->state = GST_OPT_SCHEDULER_STATE_RUNNING;
GST_DEBUG ("iterating scheduler %p", sched);
GST_DEBUG_OBJECT (sched, "iterating");
while (iterations) {
gboolean scheduled = FALSE;
@ -2066,6 +2166,7 @@ gst_opt_scheduler_iterate (GstScheduler *sched)
ref_chain (chain);
/* if the chain is not disabled, schedule it */
if (!GST_OPT_SCHEDULER_CHAIN_IS_DISABLED (chain)) {
GST_LOG ("scheduling chain %p", chain);
schedule_chain (chain);
scheduled = TRUE;
}
@ -2080,8 +2181,6 @@ gst_opt_scheduler_iterate (GstScheduler *sched)
osched->state = GST_OPT_SCHEDULER_STATE_RUNNING;
}
GST_LOG_OBJECT (sched, "iterate scheduled %p", chain);
chains = g_slist_next (chains);
unref_chain (chain);
}