Revert "element: Don't hold state lock all the time while sending an event"
[platform/upstream/gstreamer.git] / gst / gstelement.c
index da8e9f6..6bc013d 100644 (file)
@@ -16,8 +16,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 /**
@@ -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.
  * #GST_ELEMENT_FLAG_REQUIRE_CLOCK() flag is set, a clock should be set on the
  * element with gst_element_set_clock().
  *
- * Note that clock slection and distribution is normally handled by the
+ * 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"
 #include "gstevent.h"
 #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"
 
+#ifndef GST_DISABLE_GST_DEBUG
+#include "printf/printf.h"
+#endif
+
 /* Element signals and args */
 enum
 {
@@ -117,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);
 
@@ -129,6 +133,10 @@ static GstStateChangeReturn gst_element_set_state_func (GstElement * element,
 static gboolean gst_element_set_clock_func (GstElement * element,
     GstClock * clock);
 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);
@@ -225,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);
@@ -234,6 +243,8 @@ gst_element_class_init (GstElementClass * klass)
   klass->query = GST_DEBUG_FUNCPTR (gst_element_default_query);
   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;
 }
@@ -266,8 +277,8 @@ gst_element_base_class_init (gpointer g_class)
   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);
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "type %s : factory %p",
+      G_OBJECT_CLASS_NAME (element_class), element_class->elementfactory);
 }
 
 static void
@@ -294,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.
@@ -324,7 +342,7 @@ gst_element_release_request_pad (GstElement * element, GstPad * pad)
   /* if the element implements a custom release function we call that, else we
    * simply remove the pad from the element */
   if (oclass->release_pad)
-    (oclass->release_pad) (element, pad);
+    oclass->release_pad (element, pad);
   else
     gst_element_remove_pad (element, pad);
 }
@@ -337,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.
  */
@@ -412,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.
@@ -501,8 +522,6 @@ gst_element_get_base_time (GstElement * element)
  * 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)
@@ -534,8 +553,6 @@ gst_element_set_start_time (GstElement * element, GstClockTime time)
  * MT safe.
  *
  * Returns: the start time of the element.
- *
- * Since: 0.10.24
  */
 GstClockTime
 gst_element_get_start_time (GstElement * element)
@@ -582,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.
  */
@@ -630,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);
@@ -640,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);
 
@@ -654,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);
@@ -671,24 +685,24 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
   /* add it to the list */
   switch (gst_pad_get_direction (pad)) {
     case GST_PAD_SRC:
-      element->srcpads = g_list_prepend (element->srcpads, pad);
+      element->srcpads = g_list_append (element->srcpads, pad);
       element->numsrcpads++;
       break;
     case GST_PAD_SINK:
-      element->sinkpads = g_list_prepend (element->sinkpads, pad);
+      element->sinkpads = g_list_append (element->sinkpads, pad);
       element->numsinkpads++;
       break;
     default:
       goto no_direction;
   }
-  element->pads = g_list_prepend (element->pads, pad);
+  element->pads = g_list_append (element->pads, pad);
   element->numpads++;
   element->pads_cookie++;
   GST_OBJECT_UNLOCK (element);
 
   /* 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 */
@@ -724,14 +738,14 @@ no_direction:
 /**
  * gst_element_remove_pad:
  * @element: a #GstElement to remove pad from.
- * @pad: (transfer none): the #GstPad to remove from the element.
+ * @pad: (transfer full): 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().
  *
  * 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
@@ -800,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;
@@ -863,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.
  */
