/* GStreamer * Copyright (C) 2013 Collabora Ltd. * Author: Sebastian Dröge * Copyright (C) 2013 Sebastian Dröge * * 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 * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * 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., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * SECTION:gstcontext * @title: GstContext * @short_description: Lightweight objects to represent element contexts * @see_also: #GstMiniObject, #GstElement * * #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 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 */ #define GST_DISABLE_MINIOBJECT_INLINE_FUNCTIONS #include "gst_private.h" #include #include "gstcontext.h" #include "gstquark.h" struct _GstContext { GstMiniObject mini_object; gchar *context_type; GstStructure *structure; gboolean persistent; }; #define GST_CONTEXT_STRUCTURE(c) (((GstContext *)(c))->structure) GType _gst_context_type = 0; GST_DEFINE_MINI_OBJECT_TYPE (GstContext, gst_context); void _priv_gst_context_initialize (void) { 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); 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); #ifdef USE_POISONING memset (context, 0xff, sizeof (GstContext)); #endif g_slice_free1 (sizeof (GstContext), context); } static void gst_context_init (GstContext * context); static GstContext * _gst_context_copy (GstContext * context) { GstContext *copy; 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); copy->context_type = g_strdup (context->context_type); structure = GST_CONTEXT_STRUCTURE (context); GST_CONTEXT_STRUCTURE (copy) = gst_structure_copy (structure); gst_structure_set_parent_refcount (GST_CONTEXT_STRUCTURE (copy), ©->mini_object.refcount); copy->persistent = context->persistent; return GST_CONTEXT_CAST (copy); } static void gst_context_init (GstContext * context) { 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 * * Creates a new context. * * Returns: (transfer full): The new context. * * Since: 1.2 */ GstContext * 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_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); context->context_type = g_strdup (context_type); GST_CONTEXT_STRUCTURE (context) = structure; context->persistent = persistent; return context; } /** * gst_context_get_context_type: * @context: The #GstContext. * * Gets the type of @context. * * Returns: The type of the context. * * Since: 1.2 */ const gchar * gst_context_get_context_type (const GstContext * context) { g_return_val_if_fail (GST_IS_CONTEXT (context), NULL); return context->context_type; } /** * 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); return strcmp (context->context_type, context_type) == 0; } /** * gst_context_get_structure: * @context: The #GstContext. * * Accesses the structure of the 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. * * Since: 1.2 */ const GstStructure * gst_context_get_structure (const GstContext * context) { g_return_val_if_fail (GST_IS_CONTEXT (context), NULL); return GST_CONTEXT_STRUCTURE (context); } /** * gst_context_writable_structure: * @context: The #GstContext. * * Gets 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 GST_CONTEXT_STRUCTURE (context); } /** * gst_context_is_persistent: * @context: The #GstContext. * * Checks if @context is persistent. * * Returns: %TRUE if the context is persistent. * * Since: 1.2 */ gboolean gst_context_is_persistent (const GstContext * context) { g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE); return context->persistent; } /** * gst_context_ref: * @context: the context to ref * * Convenience macro to increase the reference count of the context. * * Returns: @context (for convenience when doing assignments) * * Since: 1.2 */ GstContext * gst_context_ref (GstContext * context) { return (GstContext *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (context)); } /** * gst_context_unref: * @context: the context to unref * * Convenience macro to decrease the reference count of the context, possibly * freeing it. * * Since: 1.2 */ void gst_context_unref (GstContext * context) { gst_mini_object_unref (GST_MINI_OBJECT_CAST (context)); } /** * gst_context_copy: * @context: the context to copy * * Creates a copy of the context. Returns a copy of the context. * * Returns: (transfer full): a new copy of @context. * * MT safe * * Since: 1.2 */ GstContext * gst_context_copy (const GstContext * context) { return GST_CONTEXT_CAST (gst_mini_object_copy (GST_MINI_OBJECT_CONST_CAST (context))); } /** * gst_context_replace: * @old_context: (inout) (transfer full): pointer to a pointer to a #GstContext * to be replaced. * @new_context: (allow-none) (transfer none): pointer to a #GstContext that will * replace the context pointed to by @old_context. * * Modifies a pointer to a #GstContext to point to a different #GstContext. The * modification is done atomically (so this is useful for ensuring thread safety * in some cases), and the reference counts are updated appropriately (the old * context is unreffed, the new one is reffed). * * Either @new_context or the #GstContext pointed to by @old_context may be %NULL. * * Returns: %TRUE if @new_context was different from @old_context * * Since: 1.2 */ gboolean gst_context_replace (GstContext ** old_context, GstContext * new_context) { return gst_mini_object_replace ((GstMiniObject **) old_context, (GstMiniObject *) new_context); }