From b90906103104216aad85ea262a97340280e70369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 28 Mar 2013 15:35:13 +0100 Subject: [PATCH] gst: Add new GstContext miniobject for sharing contexts in a pipeline --- docs/gst/gstreamer-docs.sgml | 1 + docs/gst/gstreamer-sections.txt | 38 +++++++ gst/Makefile.am | 2 + gst/gst.c | 1 + gst/gst_private.h | 3 + gst/gstbin.c | 34 ++++++ gst/gstcontext.c | 180 +++++++++++++++++++++++++++++++ gst/gstcontext.h | 153 +++++++++++++++++++++++++++ gst/gstelement.c | 26 +++++ gst/gstelement.h | 8 +- gst/gstevent.c | 50 +++++++++ gst/gstevent.h | 6 ++ gst/gstinfo.c | 20 +++- gst/gstmessage.c | 181 ++++++++++++++++++++++++++++++++ gst/gstmessage.h | 12 +++ gst/gstquark.c | 3 +- gst/gstquark.h | 8 +- gst/gstquery.c | 150 ++++++++++++++++++++++++++ gst/gstquery.h | 13 ++- win32/common/libgstbase.def | 1 + win32/common/libgstreamer.def | 19 ++++ 21 files changed, 904 insertions(+), 5 deletions(-) create mode 100644 gst/gstcontext.c create mode 100644 gst/gstcontext.h diff --git a/docs/gst/gstreamer-docs.sgml b/docs/gst/gstreamer-docs.sgml index d4388c2f11..1cfbe34715 100644 --- a/docs/gst/gstreamer-docs.sgml +++ b/docs/gst/gstreamer-docs.sgml @@ -69,6 +69,7 @@ Windows. It is released under the GNU Library General Public License + diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index e6ccf1b1d3..a96434cb5b 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -621,6 +621,26 @@ GST_PADDING_INIT GST_USING_PRINTF_EXTENSION +
+gstcontext +GstContext +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 + +GST_CONTEXT +GST_CONTEXT_CAST +GST_IS_CONTEXT +GST_TYPE_CONTEXT + +gst_context_get_type +
gstcontrolbinding @@ -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 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 + 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 GstQueryClass GST_QUERY diff --git a/gst/Makefile.am b/gst/Makefile.am index c1bdf0c165..87db0556f1 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -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 \ diff --git a/gst/gst.c b/gst/gst.c index 927472616f..6a7219e118 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -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 (); diff --git a/gst/gst_private.h b/gst/gst_private.h index 99877c4969..d42b48fdb0 100644 --- a/gst/gst_private.h +++ b/gst/gst_private.h @@ -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 diff --git a/gst/gstbin.c b/gst/gstbin.c index c28f2d72ba..b1826188c6 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -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) { diff --git a/gst/gstcontext.c b/gst/gstcontext.c new file mode 100644 index 0000000000..6c6c38e4d7 --- /dev/null +++ b/gst/gstcontext.c @@ -0,0 +1,180 @@ +/* GStreamer + * Copyright (C) 2013 Collabora Ltd. + * Author: 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 + * @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 +#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), + ©->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); +} diff --git a/gst/gstcontext.h b/gst/gstcontext.h new file mode 100644 index 0000000000..61e9180665 --- /dev/null +++ b/gst/gstcontext.h @@ -0,0 +1,153 @@ +/* GStreamer + * Copyright (C) 2013 Collabora Ltd. + * Author: 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. + */ + +#ifndef __GST_CONTEXT_H__ +#define __GST_CONTEXT_H__ + +G_BEGIN_DECLS + +typedef struct _GstContext GstContext; + +#include +#include + +#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__ */ diff --git a/gst/gstelement.c b/gst/gstelement.c index 7a7133f853..b41fa26da7 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -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); +} diff --git a/gst/gstelement.h b/gst/gstelement.h index c4c6dfaf91..afcb9c6396 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -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); diff --git a/gst/gstevent.c b/gst/gstevent.c index bb9736301b..1993eceecc 100644 --- a/gst/gstevent.c +++ b/gst/gstevent.c @@ -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)))); +} diff --git a/gst/gstevent.h b/gst/gstevent.h index 865648422c..f0de0adb23 100644 --- a/gst/gstevent.h +++ b/gst/gstevent.h @@ -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 #include #include +#include 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__ */ diff --git a/gst/gstinfo.c b/gst/gstinfo.c index 3cc9b136ab..21d53d8642 100644 --- a/gst/gstinfo.c +++ b/gst/gstinfo.c @@ -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); } diff --git a/gst/gstmessage.c b/gst/gstmessage.c index d7982bfbe9..2b231c4883 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -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); +} diff --git a/gst/gstmessage.h b/gst/gstmessage.h index 614f5cceb6..802ee1769f 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -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__ */ diff --git a/gst/gstquark.c b/gst/gstquark.c index f57810d8bf..6343726479 100644 --- a/gst/gstquark.c +++ b/gst/gstquark.c @@ -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]; diff --git a/gst/gstquark.h b/gst/gstquark.h index c632a1803e..1abc2ee160 100644 --- a/gst/gstquark.h +++ b/gst/gstquark.h @@ -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]; diff --git a/gst/gstquery.c b/gst/gstquery.c index c62b0218c9..d5f2962848 100644 --- a/gst/gstquery.c +++ b/gst/gstquery.c @@ -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; +} diff --git a/gst/gstquery.h b/gst/gstquery.h index 1f16e301cf..c8eb6f95d6 100644 --- a/gst/gstquery.h +++ b/gst/gstquery.h @@ -35,6 +35,7 @@ #include #include #include +#include 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__ */ diff --git a/win32/common/libgstbase.def b/win32/common/libgstbase.def index a36aac1d38..50d43f4195 100644 --- a/win32/common/libgstbase.def +++ b/win32/common/libgstbase.def @@ -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 diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index ba81ed2f15..0dcdce056c 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -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