gst: Add new GstContext miniobject for sharing contexts in a pipeline

This commit is contained in:
Sebastian Dröge 2013-03-28 15:35:13 +01:00
parent bd85fe34ad
commit b909061031
21 changed files with 904 additions and 5 deletions

View file

@ -69,6 +69,7 @@ Windows. It is released under the GNU Library General Public License
<xi:include href="xml/gstchildproxy.xml" />
<xi:include href="xml/gstclock.xml" />
<xi:include href="xml/gstconfig.xml" />
<xi:include href="xml/gstcontext.xml" />
<xi:include href="xml/gstcontrolbinding.xml" />
<xi:include href="xml/gstcontrolsource.xml" />
<xi:include href="xml/gstdatetime.xml" />

View file

@ -621,6 +621,26 @@ GST_PADDING_INIT
GST_USING_PRINTF_EXTENSION
</SECTION>
<SECTION>
<FILE>gstcontext</FILE>
<TITLE>GstContext</TITLE>
GstContext
gst_context_new
gst_context_ref
gst_context_unref
gst_context_copy
gst_context_get_structure
gst_context_make_writable
gst_context_is_writable
gst_context_replace
<SUBSECTION Standard>
GST_CONTEXT
GST_CONTEXT_CAST
GST_IS_CONTEXT
GST_TYPE_CONTEXT
<SUBSECTION Private>
gst_context_get_type
</SECTION>
<SECTION>
<FILE>gstcontrolbinding</FILE>
@ -753,6 +773,7 @@ gst_element_set_start_time
gst_element_get_start_time
gst_element_set_bus
gst_element_get_bus
gst_element_set_context
gst_element_get_factory
gst_element_set_name
gst_element_get_name
@ -1025,6 +1046,9 @@ gst_event_parse_toc_select
gst_event_new_segment_done
gst_event_parse_segment_done
gst_event_new_context
gst_event_parse_context
<SUBSECTION Standard>
GstEventClass
GST_EVENT
@ -1469,6 +1493,13 @@ GstProgressType
gst_message_new_progress
gst_message_parse_progress
gst_message_new_need_context
gst_message_add_context_type
gst_message_get_n_context_types
gst_message_parse_nth_context_type
gst_message_new_have_context
gst_message_parse_have_context
<SUBSECTION Standard>
GstMessageClass
GST_MESSAGE
@ -2286,6 +2317,13 @@ gst_query_has_scheduling_mode
gst_query_has_scheduling_mode_with_flags
gst_query_new_drain
gst_query_new_context
gst_query_set_context
gst_query_parse_context
gst_query_add_context_type
gst_query_get_n_context_types
gst_query_parse_nth_context_type
<SUBSECTION Standard>
GstQueryClass
GST_QUERY

View file

@ -57,6 +57,7 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
gstcaps.c \
gstchildproxy.c \
gstclock.c \
gstcontext.c \
gstcontrolbinding.c \
gstcontrolsource.c \
gstdatetime.c \
@ -153,6 +154,7 @@ gst_headers = \
gstchildproxy.h \
gstclock.h \
gstcompat.h \
gstcontext.h \
gstcontrolbinding.h \
gstcontrolsource.h \
gstdatetime.h \

View file

@ -661,6 +661,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
_priv_gst_buffer_list_initialize ();
_priv_gst_sample_initialize ();
_priv_gst_value_initialize ();
_priv_gst_context_initialize ();
g_type_class_ref (gst_param_spec_fraction_get_type ());
_priv_gst_tag_initialize ();

View file

@ -116,6 +116,7 @@ G_GNUC_INTERNAL void _priv_gst_sample_initialize (void);
G_GNUC_INTERNAL void _priv_gst_tag_initialize (void);
G_GNUC_INTERNAL void _priv_gst_value_initialize (void);
G_GNUC_INTERNAL void _priv_gst_debug_init (void);
G_GNUC_INTERNAL void _priv_gst_context_initialize (void);
/* Private registry functions */
G_GNUC_INTERNAL
@ -220,6 +221,7 @@ GST_EXPORT GstDebugCategory *GST_CAT_REGISTRY;
GST_EXPORT GstDebugCategory *GST_CAT_QOS;
GST_EXPORT GstDebugCategory *GST_CAT_META;
GST_EXPORT GstDebugCategory *GST_CAT_LOCKING;
GST_EXPORT GstDebugCategory *GST_CAT_CONTEXT;
/* Categories that should be completely private to
* libgstreamer should be done like this: */
@ -262,6 +264,7 @@ extern GstDebugCategory *_priv_GST_CAT_POLL;
#define GST_CAT_POLL NULL
#define GST_CAT_META NULL
#define GST_CAT_LOCKING NULL
#define GST_CAT_CONTEXT NULL
#endif

