8d0b186c1f88b679ff32033928a4824e414a606a
[platform/upstream/gstreamer-vaapi.git] / gst / vaapi / gstvaapipluginutil.c
1 /*
2  *  gstvaapipluginutil.h - VA-API plugin helpers
3  *
4  *  Copyright (C) 2011-2014 Intel Corporation
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
6  *  Copyright (C) 2011 Collabora
7  *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 #include "gst/vaapi/sysdeps.h"
26 #include "gstvaapivideocontext.h"
27 #if USE_DRM
28 # include <gst/vaapi/gstvaapidisplay_drm.h>
29 #endif
30 #if USE_X11
31 # include <gst/vaapi/gstvaapidisplay_x11.h>
32 #endif
33 #if USE_GLX
34 # include <gst/vaapi/gstvaapidisplay_glx.h>
35 #endif
36 #if USE_WAYLAND
37 # include <gst/vaapi/gstvaapidisplay_wayland.h>
38 #endif
39 #include "gstvaapipluginutil.h"
40 #include "gstvaapipluginbase.h"
41
42 /* Preferred first */
43 static const char *display_types[] = {
44   "gst-vaapi-display",
45   "vaapi-display",
46 #if USE_WAYLAND
47   "wl-display",
48   "wl-display-name",
49 #endif
50 #if USE_X11
51   "x11-display",
52   "x11-display-name",
53 #endif
54 #if USE_DRM
55   "drm-device",
56   "drm-device-path",
57 #endif
58   NULL
59 };
60
61 typedef struct
62 {
63   const gchar *type_str;
64   GstVaapiDisplayType type;
65   GstVaapiDisplay *(*create_display) (const gchar *);
66 } DisplayMap;
67
68 static const DisplayMap g_display_map[] = {
69 #if USE_WAYLAND
70   {"wayland",
71         GST_VAAPI_DISPLAY_TYPE_WAYLAND,
72       gst_vaapi_display_wayland_new},
73 #endif
74 #if USE_GLX
75   {"glx",
76         GST_VAAPI_DISPLAY_TYPE_GLX,
77       gst_vaapi_display_glx_new},
78 #endif
79 #if USE_X11
80   {"x11",
81         GST_VAAPI_DISPLAY_TYPE_X11,
82       gst_vaapi_display_x11_new},
83 #endif
84 #if USE_DRM
85   {"drm",
86         GST_VAAPI_DISPLAY_TYPE_DRM,
87       gst_vaapi_display_drm_new},
88 #endif
89   {NULL,}
90 };
91
92 static GstVaapiDisplay *
93 gst_vaapi_create_display (GstVaapiDisplayType display_type,
94     const gchar * display_name)
95 {
96   GstVaapiDisplay *display = NULL;
97   const DisplayMap *m;
98
99   for (m = g_display_map; m->type_str != NULL; m++) {
100     if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY && display_type != m->type)
101       continue;
102
103     display = m->create_display (display_name);
104     if (display || display_type != GST_VAAPI_DISPLAY_TYPE_ANY)
105       break;
106   }
107   return display;
108 }
109
110 gboolean
111 gst_vaapi_ensure_display (gpointer element, GstVaapiDisplayType type)
112 {
113   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
114   GstVaapiDisplay *display;
115   GstVideoContext *context;
116
117   g_return_val_if_fail (GST_IS_VIDEO_CONTEXT (element), FALSE);
118
119   context = GST_VIDEO_CONTEXT (element);
120   g_return_val_if_fail (context != NULL, FALSE);
121
122   gst_vaapi_video_context_prepare (context, display_types);
123
124   /* Neighbour found and it updated the display */
125   if (plugin->display
126       && gst_vaapi_display_type_is_compatible (plugin->display_type, type))
127     return TRUE;
128
129   /* If no neighboor, or application not interested, use system default */
130   display = gst_vaapi_create_display (type, plugin->display_name);
131   if (!display)
132     return FALSE;
133
134   gst_vaapi_video_context_propagate (context, display);
135   GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE (plugin, display);
136   gst_vaapi_display_unref (display);
137   return TRUE;
138 }
139
140 void
141 gst_vaapi_set_display (const gchar * type,
142     const GValue * value, GstVaapiDisplay ** display_ptr)
143 {
144   GstVaapiDisplay *display = NULL;
145
146   if (!strcmp (type, "vaapi-display")) {
147     g_return_if_fail (G_VALUE_HOLDS_POINTER (value));
148     display = gst_vaapi_display_new_with_display (g_value_get_pointer (value));
149   } else if (!strcmp (type, "gst-vaapi-display")) {
150     g_return_if_fail (G_VALUE_HOLDS_POINTER (value));
151     display = gst_vaapi_display_ref (g_value_get_pointer (value));
152   }
153 #if USE_DRM
154   else if (!strcmp (type, "drm-device")) {
155     gint device;
156     g_return_if_fail (G_VALUE_HOLDS_INT (value));
157     device = g_value_get_int (value);
158     display = gst_vaapi_display_drm_new_with_device (device);
159   } else if (!strcmp (type, "drm-device-path")) {
160     const gchar *device_path;
161     g_return_if_fail (G_VALUE_HOLDS_STRING (value));
162     device_path = g_value_get_string (value);
163     display = gst_vaapi_display_drm_new (device_path);
164   }
165 #endif
166 #if USE_X11
167   else if (!strcmp (type, "x11-display-name")) {
168     g_return_if_fail (G_VALUE_HOLDS_STRING (value));
169 #if USE_GLX
170     display = gst_vaapi_display_glx_new (g_value_get_string (value));
171 #endif
172     if (!display)
173       display = gst_vaapi_display_x11_new (g_value_get_string (value));
174   } else if (!strcmp (type, "x11-display")) {
175     g_return_if_fail (G_VALUE_HOLDS_POINTER (value));
176 #if USE_GLX
177     display =
178         gst_vaapi_display_glx_new_with_display (g_value_get_pointer (value));
179 #endif
180     if (!display)
181       display =
182           gst_vaapi_display_x11_new_with_display (g_value_get_pointer (value));
183   }
184 #endif
185 #if USE_WAYLAND
186   else if (!strcmp (type, "wl-display")) {
187     struct wl_display *wl_display;
188     g_return_if_fail (G_VALUE_HOLDS_POINTER (value));
189     wl_display = g_value_get_pointer (value);
190     display = gst_vaapi_display_wayland_new_with_display (wl_display);
191   } else if (!strcmp (type, "wl-display-name")) {
192     const gchar *display_name;
193     g_return_if_fail (G_VALUE_HOLDS_STRING (value));
194     display_name = g_value_get_string (value);
195     display = gst_vaapi_display_wayland_new (display_name);
196   }
197 #endif
198
199   if (display) {
200     gst_vaapi_display_replace (display_ptr, display);
201     gst_vaapi_display_unref (display);
202   }
203 }
204
205 gboolean
206 gst_vaapi_reply_to_query (GstQuery * query, GstVaapiDisplay * display)
207 {
208 #if GST_CHECK_VERSION(1,1,0)
209   const gchar *type = NULL;
210   GstContext *context;
211
212   if (GST_QUERY_TYPE (query) != GST_QUERY_CONTEXT)
213     return FALSE;
214
215   if (!display)
216     return FALSE;
217
218   if (!gst_query_parse_context_type (query, &type))
219     return FALSE;
220
221   if (g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME))
222     return FALSE;
223
224   context = gst_vaapi_video_context_new_with_display (display, FALSE);
225   gst_query_set_context (query, context);
226   gst_context_unref (context);
227
228   return TRUE;
229 #else
230   GstVaapiDisplayType display_type;
231   const gchar **types;
232   const gchar *type;
233   gint i;
234   gboolean res = FALSE;
235
236   if (GST_QUERY_TYPE (query) != GST_QUERY_CUSTOM)
237     return FALSE;
238
239   if (!display)
240     return FALSE;
241
242   types = gst_video_context_query_get_supported_types (query);
243
244   if (!types)
245     return FALSE;
246
247   display_type = gst_vaapi_display_get_display_type (display);
248   for (i = 0; types[i] && !res; i++) {
249     type = types[i];
250
251     res = TRUE;
252     if (!strcmp (type, "gst-vaapi-display")) {
253       gst_video_context_query_set_pointer (query, type, display);
254     } else if (!strcmp (type, "vaapi-display")) {
255       VADisplay vadpy = gst_vaapi_display_get_display (display);
256       gst_video_context_query_set_pointer (query, type, vadpy);
257     } else {
258       switch (display_type) {
259 #if USE_DRM
260         case GST_VAAPI_DISPLAY_TYPE_DRM:{
261           GstVaapiDisplayDRM *const drm_dpy = GST_VAAPI_DISPLAY_DRM (display);
262           if (!strcmp (type, "drm-device-path"))
263             gst_video_context_query_set_string (query, type,
264                 gst_vaapi_display_drm_get_device_path (drm_dpy));
265 #if 0
266           /* XXX: gst_video_context_query_set_int() does not exist yet */
267           else if (!strcmp (type, "drm-device"))
268             gst_video_context_query_set_int (query, type,
269                 gst_vaapi_display_drm_get_device (drm_dpy));
270 #endif
271           else
272             res = FALSE;
273           break;
274         }
275 #endif
276 #if USE_X11
277 #if USE_GLX
278         case GST_VAAPI_DISPLAY_TYPE_GLX:
279 #endif
280         case GST_VAAPI_DISPLAY_TYPE_X11:{
281           GstVaapiDisplayX11 *const xvadpy = GST_VAAPI_DISPLAY_X11 (display);
282           Display *const x11dpy = gst_vaapi_display_x11_get_display (xvadpy);
283           if (!strcmp (type, "x11-display"))
284             gst_video_context_query_set_pointer (query, type, x11dpy);
285           else if (!strcmp (type, "x11-display-name"))
286             gst_video_context_query_set_string (query, type,
287                 DisplayString (x11dpy));
288           else
289             res = FALSE;
290           break;
291         }
292 #endif
293 #if USE_WAYLAND
294         case GST_VAAPI_DISPLAY_TYPE_WAYLAND:{
295           GstVaapiDisplayWayland *const wlvadpy =
296               GST_VAAPI_DISPLAY_WAYLAND (display);
297           struct wl_display *const wldpy =
298               gst_vaapi_display_wayland_get_display (wlvadpy);
299           if (!strcmp (type, "wl-display"))
300             gst_video_context_query_set_pointer (query, type, wldpy);
301           else
302             res = FALSE;
303           break;
304         }
305 #endif
306         default:
307           res = FALSE;
308           break;
309       }
310     }
311   }
312   return res;
313 #endif /* !GST_CHECK_VERSION(1,1,0) */
314 }
315
316 gboolean
317 gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps)
318 {
319   GstStructure *structure;
320   const GValue *v_width, *v_height, *v_framerate, *v_par;
321   guint i, n_structures;
322
323   structure = gst_caps_get_structure (in_caps, 0);
324   v_width = gst_structure_get_value (structure, "width");
325   v_height = gst_structure_get_value (structure, "height");
326   v_framerate = gst_structure_get_value (structure, "framerate");
327   v_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
328   if (!v_width || !v_height)
329     return FALSE;
330
331   n_structures = gst_caps_get_size (out_caps);
332   for (i = 0; i < n_structures; i++) {
333     structure = gst_caps_get_structure (out_caps, i);
334     gst_structure_set_value (structure, "width", v_width);
335     gst_structure_set_value (structure, "height", v_height);
336     if (v_framerate)
337       gst_structure_set_value (structure, "framerate", v_framerate);
338     if (v_par)
339       gst_structure_set_value (structure, "pixel-aspect-ratio", v_par);
340   }
341   return TRUE;
342 }
343
344 gboolean
345 gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer)
346 {
347 #if GST_CHECK_VERSION(1,0,0)
348   GstVideoOverlayCompositionMeta *const cmeta =
349       gst_buffer_get_video_overlay_composition_meta (buffer);
350   GstVideoOverlayComposition *composition;
351
352   if (!cmeta)
353     return TRUE;
354   composition = cmeta->overlay;
355 #else
356   GstVideoOverlayComposition *const composition =
357       gst_video_buffer_get_overlay_composition (buffer);
358 #endif
359   if (!composition)
360     return TRUE;
361   return gst_vaapi_surface_set_subpictures_from_composition (surface,
362       composition, TRUE);
363 }
364
365 gboolean
366 gst_vaapi_value_set_format (GValue * value, GstVideoFormat format)
367 {
368 #if GST_CHECK_VERSION(1,0,0)
369   const gchar *str;
370
371   str = gst_video_format_to_string (format);
372   if (!str)
373     return FALSE;
374
375   g_value_init (value, G_TYPE_STRING);
376   g_value_set_string (value, str);
377 #else
378   guint32 fourcc;
379
380   fourcc = gst_video_format_to_fourcc (format);
381   if (!fourcc)
382     return FALSE;
383
384   g_value_init (value, GST_TYPE_FOURCC);
385   gst_value_set_fourcc (value, fourcc);
386 #endif
387   return TRUE;
388 }
389
390 gboolean
391 gst_vaapi_value_set_format_list (GValue * value, GArray * formats)
392 {
393   GValue v_format = G_VALUE_INIT;
394   guint i;
395
396   g_value_init (value, GST_TYPE_LIST);
397   for (i = 0; i < formats->len; i++) {
398     GstVideoFormat const format = g_array_index (formats, GstVideoFormat, i);
399
400     if (!gst_vaapi_value_set_format (&v_format, format))
401       continue;
402     gst_value_list_append_value (value, &v_format);
403     g_value_unset (&v_format);
404   }
405   return TRUE;
406 }
407
408 void
409 set_video_template_caps (GstCaps * caps)
410 {
411   GstStructure *const structure = gst_caps_get_structure (caps, 0);
412
413   gst_structure_set (structure,
414       "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
415       "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
416       "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
417       "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
418 }
419
420 GstCaps *
421 gst_vaapi_video_format_new_template_caps (GstVideoFormat format)
422 {
423 #if GST_CHECK_VERSION(1,0,0)
424   GstCaps *caps;
425
426   g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
427
428   caps = gst_caps_new_empty_simple ("video/x-raw");
429   if (!caps)
430     return NULL;
431
432   gst_caps_set_simple (caps,
433       "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
434   set_video_template_caps (caps);
435   return caps;
436 #else
437   return gst_video_format_new_template_caps (format);
438 #endif
439 }
440
441 GstCaps *
442 gst_vaapi_video_format_new_template_caps_from_list (GArray * formats)
443 {
444 #if GST_CHECK_VERSION(1,0,0)
445   GValue v_formats = G_VALUE_INIT;
446   GstCaps *caps;
447
448   caps = gst_caps_new_empty_simple ("video/x-raw");
449   if (!caps)
450     return NULL;
451
452   if (!gst_vaapi_value_set_format_list (&v_formats, formats)) {
453     gst_caps_unref (caps);
454     return NULL;
455   }
456
457   gst_caps_set_value (caps, "format", &v_formats);
458   set_video_template_caps (caps);
459 #else
460   GstCaps *caps, *tmp_caps;
461   guint i;
462
463   g_return_val_if_fail (formats != NULL, NULL);
464
465   caps = gst_caps_new_empty ();
466   if (!caps)
467     return NULL;
468
469   for (i = 0; i < formats->len; i++) {
470     const GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
471     tmp_caps = gst_vaapi_video_format_new_template_caps (format);
472     if (tmp_caps)
473       gst_caps_append (caps, tmp_caps);
474   }
475 #endif
476   return caps;
477 }
478
479 GstCaps *
480 gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format,
481     const gchar * features_string)
482 {
483   GstCaps *caps;
484
485   caps = gst_vaapi_video_format_new_template_caps (format);
486   if (!caps)
487     return NULL;
488
489 #if GST_CHECK_VERSION(1,1,0)
490   GstCapsFeatures *const features =
491       gst_caps_features_new (features_string, NULL);
492   if (!features) {
493     gst_caps_unref (caps);
494     return NULL;
495   }
496   gst_caps_set_features (caps, 0, features);
497 #endif
498   return caps;
499 }
500
501 GstVaapiCapsFeature
502 gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstVideoFormat format)
503 {
504   GstVaapiCapsFeature feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
505 #if GST_CHECK_VERSION(1,1,0)
506   guint i, num_structures;
507   GstCaps *caps = NULL;
508   GstCaps *gl_texture_upload_caps = NULL;
509   GstCaps *sysmem_caps = NULL;
510   GstCaps *vaapi_caps = NULL;
511   GstCaps *out_caps;
512
513   out_caps = gst_pad_peer_query_caps (pad, NULL);
514   if (!out_caps)
515     goto cleanup;
516
517   gl_texture_upload_caps =
518       gst_vaapi_video_format_new_template_caps_with_features
519       (GST_VIDEO_FORMAT_RGBA,
520       GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META);
521   if (!gl_texture_upload_caps)
522     goto cleanup;
523
524   if (format == GST_VIDEO_FORMAT_ENCODED)
525     format = GST_VIDEO_FORMAT_I420;
526
527   vaapi_caps =
528       gst_vaapi_video_format_new_template_caps_with_features (format,
529       GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE);
530   if (!vaapi_caps)
531     goto cleanup;
532
533   sysmem_caps =
534       gst_vaapi_video_format_new_template_caps_with_features (format,
535       GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
536   if (!sysmem_caps)
537     goto cleanup;
538
539   num_structures = gst_caps_get_size (out_caps);
540   for (i = 0; i < num_structures; i++) {
541     GstCapsFeatures *const features = gst_caps_get_features (out_caps, i);
542     GstStructure *const structure = gst_caps_get_structure (out_caps, i);
543
544     caps = gst_caps_new_full (gst_structure_copy (structure), NULL);
545     if (!caps)
546       continue;
547     gst_caps_set_features (caps, 0, gst_caps_features_copy (features));
548
549     if (gst_caps_can_intersect (caps, vaapi_caps) &&
550         feature < GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
551       feature = GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE;
552     else if (gst_caps_can_intersect (caps, gl_texture_upload_caps) &&
553         feature < GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)
554       feature = GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META;
555     else if (gst_caps_can_intersect (caps, sysmem_caps) &&
556         feature < GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
557       feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
558     gst_caps_replace (&caps, NULL);
559   }
560
561 cleanup:
562   gst_caps_replace (&gl_texture_upload_caps, NULL);
563   gst_caps_replace (&sysmem_caps, NULL);
564   gst_caps_replace (&vaapi_caps, NULL);
565   gst_caps_replace (&caps, NULL);
566   gst_caps_replace (&out_caps, NULL);
567 #endif
568   return feature;
569 }
570
571 gboolean
572 gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip)
573 {
574 #if GST_CHECK_VERSION(1,0,0)
575   GstVideoInterlaceMode mode;
576   const gchar *mode_str;
577
578   mode = vip ? GST_VIDEO_INFO_INTERLACE_MODE (vip) :
579       GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
580   switch (mode) {
581     case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
582       mode_str = "progressive";
583       break;
584     case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
585       mode_str = "interleaved";
586       break;
587     case GST_VIDEO_INTERLACE_MODE_MIXED:
588       mode_str = "mixed";
589       break;
590     default:
591       GST_ERROR ("unsupported `interlace-mode' %d", mode);
592       return FALSE;
593   }
594
595   gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, mode_str, NULL);
596 #else
597   gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN,
598       vip ? GST_VIDEO_INFO_IS_INTERLACED (vip) : FALSE, NULL);
599 #endif
600   return TRUE;
601 }