@@ -947,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);
@@ -973,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)
@@ -1067,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
@@ -1081,10 +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.
- *
- * Since: 0.10.32
+ * Returns: (transfer full) (nullable): requested #GstPad if found,
+ *     otherwise %NULL.  Release after usage.
  */
 GstPad *
 gst_element_request_pad (GstElement * element,
@@ -1092,6 +1105,7 @@ gst_element_request_pad (GstElement * element,
 {
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
   g_return_val_if_fail (templ != NULL, NULL);
+  g_return_val_if_fail (templ->presence == GST_PAD_REQUEST, NULL);
 
   return _gst_element_request_pad (element, templ, name, caps);
 }
@@ -1118,8 +1132,10 @@ gst_element_iterate_pad_list (GstElement * element, GList ** padlist)
  * be freed after usage. Also more specialized iterators exists such as
  * gst_element_iterate_src_pads() or gst_element_iterate_sink_pads().
  *
- * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
- *     after use.
+ * The order of pads returned by the iterator will be the order in which
+ * the pads were added to the element.
+ *
+ * Returns: (transfer full): the #GstIterator of #GstPad.
  *
  * MT safe.
  */
@@ -1137,8 +1153,10 @@ gst_element_iterate_pads (GstElement * element)
  *
  * Retrieves an iterator of @element's source pads.
  *
- * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
- *     after use.
+ * The order of pads returned by the iterator will be the order in which
+ * the pads were added to the element.
+ *
+ * Returns: (transfer full): the #GstIterator of #GstPad.
  *
  * MT safe.
  */
@@ -1156,8 +1174,10 @@ gst_element_iterate_src_pads (GstElement * element)
  *
  * Retrieves an iterator of @element's sink pads.
  *
- * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
- *     after use.
+ * The order of pads returned by the iterator will be the order in which
+ * the pads were added to the element.
+ *
+ * Returns: (transfer full): the #GstIterator of #GstPad.
  *
  * MT safe.
  */
@@ -1230,6 +1250,34 @@ gst_element_class_add_metadata (GstElementClass * klass,
 }
 
 /**
+ * gst_element_class_add_static_metadata:
+ * @klass: class to set metadata for
+ * @key: the key to set
+ * @value: the value to set
+ *
+ * Set @key with @value as metadata in @klass.
+ *
+ * Same as gst_element_class_add_metadata(), but @value must be a static string
+ * or an inlined string, as it will not be copied. (GStreamer plugins will
+ * be made resident once loaded, so this function can be used even from
+ * dynamically loaded plugins.)
+ */
+void
+gst_element_class_add_static_metadata (GstElementClass * klass,
+    const gchar * key, const gchar * value)
+{
+  GValue val = G_VALUE_INIT;
+
+  g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+  g_return_if_fail (key != NULL);
+  g_return_if_fail (value != NULL);
+
+  g_value_init (&val, G_TYPE_STRING);
+  g_value_set_static_string (&val, value);
+  gst_structure_take_value ((GstStructure *) klass->metadata, key, &val);
+}
+
+/**
  * gst_element_class_set_metadata:
  * @klass: class to set metadata for
  * @longname: The long English name of the element. E.g. "File Sink"
@@ -1250,12 +1298,66 @@ gst_element_class_set_metadata (GstElementClass * klass,
     const gchar * description, const gchar * author)
 {
   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+  g_return_if_fail (longname != NULL && *longname != '\0');
+  g_return_if_fail (classification != NULL && *classification != '\0');
+  g_return_if_fail (description != NULL && *description != '\0');
+  g_return_if_fail (author != NULL && *author != '\0');
 
-  gst_structure_set ((GstStructure *) klass->metadata,
-      GST_ELEMENT_METADATA_LONGNAME, G_TYPE_STRING, longname,
-      GST_ELEMENT_METADATA_KLASS, G_TYPE_STRING, classification,
-      GST_ELEMENT_METADATA_DESCRIPTION, G_TYPE_STRING, description,
-      GST_ELEMENT_METADATA_AUTHOR, G_TYPE_STRING, author, NULL);
+  gst_structure_id_set ((GstStructure *) klass->metadata,
+      GST_QUARK (ELEMENT_METADATA_LONGNAME), G_TYPE_STRING, longname,
+      GST_QUARK (ELEMENT_METADATA_KLASS), G_TYPE_STRING, classification,
+      GST_QUARK (ELEMENT_METADATA_DESCRIPTION), G_TYPE_STRING, description,
+      GST_QUARK (ELEMENT_METADATA_AUTHOR), G_TYPE_STRING, author, NULL);
+}
+
+/**
+ * gst_element_class_set_static_metadata:
+ * @klass: class to set metadata 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 metadata. E.g: "Joe Bloggs &lt;joe.blogs at foo.com&gt;"
+ *
+ * Sets the detailed information for a #GstElementClass.
+ * <note>This function is for use in _class_init functions only.</note>
+ *
+ * Same as gst_element_class_set_metadata(), but @longname, @classification,
+ * @description, and @author must be static strings or inlined strings, as
+ * they will not be copied. (GStreamer plugins will be made resident once
+ * loaded, so this function can be used even from dynamically loaded plugins.)
+ */
+void
+gst_element_class_set_static_metadata (GstElementClass * klass,
+    const gchar * longname, const gchar * classification,
+    const gchar * description, const gchar * author)
+{
+  GstStructure *s = (GstStructure *) klass->metadata;
+  GValue val = G_VALUE_INIT;
+
+  g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+  g_return_if_fail (longname != NULL && *longname != '\0');
+  g_return_if_fail (classification != NULL && *classification != '\0');
+  g_return_if_fail (description != NULL && *description != '\0');
+  g_return_if_fail (author != NULL && *author != '\0');
+
+  g_value_init (&val, G_TYPE_STRING);
+
+  g_value_set_static_string (&val, longname);
+  gst_structure_id_set_value (s, GST_QUARK (ELEMENT_METADATA_LONGNAME), &val);
+
+  g_value_set_static_string (&val, classification);
+  gst_structure_id_set_value (s, GST_QUARK (ELEMENT_METADATA_KLASS), &val);
+
+  g_value_set_static_string (&val, description);
+  gst_structure_id_set_value (s, GST_QUARK (ELEMENT_METADATA_DESCRIPTION),
+      &val);
+
+  g_value_set_static_string (&val, author);
+  gst_structure_id_take_value (s, GST_QUARK (ELEMENT_METADATA_AUTHOR), &val);
 }
 
 /**
@@ -1307,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 *
@@ -1415,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,
@@ -1425,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",
@@ -1442,14 +1545,15 @@ 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 owership of the provided event so you should
+ * 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.
  *
- * Returns: %TRUE if the event was handled.
- *
  * MT safe.
+ *
+ * Returns: %TRUE if the event was handled. Events that trigger a preroll (such
+ * as flushing seeks and steps) will emit %GST_MESSAGE_ASYNC_DONE.
  */
 gboolean
 gst_element_send_event (GstElement * element, GstEvent * event)
@@ -1467,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);
 
@@ -1479,8 +1585,8 @@ gst_element_send_event (GstElement * element, GstEvent * event)
  * @rate: The new playback rate
  * @format: The format of the seek values
  * @flags: The optional seek flags.
- * @cur_type: The type and flags for the new current position
- * @cur: The value of the new current position
+ * @start_type: The type and flags for the new start position
+ * @start: The value of the new start position
  * @stop_type: The type and flags for the new stop position
  * @stop: The value of the new stop position
  *
@@ -1488,13 +1594,14 @@ gst_element_send_event (GstElement * element, GstEvent * event)
  * the parameters. The seek event is sent to the element using
  * gst_element_send_event().
  *
- * Returns: %TRUE if the event was handled.
- *
  * MT safe.
+ *
+ * Returns: %TRUE if the event was handled. Flushing seeks will trigger a
+ * preroll, which will emit %GST_MESSAGE_ASYNC_DONE.
  */
 gboolean
 gst_element_seek (GstElement * element, gdouble rate, GstFormat format,
-    GstSeekFlags flags, GstSeekType cur_type, gint64 cur,
+    GstSeekFlags flags, GstSeekType start_type, gint64 start,
     GstSeekType stop_type, gint64 stop)
 {
   GstEvent *event;
@@ -1503,7 +1610,8 @@ gst_element_seek (GstElement * element, gdouble rate, GstFormat format,
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
 
   event =
-      gst_event_new_seek (rate, format, flags, cur_type, cur, stop_type, stop);
+      gst_event_new_seek (rate, format, flags, start_type, start, stop_type,
+      stop);
   result = gst_element_send_event (element, event);
 
   return result;
@@ -1549,45 +1657,34 @@ 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.
  */
 gboolean
 gst_element_query (GstElement * element, GstQuery * query)
 {
-  GstElementClass *oclass;
-  gboolean result = FALSE;
+  GstElementClass *klass;
+  gboolean res = FALSE;
 
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
   g_return_val_if_fail (query != NULL, FALSE);
 
-  oclass = GST_ELEMENT_GET_CLASS (element);
+  GST_TRACER_ELEMENT_QUERY_PRE (element, query);
 
-  if (oclass->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));
-    result = oclass->query (element, query);
+    res = klass->query (element, query);
   }
-  return result;
+
+  GST_TRACER_ELEMENT_QUERY_POST (element, query, res);
+  return res;
 }
 
-/**
- * gst_element_post_message:
- * @element: a #GstElement posting the message
- * @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
- * additional reference before calling.
- *
- * Returns: %TRUE if the message was successfully posted. The function returns
- * %FALSE if the element did not have a bus.
- *
- * MT safe.
- */
-gboolean
-gst_element_post_message (GstElement * element, GstMessage * message)
+static gboolean
+gst_element_post_message_default (GstElement * element, GstMessage * message)
 {
   GstBus *bus;
   gboolean result = FALSE;
@@ -1623,13 +1720,48 @@ no_bus:
 }
 
 /**
+ * gst_element_post_message:
+ * @element: a #GstElement posting the message
+ * @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
+ * additional reference before calling.
+ *
+ * Returns: %TRUE if the message was successfully posted. The function returns
+ * %FALSE if the element did not have a bus.
+ *
+ * MT safe.
+ */
+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)
+    res = klass->post_message (element, message);
+  else
+    gst_message_unref (message);
+
+  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.
  */