View file

@ -189,6 +189,8 @@ struct _GstBinPrivate
guint32 structure_cookie;
GstContext *context;
#if 0
/* cached index */
GstIndex *index;
@ -242,6 +244,7 @@ static gboolean gst_bin_send_event (GstElement * element, GstEvent * event);
static GstBusSyncReply bin_bus_handler (GstBus * bus,
GstMessage * message, GstBin * bin);
static gboolean gst_bin_query (GstElement * element, GstQuery * query);
static void gst_bin_set_context (GstElement * element, GstContext * context);
static gboolean gst_bin_do_latency_func (GstBin * bin);
@ -461,6 +464,7 @@ gst_bin_class_init (GstBinClass * klass)
gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_bin_send_event);
gstelement_class->query = GST_DEBUG_FUNCPTR (gst_bin_query);
gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_bin_set_context);
klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
@ -1140,6 +1144,9 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
* a new clock will be selected */
gst_element_set_clock (element, GST_ELEMENT_CLOCK (bin));
if (bin->priv->context)
gst_element_set_context (element, bin->priv->context);
#if 0
/* set the cached index on the children */
if (bin->priv->index)
@ -3937,6 +3944,33 @@ gst_bin_query (GstElement * element, GstQuery * query)
return res;
}
static void
set_context (const GValue * item, gpointer user_data)
{
GstElement *element = g_value_get_object (item);
gst_element_set_context (element, user_data);
}
static void
gst_bin_set_context (GstElement * element, GstContext * context)
{
GstBin *bin;
GstIterator *children;
g_return_if_fail (GST_IS_BIN (element));
bin = GST_BIN (element);
children = gst_bin_iterate_elements (bin);
while (gst_iterator_foreach (children, set_context,
context) == GST_ITERATOR_RESYNC);
gst_iterator_free (children);
GST_OBJECT_LOCK (bin);
gst_context_replace (&bin->priv->context, context);
GST_OBJECT_UNLOCK (bin);
}
static gint
compare_name (const GValue * velement, const gchar * name)
{

180
gst/gstcontext.c Normal file
View file

@ -0,0 +1,180 @@
/* GStreamer
* Copyright (C) 2013 Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* 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
* @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 GstElement::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) 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
* 4) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT message
* and send a GST_EVENT_CONTEXT event downstream, containing the complete
* context information at this time.
*
* Applications should catch the GST_MESSAGE_HAVE_CONTEXT messages and remember
* any content from it unless it has a custom version of a specific context. If
* later an element is posting a GST_MESSAGE_NEED_CONTEXT message for a specific
* context that was created by an element before the application should pass it
* to the complete pipeline.
*/
#include "gst_private.h"
#include <string.h>
#include "gstcontext.h"
#include "gstquark.h"
struct _GstContext
{
GstMiniObject mini_object;
GstStructure *structure;
};
#define GST_CONTEXT_STRUCTURE(c) (((GstContext *)(c))->structure)
static 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_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);
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 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:
*
* Create a new context.
*
* Returns: (transfer full): The new context.
*
* MT safe.
*/
GstContext *
gst_context_new (void)
{
GstContext *context;
GstStructure *structure;
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);
GST_CONTEXT_STRUCTURE (context) = structure;
return context;
}
/**
* gst_context_get_structure:
* @context: The #GstContext.
*
* Access 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.
*
* MT safe.
*/
const GstStructure *
gst_context_get_structure (GstContext * context)
{
g_return_val_if_fail (GST_IS_CONTEXT (context), NULL);
return GST_CONTEXT_STRUCTURE (context);
}

153
gst/gstcontext.h Normal file
View file

