X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstbin.c;h=17190fda1b0ea01b1a649e4a8803fdea54b47e8c;hb=dac5966da6a0f53d0443dfa1ac239289028c415d;hp=bcc163ec422886be1be97d29d4f46abab377904b;hpb=b3296183fcc8372c6e33b6aee8ea8fb1fd019d25;p=platform%2Fupstream%2Fgstreamer.git
diff --git a/gst/gstbin.c b/gst/gstbin.c
index bcc163e..17190fd 100644
--- a/gst/gstbin.c
+++ b/gst/gstbin.c
@@ -25,6 +25,7 @@
/**
* SECTION:gstbin
+ * @title: GstBin
* @short_description: Base class and element that can contain other elements
*
* #GstBin is an element that can contain other #GstElement, allowing them to be
@@ -55,104 +56,75 @@
* the bin. Likewise the #GstBin::element-removed signal is fired whenever an
* element is removed from the bin.
*
- * Notes
- *
+ * ## Notes
+ *
* A #GstBin internally intercepts every #GstMessage posted by its children and
* implements the following default behaviour for each of them:
- *
- *
- * GST_MESSAGE_EOS
- * This message is only posted by sinks in the PLAYING
- * state. If all sinks posted the EOS message, this bin will post and EOS
- * message upwards.
- *
- *
- * GST_MESSAGE_SEGMENT_START
- * just collected and never forwarded upwards.
- * The messages are used to decide when all elements have completed playback
- * of their segment.
- *
- *
- * GST_MESSAGE_SEGMENT_DONE
- * Is posted by #GstBin when all elements that posted
- * a SEGMENT_START have posted a SEGMENT_DONE.
- *
- *
- * GST_MESSAGE_DURATION_CHANGED
- * Is posted by an element that detected a change
- * in the stream duration. The default bin behaviour is to clear any
- * cached duration values so that the next duration query will perform
- * a full duration recalculation. The duration change is posted to the
- * application so that it can refetch the new duration with a duration
- * query. Note that these messages can be posted before the bin is
- * prerolled, in which case the duration query might fail.
- *
- *
- *
- * GST_MESSAGE_CLOCK_LOST
- * This message is posted by an element when it
- * can no longer provide a clock. The default bin behaviour is to
- * check if the lost clock was the one provided by the bin. If so and
- * the bin is currently in the PLAYING state, the message is forwarded to
- * the bin parent.
- * This message is also generated when a clock provider is removed from
- * the bin. If this message is received by the application, it should
- * PAUSE the pipeline and set it back to PLAYING to force a new clock
- * distribution.
- *
- *
- *
- * GST_MESSAGE_CLOCK_PROVIDE
- * This message is generated when an element
- * can provide a clock. This mostly happens when a new clock
- * provider is added to the bin. The default behaviour of the bin is to
- * mark the currently selected clock as dirty, which will perform a clock
- * recalculation the next time the bin is asked to provide a clock.
- * This message is never sent tot the application but is forwarded to
- * the parent of the bin.
- *
- *
- *
- * OTHERS
- * posted upwards.
- *
- *
*
+ * * GST_MESSAGE_EOS: This message is only posted by sinks in the PLAYING
+ * state. If all sinks posted the EOS message, this bin will post and EOS
+ * message upwards.
+ *
+ * * GST_MESSAGE_SEGMENT_START: Just collected and never forwarded upwards.
+ * The messages are used to decide when all elements have completed playback
+ * of their segment.
+ *
+ * * GST_MESSAGE_SEGMENT_DONE: Is posted by #GstBin when all elements that posted
+ * a SEGMENT_START have posted a SEGMENT_DONE.
+ *
+ * * GST_MESSAGE_DURATION_CHANGED: Is posted by an element that detected a change
+ * in the stream duration. The default bin behaviour is to clear any
+ * cached duration values so that the next duration query will perform
+ * a full duration recalculation. The duration change is posted to the
+ * application so that it can refetch the new duration with a duration
+ * query. Note that these messages can be posted before the bin is
+ * prerolled, in which case the duration query might fail.
+ *
+ * * GST_MESSAGE_CLOCK_LOST: This message is posted by an element when it
+ * can no longer provide a clock. The default bin behaviour is to
+ * check if the lost clock was the one provided by the bin. If so and
+ * the bin is currently in the PLAYING state, the message is forwarded to
+ * the bin parent.
+ * This message is also generated when a clock provider is removed from
+ * the bin. If this message is received by the application, it should
+ * PAUSE the pipeline and set it back to PLAYING to force a new clock
+ * distribution.
+ *
+ * * GST_MESSAGE_CLOCK_PROVIDE: This message is generated when an element
+ * can provide a clock. This mostly happens when a new clock
+ * provider is added to the bin. The default behaviour of the bin is to
+ * mark the currently selected clock as dirty, which will perform a clock
+ * recalculation the next time the bin is asked to provide a clock.
+ * This message is never sent tot the application but is forwarded to
+ * the parent of the bin.
+ *
+ * * OTHERS: posted upwards.
*
* A #GstBin implements the following default behaviour for answering to a
* #GstQuery:
- *
- *
- * GST_QUERY_DURATION
- * If the query has been asked before with the same format
- * and the bin is a toplevel bin (ie. has no parent),
- * use the cached previous value. If no previous value was cached, the
- * query is sent to all sink elements in the bin and the MAXIMUM of all
- * values is returned. If the bin is a toplevel bin the value is cached.
- * If no sinks are available in the bin, the query fails.
- *
- *
- *
- * GST_QUERY_POSITION
- * The query is sent to all sink elements in the bin and the
- * MAXIMUM of all values is returned. If no sinks are available in the bin,
- * the query fails.
- *
- *
- *
- * OTHERS
- * the query is forwarded to all sink elements, the result
- * of the first sink that answers the query successfully is returned. If no
- * sink is in the bin, the query fails.
- *
- *
*
- * A #GstBin will by default forward any event sent to it to all sink elements.
- * If all the sinks return %TRUE, the bin will also return %TRUE, else %FALSE is
- * returned. If no sinks are in the bin, the event handler will return %TRUE.
+ * * GST_QUERY_DURATION:If the query has been asked before with the same format
+ * and the bin is a toplevel bin (ie. has no parent),
+ * use the cached previous value. If no previous value was cached, the
+ * query is sent to all sink elements in the bin and the MAXIMUM of all
+ * values is returned. If the bin is a toplevel bin the value is cached.
+ * If no sinks are available in the bin, the query fails.
+ *
+ * * GST_QUERY_POSITION:The query is sent to all sink elements in the bin and the
+ * MAXIMUM of all values is returned. If no sinks are available in the bin,
+ * the query fails.
+ *
+ * * OTHERS:the query is forwarded to all sink elements, the result
+ * of the first sink that answers the query successfully is returned. If no
+ * sink is in the bin, the query fails.
+ *
+ * A #GstBin will by default forward any event sent to it to all sink
+ * (#GST_EVENT_TYPE_DOWNSTREAM) or source (#GST_EVENT_TYPE_UPSTREAM) elements
+ * depending on the event type.
+ * If all the elements return %TRUE, the bin will also return %TRUE, else %FALSE
+ * is returned. If no elements of the required type are in the bin, the event
+ * handler will return %TRUE.
*
- *
- *
*/
#include "gst_private.h"
@@ -172,9 +144,6 @@ GST_DEBUG_CATEGORY_STATIC (bin_debug);
* a toplevel bin */
#define BIN_IS_TOPLEVEL(bin) ((GST_OBJECT_PARENT (bin) == NULL) || bin->priv->asynchandling)
-#define GST_BIN_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BIN, GstBinPrivate))
-
struct _GstBinPrivate
{
gboolean asynchandling;
@@ -300,7 +269,9 @@ static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
}
#define gst_bin_parent_class parent_class
-G_DEFINE_TYPE_WITH_CODE (GstBin, gst_bin, GST_TYPE_ELEMENT, _do_init);
+G_DEFINE_TYPE_WITH_CODE (GstBin, gst_bin, GST_TYPE_ELEMENT,
+ G_ADD_PRIVATE (GstBin)
+ _do_init);
static GObject *
gst_bin_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
@@ -368,8 +339,6 @@ gst_bin_class_init (GstBinClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
- g_type_class_add_private (klass, sizeof (GstBinPrivate));
-
gobject_class->set_property = gst_bin_set_property;
gobject_class->get_property = gst_bin_get_property;
@@ -524,13 +493,14 @@ gst_bin_init (GstBin * bin)
/* Set up a bus for listening to child elements */
bus = g_object_new (GST_TYPE_BUS, "enable-async", FALSE, NULL);
+ gst_object_ref_sink (bus);
bin->child_bus = bus;
GST_DEBUG_OBJECT (bin, "using bus %" GST_PTR_FORMAT " to listen to children",
bus);
gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bin_bus_handler, bin,
NULL);
- bin->priv = GST_BIN_GET_PRIVATE (bin);
+ bin->priv = gst_bin_get_instance_private (bin);
bin->priv->asynchandling = DEFAULT_ASYNC_HANDLING;
bin->priv->structure_cookie = 0;
bin->priv->message_forward = DEFAULT_MESSAGE_FORWARD;
@@ -1152,11 +1122,15 @@ gst_bin_do_deep_add_remove (GstBin * bin, gint sig_id, const gchar * sig_name,
while ((e = g_queue_pop_head (&elements))) {
GstObject *parent = gst_object_get_parent (GST_OBJECT_CAST (e));
- GST_LOG_OBJECT (bin, "calling %s for element %" GST_PTR_FORMAT
- " in bin %" GST_PTR_FORMAT, sig_name, e, parent);
- g_signal_emit (bin, sig_id, 0, parent, e);
- gst_object_unref (parent);
- g_object_unref (e);
+ /* an element could have removed some of its internal elements
+ * meanwhile, so protect against that */
+ if (parent) {
+ GST_LOG_OBJECT (bin, "calling %s for element %" GST_PTR_FORMAT
+ " in bin %" GST_PTR_FORMAT, sig_name, e, parent);
+ g_signal_emit (bin, sig_id, 0, parent, e);
+ gst_object_unref (parent);
+ g_object_unref (e);
+ }
}
}
gst_iterator_free (it);
@@ -1331,12 +1305,14 @@ no_state_recalc:
s = (GstStructure *) gst_message_get_structure (msg);
gst_structure_get (s, "bin.old.context", GST_TYPE_CONTEXT, &context, NULL);
gst_structure_remove_field (s, "bin.old.context");
- gst_element_post_message (GST_ELEMENT_CAST (bin), msg);
+ /* Keep the msg around while we still need access to the context_type */
+ gst_element_post_message (GST_ELEMENT_CAST (bin), gst_message_ref (msg));
/* lock to avoid losing a potential write */
GST_OBJECT_LOCK (bin);
replacement =
gst_element_get_context_unlocked (GST_ELEMENT_CAST (bin), context_type);
+ gst_message_unref (msg);
if (replacement) {
/* we got the context set from GstElement::set_context */
@@ -1395,6 +1371,8 @@ adding_itself:
GST_OBJECT_LOCK (bin);
g_warning ("Cannot add bin '%s' to itself", GST_ELEMENT_NAME (bin));
GST_OBJECT_UNLOCK (bin);
+ gst_object_ref_sink (element);
+ gst_object_unref (element);
return FALSE;
}
duplicate_name:
@@ -1403,6 +1381,8 @@ duplicate_name:
elem_name, GST_ELEMENT_NAME (bin));
GST_OBJECT_UNLOCK (bin);
g_free (elem_name);
+ gst_object_ref_sink (element);
+ gst_object_unref (element);
return FALSE;
}
had_parent:
@@ -1482,7 +1462,7 @@ gst_bin_deep_element_added_func (GstBin * bin, GstBin * sub_bin,
GST_LOG_OBJECT (parent_bin, "emitting deep-element-added for element "
"%" GST_PTR_FORMAT " which has just been added to %" GST_PTR_FORMAT,
- sub_bin, child);
+ child, sub_bin);
g_signal_emit (parent_bin, gst_bin_signals[DEEP_ELEMENT_ADDED], 0, sub_bin,
child);
@@ -1516,7 +1496,7 @@ gst_bin_deep_element_removed_func (GstBin * bin, GstBin * sub_bin,
/**
* gst_bin_add:
* @bin: a #GstBin
- * @element: (transfer full): the #GstElement to add
+ * @element: (transfer floating): the #GstElement to add
*
* Adds the given element to the bin. Sets the element's parent, and thus
* takes ownership of the element. An element can only be added to one bin.
@@ -1524,13 +1504,11 @@ gst_bin_deep_element_removed_func (GstBin * bin, GstBin * sub_bin,
* If the element's pads are linked to other pads, the pads will be unlinked
* before the element is added to the bin.
*
- *
- * When you add an element to an already-running pipeline, you will have to
- * take care to set the state of the newly-added element to the desired
- * state (usually PLAYING or PAUSED, same you set the pipeline to originally)
- * with gst_element_set_state(), or use gst_element_sync_state_with_parent().
- * The bin or pipeline will not take care of this for you.
- *
+ * > When you add an element to an already-running pipeline, you will have to
+ * > take care to set the state of the newly-added element to the desired
+ * > state (usually PLAYING or PAUSED, same you set the pipeline to originally)
+ * > with gst_element_set_state(), or use gst_element_sync_state_with_parent().
+ * > The bin or pipeline will not take care of this for you.
*
* MT safe.
*
@@ -1567,6 +1545,8 @@ no_function:
{
g_warning ("adding elements to bin '%s' is not supported",
GST_ELEMENT_NAME (bin));
+ gst_object_ref_sink (element);
+ gst_object_unref (element);
return FALSE;
}
}
@@ -2343,6 +2323,12 @@ find_element (GstElement * element, GstBinSortIterator * bit)
if (bit->best == NULL || bit->best_deg > degree) {
bit->best = element;
bit->best_deg = degree;
+ } else if (bit->best_deg == degree
+ && GST_OBJECT_FLAG_IS_SET (bit->best, GST_ELEMENT_FLAG_SOURCE)
+ && !GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE)) {
+ /* If two elements have the same degree, we want to ensure we
+ * return non-source elements first. */
+ bit->best = element;
}
}
@@ -2590,7 +2576,7 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element,
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. */
+ * an ASYNC_DONE message before we attempt to change the state. */
if ((found =
find_message (bin, GST_OBJECT_CAST (element),
GST_MESSAGE_ASYNC_START))) {
@@ -3075,12 +3061,12 @@ done:
/* check if all elements managed to commit their state already */
if (!find_message (bin, NULL, GST_MESSAGE_ASYNC_START)) {
/* nothing found, remove all old ASYNC_DONE messages. This can happen when
- * all the elements commited their state while we were doing the state
+ * all the elements committed their state while we were doing the state
* change. We will still return ASYNC for consistency but we commit the
* state already so that a _get_state() will return immediately. */
bin_remove_messages (bin, NULL, GST_MESSAGE_ASYNC_DONE);
- GST_DEBUG_OBJECT (bin, "async elements commited");
+ GST_DEBUG_OBJECT (bin, "async elements committed");
bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE,
GST_CLOCK_TIME_NONE);
}
@@ -3129,13 +3115,11 @@ undo:
}
/*
- * This function is a utility event handler for seek events.
- * It will send the event to all sinks or sources and appropriate
- * ghost pads depending on the event-direction.
+ * This function is a utility event handler. It will send the event to all sinks
+ * or sources and appropriate ghost pads depending on the event-direction.
*
- * Applications are free to override this behaviour and
- * implement their own seek handler, but this will work for
- * pretty much all cases in practice.
+ * Applications are free to override this behaviour and implement their own
+ * handler, but this will work for pretty much all cases in practice.
*/
static gboolean
gst_bin_send_event (GstElement * element, GstEvent * event)
@@ -3532,12 +3516,12 @@ nothing_pending:
static void
bin_do_eos (GstBin * bin)
{
- guint32 seqnum = 0;
+ guint32 seqnum = GST_SEQNUM_INVALID;
gboolean eos;
GST_OBJECT_LOCK (bin);
/* If all sinks are EOS, we're in PLAYING and no state change is pending
- * (or we're doing playing to playing and noone else will trigger posting
+ * (or we're doing playing to playing and no one else will trigger posting
* EOS for us) we forward the EOS message to the parent bin or application
*/
eos = GST_STATE (bin) == GST_STATE_PLAYING
@@ -3561,7 +3545,8 @@ bin_do_eos (GstBin * bin)
GST_OBJECT_UNLOCK (bin);
tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin));
- gst_message_set_seqnum (tmessage, seqnum);
+ if (seqnum != GST_SEQNUM_INVALID)
+ gst_message_set_seqnum (tmessage, seqnum);
GST_DEBUG_OBJECT (bin,
"all sinks posted EOS, posting seqnum #%" G_GUINT32_FORMAT, seqnum);
gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage);
@@ -3574,7 +3559,7 @@ bin_do_eos (GstBin * bin)
static void
bin_do_stream_start (GstBin * bin)
{
- guint32 seqnum = 0;
+ guint32 seqnum = GST_SEQNUM_INVALID;
gboolean stream_start;
gboolean have_group_id = FALSE;
guint group_id = 0;
@@ -3594,7 +3579,8 @@ bin_do_stream_start (GstBin * bin)
GST_OBJECT_UNLOCK (bin);
tmessage = gst_message_new_stream_start (GST_OBJECT_CAST (bin));
- gst_message_set_seqnum (tmessage, seqnum);
+ if (seqnum != GST_SEQNUM_INVALID)
+ gst_message_set_seqnum (tmessage, seqnum);
if (have_group_id)
gst_message_set_group_id (tmessage, group_id);
@@ -3971,7 +3957,7 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
/* nothing found, remove all old ASYNC_DONE messages */
bin_remove_messages (bin, NULL, GST_MESSAGE_ASYNC_DONE);
- GST_DEBUG_OBJECT (bin, "async elements commited");
+ GST_DEBUG_OBJECT (bin, "async elements committed");
/* when we get an async done message when a state change was busy, we
* 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
@@ -4027,24 +4013,32 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
GList *l, *contexts;
gst_message_parse_context_type (message, &context_type);
- GST_OBJECT_LOCK (bin);
- contexts = GST_ELEMENT_CAST (bin)->contexts;
- GST_LOG_OBJECT (bin, "got need-context message type: %s", context_type);
- for (l = contexts; l; l = l->next) {
- GstContext *tmp = l->data;
- const gchar *tmp_type = gst_context_get_context_type (tmp);
-
- if (strcmp (context_type, tmp_type) == 0) {
- gst_element_set_context (GST_ELEMENT (src), l->data);
- break;
+
+ if (src) {
+ GST_OBJECT_LOCK (bin);
+ contexts = GST_ELEMENT_CAST (bin)->contexts;
+ GST_LOG_OBJECT (bin, "got need-context message type: %s", context_type);
+ for (l = contexts; l; l = l->next) {
+ GstContext *tmp = l->data;
+ const gchar *tmp_type = gst_context_get_context_type (tmp);
+
+ if (strcmp (context_type, tmp_type) == 0) {
+ gst_element_set_context (GST_ELEMENT (src), l->data);
+ break;
+ }
}
- }
- GST_OBJECT_UNLOCK (bin);
+ GST_OBJECT_UNLOCK (bin);
- /* Forward if we couldn't answer the message */
- if (l == NULL) {
- goto forward;
+ /* Forward if we couldn't answer the message */
+ if (l == NULL) {
+ goto forward;
+ } else {
+ gst_message_unref (message);
+ }
} else {
+ g_warning
+ ("Got need-context message in bin '%s' without source element, dropping",
+ GST_ELEMENT_NAME (bin));
gst_message_unref (message);
}
@@ -4568,7 +4562,8 @@ compare_interface (const GValue * velement, GValue * interface)
*
* MT safe. Caller owns returned reference.
*
- * Returns: (transfer full): A #GstElement inside the bin implementing the interface
+ * Returns: (transfer full) (nullable): A #GstElement inside the bin
+ * implementing the interface
*/
GstElement *
gst_bin_get_by_interface (GstBin * bin, GType iface)