* </para>
* </refsect2>
*
- * Last reviewed on 2006-04-28 (0.10.6)
+ * Last reviewed on 2012-03-28 (0.11.3)
*/
#include "gst_private.h"
#include "gstevent.h"
#include "gstbin.h"
-#include "gstmarshal.h"
-#include "gstxml.h"
#include "gstinfo.h"
#include "gsterror.h"
-#include "gstindex.h"
-#include "gstindexfactory.h"
#include "gstutils.h"
#include "gstchildproxy.h"
-#ifdef GST_DISABLE_DEPRECATED
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
-#undef GstXmlNodePtr
-#define GstXmlNodePtr xmlNodePtr
-#include <libxml/parser.h>
-GstXmlNodePtr gst_object_save_thyself (GstObject * object,
- GstXmlNodePtr parent);
-void gst_object_restore_thyself (GstObject * object, GstXmlNodePtr parent);
-GstElement *gst_xml_make_element (xmlNodePtr cur, GstObject * parent);
-#endif
-#endif
-
-/* enable for DURATION caching.
- * FIXME currently too many elements don't update
- * their duration when it changes so we return inaccurate values. */
-#undef DURATION_CACHING
-
-/* latency is by default enabled now.
- * live-preroll and no-live-preroll in the environment var GST_COMPAT
- * to enables or disable it respectively.
- */
-static gboolean enable_latency = TRUE;
-
GST_DEBUG_CATEGORY_STATIC (bin_debug);
#define GST_CAT_DEFAULT bin_debug
guint32 structure_cookie;
+#if 0
/* cached index */
GstIndex *index;
+#endif
+
/* forward messages from our children */
gboolean message_forward;
static GstStateChangeReturn gst_bin_get_state_func (GstElement * element,
GstState * state, GstState * pending, GstClockTime timeout);
static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
- gboolean flag_pending);
-static void bin_handle_async_start (GstBin * bin, gboolean new_base_time);
+ gboolean flag_pending, GstClockTime running_time);
+static void bin_handle_async_start (GstBin * bin);
static void bin_push_state_continue (BinContinueData * data);
static void bin_do_eos (GstBin * bin);
static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
+#if 0
static void gst_bin_set_index_func (GstElement * element, GstIndex * index);
static GstIndex *gst_bin_get_index_func (GstElement * element);
+#endif
static GstClock *gst_bin_provide_clock_func (GstElement * element);
static gboolean gst_bin_set_clock_func (GstElement * element, GstClock * clock);
static gboolean gst_bin_do_latency_func (GstBin * bin);
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
-static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
-static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
-#endif
-
static void bin_remove_messages (GstBin * bin, GstObject * src,
GstMessageType types);
static void gst_bin_continue_func (BinContinueData * data);
static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
-#define _do_init(type) \
+#define _do_init \
{ \
- const gchar *compat; \
static const GInterfaceInfo iface_info = { \
gst_bin_child_proxy_init, \
NULL, \
NULL}; \
\
- g_type_add_interface_static (type, GST_TYPE_CHILD_PROXY, &iface_info); \
+ g_type_add_interface_static (g_define_type_id, GST_TYPE_CHILD_PROXY, &iface_info); \
\
GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD, \
"debugging info for the 'bin' container element"); \
\
- /* compatibility stuff */ \
- compat = g_getenv ("GST_COMPAT"); \
- if (compat != NULL) { \
- if (strstr (compat, "no-live-preroll")) \
- enable_latency = FALSE; \
- else if (strstr (compat, "live-preroll")) \
- enable_latency = TRUE; \
- } \
}
-GST_BOILERPLATE_FULL (GstBin, gst_bin, GstElement, GST_TYPE_ELEMENT, _do_init);
-
-static void
-gst_bin_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+#define gst_bin_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstBin, gst_bin, GST_TYPE_ELEMENT, _do_init);
- gst_element_class_set_details_simple (gstelement_class, "Generic bin",
- "Generic/Bin",
- "Simple container object",
- "Erik Walthinsen <omega@cse.ogi.edu>,"
- "Wim Taymans <wim.taymans@gmail.com>");
-}
-
-static GstObject *
+static GObject *
gst_bin_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
guint index)
{
gst_object_ref (res);
GST_OBJECT_UNLOCK (bin);
- return res;
+ return (GObject *) res;
}
static guint
gst_bin_class_init (GstBinClass * klass)
{
GObjectClass *gobject_class;
- GstObjectClass *gstobject_class;
GstElementClass *gstelement_class;
GError *err;
gobject_class = (GObjectClass *) klass;
- gstobject_class = (GstObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
g_type_class_add_private (klass, sizeof (GstBinPrivate));
gst_bin_signals[ELEMENT_ADDED] =
g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL,
- NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
+ NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
/**
* GstBin::element-removed:
* @bin: the #GstBin
gst_bin_signals[ELEMENT_REMOVED] =
g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
- NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
+ NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
/**
* GstBin::do-latency:
* @bin: the #GstBin
gst_bin_signals[DO_LATENCY] =
g_signal_new ("do-latency", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstBinClass, do_latency),
- _gst_boolean_accumulator, NULL, gst_marshal_BOOLEAN__VOID,
+ _gst_boolean_accumulator, NULL, g_cclosure_marshal_generic,
G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
/**
gobject_class->dispose = gst_bin_dispose;
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
- gstobject_class->save_thyself =
- ((gpointer (*)(GstObject * object,
- gpointer self)) * GST_DEBUG_FUNCPTR (gst_bin_save_thyself));
- gstobject_class->restore_thyself =
- ((void (*)(GstObject * object,
- gpointer self)) *GST_DEBUG_FUNCPTR (gst_bin_restore_thyself));
-#endif
+ gst_element_class_set_metadata (gstelement_class, "Generic bin",
+ "Generic/Bin",
+ "Simple container object",
+ "Erik Walthinsen <omega@cse.ogi.edu>,"
+ "Wim Taymans <wim.taymans@gmail.com>");
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_bin_change_state_func);
gstelement_class->state_changed = GST_DEBUG_FUNCPTR (gst_bin_state_changed);
gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state_func);
+#if 0
gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_bin_get_index_func);
gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func);
+#endif
gstelement_class->provide_clock =
GST_DEBUG_FUNCPTR (gst_bin_provide_clock_func);
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_bin_set_clock_func);
}
static void
-gst_bin_init (GstBin * bin, GstBinClass * klass)
+gst_bin_init (GstBin * bin)
{
GstBus *bus;
bin->clock_dirty = FALSE;
/* Set up a bus for listening to child elements */
- bus = gst_bus_new ();
+ bus = g_object_new (GST_TYPE_BUS, "enable-async", FALSE, NULL);
bin->child_bus = bus;
GST_DEBUG_OBJECT (bin, "using bus %" GST_PTR_FORMAT " to listen to children",
bus);
GstBus **child_bus_p = &bin->child_bus;
GstClock **provided_clock_p = &bin->provided_clock;
GstElement **clock_provider_p = &bin->clock_provider;
- GstIndex **index_p = &bin->priv->index;
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
gst_object_replace ((GstObject **) child_bus_p, NULL);
gst_object_replace ((GstObject **) provided_clock_p, NULL);
gst_object_replace ((GstObject **) clock_provider_p, NULL);
- gst_object_replace ((GstObject **) index_p, NULL);
bin_remove_messages (bin, NULL, GST_MESSAGE_ANY);
GST_OBJECT_UNLOCK (object);
*
* Creates a new bin with the given name.
*
- * Returns: (transfer full): a new #GstBin
+ * Returns: (transfer floating): a new #GstBin
*/
GstElement *
gst_bin_new (const gchar * name)
}
}
+#if 0
/* return the cached index */
static GstIndex *
gst_bin_get_index_func (GstElement * element)
gboolean done;
GstIterator *it;
GstIndex *old;
+ GValue data = { 0, };
bin = GST_BIN_CAST (element);
/* set the index on all elements in the bin */
done = FALSE;
while (!done) {
- gpointer data;
-
switch (gst_iterator_next (it, &data)) {
case GST_ITERATOR_OK:
{
- GstElement *child = GST_ELEMENT_CAST (data);
+ GstElement *child = g_value_get_object (&data);
GST_DEBUG_OBJECT (bin, "setting index on '%s'",
GST_ELEMENT_NAME (child));
gst_element_set_index (child, index);
- gst_object_unref (child);
+ g_value_reset (&data);
break;
}
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&data);
gst_iterator_free (it);
return;
return;
}
}
+#endif
/* set the clock on all elements in this bin
*
gboolean done;
GstIterator *it;
gboolean res = TRUE;
+ GValue data = { 0, };
bin = GST_BIN_CAST (element);
done = FALSE;
while (!done) {
- gpointer data;
-
switch (gst_iterator_next (it, &data)) {
case GST_ITERATOR_OK:
{
- GstElement *child = GST_ELEMENT_CAST (data);
+ GstElement *child = g_value_get_object (&data);
res &= gst_element_set_clock (child, clock);
- gst_object_unref (child);
+ g_value_reset (&data);
break;
}
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&data);
gst_iterator_free (it);
+ if (res)
+ res = GST_ELEMENT_CLASS (parent_class)->set_clock (element, clock);
+
return res;
}
GstElement *provider = NULL;
GstBin *bin;
GstIterator *it;
- gpointer val;
+ gboolean done;
+ GValue val = { 0, };
GstClock **provided_clock_p;
GstElement **clock_provider_p;
GST_DEBUG_OBJECT (bin, "finding new clock");
it = gst_bin_sort_iterator_new (bin);
+ GST_OBJECT_UNLOCK (bin);
+
+ done = FALSE;
+ while (!done) {
+ switch (gst_iterator_next (it, &val)) {
+ case GST_ITERATOR_OK:
+ {
+ GstElement *child = g_value_get_object (&val);
+ GstClock *clock;
+
+ clock = gst_element_provide_clock (child);
+ if (clock) {
+ GST_DEBUG_OBJECT (bin, "found candidate clock %p by element %s",
+ clock, GST_ELEMENT_NAME (child));
+ if (result) {
+ gst_object_unref (result);
+ gst_object_unref (provider);
+ }
+ result = clock;
+ provider = gst_object_ref (child);
+ }
- while (it->next (it, &val) == GST_ITERATOR_OK) {
- GstElement *child = GST_ELEMENT_CAST (val);
- GstClock *clock;
-
- clock = gst_element_provide_clock (child);
- if (clock) {
- GST_DEBUG_OBJECT (bin, "found candidate clock %p by element %s",
- clock, GST_ELEMENT_NAME (child));
- if (result) {
- gst_object_unref (result);
- gst_object_unref (provider);
+ g_value_reset (&val);
+ break;
}
- result = clock;
- provider = child;
- } else {
- gst_object_unref (child);
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (it);
+ break;
+ default:
+ case GST_ITERATOR_DONE:
+ done = TRUE;
+ break;
}
}
+ g_value_unset (&val);
+ gst_iterator_free (it);
+
+ GST_OBJECT_LOCK (bin);
+ if (!bin->clock_dirty) {
+ if (provider)
+ gst_object_unref (provider);
+ if (result)
+ gst_object_unref (result);
+ result = NULL;
+
+ goto not_dirty;
+ }
provided_clock_p = &bin->provided_clock;
clock_provider_p = &bin->clock_provider;
gst_object_unref (provider);
GST_OBJECT_UNLOCK (bin);
- gst_iterator_free (it);
-
return result;
not_dirty:
}
static void
-unlink_pads (GstPad * pad)
+unlink_pads (const GValue * item, gpointer user_data)
{
+ GstPad *pad;
GstPad *peer;
+ pad = g_value_get_object (item);
+
if ((peer = gst_pad_get_peer (pad))) {
if (gst_pad_get_direction (pad) == GST_PAD_SRC)
gst_pad_unlink (pad, peer);
gst_pad_unlink (peer, pad);
gst_object_unref (peer);
}
- gst_object_unref (pad);
}
/* vmethod that adds an element to a bin
{
gchar *elem_name;
GstIterator *it;
- gboolean is_sink, is_source;
+ gboolean is_sink, is_source, provides_clock, requires_clock;
GstMessage *clock_message = NULL, *async_message = NULL;
GstStateChangeReturn ret;
/* get the element name to make sure it is unique in this bin. */
GST_OBJECT_LOCK (element);
elem_name = g_strdup (GST_ELEMENT_NAME (element));
- is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
- is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SOURCE);
+ is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK);
+ is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE);
+ provides_clock =
+ GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+ requires_clock =
+ GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
GST_OBJECT_UNLOCK (element);
GST_OBJECT_LOCK (bin);
if (is_sink) {
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "element \"%s\" was sink",
elem_name);
- GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SINK);
+ GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SINK);
}
if (is_source) {
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "element \"%s\" was source",
elem_name);
- GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SOURCE);
+ GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SOURCE);
}
- if (gst_element_provides_clock (element)) {
+ if (provides_clock) {
GST_DEBUG_OBJECT (bin, "element \"%s\" can provide a clock", elem_name);
clock_message =
gst_message_new_clock_provide (GST_OBJECT_CAST (element), NULL, TRUE);
+ GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+ }
+ if (requires_clock) {
+ GST_DEBUG_OBJECT (bin, "element \"%s\" requires a clock", elem_name);
+ GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
}
bin->children = g_list_prepend (bin->children, element);
* that is not important right now. When the pipeline goes to PLAYING,
* a new clock will be selected */
gst_element_set_clock (element, GST_ELEMENT_CLOCK (bin));
+
+#if 0
/* set the cached index on the children */
if (bin->priv->index)
gst_element_set_index (element, bin->priv->index);
+#endif
ret = GST_STATE_RETURN (bin);
/* no need to update the state if we are in error */
{
/* create message to track this aync element when it posts an async-done
* message */
- async_message =
- gst_message_new_async_start (GST_OBJECT_CAST (element), FALSE);
+ async_message = gst_message_new_async_start (GST_OBJECT_CAST (element));
break;
}
case GST_STATE_CHANGE_NO_PREROLL:
/* ignore all async elements we might have and commit our state */
- bin_handle_async_done (bin, ret, FALSE);
+ bin_handle_async_done (bin, ret, FALSE, GST_CLOCK_TIME_NONE);
break;
case GST_STATE_CHANGE_FAILURE:
break;
/* unlink all linked pads */
it = gst_element_iterate_pads (element);
- gst_iterator_foreach (it, (GFunc) unlink_pads, element);
+ gst_iterator_foreach (it, (GstIteratorForeachFunction) unlink_pads, NULL);
gst_iterator_free (it);
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
elem_name);
- g_free (elem_name);
g_signal_emit (bin, gst_bin_signals[ELEMENT_ADDED], 0, element);
- gst_child_proxy_child_added ((GstObject *) bin, (GstObject *) element);
+ gst_child_proxy_child_added ((GstChildProxy *) bin, (GObject *) element,
+ elem_name);
+
+ g_free (elem_name);
return TRUE;
{
gchar *elem_name;
GstIterator *it;
- gboolean is_sink, is_source, othersink, othersource, found;
+ gboolean is_sink, is_source, provides_clock, requires_clock;
+ gboolean othersink, othersource, otherprovider, otherrequirer, found;
GstMessage *clock_message = NULL;
GstClock **provided_clock_p;
GstElement **clock_provider_p;
GST_DEBUG_OBJECT (bin, "element :%s", GST_ELEMENT_NAME (element));
+ GST_OBJECT_LOCK (bin);
+
GST_OBJECT_LOCK (element);
- /* Check if the element is already being removed and immediately
- * return */
- if (G_UNLIKELY (GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_UNPARENTING)))
- goto already_removing;
+ elem_name = g_strdup (GST_ELEMENT_NAME (element));
+
+ if (GST_OBJECT_PARENT (element) != GST_OBJECT_CAST (bin))
+ goto not_in_bin;
+
+ /* remove the parent ref */
+ GST_OBJECT_PARENT (element) = NULL;
- GST_OBJECT_FLAG_SET (element, GST_ELEMENT_UNPARENTING);
/* grab element name so we can print it */
- elem_name = g_strdup (GST_ELEMENT_NAME (element));
- is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
- is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SOURCE);
+ is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK);
+ is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE);
+ provides_clock =
+ GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+ requires_clock =
+ GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
GST_OBJECT_UNLOCK (element);
- /* unlink all linked pads */
- it = gst_element_iterate_pads (element);
- gst_iterator_foreach (it, (GFunc) unlink_pads, element);
- gst_iterator_free (it);
-
- GST_OBJECT_LOCK (bin);
found = FALSE;
othersink = FALSE;
othersource = FALSE;
+ otherprovider = FALSE;
+ otherrequirer = FALSE;
have_no_preroll = FALSE;
/* iterate the elements, we collect which ones are async and no_preroll. We
* also remove the element when we find it. */
/* remove the element */
bin->children = g_list_delete_link (bin->children, walk);
} else {
- gboolean child_sink, child_source;
+ gboolean child_sink, child_source, child_provider, child_requirer;
GST_OBJECT_LOCK (child);
- child_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK);
- child_source = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SOURCE);
+ child_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SINK);
+ child_source = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE);
+ child_provider =
+ GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+ child_requirer =
+ GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
/* when we remove a sink, check if there are other sinks. */
if (is_sink && !othersink && child_sink)
othersink = TRUE;
if (is_source && !othersource && child_source)
othersource = TRUE;
+ if (provides_clock && !otherprovider && child_provider)
+ otherprovider = TRUE;
+ if (requires_clock && !otherrequirer && child_requirer)
+ otherrequirer = TRUE;
/* check if we have NO_PREROLL children */
if (GST_STATE_RETURN (child) == GST_STATE_CHANGE_NO_PREROLL)
have_no_preroll = TRUE;
if (is_sink && !othersink) {
/* we're not a sink anymore */
GST_DEBUG_OBJECT (bin, "we removed the last sink");
- GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK);
+ GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_SINK);
}
if (is_source && !othersource) {
/* we're not a source anymore */
GST_DEBUG_OBJECT (bin, "we removed the last source");
- GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SOURCE);
+ GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_SOURCE);
+ }
+ if (provides_clock && !otherprovider) {
+ /* we're not a clock provider anymore */
+ GST_DEBUG_OBJECT (bin, "we removed the last clock provider");
+ GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+ }
+ if (requires_clock && !otherrequirer) {
+ /* we're not a clock requirer anymore */
+ GST_DEBUG_OBJECT (bin, "we removed the last clock requirer");
+ GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
}
-
/* if the clock provider for this element is removed, we lost
* the clock as well, we need to inform the parent of this
else
ret = GST_STATE_CHANGE_SUCCESS;
- bin_handle_async_done (bin, ret, FALSE);
+ bin_handle_async_done (bin, ret, FALSE, GST_CLOCK_TIME_NONE);
} else {
GST_DEBUG_OBJECT (bin,
"recalc state preroll: %d, other async: %d, this async %d",
GST_STATE_RETURN (bin) = ret;
}
no_state_recalc:
+ /* clear bus */
+ gst_element_set_bus (element, NULL);
+ /* Clear the clock we provided to the element */
+ gst_element_set_clock (element, NULL);
GST_OBJECT_UNLOCK (bin);
if (clock_message)
gst_element_post_message (GST_ELEMENT_CAST (bin), clock_message);
+ /* unlink all linked pads */
+ it = gst_element_iterate_pads (element);
+ gst_iterator_foreach (it, (GstIteratorForeachFunction) unlink_pads, NULL);
+ gst_iterator_free (it);
+
GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
elem_name);
- g_free (elem_name);
-
- gst_element_set_bus (element, NULL);
-
- /* Clear the clock we provided to the element */
- gst_element_set_clock (element, NULL);
-
- /* we ref here because after the _unparent() the element can be disposed
- * and we still need it to reset the UNPARENTING flag and fire a signal. */
- gst_object_ref (element);
- gst_object_unparent (GST_OBJECT_CAST (element));
-
- GST_OBJECT_LOCK (element);
- GST_OBJECT_FLAG_UNSET (element, GST_ELEMENT_UNPARENTING);
- GST_OBJECT_UNLOCK (element);
g_signal_emit (bin, gst_bin_signals[ELEMENT_REMOVED], 0, element);
- gst_child_proxy_child_removed ((GstObject *) bin, (GstObject *) element);
+ gst_child_proxy_child_removed ((GstChildProxy *) bin, (GObject *) element,
+ elem_name);
+ g_free (elem_name);
/* element is really out of our control now */
gst_object_unref (element);
{
g_warning ("Element '%s' is not in bin '%s'", elem_name,
GST_ELEMENT_NAME (bin));
+ GST_OBJECT_UNLOCK (element);
GST_OBJECT_UNLOCK (bin);
g_free (elem_name);
return FALSE;
}
-already_removing:
- {
- GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "already removing child");
- GST_OBJECT_UNLOCK (element);
- return FALSE;
- }
}
/**
}
}
-static GstIteratorItem
-iterate_child (GstIterator * it, GstElement * child)
-{
- gst_object_ref (child);
- return GST_ITERATOR_ITEM_PASS;
-}
-
/**
* gst_bin_iterate_elements:
* @bin: a #GstBin
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
GST_OBJECT_LOCK (bin);
- /* add ref because the iterator refs the bin. When the iterator
- * is freed it will unref the bin again using the provided dispose
- * function. */
- gst_object_ref (bin);
result = gst_iterator_new_list (GST_TYPE_ELEMENT,
GST_OBJECT_GET_LOCK (bin),
- &bin->children_cookie,
- &bin->children,
- bin,
- (GstIteratorItemFunction) iterate_child,
- (GstIteratorDisposeFunction) gst_object_unref);
+ &bin->children_cookie, &bin->children, (GObject *) bin, NULL);
GST_OBJECT_UNLOCK (bin);
return result;
}
static GstIteratorItem
-iterate_child_recurse (GstIterator * it, GstElement * child)
+iterate_child_recurse (GstIterator * it, const GValue * item)
{
- gst_object_ref (child);
+ GstElement *child = g_value_get_object (item);
+
if (GST_IS_BIN (child)) {
GstIterator *other = gst_bin_iterate_recurse (GST_BIN_CAST (child));
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
GST_OBJECT_LOCK (bin);
- /* add ref because the iterator refs the bin. When the iterator
- * is freed it will unref the bin again using the provided dispose
- * function. */
- gst_object_ref (bin);
result = gst_iterator_new_list (GST_TYPE_ELEMENT,
GST_OBJECT_GET_LOCK (bin),
&bin->children_cookie,
&bin->children,
- bin,
- (GstIteratorItemFunction) iterate_child_recurse,
- (GstIteratorDisposeFunction) gst_object_unref);
+ (GObject *) bin, (GstIteratorItemFunction) iterate_child_recurse);
GST_OBJECT_UNLOCK (bin);
return result;
/* we lock the child here for the remainder of the function to
* get its name and flag safely. */
GST_OBJECT_LOCK (child);
- is_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK);
+ is_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SINK);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
"child %s %s sink", GST_OBJECT_NAME (child), is_sink ? "is" : "is not");
}
static gint
-sink_iterator_filter (GstElement * child, GstBin * bin)
+sink_iterator_filter (const GValue * vchild, GValue * vbin)
{
- if (bin_element_is_sink (child, bin) == 0) {
- /* returns 0 because this is a GCompareFunc */
- return 0;
- } else {
- /* child carries a ref from gst_bin_iterate_elements -- drop if not passing
- through */
- gst_object_unref (child);
- return 1;
- }
+ GstBin *bin = g_value_get_object (vbin);
+ GstElement *child = g_value_get_object (vchild);
+
+ return (bin_element_is_sink (child, bin));
}
/**
* @bin: a #GstBin
*
* Gets an iterator for all elements in the bin that have the
- * #GST_ELEMENT_IS_SINK flag set.
+ * #GST_ELEMENT_FLAG_SINK flag set.
*
* Each element yielded by the iterator will have its refcount increased, so
* unref after use.
{
GstIterator *children;
GstIterator *result;
+ GValue vbin = { 0, };
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
+ g_value_init (&vbin, GST_TYPE_BIN);
+ g_value_set_object (&vbin, bin);
+
children = gst_bin_iterate_elements (bin);
result = gst_iterator_filter (children,
- (GCompareFunc) sink_iterator_filter, bin);
+ (GCompareFunc) sink_iterator_filter, &vbin);
+
+ g_value_unset (&vbin);
return result;
}
/* we lock the child here for the remainder of the function to
* get its name and other info safely. */
GST_OBJECT_LOCK (child);
- is_src = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SOURCE);
+ is_src = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
"child %s %s src", GST_OBJECT_NAME (child), is_src ? "is" : "is not");
}
static gint
-src_iterator_filter (GstElement * child, GstBin * bin)
+src_iterator_filter (const GValue * vchild, GValue * vbin)
{
- if (bin_element_is_src (child, bin) == 0) {
- /* returns 0 because this is a GCompareFunc */
- return 0;
- } else {
- /* child carries a ref from gst_bin_iterate_elements -- drop if not passing
- through */
- gst_object_unref (child);
- return 1;
- }
+ GstBin *bin = g_value_get_object (vbin);
+ GstElement *child = g_value_get_object (vchild);
+
+ return (bin_element_is_src (child, bin));
}
/**
* @bin: a #GstBin
*
* Gets an iterator for all elements in the bin that have the
- * #GST_ELEMENT_IS_SOURCE flag set.
+ * #GST_ELEMENT_FLAG_SOURCE flag set.
*
* Each element yielded by the iterator will have its refcount increased, so
* unref after use.
{
GstIterator *children;
GstIterator *result;
+ GValue vbin = { 0, };
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
+ g_value_init (&vbin, GST_TYPE_BIN);
+ g_value_set_object (&vbin, bin);
+
children = gst_bin_iterate_elements (bin);
result = gst_iterator_filter (children,
- (GCompareFunc) src_iterator_filter, bin);
+ (GCompareFunc) src_iterator_filter, &vbin);
+
+ g_value_unset (&vbin);
return result;
}
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "getting state");
- ret = parent_class->get_state (element, state, pending, timeout);
+ ret =
+ GST_ELEMENT_CLASS (parent_class)->get_state (element, state, pending,
+ timeout);
return ret;
}
typedef struct _GstBinSortIterator
{
GstIterator it;
- GQueue *queue; /* elements queued for state change */
+ GQueue queue; /* elements queued for state change */
GstBin *bin; /* bin we iterate */
gint mode; /* adding or removing dependency */
GstElement *best; /* next element with least dependencies */
gboolean dirty; /* we detected structure change */
} GstBinSortIterator;
+static void
+gst_bin_sort_iterator_copy (const GstBinSortIterator * it,
+ GstBinSortIterator * copy)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ copy->queue = it->queue;
+ g_queue_foreach (©->queue, (GFunc) gst_object_ref, NULL);
+
+ copy->bin = gst_object_ref (it->bin);
+ if (it->best)
+ copy->best = gst_object_ref (it->best);
+
+ copy->hash = g_hash_table_new (NULL, NULL);
+ g_hash_table_iter_init (&iter, it->hash);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ g_hash_table_insert (copy->hash, key, value);
+}
+
/* we add and subtract 1 to make sure we don't confuse NULL and 0 */
#define HASH_SET_DEGREE(bit, elem, deg) \
g_hash_table_replace (bit->hash, elem, GINT_TO_POINTER(deg+1))
GST_DEBUG_OBJECT (bit->bin, "adding '%s' to queue",
GST_ELEMENT_NAME (element));
gst_object_ref (element);
- g_queue_push_tail (bit->queue, element);
+ g_queue_push_tail (&bit->queue, element);
HASH_SET_DEGREE (bit, element, -1);
}
{
GList *find;
- if ((find = g_queue_find (bit->queue, element))) {
+ if ((find = g_queue_find (&bit->queue, element))) {
GST_DEBUG_OBJECT (bit->bin, "removing '%s' from queue",
GST_ELEMENT_NAME (element));
- g_queue_delete_link (bit->queue, find);
+ g_queue_delete_link (&bit->queue, find);
gst_object_unref (element);
} else {
GST_DEBUG_OBJECT (bit->bin, "unable to remove '%s' from queue",
/* sinks are added right away */
GST_OBJECT_LOCK (element);
- is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
+ is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK);
GST_OBJECT_UNLOCK (element);
if (is_sink) {
/* get next element in iterator. the returned element has the
* refcount increased */
static GstIteratorResult
-gst_bin_sort_iterator_next (GstBinSortIterator * bit, gpointer * result)
+gst_bin_sort_iterator_next (GstBinSortIterator * bit, GValue * result)
{
+ GstElement *best;
GstBin *bin = bit->bin;
/* empty queue, we have to find a next best element */
- if (g_queue_is_empty (bit->queue)) {
- GstElement *best;
-
+ if (g_queue_is_empty (&bit->queue)) {
bit->best = NULL;
bit->best_deg = G_MAXINT;
g_list_foreach (bin->children, (GFunc) find_element, bit);
/* best unhandled element, schedule as next element */
GST_DEBUG_OBJECT (bin, "queue empty, next best: %s",
GST_ELEMENT_NAME (best));
- gst_object_ref (best);
HASH_SET_DEGREE (bit, best, -1);
- *result = best;
+ g_value_set_object (result, best);
} else {
GST_DEBUG_OBJECT (bin, "queue empty, elements exhausted");
/* no more unhandled elements, we are done */
}
} else {
/* everything added to the queue got reffed */
- *result = g_queue_pop_head (bit->queue);
+ best = g_queue_pop_head (&bit->queue);
+ g_value_set_object (result, best);
+ gst_object_unref (best);
}
- GST_DEBUG_OBJECT (bin, "queue head gives %s", GST_ELEMENT_NAME (*result));
+ GST_DEBUG_OBJECT (bin, "queue head gives %s", GST_ELEMENT_NAME (best));
/* update degrees of linked elements */
- update_degree (GST_ELEMENT_CAST (*result), bit);
+ update_degree (best, bit);
return GST_ITERATOR_OK;
}
GST_DEBUG_OBJECT (bin, "resync");
bit->dirty = FALSE;
- clear_queue (bit->queue);
+ clear_queue (&bit->queue);
/* reset degrees */
g_list_foreach (bin->children, (GFunc) reset_degree, bit);
/* calc degrees, incrementing */
GstBin *bin = bit->bin;
GST_DEBUG_OBJECT (bin, "free");
- clear_queue (bit->queue);
- g_queue_free (bit->queue);
+ clear_queue (&bit->queue);
g_hash_table_destroy (bit->hash);
gst_object_unref (bin);
- g_free (bit);
}
/* should be called with the bin LOCK held */
GST_TYPE_ELEMENT,
GST_OBJECT_GET_LOCK (bin),
&bin->priv->structure_cookie,
+ (GstIteratorCopyFunction) gst_bin_sort_iterator_copy,
(GstIteratorNextFunction) gst_bin_sort_iterator_next,
(GstIteratorItemFunction) NULL,
(GstIteratorResyncFunction) gst_bin_sort_iterator_resync,
(GstIteratorFreeFunction) gst_bin_sort_iterator_free);
- result->queue = g_queue_new ();
+ g_queue_init (&result->queue);
result->hash = g_hash_table_new (NULL, NULL);
gst_object_ref (bin);
result->bin = bin;
GstState next)
{
GstStateChangeReturn ret;
- GstState pending, child_current, child_pending;
+ GstState child_current, child_pending;
gboolean locked;
GList *found;
GST_ELEMENT_START_TIME (element) = start_time;
element->base_time = base_time;
/* peel off the locked flag */
- locked = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
+ locked = GST_ELEMENT_IS_LOCKED_STATE (element);
/* Get the previous set_state result to preserve NO_PREROLL and ASYNC */
ret = GST_STATE_RETURN (element);
child_current = GST_STATE (element);
goto no_preroll;
}
- GST_OBJECT_LOCK (bin);
- pending = GST_STATE_PENDING (bin);
+ GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+ "current %s pending %s, desired next %s",
+ gst_element_state_get_name (child_current),
+ gst_element_state_get_name (child_pending),
+ gst_element_state_get_name (next));
+
+ /* always recurse into bins so that we can set the base time */
+ if (GST_IS_BIN (element))
+ goto do_state;
/* Try not to change the state of elements that are already in the state we're
* going to */
- if (!(next == GST_STATE_PLAYING || child_pending != GST_STATE_VOID_PENDING ||
- (child_pending == GST_STATE_VOID_PENDING &&
- ((pending > child_current && next > child_current) ||
- (pending < child_current && next < child_current)))))
+ if (child_current == next && child_pending == GST_STATE_VOID_PENDING) {
+ /* child is already at the requested state, return previous return. Note that
+ * if the child has a pending state to next, we will still call the
+ * set_state function */
goto unneeded;
+ } else if (next > current) {
+ /* upward state change */
+ if (child_pending == GST_STATE_VOID_PENDING) {
+ /* .. and the child is not busy doing anything */
+ if (child_current > next) {
+ /* .. and is already past the requested state, assume it got there
+ * without error */
+ ret = GST_STATE_CHANGE_SUCCESS;
+ goto unneeded;
+ }
+ } else if (child_pending > child_current) {
+ /* .. and the child is busy going upwards */
+ if (child_current >= next) {
+ /* .. and is already past the requested state, assume it got there
+ * without error */
+ ret = GST_STATE_CHANGE_SUCCESS;
+ goto unneeded;
+ }
+ } else {
+ /* .. and the child is busy going downwards */
+ if (child_current > next) {
+ /* .. and is already past the requested state, assume it got there
+ * without error */
+ ret = GST_STATE_CHANGE_SUCCESS;
+ goto unneeded;
+ }
+ }
+ } else if (next < current) {
+ /* downward state change */
+ if (child_pending == GST_STATE_VOID_PENDING) {
+ /* .. and the child is not busy doing anything */
+ if (child_current < next) {
+ /* .. and is already past the requested state, assume it got there
+ * without error */
+ ret = GST_STATE_CHANGE_SUCCESS;
+ goto unneeded;
+ }
+ } else if (child_pending < child_current) {
+ /* .. and the child is busy going downwards */
+ if (child_current <= next) {
+ /* .. and is already past the requested state, assume it got there
+ * without error */
+ ret = GST_STATE_CHANGE_SUCCESS;
+ goto unneeded;
+ }
+ } else {
+ /* .. and the child is busy going upwards */
+ if (child_current < next) {
+ /* .. and is already past the requested state, assume it got there
+ * without error */
+ ret = GST_STATE_CHANGE_SUCCESS;
+ goto unneeded;
+ }
+ }
+ }
+do_state:
+ GST_OBJECT_LOCK (bin);
/* the element was busy with an upwards async state change, we must wait for
* an ASYNC_DONE message before we attemp to change the state. */
if ((found =
if (next > current) {
/* We found an async element check if we can force its state to change or
* if we have to wait for it to preroll. */
- if (G_UNLIKELY (!enable_latency)) {
- g_warning ("Future versions of GStreamer will wait for element \"%s\"\n"
- "\tto preroll in order to perform correct latency calculations.\n"
- "\tPlease verify that the application continues to work correctly by\n"
- "\tsetting the environment variable GST_COMPAT to a value containing\n"
- "\tthe string 'live-preroll'.", GST_ELEMENT_NAME (element));
- goto no_latency;
- }
goto was_busy;
}
}
-no_latency:
GST_OBJECT_UNLOCK (bin);
no_preroll:
GST_STATE_UNLOCK (element);
return ret;
}
-was_busy:
- {
- GST_DEBUG_OBJECT (element, "element was busy, delaying state change");
- GST_OBJECT_UNLOCK (bin);
- GST_STATE_UNLOCK (element);
- return GST_STATE_CHANGE_ASYNC;
- }
unneeded:
{
GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
- "skipping transition from %s to %s, since bin pending"
- " is %s : last change state return follows",
+ "skipping transition from %s to %s",
gst_element_state_get_name (child_current),
- gst_element_state_get_name (next),
- gst_element_state_get_name (pending));
- GST_OBJECT_UNLOCK (bin);
+ gst_element_state_get_name (next));
GST_STATE_UNLOCK (element);
return ret;
}
+was_busy:
+ {
+ GST_DEBUG_OBJECT (element, "element was busy, delaying state change");
+ GST_OBJECT_UNLOCK (bin);
+ GST_STATE_UNLOCK (element);
+ return GST_STATE_CHANGE_ASYNC;
+ }
}
/* gst_iterator_fold functions for pads_activate
* Stop the iterator if activating one pad failed. */
static gboolean
-activate_pads (GstPad * pad, GValue * ret, gboolean * active)
+activate_pads (const GValue * vpad, GValue * ret, gboolean * active)
{
+ GstPad *pad = g_value_get_object (vpad);
gboolean cont = TRUE;
if (!(cont = gst_pad_set_active (pad, *active)))
g_value_set_boolean (ret, FALSE);
- else if (!*active)
- gst_pad_set_caps (pad, NULL);
- /* unref the object that was reffed for us by _fold */
- gst_object_unref (pad);
return cont;
}
GstClockTime base_time, start_time;
GstIterator *it;
gboolean done;
+ GValue data = { 0, };
/* we don't need to take the STATE_LOCK, it is already taken */
current = (GstState) GST_STATE_TRANSITION_CURRENT (transition);
done = FALSE;
while (!done) {
- gpointer data;
-
switch (gst_iterator_next (it, &data)) {
case GST_ITERATOR_OK:
{
GstElement *child;
- child = GST_ELEMENT_CAST (data);
+ child = g_value_get_object (&data);
/* set state and base_time now */
ret = gst_bin_element_set_state (bin, child, base_time, start_time,
parent = gst_object_get_parent (GST_OBJECT_CAST (child));
if (parent == GST_OBJECT_CAST (element)) {
/* element is still in bin, really error now */
- gst_object_unref (child);
gst_object_unref (parent);
goto done;
}
g_assert_not_reached ();
break;
}
- gst_object_unref (child);
+ g_value_reset (&data);
break;
}
case GST_ITERATOR_RESYNC:
}
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (G_UNLIKELY (ret == GST_STATE_CHANGE_FAILURE))
goto done;
}
done:
+ g_value_unset (&data);
gst_iterator_free (it);
GST_OBJECT_LOCK (bin);
bin_remove_messages (bin, NULL, GST_MESSAGE_ASYNC_DONE);
GST_DEBUG_OBJECT (bin, "async elements commited");
- bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE);
+ bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE,
+ GST_CLOCK_TIME_NONE);
}
state_end:
GstIterator *iter;
gboolean res = TRUE;
gboolean done = FALSE;
+ GValue data = { 0, };
if (GST_EVENT_IS_DOWNSTREAM (event)) {
iter = gst_bin_iterate_sources (bin);
}
while (!done) {
- gpointer data;
-
switch (gst_iterator_next (iter, &data)) {
case GST_ITERATOR_OK:
{
- GstElement *child;
+ GstElement *child = g_value_get_object (&data);;
gst_event_ref (event);
- child = GST_ELEMENT_CAST (data);
res &= gst_element_send_event (child, event);
- gst_object_unref (child);
+ GST_LOG_OBJECT (child, "After handling %s event: %d",
+ GST_EVENT_TYPE_NAME (event), res);
break;
}
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&data);
gst_iterator_free (iter);
gst_event_unref (event);
* This function is called with the OBJECT lock.
*/
static void
-bin_handle_async_start (GstBin * bin, gboolean new_base_time)
+bin_handle_async_start (GstBin * bin)
{
GstState old_state, new_state;
gboolean toplevel;
* are busy with a state change or when we are NO_PREROLL. */
if (!toplevel)
/* non toplevel bin, prepare async-start for the parent */
- amessage =
- gst_message_new_async_start (GST_OBJECT_CAST (bin), new_base_time);
+ amessage = gst_message_new_async_start (GST_OBJECT_CAST (bin));
if (bin->polling || GST_STATE_PENDING (bin) != GST_STATE_VOID_PENDING)
goto was_busy;
*/
static void
bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
- gboolean flag_pending)
+ gboolean flag_pending, GstClockTime running_time)
{
GstState current, pending, target;
GstStateChangeReturn old_ret;
target = GST_STATE_TARGET (bin);
pending = GST_STATE_PENDING (bin) = target;
- amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin));
+ amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin), running_time);
old_state = GST_STATE (bin);
/* this is the state we should go to next */
&& g_atomic_int_compare_and_exchange (&bin->priv->posted_eos, FALSE,
TRUE)) {
GstMessage *tmessage;
+
+ /* Clear out any further messages, and reset posted_eos so we can
+ detect any new EOS that happens (eg, after a seek). Since all
+ sinks have now posted an EOS, there will be no further EOS events
+ seen unless there is a new logical EOS */
+ GST_OBJECT_LOCK (bin);
+ bin_remove_messages (bin, NULL, GST_MESSAGE_EOS);
+ bin->priv->posted_eos = FALSE;
+ GST_OBJECT_UNLOCK (bin);
+
tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin));
gst_message_set_seqnum (tmessage, seqnum);
GST_DEBUG_OBJECT (bin,
}
case GST_MESSAGE_ASYNC_START:
{
- gboolean new_base_time;
GstState target;
GST_DEBUG_OBJECT (bin, "ASYNC_START message %p, %s", message,
src ? GST_OBJECT_NAME (src) : "(NULL)");
- gst_message_parse_async_start (message, &new_base_time);
-
GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
/* takes ownership of the message */
bin_replace_message (bin, message, GST_MESSAGE_ASYNC_START);
- bin_handle_async_start (bin, new_base_time);
+ bin_handle_async_start (bin);
GST_OBJECT_UNLOCK (bin);
break;
}
case GST_MESSAGE_ASYNC_DONE:
{
+ GstClockTime running_time;
GstState target;
GST_DEBUG_OBJECT (bin, "ASYNC_DONE message %p, %s", message,
src ? GST_OBJECT_NAME (src) : "(NULL)");
+ gst_message_parse_async_done (message, &running_time);
+
GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
* need to set the pending_done flag so that at the end of the state
* change we can see if we need to verify pending async elements, hence
* the TRUE argument here. */
- bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE);
+ bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE,
+ running_time);
} else {
GST_DEBUG_OBJECT (bin, "there are more async elements pending");
}
}
static gboolean
-bin_query_duration_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_duration_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
+ GstElement *item = g_value_get_object (vitem);
+
if (gst_element_query (item, fold->query)) {
gint64 duration;
fold->max = duration;
}
- gst_object_unref (item);
return TRUE;
}
GST_DEBUG_OBJECT (bin, "max duration %" G_GINT64_FORMAT, fold->max);
-#ifdef DURATION_CACHING
/* and cache now */
GST_OBJECT_LOCK (bin);
bin->messages = g_list_prepend (bin->messages,
gst_message_new_duration (GST_OBJECT_CAST (bin), format, fold->max));
GST_OBJECT_UNLOCK (bin);
-#endif
}
static gboolean
-bin_query_position_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_position_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
+ GstElement *item = g_value_get_object (vitem);
+
if (gst_element_query (item, fold->query)) {
gint64 position;
fold->max = position;
}
- gst_object_unref (item);
return TRUE;
}
}
static gboolean
-bin_query_latency_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_latency_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
+ GstElement *item = g_value_get_object (vitem);
+
if (gst_element_query (item, fold->query)) {
GstClockTime min, max;
gboolean live;
GST_DEBUG_OBJECT (item, "failed query");
}
- gst_object_unref (item);
return TRUE;
}
/* generic fold, return first valid result */
static gboolean
-bin_query_generic_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_generic_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
+ GstElement *item = g_value_get_object (vitem);
gboolean res;
if ((res = gst_element_query (item, fold->query))) {
GST_DEBUG_OBJECT (item, "answered query %p", fold->query);
}
- gst_object_unref (item);
-
/* and stop as soon as we have a valid result */
return !res;
}
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:
{
-#ifdef DURATION_CACHING
GList *cached;
GstFormat qformat;
}
}
GST_OBJECT_UNLOCK (bin);
-#endif
/* no cached value found, iterate and collect durations */
fold_func = (GstIteratorFoldFunction) bin_query_duration_fold;
fold_init = bin_query_min_max_init;
done:
gst_iterator_free (iter);
-#ifdef DURATION_CACHING
exit:
-#endif
GST_DEBUG_OBJECT (bin, "query %p result %d", query, res);
return res;
}
static gint
-compare_name (GstElement * element, const gchar * name)
+compare_name (const GValue * velement, const gchar * name)
{
gint eq;
+ GstElement *element = g_value_get_object (velement);
GST_OBJECT_LOCK (element);
eq = strcmp (GST_ELEMENT_NAME (element), name);
GST_OBJECT_UNLOCK (element);
- if (eq != 0) {
- gst_object_unref (element);
- }
return eq;
}
gst_bin_get_by_name (GstBin * bin, const gchar * name)
{
GstIterator *children;
- gpointer result;
+ GValue result = { 0, };
+ GstElement *element;
+ gboolean found;
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
GST_ELEMENT_NAME (bin), name);
children = gst_bin_iterate_recurse (bin);
- result = gst_iterator_find_custom (children,
- (GCompareFunc) compare_name, (gpointer) name);
+ found = gst_iterator_find_custom (children,
+ (GCompareFunc) compare_name, &result, (gpointer) name);
gst_iterator_free (children);
- return GST_ELEMENT_CAST (result);
+ if (found) {
+ element = g_value_dup_object (&result);
+ g_value_unset (&result);
+ } else {
+ element = NULL;
+ }
+
+ return element;
}
/**
}
static gint
-compare_interface (GstElement * element, gpointer interface)
+compare_interface (const GValue * velement, GValue * interface)
{
- GType interface_type = (GType) interface;
+ GstElement *element = g_value_get_object (velement);
+ GType interface_type = (GType) g_value_get_pointer (interface);
gint ret;
if (G_TYPE_CHECK_INSTANCE_TYPE (element, interface_type)) {
ret = 0;
} else {
- /* we did not find the element, need to release the ref
- * added by the iterator */
- gst_object_unref (element);
ret = 1;
}
return ret;
gst_bin_get_by_interface (GstBin * bin, GType iface)
{
GstIterator *children;
- gpointer result;
+ GValue result = { 0, };
+ GstElement *element;
+ gboolean found;
+ GValue viface = { 0, };
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface), NULL);
+ g_value_init (&viface, G_TYPE_POINTER);
+ g_value_set_pointer (&viface, (gpointer) iface);
+
children = gst_bin_iterate_recurse (bin);
- result = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
- (gpointer) iface);
+ found = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
+ &result, &viface);
gst_iterator_free (children);
- return GST_ELEMENT_CAST (result);
+ if (found) {
+ element = g_value_dup_object (&result);
+ g_value_unset (&result);
+ } else {
+ element = NULL;
+ }
+ g_value_unset (&viface);
+
+ return element;
}
/**
{
GstIterator *children;
GstIterator *result;
+ GValue viface = { 0, };
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface), NULL);
+ g_value_init (&viface, G_TYPE_POINTER);
+ g_value_set_pointer (&viface, (gpointer) iface);
+
children = gst_bin_iterate_recurse (bin);
result = gst_iterator_filter (children, (GCompareFunc) compare_interface,
- (gpointer) iface);
-
- return result;
-}
-
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
-static xmlNodePtr
-gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
-{
- GstBin *bin = GST_BIN_CAST (object);
- xmlNodePtr childlist, elementnode;
- GList *children;
- GstElement *child;
-
- if (GST_OBJECT_CLASS (parent_class)->save_thyself)
- GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
+ &viface);
- childlist = xmlNewChild (parent, NULL, (xmlChar *) "children", NULL);
+ g_value_unset (&viface);
- GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
- GST_ELEMENT_NAME (bin), bin->numchildren);
-
- children = g_list_last (bin->children);
- while (children) {
- child = GST_ELEMENT_CAST (children->data);
- elementnode = xmlNewChild (childlist, NULL, (xmlChar *) "element", NULL);
- gst_object_save_thyself (GST_OBJECT (child), elementnode);
- children = g_list_previous (children);
- }
- return childlist;
-}
-
-static void
-gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
-{
- GstBin *bin = GST_BIN_CAST (object);
- xmlNodePtr field = self->xmlChildrenNode;
- xmlNodePtr childlist;
-
- while (field) {
- if (!strcmp ((char *) field->name, "children")) {
- GST_CAT_INFO (GST_CAT_XML, "[%s]: loading children",
- GST_ELEMENT_NAME (object));
- childlist = field->xmlChildrenNode;
- while (childlist) {
- if (!strcmp ((char *) childlist->name, "element")) {
- /* gst_xml_make_element will gst_bin_add() the element to ourself */
- gst_xml_make_element (childlist, GST_OBJECT (bin));
- }
- childlist = childlist->next;
- }
- }
-
- field = field->next;
- }
- if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
- (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
+ return result;
}
-#endif /* GST_DISABLE_LOADSAVE */