@ -0,0 +1,153 @@
/* GStreamer
* Copyright (C) 2013 Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* 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.
*/
#ifndef __GST_CONTEXT_H__
#define __GST_CONTEXT_H__
G_BEGIN_DECLS
typedef struct _GstContext GstContext;
#include <gst/gstminiobject.h>
#include <gst/gststructure.h>
#define GST_TYPE_CONTEXT (gst_context_get_type())
#define GST_IS_CONTEXT(obj) (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_CONTEXT))
#define GST_CONTEXT_CAST(obj) ((GstContext*)(obj))
#define GST_CONTEXT(obj) (GST_CONTEXT_CAST(obj))
GType gst_context_get_type (void);
/* refcounting */
/**
* 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)
*/
#ifdef _FOOL_GTK_DOC_
G_INLINE_FUNC GstContext * gst_context_ref (GstContext * context);
#endif
static inline 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.
*/
#ifdef _FOOL_GTK_DOC_
G_INLINE_FUNC void gst_context_unref (GstContext * context);
#endif
static inline void
gst_context_unref (GstContext * context)
{
gst_mini_object_unref (GST_MINI_OBJECT_CAST (context));
}
/* copy 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
*/
#ifdef _FOOL_GTK_DOC_
G_INLINE_FUNC GstContext * gst_context_copy (const GstContext * context);
#endif
static inline GstContext *
gst_context_copy (const GstContext * context)
{
return GST_CONTEXT_CAST (gst_mini_object_copy (GST_MINI_OBJECT_CONST_CAST (context)));
}
/**
* gst_context_is_writable:
* @context: a #GstContext
*
* Tests if you can safely write into a context's structure or validly
* modify the seqnum and timestamp fields.
*/
#define gst_context_is_writable(context) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (context))
/**
* gst_context_make_writable:
* @context: (transfer full): the context to make writable
*
* Checks if a context is writable. If not, a writable copy is made and
* returned.
*
* Returns: (transfer full): a context (possibly a duplicate) that is writable.
*
* MT safe
*/
#define gst_context_make_writable(context) GST_CONTEXT_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT_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
*/
#ifdef _FOOL_GTK_DOC_
G_INLINE_FUNC gboolean gst_context_replace (GstContext **old_context, GstContext *new_context);
#endif
static inline gboolean
gst_context_replace (GstContext **old_context, GstContext *new_context)
{
return gst_mini_object_replace ((GstMiniObject **) old_context, (GstMiniObject *) new_context);
}
GstContext * gst_context_new (void) G_GNUC_MALLOC;
const GstStructure *
gst_context_get_structure (GstContext *context);
G_END_DECLS
#endif /* __GST_CONTEXT_H__ */

View file

@ -3011,3 +3011,29 @@ gst_element_get_bus (GstElement * element)
return result;
}
/**
* gst_element_set_context:
* @element: a #GstElement to set the bus 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);
}

View file

@ -593,6 +593,7 @@ struct _GstElement
* @state_changed: called immediately after a new state was set.
* @post_message: called when a message is posted on the element. Chain up to
* the parent class' handler to have it posted on the bus.
* @set_context: set a #GstContext on the element
*
* GStreamer element class. Override the vmethods to implement the element
* functionality.
@ -649,8 +650,10 @@ struct _GstElementClass
gboolean (*post_message) (GstElement *element, GstMessage *message);
void (*set_context) (GstElement *element, GstContext *context);
/*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE-1];
gpointer _gst_reserved[GST_PADDING_LARGE-2];
};
/* element class pad templates */
@ -737,6 +740,9 @@ GstClockTime gst_element_get_start_time (GstElement *element);
void gst_element_set_bus (GstElement * element, GstBus * bus);
GstBus * gst_element_get_bus (GstElement * element);
/* context */
void gst_element_set_context (GstElement * element, GstContext * context);
/* pad management */
gboolean gst_element_add_pad (GstElement *element, GstPad *pad);
gboolean gst_element_remove_pad (GstElement *element, GstPad *pad);

View file

