Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / gstelement.c
index b8c72e9..91b12be 100644 (file)
  * Core and plug-in writers can add and remove pads with gst_element_add_pad()
  * and gst_element_remove_pad().
  *
- * A pad of an element can be retrieved by name with gst_element_get_pad().
+ * An existing pad of an element can be retrieved by name with
+ * gst_element_get_static_pad(). A new dynamic pad can be created using
+ * gst_element_request_pad() with a #GstPadTemplate or 
+ * gst_element_get_request_pad() with the template name such as "src_\%d".
  * An iterator of all pads can be retrieved with gst_element_iterate_pads().
  *
  * Elements can be linked through their pads.
@@ -174,10 +177,8 @@ static void
 gst_element_class_init (GstElementClass * klass)
 {
   GObjectClass *gobject_class;
-  GstObjectClass *gstobject_class;
 
   gobject_class = (GObjectClass *) klass;
-  gstobject_class = (GstObjectClass *) klass;
 
   parent_class = g_type_class_peek_parent (klass);
 
@@ -251,14 +252,10 @@ gst_element_base_class_init (gpointer g_class)
    * from their base class but elements can add pad templates in class_init
    * instead of base_init.
    */
-  /* FIXME: Do we consider GstPadTemplates as immutable? If so we can
-   * simply ref them instead of copying.
-   */
   padtemplates = g_list_copy (element_class->padtemplates);
   for (node = padtemplates; node != NULL; node = node->next) {
     GstPadTemplate *tmpl = (GstPadTemplate *) node->data;
-    node->data = gst_pad_template_new (tmpl->name_template,
-        tmpl->direction, tmpl->presence, gst_caps_copy (tmpl->caps));
+    gst_object_ref (tmpl);
   }
   element_class->padtemplates = padtemplates;
 
@@ -290,9 +287,7 @@ gst_element_init (GstElement * element)
   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
   GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS;
 
-  /* FIXME 0.11: Store this directly in the instance struct */
-  element->state_lock = g_slice_new (GStaticRecMutex);
-  g_static_rec_mutex_init (element->state_lock);
+  g_static_rec_mutex_init (&element->state_lock);
   element->state_cond = g_cond_new ();
 }
 
@@ -869,12 +864,15 @@ gst_element_remove_pad (GstElement * element, GstPad * pad)
   /* ERRORS */
 not_our_pad:
   {
-    /* FIXME, locking order? */
+    /* locking order is element > pad */
+    GST_OBJECT_UNLOCK (pad);
+
     GST_OBJECT_LOCK (element);
+    GST_OBJECT_LOCK (pad);
     g_critical ("Padname %s:%s does not belong to element %s when removing",
         GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element));
-    GST_OBJECT_UNLOCK (element);
     GST_OBJECT_UNLOCK (pad);
+    GST_OBJECT_UNLOCK (element);
     return FALSE;
   }
 }
@@ -1013,10 +1011,8 @@ _gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
   }
 #endif
 
-  if (oclass->request_new_pad_full)
-    newpad = (oclass->request_new_pad_full) (element, templ, name, caps);
-  else if (oclass->request_new_pad)
-    newpad = (oclass->request_new_pad) (element, templ, name);
+  if (oclass->request_new_pad)
+    newpad = (oclass->request_new_pad) (element, templ, name, caps);
 
   if (newpad)
     gst_object_ref (newpad);
@@ -1029,8 +1025,8 @@ _gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
  * @element: a #GstElement to find a request pad of.
  * @name: the name of the request #GstPad to retrieve.
  *
- * Retrieves a pad from the element by name. This version only retrieves
- * request pads. The pad should be released with
+ * Retrieves a pad from the element by name (e.g. "src_\%d"). This version only
+ * retrieves request pads. The pad should be released with
  * gst_element_release_request_pad().
  *
  * This method is slow and will be deprecated in the future. New code should
