tee: Check for the removed pad flag also in the slow pushing path
[platform/upstream/gstreamer.git] / gst / gstcontext.c
index 7f610b6..c1bbe0a 100644 (file)
@@ -1,7 +1,9 @@
 /* GStreamer
- * Copyright (C) 2011 Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2013 Collabora Ltd.
+ *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (C) 2013 Sebastian Dröge <slomo@circular-chaos.org>
  *
- * gstcontext.c: GstContext subsystem
+ * gstcontext.h: Header for GstContext subsystem
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  *
  * 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.
  */
 
 /**
  * SECTION:gstcontext
- * @short_description: Structure containing events describing the context
- *                     for buffers in a pipeline
- * @see_also: #GstPad, #GstBuffer
+ * @title: GstContext
+ * @short_description: Lightweight objects to represent element contexts
+ * @see_also: #GstMiniObject, #GstElement
  *
- * Last reviewed on 2011-05-4 (0.11.0)
+ * #GstContext is a container object used to store contexts like a device
+ * context, a display server connection and similar concepts that should
+ * be shared between multiple elements.
+ *
+ * Applications can set a context on a complete pipeline by using
+ * gst_element_set_context(), which will then be propagated to all
+ * child elements. Elements can handle these in #GstElementClass.set_context()
+ * and merge them with the context information they already have.
+ *
+ * When an element needs a context it will do the following actions in this
+ * order until one step succeeds:
+ * 1. Check if the element already has a context
+ * 2. Query downstream with GST_QUERY_CONTEXT for the context
+ * 3. Query upstream with GST_QUERY_CONTEXT for the context
+ * 4. Post a GST_MESSAGE_NEED_CONTEXT message on the bus with the required
+ *    context types and afterwards check if a usable context was set now
+ * 5. Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT message
+ *    on the bus.
+ *
+ * Bins will catch GST_MESSAGE_NEED_CONTEXT messages and will set any previously
+ * known context on the element that asks for it if possible. Otherwise the
+ * application should provide one if it can.
+ *
+ * #GstContext<!-- -->s can be persistent.
+ * A persistent #GstContext is kept in elements when they reach
+ * %GST_STATE_NULL, non-persistent ones will be removed.
+ * Also, a non-persistent context won't override a previous persistent
+ * context set to an element.
+ *
+ * Since: 1.2
  */
 
-
 #include "gst_private.h"
-
-#include "gstinfo.h"
+#include <string.h>
 #include "gstcontext.h"
-#include "gstutils.h"
 #include "gstquark.h"
 
 struct _GstContext
 {
   GstMiniObject mini_object;
 
-  /*< private > */
-  GstEvent *events[GST_EVENT_MAX_STICKY];
-
-  gpointer _gst_reserved[GST_PADDING];
+  gchar *context_type;
+  GstStructure *structure;
+  gboolean persistent;
 };
 
-static GType _gst_context_type = 0;
+#define GST_CONTEXT_STRUCTURE(c)  (((GstContext *)(c))->structure)
+
+GType _gst_context_type = 0;
+GST_DEFINE_MINI_OBJECT_TYPE (GstContext, gst_context);
 