@ -116,6 +116,7 @@ static GstEventQuarks event_quarks[] = {
{GST_EVENT_BUFFERSIZE, "buffersize", 0},
{GST_EVENT_SINK_MESSAGE, "sink-message", 0},
{GST_EVENT_EOS, "eos", 0},
{GST_EVENT_CONTEXT, "context", 0},
{GST_EVENT_SEGMENT_DONE, "segment-done", 0},
{GST_EVENT_GAP, "gap", 0},
{GST_EVENT_QOS, "qos", 0},
@ -1597,3 +1598,52 @@ gst_event_parse_segment_done (GstEvent * event, GstFormat * format,
if (position != NULL)
*position = g_value_get_int64 (val);
}
/**
* gst_event_new_context:
* @msg: (transfer full): the #GstContext
*
* Create a new context event. The purpose of the context event is
* to pass a pipeline-local context to downstream elements.
*
* Returns: (transfer full): a new #GstEvent
*/
GstEvent *
gst_event_new_context (GstContext * context)
{
GstEvent *event;
GstStructure *structure;
g_return_val_if_fail (context != NULL, NULL);
GST_CAT_INFO (GST_CAT_EVENT, "creating context event");
structure = gst_structure_new_id (GST_QUARK (EVENT_SEEK),
GST_QUARK (CONTEXT), GST_TYPE_CONTEXT, context, NULL);
event = gst_event_new_custom (GST_EVENT_CONTEXT, structure);
gst_context_unref (context);
return event;
}
/**
* gst_event_parse_context:
* @event: The event to query
* @context: (out) (transfer full): a pointer to store the #GstContext in.
*
* Parse the context event. Unref @context after usage.
*/
void
gst_event_parse_context (GstEvent * event, GstContext ** context)
{
const GstStructure *structure;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_CONTEXT);
structure = GST_EVENT_STRUCTURE (event);
if (context)
*context =
GST_CONTEXT (g_value_dup_boxed (gst_structure_id_get_value
(structure, GST_QUARK (CONTEXT))));
}

View file

