diff --git a/ChangeLog b/ChangeLog index d16ffbb626..89295fc902 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,100 @@ +2004-02-24 Andy Wingo + + * 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 * gst/gstbin.c: (gst_bin_add): diff --git a/docs/pwg/building-boiler.xml b/docs/pwg/building-boiler.xml index a3fe558db0..21509a7f86 100644 --- a/docs/pwg/building-boiler.xml +++ b/docs/pwg/building-boiler.xml @@ -116,7 +116,7 @@ U gst-template/gst-app/src/Makefile.am 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 diff --git a/docs/random/wingo/without-factories b/docs/random/wingo/without-factories new file mode 100644 index 0000000000..07e38857e3 --- /dev/null +++ b/docs/random/wingo/without-factories @@ -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); diff --git a/gst/gstclock.h b/gst/gstclock.h index 09331f1fff..f4e76bce7d 100644 --- a/gst/gstclock.h +++ b/gst/gstclock.h @@ -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 diff --git a/gst/gstelement.c b/gst/gstelement.c index 5999cb89f2..8383ac253c 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -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); diff --git a/gst/gstelement.h b/gst/gstelement.h index 62dd9ef1f6..1f08184358 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -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); diff --git a/gst/gstpad.c b/gst/gstpad.c index 5b113c7321..a624951fe4 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -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); diff --git a/gst/schedulers/gstoptimalscheduler.c b/gst/schedulers/gstoptimalscheduler.c index 187d3cce85..007613917b 100644 --- a/gst/schedulers/gstoptimalscheduler.c +++ b/gst/schedulers/gstoptimalscheduler.c @@ -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); }