Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst-libs / gst / video / videocontext.c
1 /* GStreamer
2  *
3  * Copyright (C) 2011 Intel
4  * Copyright (C) 2011 Collabora Ltd.
5  *   Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
6  *
7  * video-context.c: Video Context interface and helpers
8  *
9  *
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.
14  *
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.
19  *
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.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "videocontext.h"
31
32 /**
33  * SECTION:gstvideocontext
34  * @short_description: Interface to handle video library context
35  *
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
38  * application.
39  * <note>
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.
42  * </note>
43  *
44  * <refsect2>
45  * <title>For Element</title>
46  * <para>
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.
51  * </para>
52  * <para>
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.
58  * </para>
59  * <para>
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()).
65  * </para>
66  * <para>
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.
77  * </para>
78  * <para>
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.
85  * </para>
86  * <para>
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.
90  * </para>
91  * </refsect2>
92  *
93  * <refsect2>
94  * <title>For Application</title>
95  * <para>
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.
108  *   <note>
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.
112  *   </note>
113  * </para>
114  * <refsect2>
115  * <title>Example using ClutterVideoGstVideoSink</title>
116  * <para>
117  *   This example is for user of ClutterGstVideoSink element, the
118  *   ClutterGstPlayer object transparently handle this.
119  *  </para>
120  * |[
121  * #if CLUTTER_WINDOWING_X11
122  * static GstBusSyncReply
123  * on_sync_message (GstBus * bus, GstMessage * message, gpointer user_data)
124  * {
125  *   Display *display = user_data;
126  *   GstVideoContext *context;
127  *   const gchar **types;
128  *
129  *   if (gst_video_context_message_parse_prepare (message, &types, &context)) {
130  *     gint i;
131  *
132  *     for (i = 0; types[i]; i++) {
133  *
134  *       if (!strcmp(types[i], "x11-display")) {
135  *         gst_video_context_set_context_pointer (context, "x11-display", display);
136  *       }
137  *       else if (!strcmp(types[i], "x11-display-name")) {
138  *         gst_video_context_set_context_string (context, "x11-display-name",
139  *             DisplayString (display));
140  *       } else {
141  *         continue;
142  *       }
143  *
144  *       gst_message_unref (message);
145  *       return GST_BUS_DROP;
146  *     }
147  *   }
148  *
149  *   return GST_BUS_PASS;
150  * }
151  * #endif
152  *
153  * gint
154  * main (gint argc, gchar **argv)
155  * {
156  *   GstBin *pipeline;
157  *   GstBus *bus;
158  *
159  *   ...
160  *
161  *   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
162  *
163  *   #if CLUTTER_WINDOWING_X11
164  *   gst_bus_set_sync_handler (priv->bus, on_sync_message,
165  *       clutter_x11_get_default_display ());
166  *   #endif
167  *
168  *   gst_object_unref (GST_OBJECT (priv->bus));
169  *
170  *   ...
171  * }
172  * ]|
173  * </refsect2>
174  * </refsect2>
175  */
176
177 G_DEFINE_INTERFACE (GstVideoContext, gst_video_context_iface, G_TYPE_INVALID);
178
179 static inline GstStructure *
180 gst_video_context_new_structure (const gchar ** types)
181 {
182   return gst_structure_new ("prepare-video-context",
183       "types", G_TYPE_STRV, types, NULL);
184 }
185
186 static gboolean
187 gst_video_context_pad_query (gpointer item, GValue * value, gpointer user_data)
188 {
189   GstPad *pad = GST_PAD (item);
190   GstQuery *query = user_data;
191   gboolean res;
192
193   res = gst_pad_peer_query (pad, query);
194   gst_object_unref (pad);
195
196   if (res) {
197     g_value_set_boolean (value, TRUE);
198     return FALSE;
199   }
200
201   return TRUE;
202 }
203
204 static void
205 gst_video_context_iface_default_init (GstVideoContextInterface * iface)
206 {
207   /* default virtual functions */
208   iface->set_context = NULL;
209 }
210
211 /**
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
216  *
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
219  */
220 void
221 gst_video_context_set_context (GstVideoContext * context, const gchar * type,
222     const GValue * value)
223 {
224   g_return_if_fail (GST_IS_VIDEO_CONTEXT (context));
225   g_return_if_fail (GST_VIDEO_CONTEXT_GET_IFACE (context)->set_context);
226
227   GST_VIDEO_CONTEXT_GET_IFACE (context)->set_context (context, type, value);
228 }
229
230 /**
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
235  *
236  * This helper is commonly used for setting video context represented by a
237  * string like the X11 display name ("x11-display-name")/
238  */
239 void
240 gst_video_context_set_context_string (GstVideoContext * context,
241     const gchar * type, const gchar * string)
242 {
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);
248 }
249
250 /**
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
255  *
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
258  * ("vaapi-display").
259  * <note>
260  *   Users of X11 Display should ensure that XInitThreads() was called before
261  *   opening the display.
262  * </note>
263  */
264 void
265 gst_video_context_set_context_pointer (GstVideoContext * context,
266     const gchar * type, gpointer pointer)
267 {
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);
273 }
274
275 /**
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
280  *
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.
285  */
286 void
287 gst_video_context_set_context_object (GstVideoContext * context,
288     const gchar * type, GObject * object)
289 {
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);
296 }
297
298 /**
299  * gst_video_context_prepare:
300  * @context: an element implementing #GstVideoContext interface
301  * @types: an array of supported types, prefered first
302  *
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.
308  */
309 void
310 gst_video_context_prepare (GstVideoContext * context, const gchar ** types)
311 {
312   GstQuery *query = gst_video_context_query_new (types);
313
314   /* Check neighborhood, if found call GstVideoContext */
315   if (gst_video_context_run_query (GST_ELEMENT (context), query)) {
316     const gchar *type = NULL;
317     const GValue *value;
318     gst_video_context_query_parse_value (query, &type, &value);
319     gst_video_context_set_context (context, type, value);
320   } else {
321     /* If no neighbor replyed, query the application */
322     GstMessage *message;
323     GstStructure *structure;
324
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);
328   }
329
330   gst_query_unref (query);
331 }
332
333 /**
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
338  *
339  * This helper shall be used by application to simply handling of the
340  * "prepare-video-context" message.
341  *
342  * Rerturns: #FALSE is the message was not valid "prepare-video-context"
343  *           element message, otherwise #TRUE with @types and @context set.
344  */
345 gboolean
346 gst_video_context_message_parse_prepare (GstMessage * message,
347     const gchar *** types, GstVideoContext ** context)
348 {
349   GstObject *src = GST_MESSAGE_SRC (message);
350   const GstStructure *structure;
351   const GValue *value;
352
353   if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
354     return FALSE;
355
356   if (!gst_structure_has_name (message->structure, "prepare-video-context"))
357     return FALSE;
358
359   if (!GST_IS_VIDEO_CONTEXT (src))
360     return FALSE;
361
362   structure = gst_message_get_structure (message);
363   value = gst_structure_get_value (structure, "types");
364
365   if (!G_VALUE_HOLDS (value, G_TYPE_STRV))
366     return FALSE;
367
368   if (types)
369     *types = g_value_get_boxed (value);
370
371   if (context)
372     *context = GST_VIDEO_CONTEXT (src);
373
374   return TRUE;
375 }
376
377 /**
378  * gst_video_context_query_new:
379  * @types: a string array of video context types
380  *
381  * Create a new custom #GstQuery with structure name "prepare-video-context".
382  */
383 GstQuery *
384 gst_video_context_query_new (const gchar ** types)
385 {
386   GstStructure *structure = gst_video_context_new_structure (types);
387   return gst_query_new_application (GST_QUERY_CUSTOM, structure);
388 }
389
390 /**
391  * gst_video_context_run_query:
392  * @element: a #GstElement
393  * @query: a #GstQuery
394  *
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
401  * interface.
402  */
403 gboolean
404 gst_video_context_run_query (GstElement * element, GstQuery * query)
405 {
406   GstIterator *it;
407   GstIteratorFoldFunction func = gst_video_context_pad_query;
408   GValue res = { 0 };
409
410   g_value_init (&res, G_TYPE_BOOLEAN);
411   g_value_set_boolean (&res, FALSE);
412
413   /* Ask downstream neighbor (mainly static pipeline case) */
414   it = gst_element_iterate_src_pads (element);
415
416   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
417     gst_iterator_resync (it);
418
419   gst_iterator_free (it);
420
421   /* If none, ask upstream neighbor (auto-plugged case) */
422   if (!g_value_get_boolean (&res)) {
423     it = gst_element_iterate_sink_pads (element);
424
425     while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
426       gst_iterator_resync (it);
427
428     gst_iterator_free (it);
429   }
430
431   return g_value_get_boolean (&res);
432 }
433
434 /**
435  * gst_video_context_query_get_supported_types:
436  * @query: a #GstQuery
437  *
438  * Returns: An array of supported video context types
439  */
440 const gchar **
441 gst_video_context_query_get_supported_types (GstQuery * query)
442 {
443   GstStructure *structure = gst_query_get_structure (query);
444   const GValue *value = gst_structure_get_value (structure, "types");
445
446   if (G_VALUE_HOLDS (value, G_TYPE_STRV))
447     return g_value_get_boxed (value);
448
449   return NULL;
450 }
451
452 /**
453  * gst_video_context_query_parse_value:
454  * @query: a #GstQuery
455  * @type: return video context type
456  * @value: return video context #GValue
457  *
458  * Helper to extract the video context type and value from a #GstQuery.
459  */
460 void
461 gst_video_context_query_parse_value (GstQuery * query, const gchar ** type,
462     const GValue ** value)
463 {
464   GstStructure *structure = gst_query_get_structure (query);
465
466   if (type)
467     *type = gst_structure_get_string (structure, "video-context-type");
468
469   if (value)
470     *value = gst_structure_get_value (structure, "video-context");
471 }
472
473 /**
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
478  *
479  * Helper to set the video context as a #GValue inside the #GstQuery.
480  */
481 void
482 gst_video_context_query_set_value (GstQuery * query, const gchar * type,
483     GValue * value)
484 {
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);
488 }
489
490 /**
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
495  *
496  * Helper to set the video context as a string inside the #GstQuery.
497  */
498 void
499 gst_video_context_query_set_string (GstQuery * query, const gchar * type,
500     const gchar * value)
501 {
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);
505 }
506
507 /**
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
512  *
513  * Helper to set the video context as a #gpointer inside the #GstQuery.
514  */
515 void
516 gst_video_context_query_set_pointer (GstQuery * query, const gchar * type,
517     gpointer value)
518 {
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);
522 }
523
524 /**
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
529  *
530  * Helper to set the video context as a #GObject inside the #GstQuery.
531  */
532 void
533 gst_video_context_query_set_object (GstQuery * query, const gchar * type,
534     GObject * value)
535 {
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);
539 }