@ -147,6 +147,7 @@ typedef enum {
GST_EVENT_SINK_MESSAGE = GST_EVENT_MAKE_TYPE (100, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
GST_EVENT_EOS = GST_EVENT_MAKE_TYPE (110, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_TOC = GST_EVENT_MAKE_TYPE (120, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
GST_EVENT_CONTEXT = GST_EVENT_MAKE_TYPE (130, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
/* non-sticky downstream serialized */
GST_EVENT_SEGMENT_DONE = GST_EVENT_MAKE_TYPE (150, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
@ -180,6 +181,7 @@ typedef enum {
#include <gst/gstsegment.h>
#include <gst/gstsegment.h>
#include <gst/gstmessage.h>
#include <gst/gstcontext.h>
G_BEGIN_DECLS
@ -545,6 +547,10 @@ void gst_event_parse_toc_select (GstEvent *event, gchar **uid);
GstEvent* gst_event_new_segment_done (GstFormat format, gint64 position) G_GNUC_MALLOC;
void gst_event_parse_segment_done (GstEvent *event, GstFormat *format, gint64 *position);
/* context */
GstEvent* gst_event_new_context (GstContext * context) G_GNUC_MALLOC;
void gst_event_parse_context (GstEvent *event, GstContext **context);
G_END_DECLS
#endif /* __GST_EVENT_H__ */

View file

@ -174,6 +174,7 @@ GstDebugCategory *GST_CAT_QOS = NULL;
GstDebugCategory *_priv_GST_CAT_POLL = NULL;
GstDebugCategory *GST_CAT_META = NULL;
GstDebugCategory *GST_CAT_LOCKING = NULL;
GstDebugCategory *GST_CAT_CONTEXT = NULL;
#endif /* !defined(GST_DISABLE_GST_DEBUG) || !defined(GST_REMOVE_DISABLED) */
@ -413,7 +414,7 @@ _priv_gst_debug_init (void)
_priv_GST_CAT_POLL = _gst_debug_category_new ("GST_POLL", 0, "poll");
GST_CAT_META = _gst_debug_category_new ("GST_META", 0, "meta");
GST_CAT_LOCKING = _gst_debug_category_new ("GST_LOCKING", 0, "locking");
GST_CAT_CONTEXT = _gst_debug_category_new ("GST_CONTEXT", 0, NULL);
/* print out the valgrind message if we're in valgrind */
_priv_gst_in_valgrind ();
@ -718,6 +719,23 @@ gst_debug_print_object (gpointer ptr)
g_free (s);
return ret;
}
if (GST_IS_CONTEXT (object)) {
GstContext *context = GST_CONTEXT_CAST (object);
gchar *s, *ret;
const GstStructure *structure;
structure = gst_context_get_structure (context);
if (structure) {
s = gst_info_structure_to_string (structure);
} else {
s = g_strdup ("(NULL)");
}
ret = g_strdup_printf ("context '%s'", s);
g_free (s);
return ret;
}
return g_strdup_printf ("%p", ptr);
}

View file

@ -2150,3 +2150,184 @@ gst_message_new_stream_start (GstObject * src)
return message;
}
/**
* gst_message_new_need_context:
* @src: (transfer none): The object originating the message.
*
* This message is posted when an element needs a specific #GstContext.
*
* Returns: (transfer full): The new need-context message.
*
* MT safe.
*/
GstMessage *
gst_message_new_need_context (GstObject * src)
{
GstMessage *message;
GstStructure *structure;
structure = gst_structure_new_id_empty (GST_QUARK (MESSAGE_NEED_CONTEXT));
message = gst_message_new_custom (GST_MESSAGE_NEED_CONTEXT, src, structure);
return message;
}
static GArray *
ensure_array (GstStructure * s, GQuark quark, gsize element_size,
GDestroyNotify clear_func)
{
GArray *array;
const GValue *value;
value = gst_structure_id_get_value (s, quark);
if (value) {
array = (GArray *) g_value_get_boxed (value);
} else {
GValue new_array_val = { 0, };
array = g_array_new (FALSE, TRUE, element_size);
if (clear_func)
g_array_set_clear_func (array, clear_func);
g_value_init (&new_array_val, G_TYPE_ARRAY);
g_value_take_boxed (&new_array_val, array);
gst_structure_id_take_value (s, quark, &new_array_val);
}
return array;
}
static void
free_array_string (gpointer ptr)
{
gchar *str = *(gchar **) ptr;
g_free (str);
}
/**
* gst_message_add_context_type:
* @message: a GST_MESSAGE_NEED_CONTEXT type message
* @context_type: a context type
*
* Add a new context type to @message.
*/
void
gst_message_add_context_type (GstMessage * message, const gchar * context_type)
{
GstStructure *structure;
GArray *array;
gchar *copy;
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT);
g_return_if_fail (gst_message_is_writable (message));
structure = GST_MESSAGE_STRUCTURE (message);
array = ensure_array (structure, GST_QUARK (CONTEXT_TYPES),
sizeof (gchar *), free_array_string);
copy = g_strdup (context_type);
g_array_append_val (array, copy);
}
/**
* gst_message_get_n_context_types:
* @message: a GST_MESSAGE_NEED_CONTEXT type message
*
* Retrieve the number of values currently stored in the
* context-types array of the message's structure.
*
* Returns: the context-types array size as a #guint.
*/
guint
gst_message_get_n_context_types (GstMessage * message)
{
GstStructure *structure;
GArray *array;
g_return_val_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT,
0);
structure = GST_MESSAGE_STRUCTURE (message);
array = ensure_array (structure, GST_QUARK (CONTEXT_TYPES),
sizeof (gchar *), free_array_string);
return array->len;
}
/**
* gst_message_parse_nth_context_type:
* @message: a GST_MESSAGE_NEED_CONTEXT type message
* @context_type: (out) (allow-none): the context type, or NULL
*
* Parse a context type from an existing GST_MESSAGE_NEED_CONTEXT message
* from @index.
*
* Returns: a #gboolean indicating if the parsing succeeded.
*/
gboolean
gst_message_parse_nth_context_type (GstMessage * message, guint index,
const gchar ** context_type)
{
GstStructure *structure;
GArray *array;
g_return_val_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT,
FALSE);
structure = GST_MESSAGE_STRUCTURE (message);
array = ensure_array (structure, GST_QUARK (CONTEXT_TYPES),
sizeof (gchar *), free_array_string);
g_return_val_if_fail (index < array->len, FALSE);
if (context_type)
*context_type = g_array_index (array, gchar *, index);
return TRUE;
}
/**
* gst_message_new_have_context:
* @src: (transfer none): The object originating the message.
* @context: (transfer full): the context
*
* This message is posted when an element has a new local #GstContext.
*
* Returns: (transfer full): The new have-context message.
*
* MT safe.
*/
GstMessage *
gst_message_new_have_context (GstObject * src, GstContext * context)
{
GstMessage *message;
GstStructure *structure;
structure = gst_structure_new_id (GST_QUARK (MESSAGE_HAVE_CONTEXT),
GST_QUARK (CONTEXT), GST_TYPE_CONTEXT, context, NULL);
message = gst_message_new_custom (GST_MESSAGE_HAVE_CONTEXT, src, structure);
gst_context_unref (context);
return message;
}
/**
* gst_message_parse_have_context:
* @message: A valid #GstMessage of type GST_MESSAGE_HAVE_CONTEXT.
* @context: (out) (transfer full): Result location for the context or NULL
*
* Extract the context from the HAVE_CONTEXT message.
*
* MT safe.
*/
void
gst_message_parse_have_context (GstMessage * message, GstContext ** context)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_HAVE_CONTEXT);
if (context)
gst_structure_id_get (GST_MESSAGE_STRUCTURE (message),
GST_QUARK (CONTEXT), GST_TYPE_CONTEXT, context, NULL);
}

