diff --git a/gst/gstelement.c b/gst/gstelement.c
index ef51867898a726dec1c932a196adc59e1e232fb9..afa25b9d3717cbe247c5606cf9bbd57e73886cc7 100644 (file)
--- a/gst/gstelement.c
+++ b/gst/gstelement.c
* @short_description: Abstract base class for all pipeline elements
* @see_also: #GstElementFactory, #GstPad
*
- * GstElement is the abstract base class needed to construct an element that
+ * GstElement is the abstract base class needed to construct an element that
* can be used in a GStreamer pipeline. Please refer to the plugin writers
* guide for more information on creating #GstElement subclasses.
*
* Core and plug-in writers can add and remove pads with gst_element_add_pad()
* and gst_element_remove_pad().
*
- * A pad of an element can be retrieved by name with gst_element_get_pad().
+ * An existing pad of an element can be retrieved by name with
+ * gst_element_get_static_pad(). A new dynamic pad can be created using
+ * gst_element_request_pad() with a #GstPadTemplate or
+ * gst_element_get_request_pad() with the template name such as "src_\%d".
* An iterator of all pads can be retrieved with gst_element_iterate_pads().
*
* Elements can be linked through their pads.
*
* Each element has a state (see #GstState). You can get and set the state
* of an element with gst_element_get_state() and gst_element_set_state().
- * To get a string representation of a #GstState, use
- * gst_element_state_get_name().
+ * Setting a state triggers a #GstStateChange. To get a string representation
+ * of a #GstState, use gst_element_state_get_name().
*
* You can get and set a #GstClock on an element using gst_element_get_clock()
* and gst_element_set_clock().
* 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"
#include <gobject/gvaluecollector.h>
#include "gstelement.h"
+#include "gstelementdetails.h"
#include "gstenumtypes.h"
#include "gstbus.h"
#include "gstmarshal.h"
#include "gstevent.h"
#include "gstutils.h"
#include "gstinfo.h"
+#include "gstvalue.h"
#include "gst-i18n-lib.h"
/* Element signals and args */
/* FILL ME */
};
-extern void __gst_element_details_clear (GstElementDetails * dp);
-extern void __gst_element_details_copy (GstElementDetails * dest,
- const GstElementDetails * src);
+#ifdef GST_DISABLE_DEPRECATED
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
+#include <libxml/parser.h>
+xmlNodePtr gst_object_save_thyself (const GstObject * object,
+ xmlNodePtr parent);
+GstObject *gst_object_load_thyself (xmlNodePtr parent);
+void gst_pad_load_and_link (xmlNodePtr self, GstObject * parent);
+#endif
+#endif
static void gst_element_class_init (GstElementClass * klass);
static void gst_element_init (GstElement * element);
static gboolean gst_element_default_query (GstElement * element,
GstQuery * query);
-#ifndef GST_DISABLE_LOADSAVE
+static GstPadTemplate
+ * gst_element_class_get_request_pad_template (GstElementClass *
+ element_class, const gchar * name);
+
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
static xmlNodePtr gst_element_save_thyself (GstObject * object,
xmlNodePtr parent);
static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self);
@@ -141,12 +156,16 @@ static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self);
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;
+
GType
gst_element_get_type (void)
{
- static GType gst_element_type = 0;
+ static volatile gsize gst_element_type = 0;
- if (G_UNLIKELY (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,
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;
}
static void
gst_element_class_init (GstElementClass * klass)
{
- GObjectClass *gobject_class;
- GstObjectClass *gstobject_class;
-
- gobject_class = (GObjectClass *) klass;
- gstobject_class = (GstObjectClass *) klass;
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
+ GstObjectClass *gstobject_class = (GstObjectClass *) klass;
+#endif
parent_class = g_type_class_peek_parent (klass);
* @gstelement: the object which received the signal
* @new_pad: the pad that has been added
*
- * a new #GstPad has been added to the element.
+ * a new #GstPad has been added to the element. Note that this signal will
+ * usually be emitted from the context of the streaming thread. Also keep in
+ * mind that if you add new elements to the pipeline in the signal handler
+ * you will need to set them to the desired target state with
+ * gst_element_set_state() or gst_element_sync_state_with_parent().
*/
gst_element_signals[PAD_ADDED] =
g_signal_new ("pad-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
* @gstelement: the object which received the signal
*
* This signals that the element will not generate more dynamic pads.
+ * Note that this signal will usually be emitted from the context of
+ * the streaming thread.
*/
gst_element_signals[NO_MORE_PADS] =
g_signal_new ("no-more-pads", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, no_more_pads), NULL,
NULL, gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
- gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_element_finalize);
+ gobject_class->dispose = gst_element_dispose;
+ gobject_class->finalize = gst_element_finalize;
-#ifndef GST_DISABLE_LOADSAVE
- gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
+ gstobject_class->save_thyself =
+ ((gpointer (*)(GstObject * object,
+ gpointer self)) * GST_DEBUG_FUNCPTR (gst_element_save_thyself));
gstobject_class->restore_thyself =
- GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
+ ((void (*)(GstObject * object,
+ gpointer self)) *GST_DEBUG_FUNCPTR (gst_element_restore_thyself));
#endif
klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state_func);
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ /* FIXME 0.11: Copy the element details and instead of clearing the
+ * pad template list copy the list and increase the refcount of
+ * the pad templates by one.
+ *
+ * This will make it possible to add pad templates and set element
+ * details in the class_init functions and is the real GObject way
+ * of doing things.
+ * See http://bugzilla.gnome.org/show_bug.cgi?id=491501
+ */
memset (&element_class->details, 0, sizeof (GstElementDetails));
+ element_class->meta_data = NULL;
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
g_list_foreach (klass->padtemplates, (GFunc) gst_object_unref, NULL);
g_list_free (klass->padtemplates);
__gst_element_details_clear (&klass->details);
+ if (klass->meta_data) {
+ gst_structure_free (klass->meta_data);
+ klass->meta_data = NULL;
+ }
}
static void
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS;
- element->state_lock = g_new0 (GStaticRecMutex, 1);
+ /* FIXME 0.11: Store this directly in the instance struct */
+ element->state_lock = g_slice_new (GStaticRecMutex);
g_static_rec_mutex_init (element->state_lock);
element->state_cond = g_cond_new ();
}
-/**
- * gst_element_default_error:
- * @object: a #GObject that signalled the error.
- * @orig: the #GstObject that initiated the error.
- * @error: the GError.
- * @debug: an additional debug information string, or %NULL.
- *
- * A default error signal callback to attach to an element.
- * The user data passed to the g_signal_connect is ignored.
- *
- * The default handler will simply print the error string using g_print.
- *
- * MT safe.
- */
-void
-gst_element_default_error (GObject * object, GstObject * source, GError * error,
- gchar * debug)
-{
- gchar *name = gst_object_get_path_string (source);
-
- g_print (_("ERROR: from element %s: %s\n"), name, error->message);
- if (debug)
- g_print (_("Additional debug info:\n%s\n"), debug);
-
- g_free (name);
-}
-
/**
* gst_element_release_request_pad:
* @element: a #GstElement to release the request pad of.
@@ -298,6 +324,10 @@ gst_element_default_error (GObject * object, GstObject * source, GError * error,
* 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.
*/
void
* @element: a #GstElement to query
*
* Query if the element provides a clock. A #GstClock provided by an
- * element can be used as the global #GstClock for the pipeline.
+ * element can be used as the global #GstClock for the pipeline.
* An element that can provide a clock is only required to do so in the PAUSED
* state, this means when it is fully negotiated and has allocated the resources
* to operate the clock.
* gst_element_provide_clock:
* @element: a #GstElement to query
*
- * Get the clock provided by the given element.
+ * Get the clock provided by the given element.
* <note>An element is only required to provide a clock in the PAUSED
* state. Some elements can provide a clock in other states.</note>
*
- * Returns: the GstClock provided by the element or %NULL
+ * Returns: (transfer full): the GstClock provided by the element or %NULL
* if no clock could be provided. Unref after usage.
*
* MT safe.
GstClock **clock_p;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+ g_return_val_if_fail (clock == NULL || GST_IS_CLOCK (clock), FALSE);
oclass = GST_ELEMENT_GET_CLASS (element);
- GST_DEBUG_OBJECT (element, "setting clock %p", clock);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, "setting clock %p", clock);
if (oclass->set_clock)
res = oclass->set_clock (element, clock);
* Gets the currently configured clock of the element. This is the clock as was
* last set with gst_element_set_clock().
*
- * Returns: the #GstClock of the element. unref after usage.
+ * Returns: (transfer full): the #GstClock of the element. unref after usage.
*
* MT safe.
*/
void
gst_element_set_base_time (GstElement * element, GstClockTime time)
{
+ GstClockTime old;
+
g_return_if_fail (GST_IS_ELEMENT (element));
GST_OBJECT_LOCK (element);
+ old = element->base_time;
element->base_time = time;
GST_OBJECT_UNLOCK (element);
- GST_DEBUG_OBJECT (element, "set base_time=%" GST_TIME_FORMAT,
- GST_TIME_ARGS (time));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element,
+ "set base_time=%" GST_TIME_FORMAT ", old %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (time), GST_TIME_ARGS (old));
}
/**
* 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.
*
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
+ */
+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
+ */
+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.
/**
* gst_element_set_index:
* @element: a #GstElement.
- * @index: a #GstIndex.
+ * @index: (transfer none): a #GstIndex.
*
* Set @index on the element. The refcount of the index
* will be increased, any previously set index is unreffed.
GstElementClass *oclass;
g_return_if_fail (GST_IS_ELEMENT (element));
- g_return_if_fail (GST_IS_INDEX (index));
+ g_return_if_fail (index == NULL || GST_IS_INDEX (index));
oclass = GST_ELEMENT_GET_CLASS (element);
*
* Gets the index from the element.
*
- * Returns: a #GstIndex or %NULL when no index was set on the
+ * Returns: (transfer full): a #GstIndex or %NULL when no index was set on the
* element. unref after usage.
*
* MT safe.
return result;
}
-#endif
/**
* gst_element_add_pad:
* @element: a #GstElement to add the pad to.
- * @pad: the #GstPad to add to the element.
+ * @pad: (transfer full): 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.
/* check for flushing pads */
if (flushing && (GST_STATE (element) > GST_STATE_READY ||
GST_STATE_NEXT (element) == GST_STATE_PAUSED)) {
- g_warning ("adding flushing pad '%s' to running element '%s'",
+ g_warning ("adding flushing 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));
/* unset flushing */
GST_OBJECT_LOCK (pad);
/**
* gst_element_remove_pad:
* @element: a #GstElement to remove pad from.
- * @pad: 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().
* Retrieves a pad from @element by name. This version only retrieves
* already-existing (i.e. 'static') pads.
*
- * Returns: the requested #GstPad if found, otherwise %NULL. unref after
- * usage.
+ * Returns: (transfer full): the requested #GstPad if found, otherwise %NULL.
+ * unref after usage.
*
* MT safe.
*/
}
static GstPad *
-gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
- const gchar * name)
+_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);
- if (oclass->request_new_pad)
+#ifndef G_DISABLE_CHECKS
+ /* Some sanity checking here */
+ if (name) {
+ GstPad *pad;
+
+ /* 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 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);
+
+ data = name + (str - templ->name_template);
+
+ /* Can either be %s or %d or %u, do sanity checking for %d */
+ if (*(str + 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') {
+ guint64 tmp;
+
+ /* it's an int */
+ tmp = g_ascii_strtoull (data, &endptr, 10);
+ g_return_val_if_fail (tmp <= G_MAXUINT && *endptr == '\0', NULL);
+ }
+ }
+
+ pad = gst_element_get_static_pad (element, name);
+ if (pad) {
+ gst_object_unref (pad);
+ /* FIXME 0.11: Change this to g_return_val_if_fail() */
+ g_critical ("Element %s already has a pad named %s, the behaviour of "
+ " gst_element_get_request_pad() for existing pads is undefined!",
+ GST_ELEMENT_NAME (element), name);
+ }
+ }
+#endif
+
+ if (oclass->request_new_pad_full)
+ newpad = (oclass->request_new_pad_full) (element, templ, name, caps);
+ else if (oclass->request_new_pad)
newpad = (oclass->request_new_pad) (element, templ, name);
if (newpad)
* @element: a #GstElement to find a request pad of.
* @name: the name of the request #GstPad to retrieve.
*
- * Retrieves a pad from the element by name. This version only retrieves
- * request pads. The pad should be released with
+ * Retrieves a pad from the element by name (e.g. "src_\%d"). This version only
+ * retrieves request pads. The pad should be released with
* gst_element_release_request_pad().
*
- * Returns: requested #GstPad if found, otherwise %NULL. Release after usage.
+ * This method is slow and will be deprecated in the future. New code should
+ * use gst_element_request_pad() with the requested template.
+ *
+ * Returns: (transfer full): requested #GstPad if found, otherwise %NULL.
+ * Release after usage.
*/
GstPad *
gst_element_get_request_pad (GstElement * element, const gchar * name)
const gchar *req_name = NULL;
gboolean templ_found = FALSE;
GList *list;
- gint n;
const gchar *data;
gchar *str, *endptr = NULL;
GstElementClass *class;
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_pad_template (class, name);
+ templ = gst_element_class_get_request_pad_template (class, name);
req_name = NULL;
if (templ)
templ_found = TRUE;
} else {
- list = gst_element_class_get_pad_template_list (class);
+ /* there is no % in the name, try to find a matching template */
+ list = class->padtemplates;
while (!templ_found && list) {
templ = (GstPadTemplate *) list->data;
if (templ->presence == GST_PAD_REQUEST) {
- /* Because of sanity checks in gst_pad_template_new(), we know that %s
- and %d, occurring at the end of the name_template, are the only
- possibilities. */
GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name,
templ->name_template);
- if ((str = strchr (templ->name_template, '%'))
+ /* see if we find an exact match */
+ if (strcmp (name, templ->name_template) == 0) {
+ 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 */
- n = (gint) strtol (data, &endptr, 10);
- if (endptr && *endptr == '\0') {
+ 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;
if (!templ_found)
return NULL;
- pad = gst_element_request_pad (element, templ, req_name);
+ pad = _gst_element_request_pad (element, templ, req_name, NULL);
return pad;
}
+/**
+ * gst_element_request_pad:
+ * @element: a #GstElement to find a request pad of.
+ * @templ: a #GstPadTemplate of which we want a pad of.
+ * @name: (transfer none) (allow-none): the name of the request #GstPad
+ * to retrieve. Can be %NULL.
+ * @caps: (transfer none) (allow-none): the caps of the pad we want to
+ * request. Can be %NULL.
+ *
+ * Retrieves a request pad from the element according to the provided template.
+ * Pad templates can be looked up using
+ * gst_element_factory_get_static_pad_templates().
+ *
+ * If the @caps are specified and the element implements thew new
+ * request_new_pad_full virtual method, the element will use them to select
+ * which pad to create.
+ *
+ * The pad should be released with gst_element_release_request_pad().
+ *
+ * Returns: (transfer full): requested #GstPad if found, otherwise %NULL.
+ * Release after usage.
+ *
+ * Since: 0.10.32
+ */
+GstPad *
+gst_element_request_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+ g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+ g_return_val_if_fail (templ != NULL, NULL);
+
+ return _gst_element_request_pad (element, templ, name, caps);
+}
+
/**
* gst_element_get_pad:
* @element: a #GstElement.
* Retrieves a pad from @element by name. Tries gst_element_get_static_pad()
* first, then gst_element_get_request_pad().
*
- * <note>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.</note>
+ * 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,
+ * Returns: (transfer full): the #GstPad if found, otherwise %NULL. Unref or Release after usage,
* depending on the type of the pad.
*/
+#ifndef GST_REMOVE_DEPRECATED
+#ifdef GST_DISABLE_DEPRECATED
+GstPad *gst_element_get_pad (GstElement * element, const gchar * name);
+#endif
GstPad *
gst_element_get_pad (GstElement * element, const gchar * name)
{
return pad;
}
+#endif /* GST_REMOVE_DEPRECATED */
static GstIteratorItem
iterate_pad (GstIterator * it, GstPad * pad)
* gst_element_iterate_pads:
* @element: a #GstElement to iterate pads of.
*
- * Retrieves an iterattor of @element's pads. The iterator should
- * be freed after usage.
+ * Retrieves an iterator of @element's pads. The iterator should
+ * be freed after usage. Also more specialized iterators exists such as
+ * gst_element_iterate_src_pads() or gst_element_iterate_sink_pads().
*
- * Returns: the #GstIterator of #GstPad. Unref each pad after use.
+ * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
+ * after use.
*
* MT safe.
*/
*
* Retrieves an iterator of @element's source pads.
*
- * Returns: the #GstIterator of #GstPad. Unref each pad after use.
+ * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
+ * after use.
*
* MT safe.
*/
*
* Retrieves an iterator of @element's sink pads.
*
- * Returns: the #GstIterator of #GstPad. Unref each pad after use.
+ * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
+ * after use.
*
* MT safe.
*/
/**
* gst_element_class_add_pad_template:
* @klass: the #GstElementClass to add the pad template to.
- * @templ: a #GstPadTemplate to add to the element class.
+ * @templ: (transfer none): a #GstPadTemplate to add to the element class.
*
* Adds a padtemplate to an element class. This is mainly used in the _base_init
* functions of classes.
g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
+ /* FIXME 0.11: allow replacing the pad templates by
+ * calling this with the same name as an already existing pad
+ * template. For this we _must_ _not_ ref the added pad template
+ * a second time and _must_ document that this function takes
+ * ownership of the pad template. Otherwise we will leak pad templates
+ * or the caller unref's the pad template and it disappears */
/* avoid registering pad templates with the same name */
g_return_if_fail (gst_element_class_get_pad_template (klass,
templ->name_template) == NULL);
klass->numpadtemplates++;
}
+/**
+ * gst_element_class_add_static_pad_template:
+ * @klass: the #GstElementClass to add the pad template to.
+ * @templ: (transfer none): a #GstStaticPadTemplate describing the pad
+ * to add to the element class.
+ *
+ * Adds a padtemplate to an element class. This is mainly used in the _base_init
+ * functions of classes.
+ *
+ * Since: 0.10.36
+ */
+void
+gst_element_class_add_static_pad_template (GstElementClass * klass,
+ GstStaticPadTemplate * templ)
+{
+ GstPadTemplate *pt;
+
+ g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+
+ pt = gst_static_pad_template_get (templ);
+ gst_element_class_add_pad_template (klass, pt);
+ gst_object_unref (pt);
+}
+
+static void
+gst_element_class_add_meta_data (GstElementClass * klass,
+ const gchar * key, const gchar * value)
+{
+ if (!klass->meta_data) {
+ /* FIXME: use a quark for "metadata" */
+ klass->meta_data = gst_structure_empty_new ("metadata");
+ }
+
+ gst_structure_set ((GstStructure *) klass->meta_data,
+ key, G_TYPE_STRING, value, NULL);
+}
+
+/**
+ * gst_element_class_set_documentation_uri:
+ * @klass: class to set details for
+ * @uri: uri of element documentation
+ *
+ * Set uri pointing to user documentation. Applications can use this to show
+ * help for e.g. effects to users.
+ *
+ * Since: 0.10.31
+ */
+void
+gst_element_class_set_documentation_uri (GstElementClass * klass,
+ const gchar * uri)
+{
+ g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+
+ gst_element_class_add_meta_data (klass, "doc-uri", uri);
+}
+
+/**
+ * gst_element_class_set_icon_name:
+ * @klass: class to set details for
+ * @name: name of an icon
+ *
+ * Elements that bridge to certain other products can include an icon of that
+ * used product. Application can show the icon in menus/selectors to help
+ * identifying specific elements.
+ *
+ * Since: 0.10.31
+ */
+void
+gst_element_class_set_icon_name (GstElementClass * klass, const gchar * name)
+{
+ g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+
+ gst_element_class_add_meta_data (klass, "icon-name", name);
+}
+
+/* FIXME-0.11: deprecate and remove gst_element_class_set_details*() */
/**
* gst_element_class_set_details:
* @klass: class to set details for
* <note>This function is for use in _base_init functions only.</note>
*
* The @details are copied.
+ *
+ * Deprecated: Use gst_element_class_set_details_simple() instead.
*/
+#ifndef GST_REMOVE_DEPRECATED
+#ifdef GST_DISABLE_DEPRECATED
+void gst_element_class_set_details (GstElementClass * klass,
+ const GstElementDetails * details);
+#endif
void
gst_element_class_set_details (GstElementClass * klass,
const GstElementDetails * details)
__gst_element_details_copy (&klass->details, details);
}
+#endif
+
+/**
+ * gst_element_class_set_details_simple:
+ * @klass: class to set details for
+ * @longname: The long English name of the element. E.g. "File Sink"
+ * @classification: String describing the type of element, as an unordered list
+ * separated with slashes ('/'). See draft-klass.txt of the design docs
+ * for more details and common types. E.g: "Sink/File"
+ * @description: Sentence describing the purpose of the element.
+ * E.g: "Write stream to a file"
+ * @author: Name and contact details of the author(s). Use \n to separate
+ * multiple author details. E.g: "Joe Bloggs <joe.blogs at foo.com>"
+ *
+ * Sets the detailed information for a #GstElementClass. Simpler version of
+ * gst_element_class_set_details() that generates less linker overhead.
+ * <note>This function is for use in _base_init functions only.</note>
+ *
+ * The detail parameter strings are copied into the #GstElementDetails for
+ * the element class.
+ *
+ * Since: 0.10.14
+ */
+void
+gst_element_class_set_details_simple (GstElementClass * klass,
+ const gchar * longname, const gchar * classification,
+ const gchar * description, const gchar * author)
+{
+ const GstElementDetails details =
+ GST_ELEMENT_DETAILS ((gchar *) longname, (gchar *) classification,
+ (gchar *) description, (gchar *) author);
+
+ g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+
+ __gst_element_details_copy (&klass->details, &details);
+}
/**
* gst_element_class_get_pad_template_list:
* that has subclasses, make sure to pass the g_class parameter of the
* #GInstanceInitFunc here.</note>
*
- * Returns: the #GList of padtemplates.
+ * Returns: (transfer none) (element-type Gst.PadTemplate): the #GList of
+ * pad templates.
*/
GList *
gst_element_class_get_pad_template_list (GstElementClass * element_class)
* that has subclasses, make sure to pass the g_class parameter of the
* #GInstanceInitFunc here.</note>
*
- * Returns: the #GstPadTemplate with the given name, or %NULL if none was found.
- * No unreferencing is necessary.
+ * Returns: (transfer none): the #GstPadTemplate with the given name, or %NULL
+ * if none was found. No unreferencing is necessary.
*/
GstPadTemplate *
-gst_element_class_get_pad_template (GstElementClass * element_class,
- const gchar * name)
+gst_element_class_get_pad_template (GstElementClass *
+ element_class, const gchar * name)
{
GList *padlist;
g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
g_return_val_if_fail (name != NULL, NULL);
- padlist = gst_element_class_get_pad_template_list (element_class);
+ padlist = element_class->padtemplates;
while (padlist) {
GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
return NULL;
}
+static GstPadTemplate *
+gst_element_class_get_request_pad_template (GstElementClass *
+ element_class, const gchar * name)
+{
+ GstPadTemplate *tmpl;
+
+ tmpl = gst_element_class_get_pad_template (element_class, name);
+ if (tmpl != NULL && tmpl->presence == GST_PAD_REQUEST)
+ return tmpl;
+
+ return NULL;
+}
+
/* 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.
*/
static GstPad *
-gst_element_get_random_pad (GstElement * element, gboolean need_linked,
- GstPadDirection dir)
+gst_element_get_random_pad (GstElement * element,
+ gboolean need_linked, GstPadDirection dir)
{
GstPad *result = NULL;
GList *pads;
} else {
GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "can't send %s event on element %s",
GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element));
+ gst_event_unref (event);
}
return result;
}
/**
* gst_element_send_event:
* @element: a #GstElement to send the event to.
- * @event: the #GstEvent to send to the element.
+ * @event: (transfer full): the #GstEvent to send to the element.
*
* Sends an event to an element. If the element doesn't implement an
* event handler, the event will be pushed on a random linked sink pad for
- * upstream events or a random linked source pad for downstream events.
+ * upstream events or a random linked source pad for downstream events.
*
* This function takes owership of the provided event so you should
* gst_event_ref() it if you want to reuse the event after this call.
/**
* gst_element_query:
* @element: a #GstElement to perform the query on.
- * @query: the #GstQuery.
+ * @query: (transfer none): the #GstQuery.
*
* Performs a query on the given element.
*
* forwards the query to a random srcpad or to the peer of a
* random linked sinkpad of this element.
*
+ * Please note that some queries might need a running pipeline to work.
+ *
* Returns: TRUE if the query could be performed.
*
* MT safe.
/**
* gst_element_post_message:
* @element: a #GstElement posting the message
- * @message: a #GstMessage to post
+ * @message: (transfer full): a #GstMessage to post
*
* Post a message on the element's #GstBus. This function takes ownership of the
* message; if you want to access the message after this call, you should add an
/* ERRORS */
no_bus:
{
- GST_DEBUG_OBJECT (element, "not posting message %p: no bus", message);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_MESSAGE, element,
+ "not posting message %p: no bus", message);
GST_OBJECT_UNLOCK (element);
gst_message_unref (message);
return FALSE;
*
* This function is only used internally by the gst_element_error() macro.
*
- * Returns: a newly allocated string, or %NULL if the format was %NULL or ""
+ * Returns: (transfer full): a newly allocated string, or %NULL if the format
+ * was %NULL or ""
*
* MT safe.
*/
* @type: the #GstMessageType
* @domain: the GStreamer GError domain this message belongs to
* @code: the GError code belonging to the domain
- * @text: an allocated text string to be used as a replacement for the
- * default message connected to code, or %NULL
- * @debug: an allocated debug message to be used as a replacement for the
- * default debugging information, or %NULL
+ * @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
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));
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);
gst_element_sync_state_with_parent (GstElement * element)
{
GstElement *parent;
+ GstState target;
+ GstStateChangeReturn ret;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
if ((parent = GST_ELEMENT_CAST (gst_element_get_parent (element)))) {
GstState parent_current, parent_pending;
- GstStateChangeReturn ret;
GST_OBJECT_LOCK (parent);
parent_current = GST_STATE (parent);
parent_pending = GST_STATE_PENDING (parent);
GST_OBJECT_UNLOCK (parent);
- GST_CAT_DEBUG (GST_CAT_STATES,
- "syncing state of element %s (%s) to %s (%s, %s)",
- GST_ELEMENT_NAME (element),
+ /* set to pending if there is one, else we set it to the current state of
+ * the parent */
+ if (parent_pending != GST_STATE_VOID_PENDING)
+ target = parent_pending;
+ else
+ target = parent_current;
+
+ GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
+ "syncing state (%s) to parent %s %s (%s, %s)",
gst_element_state_get_name (GST_STATE (element)),
- GST_ELEMENT_NAME (parent), gst_element_state_get_name (parent_current),
+ GST_ELEMENT_NAME (parent), gst_element_state_get_name (target),
+ gst_element_state_get_name (parent_current),
gst_element_state_get_name (parent_pending));
- ret = gst_element_set_state (element, parent_current);
+ ret = gst_element_set_state (element, target);
if (ret == GST_STATE_CHANGE_FAILURE)
goto failed;
gst_object_unref (parent);
return TRUE;
+ } else {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "element has no parent");
}
return FALSE;
/* ERROR */
failed:
{
+ 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;
}
}
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
gst_element_state_change_return_get_name (ret));
- GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
- gst_element_state_change_return_get_name (ret));
-
- /* we got an error, report immediatly */
+ /* we got an error, report immediately */
if (ret == GST_STATE_CHANGE_FAILURE)
goto done;
- /* we got no_preroll, report immediatly */
+ /* we got no_preroll, report immediately */
if (ret == GST_STATE_CHANGE_NO_PREROLL)
goto done;
} 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,
ret = GST_STATE_CHANGE_FAILURE;
}
}
- }
- /* if nothing is pending anymore we can return SUCCESS */
- if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) {
- GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "nothing pending");
- ret = GST_STATE_CHANGE_SUCCESS;
+ /* if nothing is pending anymore we can return SUCCESS */
+ if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) {
+ GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "nothing pending");
+ ret = GST_STATE_CHANGE_SUCCESS;
+ }
}
done:
if (pending)
*pending = GST_STATE_VOID_PENDING;
- GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "get_state() interruped");
+ GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "interruped");
GST_OBJECT_UNLOCK (element);
/**
* gst_element_get_state:
* @element: a #GstElement to get the state of.
- * @state: a pointer to #GstState to hold the state. Can be %NULL.
- * @pending: a pointer to #GstState to hold the pending state.
- * Can be %NULL.
+ * @state: (out) (allow-none): a pointer to #GstState to hold the state.
+ * Can be %NULL.
+ * @pending: (out) (allow-none): a pointer to #GstState to hold the pending
+ * state. Can be %NULL.
* @timeout: a #GstClockTime to specify the timeout for an async
* state change or %GST_CLOCK_TIME_NONE for infinite timeout.
*
*
* This function returns %GST_STATE_CHANGE_NO_PREROLL if the element
* successfully changed its state but is not able to provide data yet.
- * This mostly happens for live sources that only produce data in the PLAYING
- * state. While the state change return is equivalent to
+ * This mostly happens for live sources that only produce data in
+ * %GST_STATE_PLAYING. While the state change return is equivalent to
* %GST_STATE_CHANGE_SUCCESS, it is returned to the application to signal that
* some sink elements might not be able to complete their state change because
* an element is not producing data to complete the preroll. When setting the
}
}
+/* Not static because GstBin has manual state handling too */
+void
+_priv_gst_element_state_changed (GstElement * element, GstState oldstate,
+ GstState newstate, GstState pending)
+{
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+ GstMessage *message;
+
+ GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+ "notifying about state-changed %s to %s (%s pending)",
+ gst_element_state_get_name (oldstate),
+ gst_element_state_get_name (newstate),
+ gst_element_state_get_name (pending));
+
+ if (klass->state_changed)
+ klass->state_changed (element, oldstate, newstate, pending);
+
+ message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
+ oldstate, newstate, pending);
+ gst_element_post_message (element, message);
+}
+
/**
- * gst_element_continue_state:
- * @element: a #GstElement to continue the state change of.
+ * gst_element_continue_state:
+ * @element: a #GstElement to continue the state change of.
* @ret: The previous state return value
- *
- * Commit the state change of the element and proceed to the next
- * pending state if any. This function is used
- * by elements that do asynchronous state changes.
- * The core will normally call this method automatically when an
- * element returned %GST_STATE_CHANGE_SUCCESS from the state change function.
- *
- * If after calling this method the element still has not reached
- * the pending state, the next state change is performed.
- *
+ *
+ * Commit the state change of the element and proceed to the next
+ * pending state if any. This function is used
+ * by elements that do asynchronous state changes.
+ * The core will normally call this method automatically when an
+ * element returned %GST_STATE_CHANGE_SUCCESS from the state change function.
+ *
+ * If after calling this method the element still has not reached
+ * the pending state, the next state change is performed.
+ *
* This method is used internally and should normally not be called by plugins
* or applications.
- *
- * Returns: The result of the commit state change.
- *
- * MT safe.
+ *
+ * Returns: The result of the commit state change.
+ *
+ * MT safe.
*/
GstStateChangeReturn
gst_element_continue_state (GstElement * element, GstStateChangeReturn ret)
GstStateChangeReturn old_ret;
GstState old_state, old_next;
GstState current, next, pending;
- GstMessage *message;
GstStateChange transition;
GST_OBJECT_LOCK (element);
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);
- gst_element_post_message (element, message);
+ _priv_gst_element_state_changed (element, old_state, old_next, pending);
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
"continue state change %s to %s, final %s",
/* don't post silly messages with the same state. This can happen
* when an element state is changed to what it already was. For bins
* this can be the result of a lost state, which we check with the
- * previous return value.
- * We do signal the cond though as a _get_state() might be blocking
+ * previous return value.
+ * We do signal the cond though as a _get_state() might be blocking
* on it. */
- if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) {
- message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
- old_state, old_next, GST_STATE_VOID_PENDING);
- gst_element_post_message (element, message);
- }
+ if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC)
+ _priv_gst_element_state_changed (element, old_state, old_next,
+ GST_STATE_VOID_PENDING);
GST_STATE_BROADCAST (element);
}
/**
- * 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.
* plugins or applications.
*
* MT safe.
+ *
+ * Since: 0.10.24
*/
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;
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
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);
+ _priv_gst_element_state_changed (element, new_state, new_state, new_state);
- 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;
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.
+ */
+void
+gst_element_lost_state (GstElement * element)
+{
+ gst_element_lost_state_full (element, TRUE);
}
/**
* 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.
/*
* default set state function, calculates the next state based
- * on current state and calls the change_state function
+ * on current state and calls the change_state function
*/
static GstStateChangeReturn
gst_element_set_state_func (GstElement * element, GstState state)
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "set_state to %s",
gst_element_state_get_name (state));
- /* state lock is taken to protect the set_state() and get_state()
+ /* state lock is taken to protect the set_state() and get_state()
* procedures, it does not lock any variables. */
GST_STATE_LOCK (element);
current = GST_STATE (element);
next = GST_STATE_NEXT (element);
old_pending = GST_STATE_PENDING (element);
- /* increment state cookie so that we can track each state change */
- element->state_cookie++;
/* this is the (new) state we should go to. TARGET is the last state we set on
* the element. */
- GST_STATE_TARGET (element) = state;
+ 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. */
+ element->state_cookie++;
+ }
GST_STATE_PENDING (element) = state;
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
(next != state ? "intermediate" : "final"),
gst_element_state_get_name (current), gst_element_state_get_name (next));
- /* now signal any waiters, they will error since the cookie was increased */
+ /* now signal any waiters, they will error since the cookie was incremented */
GST_STATE_BROADCAST (element);
GST_OBJECT_UNLOCK (element);
{
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);
}
/* gst_iterator_fold functions for pads_activate
- * Note how we don't stop the iterator when we fail an activation. This is
- * probably a FIXME since when one pad activation fails, we don't want to
- * continue our state change. */
+ * Stop the iterator if activating one pad failed. */
static gboolean
activate_pads (GstPad * pad, GValue * ret, gboolean * active)
{
- if (!gst_pad_set_active (pad, *active))
+ gboolean cont = TRUE;
+
+ if (!(cont = gst_pad_set_active (pad, *active)))
g_value_set_boolean (ret, FALSE);
/* unref the object that was reffed for us by _fold */
gst_object_unref (pad);
- return TRUE;
+ return cont;
}
/* set the caps on the pad to NULL */
return TRUE;
}
-/* returns false on error or early cutout (will never happen because the fold
- * function always returns TRUE, see FIXME above) of the fold, true if all
+/* returns false on error or early cutout of the fold, true if all
* pads in @iter were (de)activated successfully. */
static gboolean
iterator_activate_fold_with_resync (GstIterator * iter,
/* all pads iterated, return collected value */
goto done;
default:
- /* iterator returned _ERROR or premature end with _OK,
+ /* iterator returned _ERROR or premature end with _OK,
* mark an error and exit */
g_value_set_boolean (&ret, FALSE);
goto done;
/* is called with STATE_LOCK
*
- * Pads are activated from source pads to sinkpads.
+ * Pads are activated from source pads to sinkpads.
*/
static gboolean
gst_element_pads_activate (GstElement * element, gboolean active)
GstIterator *iter;
gboolean res;
- GST_DEBUG_OBJECT (element, "pads_activate with active %d", active);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+ "pads_activate with active %d", active);
iter = gst_element_iterate_src_pads (element);
res =
goto caps_failed;
}
- GST_DEBUG_OBJECT (element, "pads_activate successful");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+ "pads_activate successful");
return TRUE;
/* 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;
}
}
@@ -2528,6 +2963,7 @@ gst_element_change_state_func (GstElement * element, GstStateChange transition)
{
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);
@@ -2564,6 +3000,12 @@ gst_element_change_state_func (GstElement * element, GstStateChange transition)
} 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;
*
* Retrieves the factory that was used to create this element.
*
- * Returns: the #GstElementFactory used for creating this element.
- * no refcounting is needed.
+ * Returns: (transfer none): the #GstElementFactory used for creating this
+ * element. no refcounting is needed.
*/
GstElementFactory *
gst_element_get_factory (GstElement * element)
static void
gst_element_dispose (GObject * object)
{
- GstElement *element = GST_ELEMENT (object);
+ GstElement *element = GST_ELEMENT_CAST (object);
GstClock **clock_p;
GstBus **bus_p;
if (GST_STATE (element) != GST_STATE_NULL)
goto not_null;
- GST_DEBUG_OBJECT (element, "removing %d pads", g_list_length (element->pads));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+ "removing %d pads", g_list_length (element->pads));
/* first we break all our links with the outside */
while (element->pads && element->pads->data) {
/* don't call _remove_pad with NULL */
gst_element_remove_pad (element, GST_PAD_CAST (element->pads->data));
}
- if (G_UNLIKELY (element->pads != 0)) {
+ if (G_UNLIKELY (element->pads != NULL)) {
g_critical ("could not remove pads from element %s",
GST_STR_NULL (GST_OBJECT_NAME (object)));
}
/* ERRORS */
not_null:
{
+ gboolean is_locked;
+
+ is_locked = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
g_critical
- ("\nTrying to dispose element %s, but it is not in the NULL state.\n"
+ ("\nTrying to dispose element %s, but it is in %s%s instead of the NULL"
+ " state.\n"
"You need to explicitly set elements to the NULL state before\n"
- "dropping the final reference, to allow them to clean up.\n",
- GST_OBJECT_NAME (element));
+ "dropping the final reference, to allow them to clean up.\n"
+ "This problem may also be caused by a refcounting bug in the\n"
+ "application or some element.\n",
+ GST_OBJECT_NAME (element),
+ gst_element_state_get_name (GST_STATE (element)),
+ is_locked ? " (locked)" : "");
return;
}
}
static void
gst_element_finalize (GObject * object)
{
- GstElement *element = GST_ELEMENT (object);
+ GstElement *element = GST_ELEMENT_CAST (object);
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize");
element->state_cond = NULL;
GST_STATE_UNLOCK (element);
g_static_rec_mutex_free (element->state_lock);
- g_free (element->state_lock);
+ g_slice_free (GStaticRecMutex, element->state_lock);
element->state_lock = NULL;
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize parent");
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-#ifndef GST_DISABLE_LOADSAVE
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
/**
* gst_element_save_thyself:
* @element: a #GstElement to save.
g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
- element = GST_ELEMENT (object);
+ element = GST_ELEMENT_CAST (object);
oclass = GST_ELEMENT_GET_CLASS (element);
xmlNodePtr param;
char *contents;
- g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (spec));
+ g_value_init (&value, spec->value_type);
g_object_get_property (G_OBJECT (element), spec->name, &value);
param = xmlNewChild (parent, NULL, (xmlChar *) "param", NULL);
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);
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);
/* figure out if it's a direct pad or a ghostpad */
- if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
+ if (GST_ELEMENT_CAST (GST_OBJECT_PARENT (pad)) == element) {
xmlNodePtr padtag = xmlNewChild (parent, NULL, (xmlChar *) "pad", NULL);
gst_object_save_thyself (GST_OBJECT_CAST (pad), padtag);
}
- pads = g_list_next (pads);
+ pads = g_list_previous (pads);
}
return parent;
gchar *name = NULL;
gchar *value = NULL;
- element = GST_ELEMENT (object);
+ element = GST_ELEMENT_CAST (object);
g_return_if_fail (element != NULL);
/* parameters */
/**
* gst_element_set_bus:
* @element: a #GstElement to set the bus of.
- * @bus: the #GstBus to set.
+ * @bus: (transfer 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.
* gst_element_get_bus:
* @element: a #GstElement to get the bus of.
*
- * Returns the bus of the element.
+ * Returns the bus of the element. Note that only a #GstPipeline will provide a
+ * bus for the application.
*
- * Returns: the element's #GstBus. unref after usage.
+ * Returns: (transfer full): the element's #GstBus. unref after usage.
*
* MT safe.
*/
gst_object_ref (result);
GST_OBJECT_UNLOCK (element);
- GST_DEBUG_OBJECT (element, "got bus %" GST_PTR_FORMAT, result);
+ GST_CAT_DEBUG_OBJECT (GST_CAT_BUS, element, "got bus %" GST_PTR_FORMAT,
+ result);
return result;
}