@@ -1638,6 +1770,7 @@ _gst_element_error_printf (const gchar * format, ...)
 {
   va_list args;
   gchar *buffer;
+  int len;
 
   if (format == NULL)
     return NULL;
@@ -1645,8 +1778,14 @@ _gst_element_error_printf (const gchar * format, ...)
     return NULL;
 
   va_start (args, format);
-  buffer = g_strdup_vprintf (format, args);
+
+  len = __gst_vasprintf (&buffer, format, args);
+
   va_end (args);
+
+  if (len < 0)
+    buffer = NULL;
+
   return buffer;
 }
 
@@ -1760,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)
@@ -1779,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
@@ -1831,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.
  */
@@ -2320,7 +2459,8 @@ only_async_start:
  * element will perform the remainder of the state change asynchronously in
  * another thread.
  * 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.
+ * of the state change or it can wait for a %GST_MESSAGE_ASYNC_DONE or
+ * %GST_MESSAGE_STATE_CHANGED on the bus.
  *
  * State changes to %GST_STATE_READY or %GST_STATE_NULL never return
  * #GST_STATE_CHANGE_ASYNC.
@@ -2481,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,
@@ -2561,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;
 }
@@ -2621,7 +2770,7 @@ gst_element_pads_activate (GstElement * element, gboolean active)
   gboolean res;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
