diff -r 9b2c3c7a1a9c -r 567bb019e3e3 gstreamer_core/gst/gstelement.c --- a/gstreamer_core/gst/gstelement.c Wed Mar 31 22:03:18 2010 +0300 +++ b/gstreamer_core/gst/gstelement.c Tue Aug 31 15:30:33 2010 +0300 @@ -73,7 +73,7 @@ * toplevel #GstPipeline so the clock functions are only to be used in very * specific situations. * - * Last reviewed on 2006-03-12 (0.10.5) + * Last reviewed on 2009-05-29 (0.10.24) */ #include "gst_private.h" @@ -89,6 +89,7 @@ #include "gstevent.h" #include "gstutils.h" #include "gstinfo.h" +#include "gstvalue.h" #include "gst-i18n-lib.h" #ifdef __SYMBIAN32__ @@ -111,8 +112,9 @@ /* FILL ME */ }; -extern void __gst_element_details_clear (GstElementDetails * dp); -extern void __gst_element_details_copy (GstElementDetails * dest, +IMPORT_C extern void __gst_element_details_clear (GstElementDetails * dp); + +IMPORT_C extern void __gst_element_details_copy (GstElementDetails * dest, const GstElementDetails * src); static void gst_element_class_init (GstElementClass * klass); @@ -148,6 +150,9 @@ static GstObjectClass *parent_class = NULL; static guint gst_element_signals[LAST_SIGNAL] = { 0 }; + +/* this is used in gstelementfactory.c:gst_element_register() */ +GQuark _gst_elementclass_factory = 0; #ifdef __SYMBIAN32__ EXPORT_C #endif @@ -156,9 +161,10 @@ GType gst_element_get_type (void) { - static GType gst_element_type = 0; - - if (G_UNLIKELY (gst_element_type == 0)) { + static volatile gsize gst_element_type = 0; + + if (g_once_init_enter (&gst_element_type)) { + GType _type; static const GTypeInfo element_info = { sizeof (GstElementClass), gst_element_base_class_init, @@ -172,8 +178,12 @@ NULL }; - gst_element_type = g_type_register_static (GST_TYPE_OBJECT, "GstElement", + _type = g_type_register_static (GST_TYPE_OBJECT, "GstElement", &element_info, G_TYPE_FLAG_ABSTRACT); + + _gst_elementclass_factory = + g_quark_from_static_string ("GST_ELEMENTCLASS_FACTORY"); + g_once_init_leave (&gst_element_type, _type); } return gst_element_type; } @@ -258,6 +268,13 @@ */ memset (&element_class->details, 0, sizeof (GstElementDetails)); element_class->padtemplates = NULL; + + /* set the factory, see gst_element_register() */ + element_class->elementfactory = + g_type_get_qdata (G_TYPE_FROM_CLASS (element_class), + _gst_elementclass_factory); + GST_DEBUG ("type %s : factory %p", G_OBJECT_CLASS_NAME (element_class), + element_class->elementfactory); } static void @@ -323,6 +340,10 @@ * Makes the element free the previously requested pad as obtained * with gst_element_get_request_pad(). * + * This does not unref the pad. If the pad was created by using + * gst_element_get_request_pad(), gst_element_release_request_pad() needs to be + * followed by gst_object_unref() to free the @pad. + * * MT safe. */ #ifdef __SYMBIAN32__ @@ -548,7 +569,7 @@ * Returns the base time of the element. The base time is the * absolute time of the clock when this element was last put to * PLAYING. Subtracting the base time from the clock time gives - * the stream time of the element. + * the running time of the element. * * Returns: the base time of the element. * @@ -572,7 +593,81 @@ return result; } -#ifndef GST_DISABLE_INDEX +/** + * gst_element_set_start_time: + * @element: a #GstElement. + * @time: the base time to set. + * + * Set the start time of an element. The start time of the element is the + * running time of the element when it last went to the PAUSED state. In READY + * or after a flushing seek, it is set to 0. + * + * Toplevel elements like #GstPipeline will manage the start_time and + * base_time on its children. Setting the start_time to #GST_CLOCK_TIME_NONE + * on such a toplevel element will disable the distribution of the base_time to + * the children and can be useful if the application manages the base_time + * itself, for example if you want to synchronize capture from multiple + * pipelines, and you can also ensure that the pipelines have the same clock. + * + * MT safe. + * + * Since: 0.10.24 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +void +gst_element_set_start_time (GstElement * element, GstClockTime time) +{ + GstClockTime old; + + g_return_if_fail (GST_IS_ELEMENT (element)); + + GST_OBJECT_LOCK (element); + old = GST_ELEMENT_START_TIME (element); + GST_ELEMENT_START_TIME (element) = time; + GST_OBJECT_UNLOCK (element); + + GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, + "set start_time=%" GST_TIME_FORMAT ", old %" GST_TIME_FORMAT, + GST_TIME_ARGS (time), GST_TIME_ARGS (old)); +} + +/** + * gst_element_get_start_time: + * @element: a #GstElement. + * + * Returns the start time of the element. The start time is the + * running time of the clock when this element was last put to PAUSED. + * + * Usually the start_time is managed by a toplevel element such as + * #GstPipeline. + * + * MT safe. + * + * Returns: the start time of the element. + * + * Since: 0.10.24 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +GstClockTime +gst_element_get_start_time (GstElement * element) +{ + GstClockTime result; + + g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE); + + GST_OBJECT_LOCK (element); + result = GST_ELEMENT_START_TIME (element); + GST_OBJECT_UNLOCK (element); + + return result; +} + /** * gst_element_is_indexable: * @element: a #GstElement. @@ -657,7 +752,6 @@ return result; } -#endif /** * gst_element_add_pad: @@ -1083,17 +1177,18 @@ * Retrieves a pad from @element by name. Tries gst_element_get_static_pad() * first, then gst_element_get_request_pad(). * - * Usage of this function is not recommended as it is unclear if the reference + * Deprecated: This function is deprecated as it's unclear if the reference * to the result pad should be released with gst_object_unref() in case of a static pad - * or gst_element_release_request_pad() in case of a request pad. + * or gst_element_release_request_pad() in case of a request pad. + * Use gst_element_get_static_pad() or gst_element_get_request_pad() instead. * * Returns: the #GstPad if found, otherwise %NULL. Unref or Release after usage, * depending on the type of the pad. */ +#ifndef GST_REMOVE_DEPRECATED #ifdef __SYMBIAN32__ EXPORT_C #endif - GstPad * gst_element_get_pad (GstElement * element, const gchar * name) { @@ -1108,6 +1203,7 @@ return pad; } +#endif /* GST_REMOVE_DEPRECATED */ static GstIteratorItem iterate_pad (GstIterator * it, GstPad * pad) @@ -1793,7 +1889,7 @@ GstMessage *message = NULL; /* checks */ - GST_DEBUG_OBJECT (element, "start"); + GST_CAT_DEBUG_OBJECT (GST_CAT_MESSAGE, element, "start"); g_return_if_fail (GST_IS_ELEMENT (element)); g_return_if_fail ((type == GST_MESSAGE_ERROR) || (type == GST_MESSAGE_WARNING) || (type == GST_MESSAGE_INFO)); @@ -1932,7 +2028,7 @@ was_ok: { - GST_CAT_DEBUG (GST_CAT_STATES, "elements %s was in locked state %d", + GST_CAT_DEBUG (GST_CAT_STATES, "elements %s was already in locked state %d", GST_ELEMENT_NAME (element), old); GST_OBJECT_UNLOCK (element); @@ -2004,6 +2100,7 @@ GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "syncing state failed (%s)", gst_element_state_change_return_get_name (ret)); + gst_object_unref (parent); return FALSE; } } @@ -2054,7 +2151,7 @@ } else { timeval = NULL; } - /* get cookie to dected state change during waiting */ + /* get cookie to detect state changes during waiting */ cookie = element->state_cookie; GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, @@ -2292,10 +2389,10 @@ GST_OBJECT_UNLOCK (element); GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, - "committing state from %s to %s, pending %s", + "committing state from %s to %s, pending %s, next %s", gst_element_state_get_name (old_state), gst_element_state_get_name (old_next), - gst_element_state_get_name (pending)); + gst_element_state_get_name (pending), gst_element_state_get_name (next)); message = gst_message_new_state_changed (GST_OBJECT_CAST (element), old_state, old_next, pending); @@ -2349,15 +2446,16 @@ } /** - * gst_element_lost_state: + * gst_element_lost_state_full: * @element: a #GstElement the state is lost of + * @new_base_time: if a new base time should be distributed * * Brings the element to the lost state. The current state of the * element is copied to the pending state so that any call to * gst_element_get_state() will return %GST_STATE_CHANGE_ASYNC. * - * An ASYNC_START message is posted with an indication to distribute a new - * base_time to the element. + * An ASYNC_START message is posted with indication to distribute a new + * base_time to the element when @new_base_time is %TRUE. * If the element was PLAYING, it will go to PAUSED. The element * will be restored to its PLAYING state by the parent pipeline when it * prerolls again. @@ -2372,13 +2470,15 @@ * plugins or applications. * * MT safe. + * + * Since: 0.10.24 */ #ifdef __SYMBIAN32__ EXPORT_C #endif void -gst_element_lost_state (GstElement * element) +gst_element_lost_state_full (GstElement * element, gboolean new_base_time) { GstState old_state, new_state; GstMessage *message; @@ -2386,10 +2486,12 @@ g_return_if_fail (GST_IS_ELEMENT (element)); GST_OBJECT_LOCK (element); - if (GST_STATE_PENDING (element) != GST_STATE_VOID_PENDING || - GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE) + if (GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE) goto nothing_lost; + if (GST_STATE_PENDING (element) != GST_STATE_VOID_PENDING) + goto only_async_start; + old_state = GST_STATE (element); /* when we were PLAYING, the new state is PAUSED. We will also not @@ -2408,13 +2510,16 @@ GST_STATE_NEXT (element) = new_state; GST_STATE_PENDING (element) = new_state; GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC; + if (new_base_time) + GST_ELEMENT_START_TIME (element) = 0; GST_OBJECT_UNLOCK (element); message = gst_message_new_state_changed (GST_OBJECT_CAST (element), new_state, new_state, new_state); gst_element_post_message (element, message); - message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE); + message = + gst_message_new_async_start (GST_OBJECT_CAST (element), new_base_time); gst_element_post_message (element, message); return; @@ -2424,6 +2529,36 @@ GST_OBJECT_UNLOCK (element); return; } +only_async_start: + { + GST_OBJECT_UNLOCK (element); + + message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE); + gst_element_post_message (element, message); + return; + } +} + +/** + * gst_element_lost_state: + * @element: a #GstElement the state is lost of + * + * Brings the element to the lost state. This function calls + * gst_element_lost_state_full() with the new_base_time set to %TRUE. + * + * This function is used internally and should normally not be called from + * plugins or applications. + * + * MT safe. + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +void +gst_element_lost_state (GstElement * element) +{ + gst_element_lost_state_full (element, TRUE); } /** @@ -2441,6 +2576,9 @@ * An application can use gst_element_get_state() to wait for the completion * of the state change or it can wait for a state change message on the bus. * + * State changes to %GST_STATE_READY or %GST_STATE_NULL never return + * #GST_STATE_CHANGE_ASYNC. + * * Returns: Result of the state change using #GstStateChangeReturn. * * MT safe. @@ -2504,6 +2642,8 @@ /* this is the (new) state we should go to. TARGET is the last state we set on * the element. */ if (state != GST_STATE_TARGET (element)) { + GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, + "setting target state to %s", gst_element_state_get_name (state)); GST_STATE_TARGET (element) = state; /* increment state cookie so that we can track each state change. We only do * this if this is actually a new state change. */ @@ -2600,15 +2740,9 @@ { GstElementClass *oclass; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstState current; - GstState next; oclass = GST_ELEMENT_GET_CLASS (element); - /* start with the current state. */ - current = (GstState) GST_STATE_TRANSITION_CURRENT (transition); - next = GST_STATE_TRANSITION_NEXT (transition); - /* call the state change function so it can set the state */ if (oclass->change_state) ret = (oclass->change_state) (element, transition); @@ -2797,17 +2931,20 @@ /* ERRORS */ src_failed: { - GST_DEBUG_OBJECT (element, "source pads_activate failed"); + GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, + "source pads_activate failed"); return FALSE; } sink_failed: { - GST_DEBUG_OBJECT (element, "sink pads_activate failed"); + GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, + "sink pads_activate failed"); return FALSE; } caps_failed: { - GST_DEBUG_OBJECT (element, "failed to clear caps on pads"); + GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element, + "failed to clear caps on pads"); return FALSE; } } @@ -2818,6 +2955,7 @@ { GstState state, next; GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS; + GstClock **clock_p; g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE); @@ -2854,6 +2992,12 @@ } else { gst_element_set_base_time (element, 0); } + + /* In null state release the reference to the clock */ + GST_OBJECT_LOCK (element); + clock_p = &element->clock; + gst_object_replace ((GstObject **) clock_p, NULL); + GST_OBJECT_UNLOCK (element); break; default: /* this will catch real but unhandled state changes; @@ -3031,7 +3175,13 @@ else if (G_IS_PARAM_SPEC_INT64 (spec)) contents = g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (&value)); - else + else if (GST_VALUE_HOLDS_STRUCTURE (&value)) { + if (g_value_get_boxed (&value) != NULL) { + contents = g_strdup_value_contents (&value); + } else { + contents = g_strdup ("NULL"); + } + } else contents = g_strdup_value_contents (&value); xmlNewChild (param, NULL, (xmlChar *) "value", (xmlChar *) contents); @@ -3043,7 +3193,7 @@ g_free (specs); - pads = GST_ELEMENT_PADS (element); + pads = g_list_last (GST_ELEMENT_PADS (element)); while (pads) { GstPad *pad = GST_PAD_CAST (pads->data); @@ -3054,7 +3204,7 @@ gst_object_save_thyself (GST_OBJECT_CAST (pad), padtag); } - pads = g_list_next (pads); + pads = g_list_previous (pads); } return parent;