Revert "element: Don't hold state lock all the time while sending an event"
[platform/upstream/gstreamer.git] / gst / gstelement.c
index 4a58a7c..6bc013d 100644 (file)
@@ -43,8 +43,7 @@
  *
  * 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_\%u".
+ * gst_element_request_pad() with a #GstPadTemplate.
  * An iterator of all pads can be retrieved with gst_element_iterate_pads().
  *
  * Elements can be linked through their pads.
@@ -75,8 +74,6 @@
  * Note that clock selection and distribution is normally handled by the
  * toplevel #GstPipeline so the clock functions are only to be used in very
  * specific situations.
- *
- * Last reviewed on 2012-03-28 (0.11.3)
  */
 
 #include "gst_private.h"
@@ -93,6 +90,7 @@
 #include "gstutils.h"
 #include "gstinfo.h"
 #include "gstquark.h"
+#include "gsttracerutils.h"
 #include "gstvalue.h"
 #include "gst-i18n-lib.h"
 #include "glib-compat-private.h"
@@ -122,6 +120,7 @@ static void gst_element_init (GstElement * element);
 static void gst_element_base_class_init (gpointer g_class);
 static void gst_element_base_class_finalize (gpointer g_class);
 
+static void gst_element_constructed (GObject * object);
 static void gst_element_dispose (GObject * object);
 static void gst_element_finalize (GObject * object);
 
@@ -136,6 +135,8 @@ static gboolean gst_element_set_clock_func (GstElement * element,
 static void gst_element_set_bus_func (GstElement * element, GstBus * bus);
 static gboolean gst_element_post_message_default (GstElement * element,
     GstMessage * message);
+static void gst_element_set_context_default (GstElement * element,
+    GstContext * context);
 
 static gboolean gst_element_default_send_event (GstElement * element,
     GstEvent * event);
@@ -232,6 +233,7 @@ gst_element_class_init (GstElementClass * klass)
 
   gobject_class->dispose = gst_element_dispose;
   gobject_class->finalize = gst_element_finalize;
+  gobject_class->constructed = gst_element_constructed;
 
   klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state_func);
   klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func);
@@ -242,6 +244,7 @@ gst_element_class_init (GstElementClass * klass)
   klass->send_event = GST_DEBUG_FUNCPTR (gst_element_default_send_event);
   klass->numpadtemplates = 0;
   klass->post_message = GST_DEBUG_FUNCPTR (gst_element_post_message_default);
+  klass->set_context = GST_DEBUG_FUNCPTR (gst_element_set_context_default);
 
   klass->elementfactory = NULL;
 }
@@ -302,16 +305,23 @@ gst_element_init (GstElement * element)
   g_cond_init (&element->state_cond);
 }
 
+static void
+gst_element_constructed (GObject * object)
+{
+  GST_TRACER_ELEMENT_NEW (GST_ELEMENT_CAST (object));
+  G_OBJECT_CLASS (parent_class)->constructed (object);
+}
+
 /**
  * gst_element_release_request_pad:
  * @element: a #GstElement to release the request pad of.
  * @pad: the #GstPad to release.
  *
  * Makes the element free the previously requested pad as obtained
- * with gst_element_get_request_pad().
+ * with gst_element_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
+ * gst_element_request_pad(), gst_element_release_request_pad() needs to be
  * followed by gst_object_unref() to free the @pad.
  *
  * MT safe.
@@ -345,8 +355,8 @@ gst_element_release_request_pad (GstElement * element, GstPad * pad)
  * <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: (transfer full): the GstClock provided by the element or %NULL
- * if no clock could be provided.  Unref after usage.
+ * Returns: (transfer full) (nullable): the GstClock provided by the
+ * element or %NULL if no clock could be provided.  Unref after usage.
  *
  * MT safe.
  */
@@ -420,6 +430,9 @@ gst_element_set_clock (GstElement * element, GstClock * clock)
  * Gets the currently configured clock of the element. This is the clock as was
  * last set with gst_element_set_clock().
  *
+ * Elements in a pipeline will only have their clock set when the
+ * pipeline is in the PLAYING state.
+ *
  * Returns: (transfer full): the #GstClock of the element. unref after usage.
  *
  * MT safe.