@@ -1136,6 +1132,8 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
  * request. Can be %NULL.
  *
  * Retrieves a request pad from the element according to the provided template.
+ * Pad templates can be looked up using
+ * gst_element_factory_get_static_pad_templates().
  *
  * If the @caps are specified and the element implements thew new
  * request_new_pad_full virtual method, the element will use them to select
@@ -1158,42 +1156,6 @@ gst_element_request_pad (GstElement * element,
   return _gst_element_request_pad (element, templ, name, caps);
 }
 
-/**
- * gst_element_get_pad:
- * @element: a #GstElement.
- * @name: the name of the pad to retrieve.
- *
- * Retrieves a pad from @element by name. Tries gst_element_get_static_pad()
- * first, then gst_element_get_request_pad().
- *
- * Deprecated: This function is deprecated as it's unclear if the reference
- * to the result pad should be released with gst_object_unref() in case of a static pad
- * or gst_element_release_request_pad() in case of a request pad.
- * Use gst_element_get_static_pad() or gst_element_get_request_pad() instead.
- *
- * Returns: (transfer full): the #GstPad if found, otherwise %NULL. Unref or Release after usage,
- * depending on the type of the pad.
- */
-#ifndef GST_REMOVE_DEPRECATED
-#ifdef GST_DISABLE_DEPRECATED
-GstPad *gst_element_get_pad (GstElement * element, const gchar * name);
-#endif
-GstPad *
-gst_element_get_pad (GstElement * element, const gchar * name)
-{
-  GstPad *pad;
-
-  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
-  g_return_val_if_fail (name != NULL, NULL);
-
-  pad = gst_element_get_static_pad (element, name);
-  if (!pad)
-    pad = gst_element_get_request_pad (element, name);
-
-  return pad;
-}
-#endif /* GST_REMOVE_DEPRECATED */
-
 static GstIterator *
 gst_element_iterate_pad_list (GstElement * element, GList ** padlist)
 {
@@ -1212,8 +1174,9 @@ gst_element_iterate_pad_list (GstElement * element, GList ** padlist)
  * gst_element_iterate_pads:
  * @element: a #GstElement to iterate pads of.
  *
- * Retrieves an iterattor of @element's pads. The iterator should
- * be freed after usage.
+ * Retrieves an iterator of @element's pads. The iterator should
+ * be freed after usage. Also more specialized iterators exists such as
+ * gst_element_iterate_src_pads() or gst_element_iterate_sink_pads().
  *
  * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
  *     after use.
@@ -1299,6 +1262,9 @@ gst_element_class_add_pad_template (GstElementClass * klass,
     template_list = g_list_next (template_list);
   }
 
+  /* Take ownership of the floating ref */
+  g_object_ref_sink (templ);
+
   klass->padtemplates = g_list_append (klass->padtemplates, templ);
   klass->numpadtemplates++;
 }
@@ -1353,6 +1319,24 @@ gst_element_class_set_metadata (GstElementClass * klass,
 }
 
 /**
+ * gst_element_class_get_metadata:
+ * @klass: class to get metadata for
+ * @key: the key to get
+ *
+ * Get metadata with @key in @klass.
+ *
+ * Returns: the metadata for @key.
+ */
+const gchar *
+gst_element_class_get_metadata (GstElementClass * klass, const gchar * key)
+{
+  g_return_val_if_fail (GST_IS_ELEMENT_CLASS (klass), NULL);
+  g_return_val_if_fail (key != NULL, NULL);
+
+  return gst_structure_get_string ((GstStructure *) klass->metadata, key);
+}
+
+/**
  * gst_element_class_get_pad_template_list:
  * @element_class: a #GstElementClass to get pad templates of.
  *
@@ -2033,7 +2017,7 @@ gst_element_get_state_func (GstElement * element,
   if (ret == GST_STATE_CHANGE_FAILURE)
     goto done;
 
-  /* we got no_preroll, report immediatly */
+  /* we got no_preroll, report immediately */
   if (ret == GST_STATE_CHANGE_NO_PREROLL)
     goto done;
 
