diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt index 9e0d034e02..09a395dab4 100644 --- a/docs/libs/gst-plugins-bad-libs-sections.txt +++ b/docs/libs/gst-plugins-bad-libs-sections.txt @@ -405,6 +405,29 @@ gst_base_video_encoded_video_convert gst_video_state_get_timestamp +
+gstvideocontext +GstVideoContextInterface +GST_IS_VIDEO_CONTEXT +GstVideoContext +GstVideoContextInterface +gst_video_context_iface_get_type +gst_video_context_set_context +gst_video_context_set_context_string +gst_video_context_set_context_pointer +gst_video_context_set_context_object +gst_video_context_prepare +gst_video_context_message_parse_prepare +gst_video_context_query_new +gst_video_context_run_query +gst_video_context_query_get_supported_types +gst_video_context_query_parse_value +gst_video_context_query_set_value +gst_video_context_query_set_string +gst_video_context_query_set_pointer +gst_video_context_query_set_object +
+
gstsurfacebuffer GstSurfaceBuffer diff --git a/gst-libs/gst/video/videocontext.c b/gst-libs/gst/video/videocontext.c new file mode 100644 index 0000000000..a5458a2e26 --- /dev/null +++ b/gst-libs/gst/video/videocontext.c @@ -0,0 +1,539 @@ +/* GStreamer + * + * Copyright (C) 2011 Intel + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * video-context.c: Video Context interface and helpers + * + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "videocontext.h" + +/** + * SECTION:gstvideocontext + * @short_description: Interface to handle video library context + * + * The Video Context interface enable sharing video context (such as display + * name, X11 Display, VA-API Display, etc) between neighboor elements and the + * application. + * + * The GstVideoContext interface is unstable API and may change in future. + * One can define GST_USE_UNSTABLE_API to acknowledge and avoid this warning. + * + * + * + * For Element + * + * This interface shall be implement by group of elements that need to share + * a specific video context (like VDPAU, LibVA, OpenGL elements) or by video + * sink in order to let the application select appropriate display information + * (like the X11 display name) when those sink are auto-plugged. + * + * + * Along with implementing the interface, elements will need to query + * neighboor elements or send message to the application when preparing + * the context (see gst_video_context_prepare()). They also need to reply + * to the neighboors element queries, so the context can be shared without + * the application help. + * + * + * Elements that are guarantied to have both upstream and downstream + * neighboors element implementing the #GstVideoContext (like the gloverlay + * element in gst-plugins-opengl) is not required to also implement the + * interface. Relying on neighboors query shall be sufficient (see + * gst_video_context_run_query()). + * + * + * The query is an application query with a structure name set to + * "prepare-video-context" and an array of supported video context types set + * in the field named "types". This query shall be send downstream and + * upstream, iterating the pads in order to find neighboors regardless of a + * static (sink to src) or a dynamic (src to sink) activation. Element should + * used the helpers method gst_video_context_prepare() (or + * gst_video_context_run_query() if no GstVideoContext interface) to + * correctly execute the query . The result is set using the query helper + * functions, the structures fields name being "video-context-type" as + * string and "video-context" as a #GValue. + * + * + * If the query is not handled by any neighboor, the element should ask the + * application using the "prepare-video-context" message. The application + * may then use the interface to set the video context information. If no + * context was set, the element shall create one using default configuration. + * Elements with multiple src or sink pad shall implement proper locking to + * prevent the race of parallel queries being replied. + * + * + * Well known video-context are: "x11-display-name" a string representing the + * X11 display to use, "x11-display" the X11 Display structure, "va-display", + * the VADisplay structure and more. + * + * + * + * + * For Application + * + * In the case there is no neighboor element with video context to share, + * the element will first turn toward the application, by sending a + * "prepare-video-context" message. This message is sent along with a list + * of supported display types. The application can optionally reply to this + * message by calling appropriate setter through the #GstVideoContext + * interface. If the application supports more then one video context type, + * it should choose the first one to occure in the supported list. It's + * important to remember that the message is delivered from the streaming + * thread, and appropriate locking should be considered. If the application + * does not have a video context to share, the element will simply allocate + * one base on default settings. Usually, only applications using OpenGL + * base sink, or running on special X11 display need to share a video context. + * + * Applications sharing X11 Display structure should always initialize the + * X11 threading support using XInitThreads() as GStreamer will need to + * manipulate the display from a separeate threads. + * + * + * + * Example using ClutterVideoGstVideoSink + * + * This example is for user of ClutterGstVideoSink element, the + * ClutterGstPlayer object transparently handle this. + * + * |[ + * #if CLUTTER_WINDOWING_X11 + * static GstBusSyncReply + * on_sync_message (GstBus * bus, GstMessage * message, gpointer user_data) + * { + * Display *display = user_data; + * GstVideoContext *context; + * const gchar **types; + * + * if (gst_video_context_message_parse_prepare (message, &types, &context)) { + * gint i; + * + * for (i = 0; types[i]; i++) { + * + * if (!strcmp(types[i], "x11-display")) { + * gst_video_context_set_context_pointer (context, "x11-display", display); + * } + * else if (!strcmp(types[i], "x11-display-name")) { + * gst_video_context_set_context_string (context, "x11-display-name", + * DisplayString (display)); + * } else { + * continue; + * } + * + * gst_message_unref (message); + * return GST_BUS_DROP; + * } + * } + * + * return GST_BUS_PASS; + * } + * #endif + * + * gint + * main (gint argc, gchar **argv) + * { + * GstBin *pipeline; + * GstBus *bus; + * + * ... + * + * bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + * + * #if CLUTTER_WINDOWING_X11 + * gst_bus_set_sync_handler (priv->bus, on_sync_message, + * clutter_x11_get_default_display ()); + * #endif + * + * gst_object_unref (GST_OBJECT (priv->bus)); + * + * ... + * } + * ]| + * + * + */ + +G_DEFINE_INTERFACE (GstVideoContext, gst_video_context_iface, G_TYPE_INVALID); + +static inline GstStructure * +gst_video_context_new_structure (const gchar ** types) +{ + return gst_structure_new ("prepare-video-context", + "types", G_TYPE_STRV, types, NULL); +} + +static gboolean +gst_video_context_pad_query (gpointer item, GValue * value, gpointer user_data) +{ + GstPad *pad = GST_PAD (item); + GstQuery *query = user_data; + gboolean res; + + res = gst_pad_peer_query (pad, query); + gst_object_unref (pad); + + if (res) { + g_value_set_boolean (value, TRUE); + return FALSE; + } + + return TRUE; +} + +static void +gst_video_context_iface_default_init (GstVideoContextInterface * iface) +{ + /* default virtual functions */ + iface->set_context = NULL; +} + +/** + * gst_video_context_set_context: + * @context: an element implementing #GstVideoContext + * @type: the type of display being set + * @value: a #GValue containing the context + * + * This is a wrapper for the set_context() virtual method. It is suggested to + * use one of the helpers to avoid having to manipulate #GValue + */ +void +gst_video_context_set_context (GstVideoContext * context, const gchar * type, + const GValue * value) +{ + g_return_if_fail (GST_IS_VIDEO_CONTEXT (context)); + g_return_if_fail (GST_VIDEO_CONTEXT_GET_IFACE (context)->set_context); + + GST_VIDEO_CONTEXT_GET_IFACE (context)->set_context (context, type, value); +} + +/** + * gst_video_context_set_context_string: + * @context: an element implementing #GstVideoContext + * @type: the type of display being set + * @string: a string representing the video context + * + * This helper is commonly used for setting video context represented by a + * string like the X11 display name ("x11-display-name")/ + */ +void +gst_video_context_set_context_string (GstVideoContext * context, + const gchar * type, const gchar * string) +{ + GValue value = { 0 }; + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, string); + gst_video_context_set_context (context, type, &value); + g_value_unset (&value); +} + +/** + * gst_video_context_set_context_pointer: + * @context: an element implementing #GstVideoContext + * @type: the type of display being set + * @pointer: a pointer to the video context + * + * This helper is used for setting video context using a pointer, typically to + * a structure like the X11 Display ("x11-display") or the VADisplay + * ("vaapi-display"). + * + * Users of X11 Display should ensure that XInitThreads() was called before + * opening the display. + * + */ +void +gst_video_context_set_context_pointer (GstVideoContext * context, + const gchar * type, gpointer pointer) +{ + GValue value = { 0 }; + g_value_init (&value, G_TYPE_POINTER); + g_value_set_pointer (&value, pointer); + gst_video_context_set_context (context, type, &value); + g_value_unset (&value); +} + +/** + * gst_video_context_set_context_object: + * @context: an element implementing #GstVideoContext + * @type: the type of display being set + * @object: a #GObject resenting the display + * + * This is for video context that are #GObject, this helper allow taking + * benifit of the #GObject refcounting. It is particularly handy for element + * to have refcounting as the order in which element will stop using the + * display is not defined. + */ +void +gst_video_context_set_context_object (GstVideoContext * context, + const gchar * type, GObject * object) +{ + GValue value = { 0 }; + g_return_if_fail (G_IS_OBJECT (object)); + g_value_init (&value, G_TYPE_OBJECT); + g_value_set_object (&value, object); + gst_video_context_set_context (context, type, &value); + g_value_unset (&value); +} + +/** + * gst_video_context_prepare: + * @context: an element implementing #GstVideoContext interface + * @types: an array of supported types, prefered first + * + * This method run "prepare-video-context" custom query dowstream, and + * upstream. If * the query has a reply, it sets the context value using + * gst_video_context_set_context(). Otherwise, it sends a + * "prepare-video-context" message to the application. The element can then + * continue video context initialization. + */ +void +gst_video_context_prepare (GstVideoContext * context, const gchar ** types) +{ + GstQuery *query = gst_video_context_query_new (types); + + /* Check neighborhood, if found call GstVideoContext */ + if (gst_video_context_run_query (GST_ELEMENT (context), query)) { + const gchar *type = NULL; + const GValue *value; + gst_video_context_query_parse_value (query, &type, &value); + gst_video_context_set_context (context, type, value); + } else { + /* If no neighbor replyed, query the application */ + GstMessage *message; + GstStructure *structure; + + structure = gst_video_context_new_structure (types); + message = gst_message_new_element (GST_OBJECT (context), structure); + gst_element_post_message (GST_ELEMENT (context), message); + } + + gst_query_unref (query); +} + +/** + * gst_video_context_message_parse_prepare: + * @message: a #GstMessage + * @types: return value for supported types + * @context: return value for the element the implements #GstVideoContext + * + * This helper shall be used by application to simply handling of the + * "prepare-video-context" message. + * + * Rerturns: #FALSE is the message was not valid "prepare-video-context" + * element message, otherwise #TRUE with @types and @context set. + */ +gboolean +gst_video_context_message_parse_prepare (GstMessage * message, + const gchar *** types, GstVideoContext ** context) +{ + GstObject *src = GST_MESSAGE_SRC (message); + const GstStructure *structure; + const GValue *value; + + if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + return FALSE; + + if (!gst_structure_has_name (message->structure, "prepare-video-context")) + return FALSE; + + if (!GST_IS_VIDEO_CONTEXT (src)) + return FALSE; + + structure = gst_message_get_structure (message); + value = gst_structure_get_value (structure, "types"); + + if (!G_VALUE_HOLDS (value, G_TYPE_STRV)) + return FALSE; + + if (types) + *types = g_value_get_boxed (value); + + if (context) + *context = GST_VIDEO_CONTEXT (src); + + return TRUE; +} + +/** + * gst_video_context_query_new: + * @types: a string array of video context types + * + * Create a new custom #GstQuery with structure name "prepare-video-context". + */ +GstQuery * +gst_video_context_query_new (const gchar ** types) +{ + GstStructure *structure = gst_video_context_new_structure (types); + return gst_query_new_application (GST_QUERY_CUSTOM, structure); +} + +/** + * gst_video_context_run_query: + * @element: a #GstElement + * @query: a #GstQuery + * + * This helper runs the query on each downstream, then upstream pads in an + * element. This is called by gst_video_context_prepare(). This method is only + * used directly within elements that are required to have two neighboors + * elements with appropriate video context. This would be the case of + * specialized filters that only manipulate non-raw buffers (e.g. + * gldeinterlace). Those elements do not have to implement #GstVideoContext + * interface. + */ +gboolean +gst_video_context_run_query (GstElement * element, GstQuery * query) +{ + GstIterator *it; + GstIteratorFoldFunction func = gst_video_context_pad_query; + GValue res = { 0 }; + + g_value_init (&res, G_TYPE_BOOLEAN); + g_value_set_boolean (&res, FALSE); + + /* Ask downstream neighbor (mainly static pipeline case) */ + it = gst_element_iterate_src_pads (element); + + while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC) + gst_iterator_resync (it); + + gst_iterator_free (it); + + /* If none, ask upstream neighbor (auto-plugged case) */ + if (!g_value_get_boolean (&res)) { + it = gst_element_iterate_sink_pads (element); + + while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC) + gst_iterator_resync (it); + + gst_iterator_free (it); + } + + return g_value_get_boolean (&res); +} + +/** + * gst_video_context_query_get_supported_types: + * @query: a #GstQuery + * + * Returns: An array of supported video context types + */ +const gchar ** +gst_video_context_query_get_supported_types (GstQuery * query) +{ + GstStructure *structure = gst_query_get_structure (query); + const GValue *value = gst_structure_get_value (structure, "types"); + + if (G_VALUE_HOLDS (value, G_TYPE_STRV)) + return g_value_get_boxed (value); + + return NULL; +} + +/** + * gst_video_context_query_parse_value: + * @query: a #GstQuery + * @type: return video context type + * @value: return video context #GValue + * + * Helper to extract the video context type and value from a #GstQuery. + */ +void +gst_video_context_query_parse_value (GstQuery * query, const gchar ** type, + const GValue ** value) +{ + GstStructure *structure = gst_query_get_structure (query); + + if (type) + *type = gst_structure_get_string (structure, "video-context-type"); + + if (value) + *value = gst_structure_get_value (structure, "video-context"); +} + +/** + * gst_video_context_query_set_value: + * @query: a #GstQuery + * @type: the video context type + * @value: a #GValue set with video context + * + * Helper to set the video context as a #GValue inside the #GstQuery. + */ +void +gst_video_context_query_set_value (GstQuery * query, const gchar * type, + GValue * value) +{ + GstStructure *structure = gst_query_get_structure (query); + gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type, + "video-context", G_TYPE_VALUE, value, NULL); +} + +/** + * gst_video_context_query_set_string: + * @query: a #GstQuery + * @type: the video context type + * @value: a string representing the video context + * + * Helper to set the video context as a string inside the #GstQuery. + */ +void +gst_video_context_query_set_string (GstQuery * query, const gchar * type, + const gchar * value) +{ + GstStructure *structure = gst_query_get_structure (query); + gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type, + "video-context", G_TYPE_STRING, value, NULL); +} + +/** + * gst_video_context_query_set_pointer: + * @query: a #GstQuery + * @type: the video context type + * @value: a #gpointer representing the video context + * + * Helper to set the video context as a #gpointer inside the #GstQuery. + */ +void +gst_video_context_query_set_pointer (GstQuery * query, const gchar * type, + gpointer value) +{ + GstStructure *structure = gst_query_get_structure (query); + gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type, + "video-context", G_TYPE_POINTER, value, NULL); +} + +/** + * gst_video_context_query_set_object: + * @query: a #GstQuery + * @type: the video context type + * @value: a #GObject representing the video context + * + * Helper to set the video context as a #GObject inside the #GstQuery. + */ +void +gst_video_context_query_set_object (GstQuery * query, const gchar * type, + GObject * value) +{ + GstStructure *structure = gst_query_get_structure (query); + gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type, + "video-context", G_TYPE_OBJECT, value, NULL); +} diff --git a/gst-libs/gst/video/videocontext.h b/gst-libs/gst/video/videocontext.h new file mode 100644 index 0000000000..5becb56163 --- /dev/null +++ b/gst-libs/gst/video/videocontext.h @@ -0,0 +1,117 @@ +/* GStreamer + * + * Copyright (C) 2011 Intel + * Copyright (C) 2011 Collabora Ltd. + * Author: Nicolas Dufresne + * + * video-context.h: Video Context interface and helpers + * + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VIDEO_CONTEXT_H__ +#define __GST_VIDEO_CONTEXT_H__ + +#ifndef GST_USE_UNSTABLE_API +#warning "The GstVideoContext interface is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VIDEO_CONTEXT (gst_video_context_iface_get_type ()) +#define GST_VIDEO_CONTEXT(obj) (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VIDEO_CONTEXT, GstVideoContext)) +#define GST_IS_VIDEO_CONTEXT(obj) (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VIDEO_CONTEXT)) +#define GST_VIDEO_CONTEXT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_VIDEO_CONTEXT, GstVideoContextInterface)) + +/** + * GstVideoContext: + * + * Opaque #GstVideoContext data structure. + */ +typedef struct _GstVideoContext GstVideoContext; +typedef struct _GstVideoContextInterface GstVideoContextInterface; + +/** + * GstVideoContextInterface: + * @parent: parent interface type. + * @set_context: vmethod to set video context. + * + * #GstVideoContextInterface interface. + */ +struct _GstVideoContextInterface +{ + GTypeInterface parent; + + /* virtual functions */ + void (*set_context) (GstVideoContext * context, + const gchar * type, + const GValue * value); + +}; + +GType gst_video_context_iface_get_type (void); + +/* virtual class method and associated helpers */ +void gst_video_context_set_context (GstVideoContext * context, + const gchar * type, + const GValue * value); +void gst_video_context_set_context_string (GstVideoContext * context, + const gchar * type, + const gchar * value); +void gst_video_context_set_context_pointer (GstVideoContext * context, + const gchar * type, + gpointer value); +void gst_video_context_set_context_object (GstVideoContext * context, + const gchar * type, + GObject * value); + + +/* message helpers */ +void gst_video_context_prepare (GstVideoContext *context, + const gchar ** types); + +gboolean gst_video_context_message_parse_prepare (GstMessage * message, + const gchar *** types, + GstVideoContext ** ctx); + +/* query helpers */ +GstQuery * gst_video_context_query_new (const gchar ** types); +gboolean gst_video_context_run_query (GstElement *element, + GstQuery *query); +const gchar ** gst_video_context_query_get_supported_types (GstQuery * query); +void gst_video_context_query_parse_value (GstQuery * query, + const gchar ** type, + const GValue ** value); +void gst_video_context_query_set_value (GstQuery * query, + const gchar * type, + GValue * value); +void gst_video_context_query_set_string (GstQuery * query, + const gchar * type, + const gchar * value); +void gst_video_context_query_set_pointer (GstQuery * query, + const gchar * type, + gpointer value); +void gst_video_context_query_set_object (GstQuery * query, + const gchar * type, + GObject * value); + +G_END_DECLS + +#endif /* __GST_VIDEO_CONTEXT_H__ */