X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstelement.c;h=64aa39a04fd1db11d99c795e5e1e8d83e2e29869;hb=ce43de86902c4e9c8ed4e9682602664cb9bce2ee;hp=dd1f9dcab0758922ae8985970d96b9ae8d8084b6;hpb=38c74e41c7a1957e6fcb19b105a58d8c0196025c;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstelement.c b/gst/gstelement.c index dd1f9dc..64aa39a 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -22,6 +22,7 @@ /** * SECTION:gstelement + * @title: GstElement * @short_description: Abstract base class for all pipeline elements * @see_also: #GstElementFactory, #GstPad * @@ -187,10 +188,24 @@ gst_element_get_type (void) } static void +gst_element_setup_thread_pool (void) +{ + GError *err = NULL; + + GST_DEBUG ("creating element thread pool"); + gst_element_pool = + g_thread_pool_new ((GFunc) gst_element_call_async_func, NULL, -1, FALSE, + &err); + if (err != NULL) { + g_critical ("could not alloc threadpool %s", err->message); + g_clear_error (&err); + } +} + +static void gst_element_class_init (GstElementClass * klass) { GObjectClass *gobject_class; - GError *err = NULL; gobject_class = (GObjectClass *) klass; @@ -252,14 +267,7 @@ gst_element_class_init (GstElementClass * klass) klass->elementfactory = NULL; - GST_DEBUG ("creating element thread pool"); - gst_element_pool = - g_thread_pool_new ((GFunc) gst_element_call_async_func, NULL, -1, FALSE, - &err); - if (err != NULL) { - g_critical ("could not alloc threadpool %s", err->message); - g_clear_error (&err); - } + gst_element_setup_thread_pool (); } static void @@ -338,6 +346,7 @@ gst_element_release_request_pad (GstElement * element, GstPad * pad) g_return_if_fail (GST_PAD_PAD_TEMPLATE (pad) == NULL || GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad)) == GST_PAD_REQUEST); + g_return_if_fail (GST_PAD_PARENT (pad) == element); oclass = GST_ELEMENT_GET_CLASS (element); @@ -354,8 +363,8 @@ gst_element_release_request_pad (GstElement * element, GstPad * pad) * @element: a #GstElement to query * * Get the clock provided by the given element. - * An element is only required to provide a clock in the PAUSED - * state. Some elements can provide a clock in other states. + * > An element is only required to provide a clock in the PAUSED + * > state. Some elements can provide a clock in other states. * * Returns: (transfer full) (nullable): the GstClock provided by the * element or %NULL if no clock could be provided. Unref after usage. @@ -394,7 +403,7 @@ gst_element_set_clock_func (GstElement * element, GstClock * clock) /** * gst_element_set_clock: * @element: a #GstElement to set the clock for. - * @clock: the #GstClock to set for the element. + * @clock: (transfer none) (allow-none): the #GstClock to set for the element. * * Sets the clock for the element. This function increases the * refcount on the clock. Any previously set clock on the object @@ -435,7 +444,7 @@ gst_element_set_clock (GstElement * element, GstClock * clock) * Elements in a pipeline will only have their clock set when the * pipeline is in the PLAYING state. * - * Returns: (transfer full): the #GstClock of the element. unref after usage. + * Returns: (transfer full) (nullable): the #GstClock of the element. unref after usage. * * MT safe. */ @@ -626,14 +635,13 @@ gst_element_get_index (GstElement * element) /** * gst_element_add_pad: * @element: a #GstElement to add the pad to. - * @pad: (transfer full): the #GstPad to add to the element. + * @pad: (transfer floating): the #GstPad to add to the element. * * Adds a pad (link point) to @element. @pad's parent will be set to @element; * see gst_object_set_parent() for refcounting information. * - * Pads are not automatically activated so elements should perform the needed - * steps to activate the pad in case this pad is added in the PAUSED or PLAYING - * state. See gst_pad_set_active() for more information about activating pads. + * Pads are automatically activated when added in the PAUSED or PLAYING + * state. * * The pad and the element should be unlocked when calling this function. * @@ -676,9 +684,6 @@ gst_element_add_pad (GstElement * element, GstPad * pad) /* check for active pads */ if (!active && (GST_STATE (element) > GST_STATE_READY || GST_STATE_NEXT (element) == GST_STATE_PAUSED)) { - g_warning ("adding inactive pad '%s' to running element '%s', you need to " - "use gst_pad_set_active(pad,TRUE) before adding it.", - GST_STR_NULL (pad_name), GST_ELEMENT_NAME (element)); gst_pad_set_active (pad, TRUE); } @@ -714,6 +719,8 @@ name_exists: pad_name, GST_ELEMENT_NAME (element)); GST_OBJECT_UNLOCK (element); g_free (pad_name); + gst_object_ref_sink (pad); + gst_object_unref (pad); return FALSE; } had_parent: @@ -740,7 +747,7 @@ no_direction: /** * gst_element_remove_pad: * @element: a #GstElement to remove pad from. - * @pad: (transfer full): the #GstPad to remove from the element. + * @pad: (transfer none): the #GstPad to remove from the element. * * Removes @pad from @element. @pad will be destroyed if it has not been * referenced elsewhere using gst_object_unparent(). @@ -913,52 +920,138 @@ gst_element_get_static_pad (GstElement * element, const gchar * name) return result; } -static GstPad * -_gst_element_request_pad (GstElement * element, GstPadTemplate * templ, - const gchar * name, const GstCaps * caps) +static gboolean +gst_element_is_valid_request_template_name (const gchar * templ_name, + const gchar * name) { - GstPad *newpad = NULL; - GstElementClass *oclass; + gchar *endptr; + const gchar *templ_name_ptr, *name_ptr; + gboolean next_specifier; + guint templ_postfix_len = 0, name_postfix_len = 0; - oclass = GST_ELEMENT_GET_CLASS (element); + g_return_val_if_fail (templ_name != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); -#ifndef G_DISABLE_CHECKS - /* Some sanity checking here */ - if (name) { - GstPad *pad; + /* Is this the template name? */ + if (strcmp (templ_name, name) == 0) + return TRUE; - /* Is this the template name? */ - if (strstr (name, "%") || !strchr (templ->name_template, '%')) { - g_return_val_if_fail (strcmp (name, templ->name_template) == 0, NULL); - } else { - const gchar *str, *data; - gchar *endptr; + /* otherwise check all the specifiers */ + do { + /* Because of sanity checks in gst_pad_template_new(), we know that %s + * and %d and %u, occurring at the template_name */ + templ_name_ptr = strchr (templ_name, '%'); - /* Otherwise check if it's a valid name for the name template */ - str = strchr (templ->name_template, '%'); - g_return_val_if_fail (str != NULL, NULL); - g_return_val_if_fail (strncmp (templ->name_template, name, - str - templ->name_template) == 0, NULL); - g_return_val_if_fail (strlen (name) > str - templ->name_template, NULL); + /* check characters ahead of the specifier */ + if (!templ_name_ptr || strlen (name) <= templ_name_ptr - templ_name + || strncmp (templ_name, name, templ_name_ptr - templ_name) != 0) { + return FALSE; + } - data = name + (str - templ->name_template); + /* %s is not allowed for multiple specifiers, just a single specifier can be + * accepted in gst_pad_template_new() and can not be mixed with other + * specifier '%u' and '%d' */ + if (*(templ_name_ptr + 1) == 's' && g_strcmp0 (templ_name, name) == 0) { + return TRUE; + } + + name_ptr = name + (templ_name_ptr - templ_name); + + /* search next specifier, each of specifier should be separated by '_' */ + templ_name = strchr (templ_name_ptr, '_'); + name = strchr (name_ptr, '_'); + + /* don't match the number of specifiers */ + if ((templ_name && !name) || (!templ_name && name)) + return FALSE; - /* Can either be %s or %d or %u, do sanity checking for %d */ - if (*(str + 1) == 'd') { + if (templ_name && name) + next_specifier = TRUE; + else + next_specifier = FALSE; + + /* check characters followed by the specifier */ + if (*(templ_name_ptr + 2) != '\0' && *(templ_name_ptr + 2) != '_') { + if (next_specifier) { + templ_postfix_len = templ_name - (templ_name_ptr + 2); + name_postfix_len = name - name_ptr; + } else { + templ_postfix_len = strlen (templ_name_ptr + 2); + name_postfix_len = strlen (name_ptr); + } + + if (strncmp (templ_name_ptr + 2, + name_ptr + name_postfix_len - templ_postfix_len, + templ_postfix_len) != 0) { + return FALSE; + } + } + + /* verify the specifier */ + if (*(name_ptr) == '%') { + guint len; + + len = (next_specifier) ? name - name_ptr : strlen (name_ptr); + + if (strncmp (name_ptr, templ_name_ptr, len) != 0) + return FALSE; + + } else { + const gchar *specifier; + gchar *target = NULL; + + /* extract specifier when it has postfix characters */ + if (name_postfix_len > templ_postfix_len) { + target = g_strndup (name_ptr, name_postfix_len - templ_postfix_len); + } + specifier = target ? target : name_ptr; + + if (*(templ_name_ptr + 1) == 'd') { gint64 tmp; /* it's an int */ - tmp = g_ascii_strtoll (data, &endptr, 10); - g_return_val_if_fail (tmp >= G_MININT && tmp <= G_MAXINT - && *endptr == '\0', NULL); - } else if (*(str + 1) == 'u') { + tmp = g_ascii_strtoll (specifier, &endptr, 10); + if (tmp < G_MININT || tmp > G_MAXINT || (*endptr != '\0' + && *endptr != '_')) + return FALSE; + } else if (*(templ_name_ptr + 1) == 'u') { guint64 tmp; /* it's an int */ - tmp = g_ascii_strtoull (data, &endptr, 10); - g_return_val_if_fail (tmp <= G_MAXUINT && *endptr == '\0', NULL); + tmp = g_ascii_strtoull (specifier, &endptr, 10); + if (tmp > G_MAXUINT || (*endptr != '\0' && *endptr != '_')) + return FALSE; } + + g_free (target); + } + + /* otherwise we increment these from NULL to 1 */ + if (next_specifier) { + templ_name++; + name++; } + } while (next_specifier); + + return TRUE; +} + +static GstPad * +_gst_element_request_pad (GstElement * element, GstPadTemplate * templ, + const gchar * name, const GstCaps * caps) +{ + GstPad *newpad = NULL; + GstElementClass *oclass; + + oclass = GST_ELEMENT_GET_CLASS (element); + +#ifndef G_DISABLE_CHECKS + /* Some sanity checking here */ + if (name) { + GstPad *pad; + + g_return_val_if_fail (gst_element_is_valid_request_template_name + (templ->name_template, name), NULL); pad = gst_element_get_static_pad (element, name); if (pad) { @@ -1004,8 +1097,6 @@ gst_element_get_request_pad (GstElement * element, const gchar * name) const gchar *req_name = NULL; gboolean templ_found = FALSE; GList *list; - const gchar *data; - gchar *str, *endptr = NULL; GstElementClass *class; g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); @@ -1013,13 +1104,10 @@ gst_element_get_request_pad (GstElement * element, const gchar * name) class = GST_ELEMENT_GET_CLASS (element); - /* if the name contains a %, we assume it's the complete template name. Get - * the template and try to get a pad */ - if (strstr (name, "%")) { - templ = gst_element_class_get_request_pad_template (class, name); - req_name = NULL; - if (templ) - templ_found = TRUE; + templ = gst_element_class_get_request_pad_template (class, name); + if (templ) { + req_name = strstr (name, "%") ? NULL : name; + templ_found = TRUE; } else { /* there is no % in the name, try to find a matching template */ list = class->padtemplates; @@ -1028,48 +1116,12 @@ gst_element_get_request_pad (GstElement * element, const gchar * name) if (templ->presence == GST_PAD_REQUEST) { GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template); - /* see if we find an exact match */ - if (strcmp (name, templ->name_template) == 0) { + if (gst_element_is_valid_request_template_name (templ->name_template, + name)) { templ_found = TRUE; req_name = name; break; } - /* Because of sanity checks in gst_pad_template_new(), we know that %s - and %d and %u, occurring at the end of the name_template, are the only - possibilities. */ - else if ((str = strchr (templ->name_template, '%')) - && strncmp (templ->name_template, name, - str - templ->name_template) == 0 - && strlen (name) > str - templ->name_template) { - data = name + (str - templ->name_template); - if (*(str + 1) == 'd') { - glong tmp; - - /* it's an int */ - tmp = strtol (data, &endptr, 10); - if (tmp != G_MINLONG && tmp != G_MAXLONG && endptr && - *endptr == '\0') { - templ_found = TRUE; - req_name = name; - break; - } - } else if (*(str + 1) == 'u') { - gulong tmp; - - /* it's an int */ - tmp = strtoul (data, &endptr, 10); - if (tmp != G_MAXULONG && endptr && *endptr == '\0') { - templ_found = TRUE; - req_name = name; - break; - } - } else { - /* it's a string */ - templ_found = TRUE; - req_name = name; - break; - } - } } list = list->next; } @@ -1191,15 +1243,133 @@ gst_element_iterate_sink_pads (GstElement * element) return gst_element_iterate_pad_list (element, &element->sinkpads); } +static gboolean +gst_element_do_foreach_pad (GstElement * element, + GstElementForeachPadFunc func, gpointer user_data, + GList ** p_pads, guint16 * p_npads) +{ + gboolean ret = TRUE; + GstPad **pads; + guint n_pads, i; + GList *l; + + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + g_return_val_if_fail (func != NULL, FALSE); + + GST_OBJECT_LOCK (element); + n_pads = *p_npads; + pads = g_newa (GstPad *, n_pads + 1); + for (l = *p_pads, i = 0; l != NULL; l = l->next) { + g_assert (i < n_pads); + pads[i++] = gst_object_ref (l->data); + } + GST_OBJECT_UNLOCK (element); + + if (n_pads == 0) + return FALSE; + + for (i = 0; i < n_pads; ++i) { + ret = func (element, pads[i], user_data); + if (!ret) + break; + } + + for (i = 0; i < n_pads; ++i) + gst_object_unref (pads[i]); + + return ret; +} + +/** + * gst_element_foreach_sink_pad: + * @element: a #GstElement to iterate sink pads of + * @func: (scope call): function to call for each sink pad + * @user_data: (closure): user data passed to @func + * + * Call @func with @user_data for each of @element's sink pads. @func will be + * called exactly once for each sink pad that exists at the time of this call, + * unless one of the calls to @func returns %FALSE in which case we will stop + * iterating pads and return early. If new sink pads are added or sink pads + * are removed while the sink pads are being iterated, this will not be taken + * into account until next time this function is used. + * + * Returns: %FALSE if @element had no sink pads or if one of the calls to @func + * returned %FALSE. + * + * Since: 1.14 + */ +gboolean +gst_element_foreach_sink_pad (GstElement * element, + GstElementForeachPadFunc func, gpointer user_data) +{ + return gst_element_do_foreach_pad (element, func, user_data, + &element->sinkpads, &element->numsinkpads); +} + +/** + * gst_element_foreach_src_pad: + * @element: a #GstElement to iterate source pads of + * @func: (scope call): function to call for each source pad + * @user_data: (closure): user data passed to @func + * + * Call @func with @user_data for each of @element's source pads. @func will be + * called exactly once for each source pad that exists at the time of this call, + * unless one of the calls to @func returns %FALSE in which case we will stop + * iterating pads and return early. If new source pads are added or source pads + * are removed while the source pads are being iterated, this will not be taken + * into account until next time this function is used. + * + * Returns: %FALSE if @element had no source pads or if one of the calls + * to @func returned %FALSE. + * + * Since: 1.14 + */ +gboolean +gst_element_foreach_src_pad (GstElement * element, + GstElementForeachPadFunc func, gpointer user_data) +{ + return gst_element_do_foreach_pad (element, func, user_data, + &element->srcpads, &element->numsrcpads); +} + +/** + * gst_element_foreach_pad: + * @element: a #GstElement to iterate pads of + * @func: (scope call): function to call for each pad + * @user_data: (closure): user data passed to @func + * + * Call @func with @user_data for each of @element's pads. @func will be called + * exactly once for each pad that exists at the time of this call, unless + * one of the calls to @func returns %FALSE in which case we will stop + * iterating pads and return early. If new pads are added or pads are removed + * while pads are being iterated, this will not be taken into account until + * next time this function is used. + * + * Returns: %FALSE if @element had no pads or if one of the calls to @func + * returned %FALSE. + * + * Since: 1.14 + */ +gboolean +gst_element_foreach_pad (GstElement * element, GstElementForeachPadFunc func, + gpointer user_data) +{ + return gst_element_do_foreach_pad (element, func, user_data, + &element->pads, &element->numpads); +} + /** * gst_element_class_add_pad_template: * @klass: the #GstElementClass to add the pad template to. - * @templ: (transfer full): a #GstPadTemplate to add to the element class. + * @templ: (transfer floating): a #GstPadTemplate to add to the element class. * * Adds a padtemplate to an element class. This is mainly used in the _class_init * functions of classes. If a pad template with the same name as an already * existing one is added the old one is replaced by the new one. * + * @templ's reference count will be incremented, and any floating + * reference will be removed (see gst_object_ref_sink()) + * */ void gst_element_class_add_pad_template (GstElementClass * klass, @@ -1217,6 +1387,7 @@ gst_element_class_add_pad_template (GstElementClass * klass, /* Found pad with the same name, replace and return */ if (strcmp (templ->name_template, padtempl->name_template) == 0) { + gst_object_ref_sink (padtempl); gst_object_unref (padtempl); template_list->data = templ; return; @@ -1252,6 +1423,28 @@ gst_element_class_add_static_pad_template (GstElementClass * klass, } /** + * gst_element_class_add_static_pad_template_with_gtype: + * @klass: the #GstElementClass to add the pad template to. + * @static_templ: #GstStaticPadTemplate to add as pad template to the element class. + * @pad_type: The #GType of the pad to create + * + * Adds a pad template to an element class based on the static pad template + * @templ. This is mainly used in the _class_init functions of element + * implementations. If a pad template with the same name already exists, + * the old one is replaced by the new one. + * + * Since: 1.14 + */ +void +gst_element_class_add_static_pad_template_with_gtype (GstElementClass * klass, + GstStaticPadTemplate * static_templ, GType pad_type) +{ + gst_element_class_add_pad_template (klass, + gst_pad_template_new_from_static_pad_template_with_gtype (static_templ, + pad_type)); +} + +/** * gst_element_class_add_metadata: * @klass: class to set metadata for * @key: the key to set @@ -1312,7 +1505,7 @@ gst_element_class_add_static_metadata (GstElementClass * klass, * multiple author metadata. E.g: "Joe Bloggs <joe.blogs at foo.com>" * * Sets the detailed information for a #GstElementClass. - * This function is for use in _class_init functions only. + * > This function is for use in _class_init functions only. */ void gst_element_class_set_metadata (GstElementClass * klass, @@ -1345,7 +1538,8 @@ gst_element_class_set_metadata (GstElementClass * klass, * multiple author metadata. E.g: "Joe Bloggs <joe.blogs at foo.com>" * * Sets the detailed information for a #GstElementClass. - * This function is for use in _class_init functions only. + * + * > This function is for use in _class_init functions only. * * Same as gst_element_class_set_metadata(), but @longname, @classification, * @description, and @author must be static strings or inlined strings, as @@ -1401,14 +1595,34 @@ gst_element_class_get_metadata (GstElementClass * klass, const gchar * key) } /** + * gst_element_get_metadata: + * @element: class to get metadata for + * @key: the key to get + * + * Get metadata with @key in @klass. + * + * Returns: the metadata for @key. + * + * Since: 1.14 + */ +const gchar * +gst_element_get_metadata (GstElement * element, const gchar * key) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + g_return_val_if_fail (key != NULL, NULL); + + return gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), key); +} + +/** * gst_element_class_get_pad_template_list: * @element_class: a #GstElementClass to get pad templates of. * * Retrieves a list of the pad templates associated with @element_class. The * list must not be modified by the calling code. - * If you use this function in the #GInstanceInitFunc of an object class - * that has subclasses, make sure to pass the g_class parameter of the - * #GInstanceInitFunc here. + * > If you use this function in the #GInstanceInitFunc of an object class + * > that has subclasses, make sure to pass the g_class parameter of the + * > #GInstanceInitFunc here. * * Returns: (transfer none) (element-type Gst.PadTemplate): the #GList of * pad templates. @@ -1422,14 +1636,35 @@ gst_element_class_get_pad_template_list (GstElementClass * element_class) } /** + * gst_element_get_pad_template_list: + * @element: a #GstElement to get pad templates of. + * + * Retrieves a list of the pad templates associated with @element. The + * list must not be modified by the calling code. + * + * Returns: (transfer none) (element-type Gst.PadTemplate): the #GList of + * pad templates. + * + * Since: 1.14 + */ +GList * +gst_element_get_pad_template_list (GstElement * element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + + return + gst_element_class_get_pad_template_list (GST_ELEMENT_GET_CLASS (element)); +} + +/** * gst_element_class_get_pad_template: * @element_class: a #GstElementClass to get the pad template of. * @name: the name of the #GstPadTemplate to get. * * Retrieves a padtemplate from @element_class with the given name. - * If you use this function in the #GInstanceInitFunc of an object class - * that has subclasses, make sure to pass the g_class parameter of the - * #GInstanceInitFunc here. + * > If you use this function in the #GInstanceInitFunc of an object class + * > that has subclasses, make sure to pass the g_class parameter of the + * > #GInstanceInitFunc here. * * Returns: (transfer none) (nullable): the #GstPadTemplate with the * given name, or %NULL if none was found. No unreferencing is @@ -1458,6 +1693,29 @@ gst_element_class_get_pad_template (GstElementClass * return NULL; } +/** + * gst_element_get_pad_template: + * @element: a #GstElement to get the pad template of. + * @name: the name of the #GstPadTemplate to get. + * + * Retrieves a padtemplate from @element with the given name. + * + * Returns: (transfer none) (nullable): the #GstPadTemplate with the + * given name, or %NULL if none was found. No unreferencing is + * necessary. + * + * Since: 1.14 + */ +GstPadTemplate * +gst_element_get_pad_template (GstElement * element, const gchar * name) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + g_return_val_if_fail (name != NULL, NULL); + + return gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element), + name); +} + static GstPadTemplate * gst_element_class_get_request_pad_template (GstElementClass * element_class, const gchar * name) @@ -1472,7 +1730,7 @@ gst_element_class_get_request_pad_template (GstElementClass * } /* get a random pad on element of the given direction. - * The pad is random in a sense that it is the first pad that is (optionaly) linked. + * The pad is random in a sense that it is the first pad that is (optionally) linked. */ static GstPad * gst_element_get_random_pad (GstElement * element, @@ -1812,7 +2070,7 @@ _gst_element_error_printf (const gchar * format, ...) } /** - * gst_element_message_full: + * gst_element_message_full_with_details: * @element: a #GstElement to send message from * @type: the #GstMessageType * @domain: the GStreamer GError domain this message belongs to @@ -1826,18 +2084,20 @@ _gst_element_error_printf (const gchar * format, ...) * @file: the source code file where the error was generated * @function: the source code function where the error was generated * @line: the source code line where the error was generated + * @structure:(transfer full): optional details structure * * Post an error, warning or info message on the bus from inside an element. * * @type must be of #GST_MESSAGE_ERROR, #GST_MESSAGE_WARNING or * #GST_MESSAGE_INFO. * - * MT safe. + * Since: 1.10 */ -void gst_element_message_full +void gst_element_message_full_with_details (GstElement * element, GstMessageType type, GQuark domain, gint code, gchar * text, - gchar * debug, const gchar * file, const gchar * function, gint line) + gchar * debug, const gchar * file, const gchar * function, gint line, + GstStructure * structure) { GError *gerror = NULL; gchar *name; @@ -1884,20 +2144,24 @@ void gst_element_message_full switch (type) { case GST_MESSAGE_ERROR: message = - gst_message_new_error (GST_OBJECT_CAST (element), gerror, sent_debug); + gst_message_new_error_with_details (GST_OBJECT_CAST (element), gerror, + sent_debug, structure); break; case GST_MESSAGE_WARNING: - message = gst_message_new_warning (GST_OBJECT_CAST (element), gerror, - sent_debug); + message = + gst_message_new_warning_with_details (GST_OBJECT_CAST (element), + gerror, sent_debug, structure); break; case GST_MESSAGE_INFO: - message = gst_message_new_info (GST_OBJECT_CAST (element), gerror, - sent_debug); + message = + gst_message_new_info_with_details (GST_OBJECT_CAST (element), gerror, + sent_debug, structure); break; default: g_assert_not_reached (); break; } + gst_element_post_message (element, message); GST_CAT_INFO_OBJECT (GST_CAT_ERROR_SYSTEM, element, "posted %s message: %s", @@ -1910,6 +2174,38 @@ void gst_element_message_full } /** + * gst_element_message_full: + * @element: a #GstElement to send message from + * @type: the #GstMessageType + * @domain: the GStreamer GError domain this message belongs to + * @code: the GError code belonging to the domain + * @text: (allow-none) (transfer full): an allocated text string to be used + * as a replacement for the default message connected to code, + * or %NULL + * @debug: (allow-none) (transfer full): an allocated debug message to be + * used as a replacement for the default debugging information, + * or %NULL + * @file: the source code file where the error was generated + * @function: the source code function where the error was generated + * @line: the source code line where the error was generated + * + * Post an error, warning or info message on the bus from inside an element. + * + * @type must be of #GST_MESSAGE_ERROR, #GST_MESSAGE_WARNING or + * #GST_MESSAGE_INFO. + * + * MT safe. + */ +void gst_element_message_full + (GstElement * element, GstMessageType type, + GQuark domain, gint code, gchar * text, + gchar * debug, const gchar * file, const gchar * function, gint line) +{ + gst_element_message_full_with_details (element, type, domain, code, text, + debug, file, function, line, NULL); +} + +/** * gst_element_is_locked_state: * @element: a #GstElement. * @@ -1945,6 +2241,10 @@ gst_element_is_locked_state (GstElement * element) * Locks the state of an element, so state changes of the parent don't affect * this element anymore. * + * Note that this is racy if the state lock of the parent bin is not taken. + * The parent bin might've just checked the flag in another thread and as the + * next step proceed to change the child element's state. + * * MT safe. * * Returns: %TRUE if the state was changed, %FALSE if bad parameters were given @@ -2148,7 +2448,7 @@ interrupted: if (pending) *pending = GST_STATE_VOID_PENDING; - GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "interruped"); + GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "interrupted"); GST_OBJECT_UNLOCK (element); @@ -2303,6 +2603,8 @@ _priv_gst_element_state_changed (GstElement * element, GstState oldstate, * This method is used internally and should normally not be called by plugins * or applications. * + * This function must be called with STATE_LOCK held. + * * Returns: The result of the commit state change. * * MT safe. @@ -2684,14 +2986,14 @@ gst_element_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_SUCCESS: GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "element changed state SUCCESS"); - /* we can commit the state now which will proceeed to + /* we can commit the state now which will proceed to * the next state */ ret = gst_element_continue_state (element, ret); break; case GST_STATE_CHANGE_NO_PREROLL: GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "element changed state NO_PREROLL"); - /* we can commit the state now which will proceeed to + /* we can commit the state now which will proceed to * the next state */ ret = gst_element_continue_state (element, ret); break; @@ -2924,8 +3226,8 @@ was_ok: * * Retrieves the factory that was used to create this element. * - * Returns: (transfer none): the #GstElementFactory used for creating this - * element. no refcounting is needed. + * Returns: (transfer none) (nullable): the #GstElementFactory used for creating this + * element or %NULL if element has not been registered (static element). no refcounting is needed. */ GstElementFactory * gst_element_get_factory (GstElement * element) @@ -3052,7 +3354,7 @@ gst_element_set_bus_func (GstElement * element, GstBus * bus) /** * gst_element_set_bus: * @element: a #GstElement to set the bus of. - * @bus: (transfer none): the #GstBus to set. + * @bus: (transfer none) (allow-none): the #GstBus to set. * * Sets the bus of the element. Increases the refcount on the bus. * For internal use only, unless you're testing elements. @@ -3079,7 +3381,8 @@ gst_element_set_bus (GstElement * element, GstBus * bus) * Returns the bus of the element. Note that only a #GstPipeline will provide a * bus for the application. * - * Returns: (transfer full): the element's #GstBus. unref after usage. + * Returns: (transfer full) (nullable): the element's #GstBus. unref after + * usage. * * MT safe. */ @@ -3107,15 +3410,18 @@ gst_element_set_context_default (GstElement * element, GstContext * context) const gchar *context_type; GList *l; - GST_OBJECT_LOCK (element); + g_return_if_fail (GST_IS_CONTEXT (context)); context_type = gst_context_get_context_type (context); + g_return_if_fail (context_type != NULL); + + GST_OBJECT_LOCK (element); for (l = element->contexts; l; l = l->next) { GstContext *tmp = l->data; const gchar *tmp_type = gst_context_get_context_type (tmp); /* Always store newest context but never replace * a persistent one by a non-persistent one */ - if (strcmp (context_type, tmp_type) == 0 && + if (g_strcmp0 (context_type, tmp_type) == 0 && (gst_context_is_persistent (context) || !gst_context_is_persistent (tmp))) { gst_context_replace ((GstContext **) & l->data, context); @@ -3145,6 +3451,7 @@ gst_element_set_context (GstElement * element, GstContext * context) GstElementClass *oclass; g_return_if_fail (GST_IS_ELEMENT (element)); + g_return_if_fail (GST_IS_CONTEXT (context)); oclass = GST_ELEMENT_GET_CLASS (element); @@ -3199,7 +3506,7 @@ _match_context_type (GstContext * c1, const gchar * context_type) * * Gets the context with @context_type set on the element or NULL. * - * Returns: (transfer full): A #GstContext or NULL + * Returns: (transfer full) (nullable): A #GstContext or NULL * * Since: 1.8 */ @@ -3423,3 +3730,28 @@ gst_element_call_async (GstElement * element, GstElementCallAsyncFunc func, g_thread_pool_push (gst_element_pool, async_data, NULL); } + +void +_priv_gst_element_cleanup (void) +{ + if (gst_element_pool) { + g_thread_pool_free (gst_element_pool, FALSE, TRUE); + gst_element_setup_thread_pool (); + } +} + +GstStructure * +gst_make_element_message_details (const char *name, ...) +{ + GstStructure *structure; + va_list varargs; + + if (name == NULL) + return NULL; + + va_start (varargs, name); + structure = gst_structure_new_valist ("details", name, varargs); + va_end (varargs); + + return structure; +}