-      "pads_activate with active %d", active);
+      "%s pads", active ? "activate" : "deactivate");
 
   iter = gst_element_iterate_src_pads (element);
   res =
@@ -2640,7 +2789,7 @@ gst_element_pads_activate (GstElement * element, gboolean active)
     goto sink_failed;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
-      "pads_activate successful");
+      "pad %sactivation successful", active ? "" : "de");
 
   return TRUE;
 
@@ -2648,7 +2797,7 @@ gst_element_pads_activate (GstElement * element, gboolean active)
 src_failed:
   {
     GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
-        "source pads_activate failed");
+        "pad %sactivation failed", active ? "" : "de");
     return FALSE;
   }
 sink_failed:
@@ -2693,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:
@@ -2750,6 +2920,7 @@ gst_element_dispose (GObject * object)
   GstClock **clock_p;
   GstBus **bus_p;
   GstElementClass *oclass;
+  GList *walk;
 
   oclass = GST_ELEMENT_GET_CLASS (element);
 
@@ -2758,23 +2929,36 @@ gst_element_dispose (GObject * object)
   if (GST_STATE (element) != GST_STATE_NULL)
     goto not_null;
 
-  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) {
-    GstPad *pad = GST_PAD_CAST (element->pads->data);
+  /* start by releasing all request pads, this might also remove some dynamic
+   * pads */
+  walk = element->pads;
+  while (walk) {
+    GstPad *pad = GST_PAD_CAST (walk->data);
+
+    walk = walk->next;
 
-    /* don't call _remove_pad with NULL */
     if (oclass->release_pad && GST_PAD_PAD_TEMPLATE (pad) &&
         GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad))
-        == GST_PAD_REQUEST)
-      (oclass->release_pad) (element, GST_PAD_CAST (element->pads->data));
-    else
-      gst_element_remove_pad (element, GST_PAD_CAST (element->pads->data));
+        == GST_PAD_REQUEST) {
+      GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+          "removing request pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+      oclass->release_pad (element, pad);
+
+      /* in case the release_pad function removed the next pad too */
+      if (walk && g_list_position (element->pads, walk) == -1)
+        walk = element->pads;
+    }
   }
-  if (G_UNLIKELY (element->pads != NULL)) {
-    g_critical ("could not remove pads from element %s",
-        GST_STR_NULL (GST_OBJECT_NAME (object)));
+  /* remove the remaining pads */
+  while (element->pads) {
+    GstPad *pad = GST_PAD_CAST (element->pads->data);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+        "removing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+    if (!gst_element_remove_pad (element, pad)) {
+      /* only happens when someone unparented our pad.. */
+      g_critical ("failed to remove pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+      break;
+    }
   }
 
   GST_OBJECT_LOCK (element);
@@ -2782,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");
@@ -2891,3 +3076,150 @@ 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.
+ * @context: (transfer none): the #GstContext to set.
+ *
+ * Sets the context of the element. Increases the refcount of the context.
+ *
+ * MT safe.
+ */
+void
+gst_element_set_context (GstElement * element, GstContext * context)
+{
+  GstElementClass *oclass;
+
+  g_return_if_fail (GST_IS_ELEMENT (element));
+
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element,
+      "set context %p %" GST_PTR_FORMAT, context,
+      gst_context_get_structure (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;
+}