3 * Copyright (C) 2011 Intel
4 * Copyright (C) 2011 Collabora Ltd.
5 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
7 * video-context.c: Video Context interface and helpers
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
30 #include "videocontext.h"
33 * SECTION:gstvideocontext
34 * @short_description: Interface to handle video library context
36 * The Video Context interface enable sharing video context (such as display
37 * name, X11 Display, VA-API Display, etc) between neighboor elements and the
40 * The GstVideoContext interface is unstable API and may change in future.
41 * One can define GST_USE_UNSTABLE_API to acknowledge and avoid this warning.
45 * <title>For Element</title>
47 * This interface shall be implement by group of elements that need to share
48 * a specific video context (like VDPAU, LibVA, OpenGL elements) or by video
49 * sink in order to let the application select appropriate display information
50 * (like the X11 display name) when those sink are auto-plugged.
53 * Along with implementing the interface, elements will need to query
54 * neighboor elements or send message to the application when preparing
55 * the context (see gst_video_context_prepare()). They also need to reply
56 * to the neighboors element queries, so the context can be shared without
57 * the application help.
60 * Elements that are guarantied to have both upstream and downstream
61 * neighboors element implementing the #GstVideoContext (like the gloverlay
62 * element in gst-plugins-opengl) is not required to also implement the
63 * interface. Relying on neighboors query shall be sufficient (see
64 * gst_video_context_run_query()).
67 * The query is an application query with a structure name set to
68 * "prepare-video-context" and an array of supported video context types set
69 * in the field named "types". This query shall be send downstream and
70 * upstream, iterating the pads in order to find neighboors regardless of a
71 * static (sink to src) or a dynamic (src to sink) activation. Element should
72 * used the helpers method gst_video_context_prepare() (or
73 * gst_video_context_run_query() if no GstVideoContext interface) to
74 * correctly execute the query . The result is set using the query helper
75 * functions, the structures fields name being "video-context-type" as
76 * string and "video-context" as a #GValue.
79 * If the query is not handled by any neighboor, the element should ask the
80 * application using the "prepare-video-context" message. The application
81 * may then use the interface to set the video context information. If no
82 * context was set, the element shall create one using default configuration.
83 * Elements with multiple src or sink pad shall implement proper locking to
84 * prevent the race of parallel queries being replied.
87 * Well known video-context are: "x11-display-name" a string representing the
88 * X11 display to use, "x11-display" the X11 Display structure, "va-display",
89 * the VADisplay structure and more.
94 * <title>For Application</title>
96 * In the case there is no neighboor element with video context to share,
97 * the element will first turn toward the application, by sending a
98 * "prepare-video-context" message. This message is sent along with a list
99 * of supported display types. The application can optionally reply to this
100 * message by calling appropriate setter through the #GstVideoContext
101 * interface. If the application supports more then one video context type,
102 * it should choose the first one to occure in the supported list. It's
103 * important to remember that the message is delivered from the streaming
104 * thread, and appropriate locking should be considered. If the application
105 * does not have a video context to share, the element will simply allocate
106 * one base on default settings. Usually, only applications using OpenGL
107 * base sink, or running on special X11 display need to share a video context.
109 * Applications sharing X11 Display structure should always initialize the
110 * X11 threading support using XInitThreads() as GStreamer will need to
111 * manipulate the display from a separeate threads.
115 * <title>Example using ClutterVideoGstVideoSink</title>
117 * This example is for user of ClutterGstVideoSink element, the
118 * ClutterGstPlayer object transparently handle this.
121 * #if CLUTTER_WINDOWING_X11
122 * static GstBusSyncReply
123 * on_sync_message (GstBus * bus, GstMessage * message, gpointer user_data)
125 * Display *display = user_data;
126 * GstVideoContext *context;
127 * const gchar **types;
129 * if (gst_video_context_message_parse_prepare (message, &types, &context)) {
132 * for (i = 0; types[i]; i++) {
134 * if (!strcmp(types[i], "x11-display")) {
135 * gst_video_context_set_context_pointer (context, "x11-display", display);
137 * else if (!strcmp(types[i], "x11-display-name")) {
138 * gst_video_context_set_context_string (context, "x11-display-name",
139 * DisplayString (display));
144 * gst_message_unref (message);
145 * return GST_BUS_DROP;
149 * return GST_BUS_PASS;
154 * main (gint argc, gchar **argv)
161 * bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
163 * #if CLUTTER_WINDOWING_X11
164 * gst_bus_set_sync_handler (priv->bus, on_sync_message,
165 * clutter_x11_get_default_display ());
168 * gst_object_unref (GST_OBJECT (priv->bus));
177 G_DEFINE_INTERFACE (GstVideoContext, gst_video_context_iface, G_TYPE_INVALID);
179 static inline GstStructure *
180 gst_video_context_new_structure (const gchar ** types)
182 return gst_structure_new ("prepare-video-context",
183 "types", G_TYPE_STRV, types, NULL);
187 gst_video_context_pad_query (gpointer item, GValue * value, gpointer user_data)
189 GstPad *pad = GST_PAD (item);
190 GstQuery *query = user_data;
193 res = gst_pad_peer_query (pad, query);
194 gst_object_unref (pad);
197 g_value_set_boolean (value, TRUE);
205 gst_video_context_iface_default_init (GstVideoContextInterface * iface)
207 /* default virtual functions */
208 iface->set_context = NULL;
212 * gst_video_context_set_context:
213 * @context: an element implementing #GstVideoContext
214 * @type: the type of display being set
215 * @value: a #GValue containing the context
217 * This is a wrapper for the set_context() virtual method. It is suggested to
218 * use one of the helpers to avoid having to manipulate #GValue
221 gst_video_context_set_context (GstVideoContext * context, const gchar * type,
222 const GValue * value)
224 g_return_if_fail (GST_IS_VIDEO_CONTEXT (context));
225 g_return_if_fail (GST_VIDEO_CONTEXT_GET_IFACE (context)->set_context);
227 GST_VIDEO_CONTEXT_GET_IFACE (context)->set_context (context, type, value);
231 * gst_video_context_set_context_string:
232 * @context: an element implementing #GstVideoContext
233 * @type: the type of display being set
234 * @string: a string representing the video context
236 * This helper is commonly used for setting video context represented by a
237 * string like the X11 display name ("x11-display-name")/
240 gst_video_context_set_context_string (GstVideoContext * context,
241 const gchar * type, const gchar * string)
243 GValue value = { 0 };
244 g_value_init (&value, G_TYPE_STRING);
245 g_value_set_string (&value, string);
246 gst_video_context_set_context (context, type, &value);
247 g_value_unset (&value);
251 * gst_video_context_set_context_pointer:
252 * @context: an element implementing #GstVideoContext
253 * @type: the type of display being set
254 * @pointer: a pointer to the video context
256 * This helper is used for setting video context using a pointer, typically to
257 * a structure like the X11 Display ("x11-display") or the VADisplay
260 * Users of X11 Display should ensure that XInitThreads() was called before
261 * opening the display.
265 gst_video_context_set_context_pointer (GstVideoContext * context,
266 const gchar * type, gpointer pointer)
268 GValue value = { 0 };
269 g_value_init (&value, G_TYPE_POINTER);
270 g_value_set_pointer (&value, pointer);
271 gst_video_context_set_context (context, type, &value);
272 g_value_unset (&value);
276 * gst_video_context_set_context_object:
277 * @context: an element implementing #GstVideoContext
278 * @type: the type of display being set
279 * @object: a #GObject resenting the display
281 * This is for video context that are #GObject, this helper allow taking
282 * benifit of the #GObject refcounting. It is particularly handy for element
283 * to have refcounting as the order in which element will stop using the
284 * display is not defined.
287 gst_video_context_set_context_object (GstVideoContext * context,
288 const gchar * type, GObject * object)
290 GValue value = { 0 };
291 g_return_if_fail (G_IS_OBJECT (object));
292 g_value_init (&value, G_TYPE_OBJECT);
293 g_value_set_object (&value, object);
294 gst_video_context_set_context (context, type, &value);
295 g_value_unset (&value);
299 * gst_video_context_prepare:
300 * @context: an element implementing #GstVideoContext interface
301 * @types: an array of supported types, prefered first
303 * This method run "prepare-video-context" custom query dowstream, and
304 * upstream. If * the query has a reply, it sets the context value using
305 * gst_video_context_set_context(). Otherwise, it sends a
306 * "prepare-video-context" message to the application. The element can then
307 * continue video context initialization.
310 gst_video_context_prepare (GstVideoContext * context, const gchar ** types)
312 GstQuery *query = gst_video_context_query_new (types);
314 /* Check neighborhood, if found call GstVideoContext */
315 if (gst_video_context_run_query (GST_ELEMENT (context), query)) {
316 const gchar *type = NULL;
318 gst_video_context_query_parse_value (query, &type, &value);
319 gst_video_context_set_context (context, type, value);
321 /* If no neighbor replyed, query the application */
323 GstStructure *structure;
325 structure = gst_video_context_new_structure (types);
326 message = gst_message_new_element (GST_OBJECT (context), structure);
327 gst_element_post_message (GST_ELEMENT (context), message);
330 gst_query_unref (query);
334 * gst_video_context_message_parse_prepare:
335 * @message: a #GstMessage
336 * @types: return value for supported types
337 * @context: return value for the element the implements #GstVideoContext
339 * This helper shall be used by application to simply handling of the
340 * "prepare-video-context" message.
342 * Rerturns: #FALSE is the message was not valid "prepare-video-context"
343 * element message, otherwise #TRUE with @types and @context set.
346 gst_video_context_message_parse_prepare (GstMessage * message,
347 const gchar *** types, GstVideoContext ** context)
349 GstObject *src = GST_MESSAGE_SRC (message);
350 const GstStructure *structure;
353 if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
356 if (!gst_structure_has_name (message->structure, "prepare-video-context"))
359 if (!GST_IS_VIDEO_CONTEXT (src))
362 structure = gst_message_get_structure (message);
363 value = gst_structure_get_value (structure, "types");
365 if (!G_VALUE_HOLDS (value, G_TYPE_STRV))
369 *types = g_value_get_boxed (value);
372 *context = GST_VIDEO_CONTEXT (src);
378 * gst_video_context_query_new:
379 * @types: a string array of video context types
381 * Create a new custom #GstQuery with structure name "prepare-video-context".
384 gst_video_context_query_new (const gchar ** types)
386 GstStructure *structure = gst_video_context_new_structure (types);
387 return gst_query_new_application (GST_QUERY_CUSTOM, structure);
391 * gst_video_context_run_query:
392 * @element: a #GstElement
393 * @query: a #GstQuery
395 * This helper runs the query on each downstream, then upstream pads in an
396 * element. This is called by gst_video_context_prepare(). This method is only
397 * used directly within elements that are required to have two neighboors
398 * elements with appropriate video context. This would be the case of
399 * specialized filters that only manipulate non-raw buffers (e.g.
400 * gldeinterlace). Those elements do not have to implement #GstVideoContext
404 gst_video_context_run_query (GstElement * element, GstQuery * query)
407 GstIteratorFoldFunction func = gst_video_context_pad_query;
410 g_value_init (&res, G_TYPE_BOOLEAN);
411 g_value_set_boolean (&res, FALSE);
413 /* Ask downstream neighbor (mainly static pipeline case) */
414 it = gst_element_iterate_src_pads (element);
416 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
417 gst_iterator_resync (it);
419 gst_iterator_free (it);
421 /* If none, ask upstream neighbor (auto-plugged case) */
422 if (!g_value_get_boolean (&res)) {
423 it = gst_element_iterate_sink_pads (element);
425 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
426 gst_iterator_resync (it);
428 gst_iterator_free (it);
431 return g_value_get_boolean (&res);
435 * gst_video_context_query_get_supported_types:
436 * @query: a #GstQuery
438 * Returns: An array of supported video context types
441 gst_video_context_query_get_supported_types (GstQuery * query)
443 GstStructure *structure = gst_query_get_structure (query);
444 const GValue *value = gst_structure_get_value (structure, "types");
446 if (G_VALUE_HOLDS (value, G_TYPE_STRV))
447 return g_value_get_boxed (value);
453 * gst_video_context_query_parse_value:
454 * @query: a #GstQuery
455 * @type: return video context type
456 * @value: return video context #GValue
458 * Helper to extract the video context type and value from a #GstQuery.
461 gst_video_context_query_parse_value (GstQuery * query, const gchar ** type,
462 const GValue ** value)
464 GstStructure *structure = gst_query_get_structure (query);
467 *type = gst_structure_get_string (structure, "video-context-type");
470 *value = gst_structure_get_value (structure, "video-context");
474 * gst_video_context_query_set_value:
475 * @query: a #GstQuery
476 * @type: the video context type
477 * @value: a #GValue set with video context
479 * Helper to set the video context as a #GValue inside the #GstQuery.
482 gst_video_context_query_set_value (GstQuery * query, const gchar * type,
485 GstStructure *structure = gst_query_get_structure (query);
486 gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type,
487 "video-context", G_TYPE_VALUE, value, NULL);
491 * gst_video_context_query_set_string:
492 * @query: a #GstQuery
493 * @type: the video context type
494 * @value: a string representing the video context
496 * Helper to set the video context as a string inside the #GstQuery.
499 gst_video_context_query_set_string (GstQuery * query, const gchar * type,
502 GstStructure *structure = gst_query_get_structure (query);
503 gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type,
504 "video-context", G_TYPE_STRING, value, NULL);
508 * gst_video_context_query_set_pointer:
509 * @query: a #GstQuery
510 * @type: the video context type
511 * @value: a #gpointer representing the video context
513 * Helper to set the video context as a #gpointer inside the #GstQuery.
516 gst_video_context_query_set_pointer (GstQuery * query, const gchar * type,
519 GstStructure *structure = gst_query_get_structure (query);
520 gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type,
521 "video-context", G_TYPE_POINTER, value, NULL);
525 * gst_video_context_query_set_object:
526 * @query: a #GstQuery
527 * @type: the video context type
528 * @value: a #GObject representing the video context
530 * Helper to set the video context as a #GObject inside the #GstQuery.
533 gst_video_context_query_set_object (GstQuery * query, const gchar * type,
536 GstStructure *structure = gst_query_get_structure (query);
537 gst_structure_set (structure, "video-context-type", G_TYPE_STRING, type,
538 "video-context", G_TYPE_OBJECT, value, NULL);