@@ -2228,6 +2212,28 @@ nothing_aborted:
   }
 }
 
+/* Not static because GstBin has manual state handling too */
+void
+_priv_gst_element_state_changed (GstElement * element, GstState oldstate,
+    GstState newstate, GstState pending)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+  GstMessage *message;
+
+  GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+      "notifying about state-changed %s to %s (%s pending)",
+      gst_element_state_get_name (oldstate),
+      gst_element_state_get_name (newstate),
+      gst_element_state_get_name (pending));
+
+  if (klass->state_changed)
+    klass->state_changed (element, oldstate, newstate, pending);
+
+  message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
+      oldstate, newstate, pending);
+  gst_element_post_message (element, message);
+}
+
 /**
  * gst_element_continue_state:
  * @element: a #GstElement to continue the state change of.
@@ -2255,7 +2261,6 @@ gst_element_continue_state (GstElement * element, GstStateChangeReturn ret)
   GstStateChangeReturn old_ret;
   GstState old_state, old_next;
   GstState current, next, pending;
-  GstMessage *message;
   GstStateChange transition;
 
   GST_OBJECT_LOCK (element);
@@ -2291,9 +2296,7 @@ gst_element_continue_state (GstElement * element, GstStateChangeReturn ret)
       gst_element_state_get_name (old_next),
       gst_element_state_get_name (pending), gst_element_state_get_name (next));
 
-  message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
-      old_state, old_next, pending);
-  gst_element_post_message (element, message);
+  _priv_gst_element_state_changed (element, old_state, old_next, pending);
 
   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
       "continue state change %s to %s, final %s",
@@ -2325,16 +2328,9 @@ complete:
      * previous return value.
      * We do signal the cond though as a _get_state() might be blocking
      * on it. */
-    if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) {
-      GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
-          "posting state-changed %s to %s",
-          gst_element_state_get_name (old_state),
-          gst_element_state_get_name (old_next));
-      message =
-          gst_message_new_state_changed (GST_OBJECT_CAST (element), old_state,
-          old_next, GST_STATE_VOID_PENDING);
-      gst_element_post_message (element, message);
-    }
+    if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC)
+      _priv_gst_element_state_changed (element, old_state, old_next,
+          GST_STATE_VOID_PENDING);
 
     GST_STATE_BROADCAST (element);
 
@@ -2343,19 +2339,16 @@ complete:
 }
 
 /**
- * gst_element_lost_state_full:
+ * gst_element_lost_state:
  * @element: a #GstElement the state is lost of
- * @new_base_time: if a new base time should be distributed
  *
  * Brings the element to the lost state. The current state of the
  * element is copied to the pending state so that any call to
  * gst_element_get_state() will return %GST_STATE_CHANGE_ASYNC.
  *
- * An ASYNC_START message is posted with indication to distribute a new
- * base_time to the element when @new_base_time is %TRUE.
- * If the element was PLAYING, it will go to PAUSED. The element
- * will be restored to its PLAYING state by the parent pipeline when it
- * prerolls again.
+ * An ASYNC_START message is posted. If the element was PLAYING, it will
+ * go to PAUSED. The element will be restored to its PLAYING state by
+ * the parent pipeline when it prerolls again.
  *
  * This is mostly used for elements that lost their preroll buffer
  * in the %GST_STATE_PAUSED or %GST_STATE_PLAYING state after a flush,
@@ -2365,13 +2358,9 @@ complete:
  *
  * This function is used internally and should normally not be called from
  * plugins or applications.
- *
- * MT safe.
- *
- * Since: 0.10.24
  */
 void