-GType
-gst_context_get_type (void)
+void
+_priv_gst_context_initialize (void)
 {
-  if (G_UNLIKELY (_gst_context_type == 0)) {
-    _gst_context_type = gst_mini_object_register ("GstContext");
-  }
-  return _gst_context_type;
+  GST_CAT_INFO (GST_CAT_GST_INIT, "init contexts");
+
+  /* the GstMiniObject types need to be class_ref'd once before it can be
+   * done from multiple threads;
+   * see http://bugzilla.gnome.org/show_bug.cgi?id=304551 */
+  gst_context_get_type ();
+
+  _gst_context_type = gst_context_get_type ();
 }
 
 static void
 _gst_context_free (GstContext * context)
 {
+  GstStructure *structure;
+
   g_return_if_fail (context != NULL);
-  g_return_if_fail (GST_IS_CONTEXT (context));
 
-  GST_LOG ("freeing context %p", context);
+  GST_CAT_LOG (GST_CAT_CONTEXT, "finalize context %p: %" GST_PTR_FORMAT,
+      context, GST_CONTEXT_STRUCTURE (context));
+
+  structure = GST_CONTEXT_STRUCTURE (context);
+  if (structure) {
+    gst_structure_set_parent_refcount (structure, NULL);
+    gst_structure_free (structure);
+  }
+  g_free (context->context_type);
 
-  gst_context_clear (context);
+#ifdef USE_POISONING
+  memset (context, 0xff, sizeof (GstContext));
+#endif
 
-  g_slice_free1 (GST_MINI_OBJECT_SIZE (context), context);
+  g_slice_free1 (sizeof (GstContext), context);
 }
 
-static void gst_context_init (GstContext * context, gsize size);
+static void gst_context_init (GstContext * context);
 
 static GstContext *
 _gst_context_copy (GstContext * context)
 {
   GstContext *copy;
-  guint i;
+  GstStructure *structure;
+
+  GST_CAT_LOG (GST_CAT_CONTEXT, "copy context %p: %" GST_PTR_FORMAT, context,
+      GST_CONTEXT_STRUCTURE (context));
 
   copy = g_slice_new0 (GstContext);
 
-  gst_context_init (copy, sizeof (GstContext));
+  gst_context_init (copy);
+
+  copy->context_type = g_strdup (context->context_type);
 
-  for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
-    gst_event_replace (&copy->events[i], context->events[i]);
+  structure = GST_CONTEXT_STRUCTURE (context);
+  GST_CONTEXT_STRUCTURE (copy) = gst_structure_copy (structure);
+  gst_structure_set_parent_refcount (GST_CONTEXT_STRUCTURE (copy),
+      &copy->mini_object.refcount);
 
-  return copy;
+  copy->persistent = context->persistent;
+
+  return GST_CONTEXT_CAST (copy);
 }
 
 static void
-gst_context_init (GstContext * context, gsize size)
+gst_context_init (GstContext * context)
 {
-  gst_mini_object_init (GST_MINI_OBJECT_CAST (context), _gst_context_type,
-      size);
-
-  context->mini_object.copy = (GstMiniObjectCopyFunction) _gst_context_copy;
-  context->mini_object.free = (GstMiniObjectFreeFunction) _gst_context_free;
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (context), 0, _gst_context_type,
+      (GstMiniObjectCopyFunction) _gst_context_copy, NULL,
+      (GstMiniObjectFreeFunction) _gst_context_free);
 }
 
 /**
  * gst_context_new:
+ * @context_type: Context type
+ * @persistent: Persistent context
+ *
+ * Create a new context.
  *
- * Create a new #GstContext object that can be used to manage events.
+ * Returns: (transfer full): The new context.
  *
- * Returns: (transfer full): a new #GstContext
+ * Since: 1.2
  */
 GstContext *
-gst_context_new (void)
+gst_context_new (const gchar * context_type, gboolean persistent)
 {
   GstContext *context;
+  GstStructure *structure;
+
+  g_return_val_if_fail (context_type != NULL, NULL);
 
   context = g_slice_new0 (GstContext);
 
-  GST_DEBUG ("creating new context %p", context);
+  GST_CAT_LOG (GST_CAT_CONTEXT, "creating new context %p", context);
+
+  structure = gst_structure_new_id_empty (GST_QUARK (CONTEXT));
+  gst_structure_set_parent_refcount (structure, &context->mini_object.refcount);
+  gst_context_init (context);
 
-  gst_context_init (context, sizeof (GstContext));
+  context->context_type = g_strdup (context_type);
+  GST_CONTEXT_STRUCTURE (context) = structure;
+  context->persistent = persistent;
 
   return context;
 }
 
 /**
- * gst_context_update:
- * @context: a #GstContext
- * @event: a #GstEvent
+ * gst_context_get_context_type:
+ * @context: The #GstContext.
+ *
+ * Get the type of @context.
  *
- * Update @context with @event. The context must be writable.
+ * Returns: The type of the context.
+ *
+ * Since: 1.2
  */
