diff --git a/gst/gstelement.c b/gst/gstelement.c
index 20eeffae50e303f0a45d96fd2614a005d33c87c2..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 "gsterror.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 void gst_element_dispose (GObject * object);
static void gst_element_finalize (GObject * object);
-static GstStateChangeReturn gst_element_change_state (GstElement * element,
- GstStateChange transition);
static GstStateChangeReturn gst_element_change_state_func (GstElement * element,
GstStateChange transition);
static GstStateChangeReturn gst_element_get_state_func (GstElement * element,
GstState state);
static void gst_element_set_bus_func (GstElement * element, GstBus * bus);
-#ifndef GST_DISABLE_LOADSAVE
+static gboolean gst_element_default_send_event (GstElement * element,
+ GstEvent * event);
+static gboolean gst_element_default_query (GstElement * element,
+ GstQuery * query);
+
+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);
@@ -137,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,
G_STRUCT_OFFSET (GstElementClass, pad_added), NULL, NULL,
- gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
+ gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
/**
* GstElement::pad-removed:
* @gstelement: the object which received the signal
gst_element_signals[PAD_REMOVED] =
g_signal_new ("pad-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
- gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
+ gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
/**
* GstElement::no-more-pads:
* @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);
klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func);
klass->get_state = GST_DEBUG_FUNCPTR (gst_element_get_state_func);
klass->set_bus = GST_DEBUG_FUNCPTR (gst_element_set_bus_func);
+ klass->query = GST_DEBUG_FUNCPTR (gst_element_default_query);
+ klass->send_event = GST_DEBUG_FUNCPTR (gst_element_default_send_event);
klass->numpadtemplates = 0;
klass->elementfactory = NULL;
{
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_element_init (GstElement * element)
{
GST_STATE (element) = GST_STATE_NULL;
+ GST_STATE_TARGET (element) = GST_STATE_NULL;
GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING;
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.
@@ -291,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.
gst_element_add_pad (GstElement * element, GstPad * pad)
{
gchar *pad_name;
+ gboolean flushing;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
pad_name = g_strdup (GST_PAD_NAME (pad));
GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'",
GST_STR_NULL (pad_name));
+ flushing = GST_PAD_IS_FLUSHING (pad);
GST_OBJECT_UNLOCK (pad);
/* then check to see if there's already a pad by that name here */
GST_OBJECT_CAST (element))))
goto had_parent;
+ /* 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', 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_PAD_UNSET_FLUSHING (pad);
+ GST_OBJECT_UNLOCK (pad);
+ }
+
g_free (pad_name);
/* add it to the list */
/**
* 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().
* gst_element_release_request_pad() function instead.
*
* Pads are not automatically deactivated so elements should perform the needed
- * steps to deactivate the pad in case this pad is removed in the PAUSED or PLAYING
- * state. See gst_pad_set_active() for more information about deactivating pads.
+ * steps to deactivate the pad in case this pad is removed in the PAUSED or
+ * PLAYING state. See gst_pad_set_active() for more information about
+ * deactivating pads.
*
* The pad and the element should be unlocked when calling this function.
*
* 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 */
+ 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 */
- n = (gint) strtol (data, &endptr, 10);
- if (endptr && *endptr == '\0') {
+ 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;
}
}
+static gboolean
+gst_element_default_send_event (GstElement * element, GstEvent * event)
+{
+ gboolean result = FALSE;
+ GstPad *pad;
+
+ pad = GST_EVENT_IS_DOWNSTREAM (event) ?
+ gst_element_get_random_pad (element, TRUE, GST_PAD_SRC) :
+ gst_element_get_random_pad (element, TRUE, GST_PAD_SINK);
+
+ if (pad) {
+ GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
+ "pushing %s event to random %s pad %s:%s",
+ GST_EVENT_TYPE_NAME (event),
+ (GST_PAD_DIRECTION (pad) == GST_PAD_SRC ? "src" : "sink"),
+ GST_DEBUG_PAD_NAME (pad));
+
+ result = gst_pad_push_event (pad, event);
+ gst_object_unref (pad);
+ } 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.
oclass = GST_ELEMENT_GET_CLASS (element);
+ GST_STATE_LOCK (element);
if (oclass->send_event) {
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send %s event on element %s",
GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element));
result = oclass->send_event (element, event);
} else {
- GstPad *pad = GST_EVENT_IS_DOWNSTREAM (event) ?
- gst_element_get_random_pad (element, TRUE, GST_PAD_SRC) :
- gst_element_get_random_pad (element, TRUE, GST_PAD_SINK);
-
- if (pad) {
- GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
- "pushing %s event to random %s pad %s:%s",
- GST_EVENT_TYPE_NAME (event),
- (GST_PAD_DIRECTION (pad) == GST_PAD_SRC ? "src" : "sink"),
- GST_DEBUG_PAD_NAME (pad));
-
- result = gst_pad_push_event (pad, event);
- gst_object_unref (pad);
- } 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));
- }
+ result = gst_element_default_send_event (element, event);
}
+ GST_STATE_UNLOCK (element);
+
return result;
}
return result;
}
+static gboolean
+gst_element_default_query (GstElement * element, GstQuery * query)
+{
+ gboolean result = FALSE;
+ GstPad *pad;
+
+ pad = gst_element_get_random_pad (element, FALSE, GST_PAD_SRC);
+ if (pad) {
+ result = gst_pad_query (pad, query);
+
+ gst_object_unref (pad);
+ } else {
+ pad = gst_element_get_random_pad (element, TRUE, GST_PAD_SINK);
+ if (pad) {
+ GstPad *peer = gst_pad_get_peer (pad);
+
+ if (peer) {
+ result = gst_pad_query (peer, query);
+
+ gst_object_unref (peer);
+ }
+ gst_object_unref (pad);
+ }
+ }
+ return result;
+}
+
/**
* 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_NAME (element));
result = oclass->query (element, query);
} else {
- GstPad *pad = gst_element_get_random_pad (element, FALSE, GST_PAD_SRC);
-
- if (pad) {
- result = gst_pad_query (pad, query);
-
- gst_object_unref (pad);
- } else {
- pad = gst_element_get_random_pad (element, TRUE, GST_PAD_SINK);
- if (pad) {
- GstPad *peer = gst_pad_get_peer (pad);
-
- if (peer) {
- result = gst_pad_query (peer, query);
-
- gst_object_unref (peer);
- }
- gst_object_unref (pad);
- }
- }
+ result = gst_element_default_query (element, query);
}
return result;
}
/**
* 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
*
- * Post an error or warning message on the bus from inside an element.
+ * 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.
*/
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_WARNING) || (type == GST_MESSAGE_INFO));
/* check if we send the given text or the default error text */
if ((text == NULL) || (text[0] == 0)) {
sent_text);
gerror = g_error_new_literal (domain, code, sent_text);
- if (type == GST_MESSAGE_ERROR) {
- message =
- gst_message_new_error (GST_OBJECT_CAST (element), gerror, sent_debug);
- } else if (type == GST_MESSAGE_WARNING) {
- message = gst_message_new_warning (GST_OBJECT_CAST (element), gerror,
- sent_debug);
- } else {
- g_assert_not_reached ();
+ switch (type) {
+ case GST_MESSAGE_ERROR:
+ message =
+ gst_message_new_error (GST_OBJECT_CAST (element), gerror, sent_debug);
+ break;
+ case GST_MESSAGE_WARNING:
+ message = gst_message_new_warning (GST_OBJECT_CAST (element), gerror,
+ sent_debug);
+ break;
+ case GST_MESSAGE_INFO:
+ message = gst_message_new_info (GST_OBJECT_CAST (element), gerror,
+ sent_debug);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
}
gst_element_post_message (element, message);
*
* MT safe.
*
- * Returns: TRUE if the state was changed, FALSE if bad parameterss were given
+ * Returns: TRUE if the state was changed, FALSE if bad parameters were given
* or the elements state-locking needed no change.
*/
gboolean
return TRUE;
was_ok:
- GST_CAT_DEBUG (GST_CAT_STATES, "elements %s was in locked state %d",
- GST_ELEMENT_NAME (element), old);
- GST_OBJECT_UNLOCK (element);
+ {
+ GST_CAT_DEBUG (GST_CAT_STATES,
+ "elements %s was already in locked state %d",
+ GST_ELEMENT_NAME (element), old);
+ GST_OBJECT_UNLOCK (element);
- return FALSE;
+ return FALSE;
+ }
}
/**
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;
}
}
GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
GstState old_pending;
- GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "getting state");
+ GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "getting state, timeout %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (timeout));
GST_OBJECT_LOCK (element);
ret = GST_STATE_RETURN (element);
+ 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 %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 element to playing,
- * the preroll will complete and playback will start.
+ * 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
+ * element to playing, the preroll will complete and playback will start.
*
* Returns: %GST_STATE_CHANGE_SUCCESS if the element has no more pending state
* and the last state change succeeded, %GST_STATE_CHANGE_ASYNC if 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.
- * Elements that return %GST_STATE_CHANGE_ASYNC from the change_state function
- * should eventually call this method from the streaming thread to signal
- * successfull state change completion.
- *
- * If after calling this method the element still has not reached
- * the pending state, the next state change is performed.
- *
- * Returns: The result of the commit state change.
- *
- * MT safe.
+ *
+ * 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.
*/
GstStateChangeReturn
gst_element_continue_state (GstElement * element, GstStateChangeReturn ret)
{
- GstState pending;
- GstState old_ret, old_state, old_next;
- GstState current, next;
- GstMessage *message;
+ GstStateChangeReturn old_ret;
+ GstState old_state, old_next;
+ GstState current, next, pending;
GstStateChange transition;
GST_OBJECT_LOCK (element);
- old_ret = (GstState) GST_STATE_RETURN (element);
+ old_ret = GST_STATE_RETURN (element);
GST_STATE_RETURN (element) = ret;
pending = GST_STATE_PENDING (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",
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING;
- GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "completed state change");
+ GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+ "completed state change to %s", gst_element_state_get_name (pending));
GST_OBJECT_UNLOCK (element);
/* 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 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.
+ *
* This is mostly used for elements that lost their preroll buffer
- * in the %GST_STATE_PAUSED state after a flush, they become %GST_STATE_PAUSED
- * again if a new preroll buffer is queued.
- * This function can only be called when the element is currently
+ * in the %GST_STATE_PAUSED or %GST_STATE_PLAYING state after a flush,
+ * they will go to their pending state again when a new preroll buffer is
+ * queued. This function can only be called when the element is currently
* not in error or an async state change.
*
- * This function can only be called with the STATE_LOCK held.
+ * This function is used internally and should normally not be called from
+ * 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 current_state;
+ 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;
- current_state = GST_STATE (element);
+ 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
+ * automatically go to PLAYING but let the parent bin(s) set us to PLAYING
+ * when we preroll. */
+ if (old_state > GST_STATE_PAUSED)
+ new_state = GST_STATE_PAUSED;
+ else
+ new_state = old_state;
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
- "lost state of %s", gst_element_state_get_name (current_state));
+ "lost state of %s to %s", gst_element_state_get_name (old_state),
+ gst_element_state_get_name (new_state));
- GST_STATE_NEXT (element) = current_state;
- GST_STATE_PENDING (element) = current_state;
+ GST_STATE (element) = new_state;
+ 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),
- current_state, current_state, current_state);
- gst_element_post_message (element, message);
+ _priv_gst_element_state_changed (element, new_state, new_state, new_state);
- /* and mark us dirty */
- message = gst_message_new_state_dirty (GST_OBJECT_CAST (element));
+ 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 */
+ /* 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. */
+ 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);
}
}
-/* with STATE_LOCK */
-static GstStateChangeReturn
+/**
+ * gst_element_change_state:
+ * @element: a #GstElement
+ * @transition: the requested transition
+ *
+ * Perform @transition on @element.
+ *
+ * This function must be called with STATE_LOCK held and is mainly used
+ * internally.
+ *
+ * Returns: the #GstStateChangeReturn of the state transition.
+ */
+GstStateChangeReturn
gst_element_change_state (GstElement * element, GstStateChange transition)
{
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_element_abort_state (element);
break;
case GST_STATE_CHANGE_ASYNC:
+ {
+ GstState target;
+
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"element will change state ASYNC");
- /* if we go upwards, we give the app a change to wait for
- * completion */
- if (current < next)
+ target = GST_STATE_TARGET (element);
+
+ if (target > GST_STATE_READY)
goto async;
/* else we just continue the state change downwards */
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
- "forcing commit state %s < %s",
- gst_element_state_get_name (current),
- gst_element_state_get_name (next));
+ "forcing commit state %s <= %s",
+ gst_element_state_get_name (target),
+ gst_element_state_get_name (GST_STATE_READY));
ret = gst_element_continue_state (element, GST_STATE_CHANGE_SUCCESS);
break;
+ }
case GST_STATE_CHANGE_SUCCESS:
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"element changed state SUCCESS");
g_critical ("%s: unknown return value %d from a state change function",
GST_ELEMENT_NAME (element), ret);
+ /* we are in error now */
ret = GST_STATE_CHANGE_FAILURE;
GST_STATE_RETURN (element) = ret;
GST_OBJECT_UNLOCK (element);
}
/* 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;
}
}
@@ -2432,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);
@@ -2468,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;
- g_return_if_fail (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING);
-
- 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;
}