View file

@ -136,6 +136,8 @@ typedef enum
GST_MESSAGE_TOC = (1 << 26),
GST_MESSAGE_RESET_TIME = (1 << 27),
GST_MESSAGE_STREAM_START = (1 << 28),
GST_MESSAGE_NEED_CONTEXT = (1 << 29),
GST_MESSAGE_HAVE_CONTEXT = (1 << 30),
GST_MESSAGE_ANY = ~0
} GstMessageType;
@ -557,6 +559,16 @@ void gst_message_parse_reset_time (GstMessage *message, GstClockTi
/* STREAM_START */
GstMessage * gst_message_new_stream_start (GstObject * src) G_GNUC_MALLOC;
/* NEED_CONTEXT */
GstMessage * gst_message_new_need_context (GstObject * src) G_GNUC_MALLOC;
void gst_message_add_context_type (GstMessage * message, const gchar * context_type);
guint gst_message_get_n_context_types (GstMessage * message);
gboolean gst_message_parse_nth_context_type (GstMessage * message, guint i, const gchar ** context_type);
/* HAVE_CONTEXT */
GstMessage * gst_message_new_have_context (GstObject * src, GstContext *context) G_GNUC_MALLOC;
void gst_message_parse_have_context (GstMessage *message, GstContext **context);
G_END_DECLS
#endif /* __GST_MESSAGE_H__ */

View file

@ -66,7 +66,8 @@ static const gchar *_quark_strings[] = {
"GstMessageResetTime",
"GstMessageToc", "GstEventTocGlobal", "GstEventTocCurrent",
"GstEventSegmentDone",
"GstEventStreamStart", "stream-id"
"GstEventStreamStart", "stream-id", "GstEventContext", "GstQueryContext",
"GstMessageNeedContext", "GstMessageHaveContext", "context", "context-types"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -188,7 +188,13 @@ typedef enum _GstQuarkId
GST_QUARK_EVENT_SEGMENT_DONE = 159,
GST_QUARK_EVENT_STREAM_START = 160,
GST_QUARK_STREAM_ID = 161,
GST_QUARK_MAX = 162
GST_QUARK_EVENT_CONTEXT = 162,
GST_QUARK_QUERY_CONTEXT = 163,
GST_QUARK_MESSAGE_NEED_CONTEXT = 164,
GST_QUARK_MESSAGE_HAVE_CONTEXT = 165,
GST_QUARK_CONTEXT = 166,
GST_QUARK_CONTEXT_TYPES = 167,
GST_QUARK_MAX = 168
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -110,6 +110,7 @@ static GstQueryQuarks query_quarks[] = {
{GST_QUERY_ACCEPT_CAPS, "accept-caps", 0},
{GST_QUERY_CAPS, "caps", 0},
{GST_QUERY_DRAIN, "drain", 0},
{GST_QUERY_CONTEXT, "context", 0},
{0, NULL, 0}
};
@ -2430,3 +2431,152 @@ gst_query_new_drain (void)
return query;
}
/**
* gst_query_new_context:
*
* Constructs a new query object for querying the pipeline-local context.
*
* Free-function: gst_query_unref
*
* Returns: (transfer full): a new #GstQuery
*/
GstQuery *
gst_query_new_context (void)
{
GstQuery *query;
GstStructure *structure;
structure = gst_structure_new_id_empty (GST_QUARK (QUERY_CONTEXT));
query = gst_query_new_custom (GST_QUERY_CONTEXT, structure);
return query;
}
/**
* gst_query_set_context:
* @query: a #GstQuery with query type GST_QUERY_CONTEXT
* @context: the requested #GstContext
*
* Answer a context query by setting the requested context.
*/
void
gst_query_set_context (GstQuery * query, GstContext * context)
{
GstStructure *s;
g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT);
s = GST_QUERY_STRUCTURE (query);
gst_structure_id_set (s,
GST_QUARK (CONTEXT), GST_TYPE_CONTEXT, context, NULL);
}
/**
* gst_query_parse_context:
* @query: The query to parse
* @context: (out): A pointer to store the #GstContext
*
* Get the context from the context @query. The context remains valid as long as
* @query remains valid.
*/
void
gst_query_parse_context (GstQuery * query, GstContext ** context)
{
GstStructure *structure;
g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT);
g_return_if_fail (context != NULL);
structure = GST_QUERY_STRUCTURE (query);
*context = g_value_get_boxed (gst_structure_id_get_value (structure,
GST_QUARK (CONTEXT)));
}
static void
free_array_string (gpointer ptr)
{
gchar *str = *(gchar **) ptr;
g_free (str);
}
/**
* gst_query_add_context_type:
* @query: a GST_QUERY_NEED_CONTEXT type query
* @context_type: a context type
*
* Add a new context type to @query.
*/
void
gst_query_add_context_type (GstQuery * query, const gchar * context_type)
{
GstStructure *structure;
GArray *array;
gchar *copy;
g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT);
g_return_if_fail (gst_query_is_writable (query));
structure = GST_QUERY_STRUCTURE (query);
array = ensure_array (structure, GST_QUARK (CONTEXT_TYPES),
sizeof (gchar *), free_array_string);
copy = g_strdup (context_type);
g_array_append_val (array, copy);
}
/**
* gst_query_get_n_context_types:
* @query: a GST_QUERY_NEED_CONTEXT type query
*
* Retrieve the number of values currently stored in the
* context-types array of the query's structure.
*
* Returns: the context-types array size as a #guint.
*/
guint
gst_query_get_n_context_types (GstQuery * query)
{
GstStructure *structure;
GArray *array;
g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT, 0);
structure = GST_QUERY_STRUCTURE (query);
array = ensure_array (structure, GST_QUARK (CONTEXT_TYPES),
sizeof (gchar *), free_array_string);
return array->len;
}
/**
* gst_query_parse_nth_context_type:
* @query: a GST_QUERY_NEED_CONTEXT type query
* @context_type: (out) (allow-none): the context type, or NULL
*
* Parse a context type from an existing GST_QUERY_NEED_CONTEXT query
* from @index.
*
* Returns: a #gboolean indicating if the parsing succeeded.
*/
gboolean
gst_query_parse_nth_context_type (GstQuery * query, guint index,
const gchar ** context_type)
{
GstStructure *structure;
GArray *array;
g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT, FALSE);
structure = GST_QUERY_STRUCTURE (query);
array = ensure_array (structure, GST_QUARK (CONTEXT_TYPES),
sizeof (gchar *), free_array_string);
g_return_val_if_fail (index < array->len, FALSE);
if (context_type)
*context_type = g_array_index (array, gchar *, index);
return TRUE;
}