-gst_element_lost_state_full (GstElement * element, gboolean new_base_time)
+gst_element_lost_state (GstElement * element)
 {
   GstState old_state, new_state;
   GstMessage *message;
@@ -2403,16 +2392,11 @@ gst_element_lost_state_full (GstElement * element, gboolean new_base_time)
   GST_STATE_NEXT (element) = new_state;
   GST_STATE_PENDING (element) = new_state;
   GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC;
-  if (new_base_time)
-    GST_ELEMENT_START_TIME (element) = 0;
   GST_OBJECT_UNLOCK (element);
 
-  message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
-      new_state, new_state, new_state);
-  gst_element_post_message (element, message);
+  _priv_gst_element_state_changed (element, new_state, new_state, new_state);
 
-  message =
-      gst_message_new_async_start (GST_OBJECT_CAST (element), new_base_time);
+  message = gst_message_new_async_start (GST_OBJECT_CAST (element));
   gst_element_post_message (element, message);
 
   return;
@@ -2426,31 +2410,13 @@ only_async_start:
   {
     GST_OBJECT_UNLOCK (element);
 
-    message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE);
+    message = gst_message_new_async_start (GST_OBJECT_CAST (element));
     gst_element_post_message (element, message);
     return;
   }
 }
 
 /**
- * gst_element_lost_state:
- * @element: a #GstElement the state is lost of
- *
- * Brings the element to the lost state. This function calls
- * gst_element_lost_state_full() with the new_base_time set to %TRUE.
- *
- * This function is used internally and should normally not be called from
- * plugins or applications.
- *
- * MT safe.
- */
-void
-gst_element_lost_state (GstElement * element)
-{
-  gst_element_lost_state_full (element, TRUE);
-}
-
-/**
  * gst_element_set_state:
  * @element: a #GstElement to change state of.
  * @state: the element's new #GstState.
@@ -2714,21 +2680,9 @@ activate_pads (const GValue * vpad, GValue * ret, gboolean * active)
   if (!(cont = gst_pad_set_active (pad, *active)))
     g_value_set_boolean (ret, FALSE);
 
-  /* unref the object that was reffed for us by _fold */
   return cont;
 }
 
-/* set the caps on the pad to NULL */
-static gboolean
-clear_caps (const GValue * vpad, GValue * ret, gboolean * active)
-{
-  GstPad *pad = g_value_get_object (vpad);
-
-  gst_pad_set_caps (pad, NULL);
-
-  return TRUE;
-}
-
 /* returns false on error or early cutout of the fold, true if all
  * pads in @iter were (de)activated successfully. */
 static gboolean
@@ -2794,17 +2748,6 @@ gst_element_pads_activate (GstElement * element, gboolean active)
   if (G_UNLIKELY (!res))
     goto sink_failed;
 
-  if (!active) {
-    /* clear the caps on all pads, this should never fail */
-    iter = gst_element_iterate_pads (element);
-    res =
-        iterator_activate_fold_with_resync (iter,
-        (GstIteratorFoldFunction) clear_caps, &active);
-    gst_iterator_free (iter);
-    if (G_UNLIKELY (!res))
-      goto caps_failed;
-  }
-
   GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
       "pads_activate successful");
 
@@ -2823,12 +2766,6 @@ sink_failed:
         "sink pads_activate failed");
     return FALSE;
   }
-caps_failed:
-  {
-    GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
-        "failed to clear caps on pads");
-    return FALSE;
-  }
 }
 
 /* is called with STATE_LOCK */
@@ -2979,14 +2916,8 @@ gst_element_finalize (GObject * object)
 
   GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize");
 
-  GST_STATE_LOCK (element);
-  if (element->state_cond)
-    g_cond_free (element->state_cond);
-  element->state_cond = NULL;
-  GST_STATE_UNLOCK (element);
-  g_static_rec_mutex_free (element->state_lock);
-  g_slice_free (GStaticRecMutex, element->state_lock);
-  element->state_lock = NULL;
+  g_cond_free (element->state_cond);
+  g_static_rec_mutex_free (&element->state_lock);
 
   GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize parent");