@@ -586,8 +599,8 @@ gst_element_set_index (GstElement * element, GstIndex * index)
  *
  * Gets the index from the element.
  *
- * Returns: (transfer full): a #GstIndex or %NULL when no index was set on the
- * element. unref after usage.
+ * Returns: (transfer full) (nullable): a #GstIndex or %NULL when no
+ * index was set on the element. unref after usage.
  *
  * MT safe.
  */
@@ -634,7 +647,7 @@ gboolean
 gst_element_add_pad (GstElement * element, GstPad * pad)
 {
   gchar *pad_name;
-  gboolean flushing;
+  gboolean active;
 
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
@@ -644,7 +657,7 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
   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);
+  active = GST_PAD_IS_ACTIVE (pad);
   GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_PARENT);
   GST_OBJECT_UNLOCK (pad);
 
@@ -658,16 +671,13 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
               GST_OBJECT_CAST (element))))
     goto had_parent;
 
-  /* check for flushing pads */
-  if (flushing && (GST_STATE (element) > GST_STATE_READY ||
+  /* check for active pads */
+  if (!active && (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 "
+    g_warning ("adding inactive pad '%s' to running element '%s', you need to "
         "use gst_pad_set_active(pad,TRUE) before adding it.",
         GST_STR_NULL (pad_name), GST_ELEMENT_NAME (element));
-    /* unset flushing */
-    GST_OBJECT_LOCK (pad);
-    GST_PAD_UNSET_FLUSHING (pad);
-    GST_OBJECT_UNLOCK (pad);
+    gst_pad_set_active (pad, TRUE);
   }
 
   g_free (pad_name);
@@ -692,7 +702,7 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
 
   /* emit the PAD_ADDED signal */
   g_signal_emit (element, gst_element_signals[PAD_ADDED], 0, pad);
-
+  GST_TRACER_ELEMENT_ADD_PAD (element, pad);
   return TRUE;
 
   /* ERROR cases */
@@ -735,7 +745,7 @@ no_direction:
  *
  * This function is used by plugin developers and should not be used
  * by applications. Pads that were dynamically requested from elements
- * with gst_element_get_request_pad() should be released with the
+ * with gst_element_request_pad() should be released with the
  * gst_element_release_request_pad() function instead.
  *
  * Pads are not automatically deactivated so elements should perform the needed
@@ -804,7 +814,7 @@ gst_element_remove_pad (GstElement * element, GstPad * pad)
 
   /* emit the PAD_REMOVED signal before unparenting and losing the last ref. */
   g_signal_emit (element, gst_element_signals[PAD_REMOVED], 0, pad);
-
+  GST_TRACER_ELEMENT_REMOVE_PAD (element, pad);
   gst_object_unparent (GST_OBJECT_CAST (pad));
 
   return TRUE;
@@ -867,8 +877,8 @@ pad_compare_name (GstPad * pad1, const gchar * name)
  * Retrieves a pad from @element by name. This version only retrieves
  * already-existing (i.e. 'static') pads.
  *
- * Returns: (transfer full): the requested #GstPad if found, otherwise %NULL.
- *     unref after usage.
+ * Returns: (transfer full) (nullable): the requested #GstPad if
+ *     found, otherwise %NULL.  unref after usage.
  *
  * MT safe.
  */
@@ -951,7 +961,7 @@ _gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
     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() */
+      /* FIXME 2.0: 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);
@@ -977,11 +987,12 @@ _gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
  * retrieves request pads. The pad should be released with
  * gst_element_release_request_pad().
  *
- * This method is slow and will be deprecated in the future. New code should
- * use gst_element_request_pad() with the requested template.
+ * This method is slower than manually getting the pad template and calling
+ * gst_element_request_pad() if the pads should have a specific name (e.g.
+ * @name is "src_1" instead of "src_\%u").
  *
- * Returns: (transfer full): requested #GstPad if found, otherwise %NULL.
- *     Release after usage.
+ * Returns: (transfer full) (nullable): requested #GstPad if found,
+ *     otherwise %NULL.  Release after usage.
  */
 GstPad *
 gst_element_get_request_pad (GstElement * element, const gchar * name)
@@ -1071,7 +1082,7 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
 }
 
 /**
- * gst_element_request_pad:
+ * gst_element_request_pad: (virtual request_new_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
@@ -1085,8 +1096,8 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
  *
  * The pad should be released with gst_element_release_request_pad().
  *
- * Returns: (transfer full): requested #GstPad if found, otherwise %NULL.
- *     Release after usage.
+ * Returns: (transfer full) (nullable): requested #GstPad if found,
+ *     otherwise %NULL.  Release after usage.
  */
 GstPad *
 gst_element_request_pad (GstElement * element,
@@ -1398,8 +1409,9 @@ 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: (transfer none): the #GstPadTemplate with the given name, or %NULL
- *     if none was found. No unreferencing is necessary.
+ * Returns: (transfer none) (nullable): the #GstPadTemplate with the
+ *     given name, or %NULL if none was found. No unreferencing is
+ *     necessary.
  */
 GstPadTemplate *
 gst_element_class_get_pad_template (GstElementClass *
@@ -1506,8 +1518,8 @@ gst_element_default_send_event (GstElement * element, GstEvent * event)
   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);
+      gst_element_get_random_pad (element, TRUE, GST_PAD_SINK) :
+      gst_element_get_random_pad (element, TRUE, GST_PAD_SRC);
 
   if (pad) {
     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
@@ -1516,7 +1528,7 @@ gst_element_default_send_event (GstElement * element, GstEvent * event)
         (GST_PAD_DIRECTION (pad) == GST_PAD_SRC ? "src" : "sink"),
         GST_DEBUG_PAD_NAME (pad));
 
-    result = gst_pad_push_event (pad, event);
+    result = gst_pad_send_event (pad, event);
     gst_object_unref (pad);
   } else {
     GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "can't send %s event on element %s",
@@ -1533,7 +1545,7 @@ gst_element_default_send_event (GstElement * element, GstEvent * event)
  *
  * 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.
+ * downstream events or a random linked source pad for upstream events.
  *
  * This function takes ownership of the provided event so you should
  * gst_event_ref() it if you want to reuse the event after this call.
@@ -1559,6 +1571,8 @@ gst_element_send_event (GstElement * element, GstEvent * 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 {
+    gst_event_unref (event);
   }
   GST_STATE_UNLOCK (element);
 
@@ -1643,7 +1657,7 @@ gst_element_default_query (GstElement * element, GstQuery * query)
  *
  * Please note that some queries might need a running pipeline to work.
  *
- * Returns: TRUE if the query could be performed.
+ * Returns: %TRUE if the query could be performed.
  *
  * MT safe.
  */
@@ -1651,18 +1665,22 @@ gboolean
 gst_element_query (GstElement * element, GstQuery * query)
 {
   GstElementClass *klass;
+  gboolean res = FALSE;
 
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
   g_return_val_if_fail (query != NULL, FALSE);
 
+  GST_TRACER_ELEMENT_QUERY_PRE (element, query);
+
   klass = GST_ELEMENT_GET_CLASS (element);
   if (klass->query) {
     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send query on element %s",
         GST_ELEMENT_NAME (element));
-    return klass->query (element, query);
+    res = klass->query (element, query);
   }
 
-  return FALSE;
+  GST_TRACER_ELEMENT_QUERY_POST (element, query, res);
+  return res;
 }
 
 static gboolean
@@ -1719,25 +1737,31 @@ gboolean
 gst_element_post_message (GstElement * element, GstMessage * message)
 {
   GstElementClass *klass;
+  gboolean res = FALSE;
 
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
   g_return_val_if_fail (message != NULL, FALSE);
 
+  GST_TRACER_ELEMENT_POST_MESSAGE_PRE (element, message);
+
   klass = GST_ELEMENT_GET_CLASS (element);
   if (klass->post_message)
-    return klass->post_message (element, message);
+    res = klass->post_message (element, message);
+  else
+    gst_message_unref (message);
 
-  return FALSE;
+  GST_TRACER_ELEMENT_POST_MESSAGE_POST (element, res);
+  return res;
 }
 
 /**
  * _gst_element_error_printf:
- * @format: the printf-like format to use, or %NULL
+ * @format: (allow-none): the printf-like format to use, or %NULL
  *
  * This function is only used internally by the gst_element_error() macro.
  *
- * Returns: (transfer full): a newly allocated string, or %NULL if the format
- *     was %NULL or ""
+ * Returns: (transfer full) (nullable): a newly allocated string, or
+ *     %NULL if the format was %NULL or ""
  *
  * MT safe.
  */
@@ -1875,7 +1899,7 @@ void gst_element_message_full
  *
  * MT safe.
  *
- * Returns: TRUE, if the element's state is locked.
+ * Returns: %TRUE, if the element's state is locked.
  */
 gboolean
 gst_element_is_locked_state (GstElement * element)
@@ -1894,14 +1918,14 @@ gst_element_is_locked_state (GstElement * element)
 /**
  * gst_element_set_locked_state:
  * @element: a #GstElement
- * @locked_state: TRUE to lock the element's state
+ * @locked_state: %TRUE to lock the element's state
  *
  * Locks the state of an element, so state changes of the parent don't affect
  * this element anymore.
  *
  * MT safe.
  *
- * Returns: TRUE if the state was changed, FALSE if bad parameters were given
+ * Returns: %TRUE if the state was changed, %FALSE if bad parameters were given
  * or the elements state-locking needed no change.
  */
 gboolean
@@ -1946,9 +1970,9 @@ was_ok:
  * @element: a #GstElement.
  *
  * Tries to change the state of the element to the same as its parent.
- * If this function returns FALSE, the state of element is undefined.
+ * If this function returns %FALSE, the state of element is undefined.
  *
- * Returns: TRUE, if the element's state could be synced to the parent's state.
+ * Returns: %TRUE, if the element's state could be synced to the parent's state.
  *
  * MT safe.
  */
@@ -2597,12 +2621,16 @@ gst_element_change_state (GstElement * element, GstStateChange transition)
 
   oclass = GST_ELEMENT_GET_CLASS (element);
 
+  GST_TRACER_ELEMENT_CHANGE_STATE_PRE (element, transition);
+
   /* call the state change function so it can set the state */
   if (oclass->change_state)
     ret = (oclass->change_state) (element, transition);
   else
     ret = GST_STATE_CHANGE_FAILURE;
 
+  GST_TRACER_ELEMENT_CHANGE_STATE_POST (element, transition, ret);
+
   switch (ret) {
     case GST_STATE_CHANGE_FAILURE:
       GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
@@ -2677,15 +2705,20 @@ invalid_return:
 }
 
 /* gst_iterator_fold functions for pads_activate
- * Stop the iterator if activating one pad failed. */
+ * Stop the iterator if activating one pad failed, but only if that pad
+ * has not been removed from the element. */
 static gboolean
 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);
+  if (!gst_pad_set_active (pad, *active)) {
+    if (GST_PAD_PARENT (pad) != NULL) {
+      cont = FALSE;
+      g_value_set_boolean (ret, FALSE);
+    }
+  }
 
   return cont;
 }
@@ -2809,13 +2842,34 @@ gst_element_change_state_func (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-    case GST_STATE_CHANGE_READY_TO_NULL:
+    case GST_STATE_CHANGE_READY_TO_NULL:{
+      GList *l;
+
       /* deactivate pads in both cases, since they are activated on
          ready->paused but the element might not have made it to paused */
       if (!gst_element_pads_activate (element, FALSE)) {
         result = GST_STATE_CHANGE_FAILURE;
       }
+
+      /* Remove all non-persistent contexts */
+      GST_OBJECT_LOCK (element);
+      for (l = element->contexts; l;) {
+        GstContext *context = l->data;
+
+        if (!gst_context_is_persistent (context)) {
+          GList *next;
+
+          gst_context_unref (context);
+          next = l->next;
+          element->contexts = g_list_delete_link (element->contexts, l);
+          l = next;
+        } else {
+          l = l->next;
+        }
+      }
+      GST_OBJECT_UNLOCK (element);
       break;
+    }
     default:
       /* this will catch real but unhandled state changes;
        * can only be caused by:
@@ -2912,6 +2966,7 @@ gst_element_dispose (GObject * object)
   bus_p = &element->bus;
   gst_object_replace ((GstObject **) clock_p, NULL);
   gst_object_replace ((GstObject **) bus_p, NULL);
+  g_list_free_full (element->contexts, (GDestroyNotify) gst_context_unref);
   GST_OBJECT_UNLOCK (element);
 
   GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "parent class dispose");
@@ -3022,6 +3077,35 @@ gst_element_get_bus (GstElement * element)
   return result;
 }
 
+static void
+gst_element_set_context_default (GstElement * element, GstContext * context)
+{
+  const gchar *context_type;
+  GList *l;
+
+  GST_OBJECT_LOCK (element);
+  context_type = gst_context_get_context_type (context);
+  for (l = element->contexts; l; l = l->next) {
+    GstContext *tmp = l->data;
+    const gchar *tmp_type = gst_context_get_context_type (tmp);
+
+    /* Always store newest context but never replace
+     * a persistent one by a non-persistent one */
+    if (strcmp (context_type, tmp_type) == 0 &&
+        (gst_context_is_persistent (context) ||
+            !gst_context_is_persistent (tmp))) {
+      gst_context_replace ((GstContext **) & l->data, context);
+      break;
+    }
+  }
+  /* Not found? Add */
+  if (l == NULL) {
+    element->contexts =
+        g_list_prepend (element->contexts, gst_context_ref (context));
+  }
+  GST_OBJECT_UNLOCK (element);
+}
+
 /**
  * gst_element_set_context:
  * @element: a #GstElement to set the context of.
@@ -3047,3 +3131,95 @@ gst_element_set_context (GstElement * element, GstContext * context)
   if (oclass->set_context)
     oclass->set_context (element, context);
 }
+
+/**
+ * gst_element_get_contexts:
+ * @element: a #GstElement to set the context of.
+ *
+ * Gets the contexts set on the element.
+ *
+ * MT safe.
+ *
+ * Returns: (element-type Gst.Context) (transfer full): List of #GstContext
+ *
+ * Since: 1.8
+ */
+GList *
+gst_element_get_contexts (GstElement * element)
+{
+  GList *ret;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+
+  GST_OBJECT_LOCK (element);
+  ret = g_list_copy_deep (element->contexts, (GCopyFunc) gst_context_ref, NULL);
+  GST_OBJECT_UNLOCK (element);
+
+  return ret;
+}
+
+static gint
+_match_context_type (GstContext * c1, const gchar * context_type)
+{
+  const gchar *c1_type;
+
+  c1_type = gst_context_get_context_type (c1);
+
+  return g_strcmp0 (c1_type, context_type);
+}
+
+/**
+ * gst_element_get_context_unlocked:
+ * @element: a #GstElement to get the context of.
+ * @context_type: a name of a context to retrieve
+ *
+ * Gets the context with @context_type set on the element or NULL.
+ *
+ * Returns: (transfer full): A #GstContext or NULL
+ *
+ * Since: 1.8
+ */
+GstContext *
+gst_element_get_context_unlocked (GstElement * element,
+    const gchar * context_type)
+{
+  GstContext *ret = NULL;
+  GList *node;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+
+  node =
+      g_list_find_custom (element->contexts, context_type,
+      (GCompareFunc) _match_context_type);
+  if (node && node->data)
+    ret = gst_context_ref (node->data);
+
+  return ret;
+}
+
+/**
+ * gst_element_get_context:
+ * @element: a #GstElement to get the context of.
+ * @context_type: a name of a context to retrieve
+ *
+ * Gets the context with @context_type set on the element or NULL.
+ *
+ * MT safe.
+ *
+ * Returns: (transfer full): A #GstContext or NULL
+ *
+ * Since: 1.8
+ */
+GstContext *
+gst_element_get_context (GstElement * element, const gchar * context_type)
+{
+  GstContext *ret = NULL;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+
+  GST_OBJECT_LOCK (element);
+  ret = gst_element_get_context_unlocked (element, context_type);
+  GST_OBJECT_UNLOCK (element);
+
+  return ret;
+}