-void
-gst_context_update (GstContext * context, GstEvent * event)
+const gchar *
+gst_context_get_context_type (const GstContext * context)
 {
-  guint idx;
-
-  g_return_if_fail (context != NULL);
-  g_return_if_fail (gst_context_is_writable (context));
+  g_return_val_if_fail (GST_IS_CONTEXT (context), NULL);
 
-  idx = GST_EVENT_STICKY_IDX (event);
+  return context->context_type;
+}
 
-  GST_LOG ("storing event %s at index %u", GST_EVENT_TYPE_NAME (event), idx);
+/**
+ * gst_context_has_context_type:
+ * @context: The #GstContext.
+ * @context_type: Context type to check.
+ *
+ * Checks if @context has @context_type.
+ *
+ * Returns: %TRUE if @context has @context_type.
+ *
+ * Since: 1.2
+ */
+gboolean
+gst_context_has_context_type (const GstContext * context,
+    const gchar * context_type)
+{
+  g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE);
+  g_return_val_if_fail (context_type != NULL, FALSE);
 
-  gst_event_replace (&context->events[idx], event);
+  return strcmp (context->context_type, context_type) == 0;
 }
 
 /**
- * gst_context_get:
- * @context: a #GstContext
- * @type: a #GstEventType
+ * gst_context_get_structure:
+ * @context: The #GstContext.
+ *
+ * Access the structure of the context.
  *
- * Get the event of @type from @context.
+ * Returns: (transfer none): The structure of the context. The structure is
+ * still owned by the context, which means that you should not modify it,
+ * free it and that the pointer becomes invalid when you free the context.
  *
- * Returns: the last #GstEvent of @type that was updated on @context. This
- * function returns NULL when there is no event with the given type.
+ * Since: 1.2
  */
-GstEvent *
-gst_context_get (GstContext * context, GstEventType type)
+const GstStructure *
+gst_context_get_structure (const GstContext * context)
 {
-  guint idx;
-  GstEvent *event = NULL;
+  g_return_val_if_fail (GST_IS_CONTEXT (context), NULL);
 
-  g_return_val_if_fail (context != NULL, NULL);
-
-  idx = GST_EVENT_STICKY_IDX_TYPE (type);
+  return GST_CONTEXT_STRUCTURE (context);
+}
 
-  if ((event = context->events[idx]))
-    gst_event_ref (event);
+/**
+ * gst_context_writable_structure:
+ * @context: The #GstContext.
+ *
+ * Get a writable version of the structure.
+ *
+ * Returns: The structure of the context. The structure is still
+ * owned by the context, which means that you should not free it and
+ * that the pointer becomes invalid when you free the context.
+ * This function checks if @context is writable.
+ *
+ * Since: 1.2
+ */
+GstStructure *
+gst_context_writable_structure (GstContext * context)
+{
+  g_return_val_if_fail (GST_IS_CONTEXT (context), NULL);
+  g_return_val_if_fail (gst_context_is_writable (context), NULL);
 
-  return event;
+  return GST_CONTEXT_STRUCTURE (context);
 }
 
 /**
- * gst_context_clear:
- * @context: a #GstContext
+ * gst_context_is_persistent:
+ * @context: The #GstContext.
+ *
+ * Check if @context is persistent.
  *
- * Clear all stored events in @context
+ * Returns: %TRUE if the context is persistent.
+ *
+ * Since: 1.2
  */
-void
-gst_context_clear (GstContext * context)
+gboolean
+gst_context_is_persistent (const GstContext * context)
 {
-  guint i;
+  g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE);
 
-  for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
-    gst_event_replace (&context->events[i], NULL);
+  return context->persistent;
 }