View file

@ -35,6 +35,7 @@
#include <gst/gstpad.h>
#include <gst/gstallocator.h>
#include <gst/gsttoc.h>
#include <gst/gstcontext.h>
G_BEGIN_DECLS
@ -101,6 +102,7 @@ typedef enum {
* @GST_QUERY_ACCEPT_CAPS: the accept caps query
* @GST_QUERY_CAPS: the caps query
* @GST_QUERY_DRAIN: wait till all serialized data is consumed downstream
* @GST_QUERY_CONTEXT: query the pipeline-local context from downstream
*
* Standard predefined Query types
*/
@ -124,7 +126,8 @@ typedef enum {
GST_QUERY_SCHEDULING = GST_QUERY_MAKE_TYPE (150, FLAG(UPSTREAM)),
GST_QUERY_ACCEPT_CAPS = GST_QUERY_MAKE_TYPE (160, FLAG(BOTH)),
GST_QUERY_CAPS = GST_QUERY_MAKE_TYPE (170, FLAG(BOTH)),
GST_QUERY_DRAIN = GST_QUERY_MAKE_TYPE (180, FLAG(DOWNSTREAM) | FLAG(SERIALIZED))
GST_QUERY_DRAIN = GST_QUERY_MAKE_TYPE (180, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
GST_QUERY_CONTEXT = GST_QUERY_MAKE_TYPE (190, FLAG(DOWNSTREAM))
} GstQueryType;
#undef FLAG
@ -477,6 +480,14 @@ void gst_query_parse_caps_result (GstQuery *query, GstCaps **c
/* drain query */
GstQuery * gst_query_new_drain (void) G_GNUC_MALLOC;
/* context query */
GstQuery * gst_query_new_context (void) G_GNUC_MALLOC;
void gst_query_add_context_type (GstQuery * query, const gchar * context_type);
guint gst_query_get_n_context_types (GstQuery * query);
gboolean gst_query_parse_nth_context_type (GstQuery * query, guint i, const gchar ** context_type);
void gst_query_set_context (GstQuery *query, GstContext *context);
void gst_query_parse_context (GstQuery *query, GstContext **context);
G_END_DECLS
#endif /* __GST_QUERY_H__ */

View file

@ -31,6 +31,7 @@ EXPORTS
gst_base_parse_set_duration
gst_base_parse_set_frame_rate
gst_base_parse_set_has_timing_info
gst_base_parse_set_infer_ts
gst_base_parse_set_latency
gst_base_parse_set_min_frame_size
gst_base_parse_set_passthrough

View file

@ -5,6 +5,7 @@ EXPORTS
GST_CAT_CALL_TRACE DATA
GST_CAT_CAPS DATA
GST_CAT_CLOCK DATA
GST_CAT_CONTEXT DATA
GST_CAT_DEFAULT DATA
GST_CAT_ELEMENT_PADS DATA
GST_CAT_ERROR_SYSTEM DATA
@ -269,6 +270,9 @@ EXPORTS
gst_clock_single_shot_id_reinit
gst_clock_type_get_type
gst_clock_unadjust_unlocked
gst_context_get_structure
gst_context_get_type
gst_context_new
gst_control_binding_get_g_value_array
gst_control_binding_get_type
gst_control_binding_get_value
@ -419,6 +423,7 @@ EXPORTS
gst_element_set_base_time
gst_element_set_bus
gst_element_set_clock
gst_element_set_context
gst_element_set_locked_state
gst_element_set_start_time
gst_element_set_state
@ -436,6 +441,7 @@ EXPORTS
gst_event_has_name
gst_event_new_buffer_size
gst_event_new_caps
gst_event_new_context
gst_event_new_custom
gst_event_new_eos
gst_event_new_flush_start
@ -456,6 +462,7 @@ EXPORTS
gst_event_new_toc_select
gst_event_parse_buffer_size
gst_event_parse_caps
gst_event_parse_context
gst_event_parse_flush_stop
gst_event_parse_gap
gst_event_parse_latency
@ -540,6 +547,8 @@ EXPORTS
gst_memory_resize
gst_memory_share
gst_memory_unmap
gst_message_add_context_type
gst_message_get_n_context_types
gst_message_get_seqnum
gst_message_get_stream_status_object
gst_message_get_structure
@ -556,8 +565,10 @@ EXPORTS
gst_message_new_element
gst_message_new_eos
gst_message_new_error
gst_message_new_have_context
gst_message_new_info
gst_message_new_latency
gst_message_new_need_context
gst_message_new_new_clock
gst_message_new_progress
gst_message_new_qos
@ -581,8 +592,10 @@ EXPORTS
gst_message_parse_clock_lost
gst_message_parse_clock_provide
gst_message_parse_error
gst_message_parse_have_context
gst_message_parse_info
gst_message_parse_new_clock
gst_message_parse_nth_context_type
gst_message_parse_progress
gst_message_parse_qos
gst_message_parse_qos_stats
@ -860,12 +873,14 @@ EXPORTS
gst_query_add_allocation_param
gst_query_add_allocation_pool
gst_query_add_buffering_range
gst_query_add_context_type
gst_query_add_scheduling_mode
gst_query_find_allocation_meta
gst_query_get_n_allocation_metas
gst_query_get_n_allocation_params
gst_query_get_n_allocation_pools
gst_query_get_n_buffering_ranges
gst_query_get_n_context_types
gst_query_get_n_scheduling_modes
gst_query_get_structure
gst_query_get_type
@ -875,6 +890,7 @@ EXPORTS
gst_query_new_allocation
gst_query_new_buffering
gst_query_new_caps
gst_query_new_context
gst_query_new_convert
gst_query_new_custom
gst_query_new_drain
@ -894,6 +910,7 @@ EXPORTS
gst_query_parse_buffering_stats
gst_query_parse_caps
gst_query_parse_caps_result
gst_query_parse_context
gst_query_parse_convert
gst_query_parse_duration
gst_query_parse_latency
@ -902,6 +919,7 @@ EXPORTS
gst_query_parse_nth_allocation_param
gst_query_parse_nth_allocation_pool
gst_query_parse_nth_buffering_range
gst_query_parse_nth_context_type
gst_query_parse_nth_format
gst_query_parse_nth_scheduling_mode
gst_query_parse_position
@ -917,6 +935,7 @@ EXPORTS
gst_query_set_buffering_range
gst_query_set_buffering_stats
gst_query_set_caps_result
gst_query_set_context
gst_query_set_convert
gst_query_set_duration
gst_query_set_formats