vaapidecodebin: ensure VPP before going to READY
[platform/upstream/gstreamer.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 "gstcompat.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_EGL
37 # include <gst/vaapi/gstvaapidisplay_egl.h>
38 #endif
39 #if USE_WAYLAND
40 # include <gst/vaapi/gstvaapidisplay_wayland.h>
41 #endif
42 #include "gstvaapipluginutil.h"
43 #include "gstvaapipluginbase.h"
44
45 typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFunc) (const gchar *);
46 typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFromHandleFunc) (gpointer);
47
48 typedef struct
49 {
50   const gchar *type_str;
51   GstVaapiDisplayType type;
52   GstVaapiDisplayCreateFunc create_display;
53   GstVaapiDisplayCreateFromHandleFunc create_display_from_handle;
54 } DisplayMap;
55
56 /* *INDENT-OFF* */
57 static const DisplayMap g_display_map[] = {
58 #if USE_WAYLAND
59   {"wayland",
60    GST_VAAPI_DISPLAY_TYPE_WAYLAND,
61    gst_vaapi_display_wayland_new,
62    (GstVaapiDisplayCreateFromHandleFunc)
63    gst_vaapi_display_wayland_new_with_display},
64 #endif
65 #if USE_GLX
66   {"glx",
67    GST_VAAPI_DISPLAY_TYPE_GLX,
68    gst_vaapi_display_glx_new,
69    (GstVaapiDisplayCreateFromHandleFunc)
70    gst_vaapi_display_glx_new_with_display},
71 #endif
72 #if USE_X11
73   {"x11",
74    GST_VAAPI_DISPLAY_TYPE_X11,
75    gst_vaapi_display_x11_new,
76    (GstVaapiDisplayCreateFromHandleFunc)
77    gst_vaapi_display_x11_new_with_display},
78 #endif
79 #if USE_DRM
80   {"drm",
81    GST_VAAPI_DISPLAY_TYPE_DRM,
82    gst_vaapi_display_drm_new},
83 #endif
84   {NULL,}
85 };
86 /* *INDENT-ON* */
87
88 static GstVaapiDisplay *
89 gst_vaapi_create_display (GstVaapiDisplayType display_type,
90     const gchar * display_name)
91 {
92   GstVaapiDisplay *display = NULL;
93   const DisplayMap *m;
94
95   for (m = g_display_map; m->type_str != NULL; m++) {
96     if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY && display_type != m->type)
97       continue;
98
99     display = m->create_display (display_name);
100     if (display || display_type != GST_VAAPI_DISPLAY_TYPE_ANY)
101       break;
102   }
103   return display;
104 }
105
106 static GstVaapiDisplay *
107 gst_vaapi_create_display_from_handle (GstVaapiDisplayType display_type,
108     gpointer handle)
109 {
110   GstVaapiDisplay *display;
111   const DisplayMap *m;
112
113   if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY)
114     return NULL;
115
116   for (m = g_display_map; m->type_str != NULL; m++) {
117     if (m->type == display_type) {
118       display = m->create_display_from_handle ?
119           m->create_display_from_handle (handle) : NULL;
120       return display;
121     }
122   }
123   return NULL;
124 }
125
126 static GstVaapiDisplay *
127 gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object)
128 {
129 #if USE_GST_GL_HELPERS
130   GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object);
131   GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context);
132   gpointer native_display =
133       GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display));
134   GstVaapiDisplay *display, *out_display;
135   GstVaapiDisplayType display_type;
136
137   switch (gst_gl_display_get_handle_type (gl_display)) {
138 #if USE_X11
139     case GST_GL_DISPLAY_TYPE_X11:
140       display_type = GST_VAAPI_DISPLAY_TYPE_X11;
141       break;
142 #endif
143 #if USE_WAYLAND
144     case GST_GL_DISPLAY_TYPE_WAYLAND:
145       display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
146       break;
147 #endif
148     case GST_GL_DISPLAY_TYPE_ANY:{
149       /* Derive from the active window */
150       GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context);
151       const gchar *const gl_window_type = g_getenv ("GST_GL_WINDOW");
152
153       display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
154       if (!gl_window)
155         break;
156       native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window));
157
158       if (gl_window_type) {
159 #if USE_X11
160         if (!display_type && g_strcmp0 (gl_window_type, "x11") == 0)
161           display_type = GST_VAAPI_DISPLAY_TYPE_X11;
162 #endif
163 #if USE_WAYLAND
164         if (!display_type && g_strcmp0 (gl_window_type, "wayland") == 0)
165           display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
166 #endif
167       } else {
168 #if USE_X11
169         if (!display_type && GST_GL_HAVE_WINDOW_X11)
170           display_type = GST_VAAPI_DISPLAY_TYPE_X11;
171 #endif
172 #if USE_WAYLAND
173         if (!display_type && GST_GL_HAVE_WINDOW_WAYLAND)
174           display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
175 #endif
176       }
177       break;
178     }
179     default:
180       display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
181       break;
182   }
183   if (!display_type)
184     return NULL;
185
186   display = gst_vaapi_create_display_from_handle (display_type, native_display);
187   if (!display)
188     return NULL;
189
190   switch (gst_gl_context_get_gl_platform (gl_context)) {
191 #if USE_EGL
192     case GST_GL_PLATFORM_EGL:{
193       guint gles_version;
194
195       switch (gst_gl_context_get_gl_api (gl_context)) {
196         case GST_GL_API_GLES1:
197           gles_version = 1;
198           goto create_egl_display;
199         case GST_GL_API_GLES2:
200           gles_version = 2;
201           goto create_egl_display;
202         case GST_GL_API_OPENGL:
203         case GST_GL_API_OPENGL3:
204           gles_version = 0;
205         create_egl_display:
206           out_display = gst_vaapi_display_egl_new (display, gles_version);
207           break;
208         default:
209           out_display = NULL;
210           break;
211       }
212       if (!out_display)
213         return NULL;
214       gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (out_display),
215           GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context)));
216       break;
217     }
218 #endif
219     default:
220       out_display = gst_vaapi_display_ref (display);
221       break;
222   }
223   gst_vaapi_display_unref (display);
224   return out_display;
225 #endif
226   GST_ERROR ("unsupported GStreamer version %s", GST_API_VERSION_S);
227   return NULL;
228 }
229
230 gboolean
231 gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type)
232 {
233   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
234   GstVaapiDisplay *display;
235
236   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
237
238   gst_vaapi_video_context_prepare (element);
239
240   /* Neighbour found and it updated the display */
241   if (gst_vaapi_plugin_base_has_display_type (plugin, type))
242     return TRUE;
243
244   /* If no neighboor, or application not interested, use system default */
245   if (plugin->gl_context)
246     display = gst_vaapi_create_display_from_gl_context (plugin->gl_context);
247   else
248     display = gst_vaapi_create_display (type, plugin->display_name);
249   if (!display)
250     return FALSE;
251
252   gst_vaapi_video_context_propagate (element, display);
253   GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE (plugin, display);
254   gst_vaapi_display_unref (display);
255   return TRUE;
256 }
257
258 gboolean
259 gst_vaapi_reply_to_query (GstQuery * query, GstVaapiDisplay * display)
260 {
261   const gchar *type = NULL;
262   GstContext *context;
263
264   if (GST_QUERY_TYPE (query) != GST_QUERY_CONTEXT)
265     return FALSE;
266
267   if (!display)
268     return FALSE;
269
270   if (!gst_query_parse_context_type (query, &type))
271     return FALSE;
272
273   if (g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME))
274     return FALSE;
275
276   context = gst_vaapi_video_context_new_with_display (display, FALSE);
277   gst_query_set_context (query, context);
278   gst_context_unref (context);
279
280   return TRUE;
281 }
282
283 gboolean
284 gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps)
285 {
286   GstStructure *structure;
287   const GValue *v_width, *v_height, *v_framerate, *v_par;
288   guint i, n_structures;
289
290   structure = gst_caps_get_structure (in_caps, 0);
291   v_width = gst_structure_get_value (structure, "width");
292   v_height = gst_structure_get_value (structure, "height");
293   v_framerate = gst_structure_get_value (structure, "framerate");
294   v_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
295   if (!v_width || !v_height)
296     return FALSE;
297
298   n_structures = gst_caps_get_size (out_caps);
299   for (i = 0; i < n_structures; i++) {
300     structure = gst_caps_get_structure (out_caps, i);
301     gst_structure_set_value (structure, "width", v_width);
302     gst_structure_set_value (structure, "height", v_height);
303     if (v_framerate)
304       gst_structure_set_value (structure, "framerate", v_framerate);
305     if (v_par)
306       gst_structure_set_value (structure, "pixel-aspect-ratio", v_par);
307   }
308   return TRUE;
309 }
310
311 gboolean
312 gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer)
313 {
314   GstVideoOverlayCompositionMeta *const cmeta =
315       gst_buffer_get_video_overlay_composition_meta (buffer);
316   GstVideoOverlayComposition *composition = NULL;
317
318   if (cmeta)
319     composition = cmeta->overlay;
320   return gst_vaapi_surface_set_subpictures_from_composition (surface,
321       composition, TRUE);
322 }
323
324 gboolean
325 gst_vaapi_value_set_format (GValue * value, GstVideoFormat format)
326 {
327   const gchar *str;
328
329   str = gst_video_format_to_string (format);
330   if (!str)
331     return FALSE;
332
333   g_value_init (value, G_TYPE_STRING);
334   g_value_set_string (value, str);
335   return TRUE;
336 }
337
338 gboolean
339 gst_vaapi_value_set_format_list (GValue * value, GArray * formats)
340 {
341   GValue v_format = G_VALUE_INIT;
342   guint i;
343
344   g_value_init (value, GST_TYPE_LIST);
345   for (i = 0; i < formats->len; i++) {
346     GstVideoFormat const format = g_array_index (formats, GstVideoFormat, i);
347
348     if (!gst_vaapi_value_set_format (&v_format, format))
349       continue;
350     gst_value_list_append_value (value, &v_format);
351     g_value_unset (&v_format);
352   }
353   return TRUE;
354 }
355
356 void
357 set_video_template_caps (GstCaps * caps)
358 {
359   GstStructure *const structure = gst_caps_get_structure (caps, 0);
360
361   gst_structure_set (structure,
362       "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
363       "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
364       "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
365       "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
366 }
367
368 GstCaps *
369 gst_vaapi_video_format_new_template_caps (GstVideoFormat format)
370 {
371   GstCaps *caps;
372
373   g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
374
375   caps = gst_caps_new_empty_simple ("video/x-raw");
376   if (!caps)
377     return NULL;
378
379   gst_caps_set_simple (caps,
380       "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
381   set_video_template_caps (caps);
382   return caps;
383 }
384
385 GstCaps *
386 gst_vaapi_video_format_new_template_caps_from_list (GArray * formats)
387 {
388   GValue v_formats = G_VALUE_INIT;
389   GstCaps *caps;
390
391   caps = gst_caps_new_empty_simple ("video/x-raw");
392   if (!caps)
393     return NULL;
394
395   if (!gst_vaapi_value_set_format_list (&v_formats, formats)) {
396     gst_caps_unref (caps);
397     return NULL;
398   }
399
400   gst_caps_set_value (caps, "format", &v_formats);
401   set_video_template_caps (caps);
402   g_value_unset (&v_formats);
403   return caps;
404 }
405
406 GstCaps *
407 gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format,
408     const gchar * features_string)
409 {
410   GstCaps *caps;
411
412   caps = gst_vaapi_video_format_new_template_caps (format);
413   if (!caps)
414     return NULL;
415
416   GstCapsFeatures *const features =
417       gst_caps_features_new (features_string, NULL);
418   if (!features) {
419     gst_caps_unref (caps);
420     return NULL;
421   }
422   gst_caps_set_features (caps, 0, features);
423   return caps;
424 }
425
426 static GstCaps *
427 new_gl_texture_upload_meta_caps (void)
428 {
429   return
430       gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
431       (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
432           "{ RGBA, BGRA }"));
433 }
434
435 GstVaapiCapsFeature
436 gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstVideoFormat format,
437     GstVideoFormat * out_format_ptr)
438 {
439   GstVaapiCapsFeature feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
440   guint i, num_structures;
441   GstCaps *caps = NULL;
442   GstCaps *gl_texture_upload_caps = NULL;
443   GstCaps *sysmem_caps = NULL;
444   GstCaps *vaapi_caps = NULL;
445   GstCaps *out_caps, *templ;
446   GstVideoFormat out_format;
447
448   templ = gst_pad_get_pad_template_caps (pad);
449   out_caps = gst_pad_peer_query_caps (pad, templ);
450   gst_caps_unref (templ);
451   if (!out_caps) {
452     feature = GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED;
453     goto cleanup;
454   }
455
456   out_format = format == GST_VIDEO_FORMAT_ENCODED ?
457       GST_VIDEO_FORMAT_I420 : format;
458
459   gl_texture_upload_caps = new_gl_texture_upload_meta_caps ();
460   if (!gl_texture_upload_caps)
461     goto cleanup;
462
463   vaapi_caps =
464       gst_vaapi_video_format_new_template_caps_with_features (out_format,
465       GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE);
466   if (!vaapi_caps)
467     goto cleanup;
468
469   sysmem_caps =
470       gst_vaapi_video_format_new_template_caps_with_features (out_format,
471       GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
472   if (!sysmem_caps)
473     goto cleanup;
474
475   num_structures = gst_caps_get_size (out_caps);
476   for (i = 0; i < num_structures; i++) {
477     GstCapsFeatures *const features = gst_caps_get_features (out_caps, i);
478     GstStructure *const structure = gst_caps_get_structure (out_caps, i);
479
480 #if GST_CHECK_VERSION(1,3,0)
481     /* Skip ANY features, we need an exact match for correct evaluation */
482     if (gst_caps_features_is_any (features))
483       continue;
484 #endif
485
486     caps = gst_caps_new_full (gst_structure_copy (structure), NULL);
487     if (!caps)
488       continue;
489     gst_caps_set_features (caps, 0, gst_caps_features_copy (features));
490
491     if (gst_caps_can_intersect (caps, vaapi_caps) &&
492         feature < GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
493       feature = GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE;
494     else if (gst_caps_can_intersect (caps, gl_texture_upload_caps) &&
495         feature < GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)
496       feature = GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META;
497     else if (gst_caps_can_intersect (caps, sysmem_caps) &&
498         feature < GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
499       feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
500     gst_caps_replace (&caps, NULL);
501
502 #if GST_CHECK_VERSION(1,3,0)
503     /* Stop at the first match, the caps should already be sorted out
504        by preference order from downstream elements */
505     if (feature != GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
506       break;
507 #endif
508   }
509
510   if (out_format_ptr) {
511     if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META) {
512       GstStructure *structure;
513       gchar *format_str;
514       out_format = GST_VIDEO_FORMAT_UNKNOWN;
515       do {
516         caps = gst_caps_intersect_full (out_caps, gl_texture_upload_caps,
517             GST_CAPS_INTERSECT_FIRST);
518         if (!caps)
519           break;
520         structure = gst_caps_get_structure (caps, 0);
521         if (!structure)
522           break;
523         if (!gst_structure_get (structure, "format", G_TYPE_STRING,
524                 &format_str, NULL))
525           break;
526         out_format = gst_video_format_from_string (format_str);
527         g_free (format_str);
528       } while (0);
529       if (!out_format)
530         goto cleanup;
531     }
532     *out_format_ptr = out_format;
533   }
534
535 cleanup:
536   gst_caps_replace (&gl_texture_upload_caps, NULL);
537   gst_caps_replace (&sysmem_caps, NULL);
538   gst_caps_replace (&vaapi_caps, NULL);
539   gst_caps_replace (&caps, NULL);
540   gst_caps_replace (&out_caps, NULL);
541   return feature;
542 }
543
544 const gchar *
545 gst_vaapi_caps_feature_to_string (GstVaapiCapsFeature feature)
546 {
547   const gchar *str;
548
549   switch (feature) {
550     case GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY:
551       str = GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY;
552       break;
553     case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
554       str = GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META;
555       break;
556     case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:
557       str = GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE;
558       break;
559     default:
560       str = NULL;
561       break;
562   }
563   return str;
564 }
565
566 gboolean
567 gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip)
568 {
569   GstVideoInterlaceMode mode;
570   const gchar *mode_str;
571
572   mode = vip ? GST_VIDEO_INFO_INTERLACE_MODE (vip) :
573       GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
574   switch (mode) {
575     case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
576       mode_str = "progressive";
577       break;
578     case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
579       mode_str = "interleaved";
580       break;
581     case GST_VIDEO_INTERLACE_MODE_MIXED:
582       mode_str = "mixed";
583       break;
584     default:
585       GST_ERROR ("unsupported `interlace-mode' %d", mode);
586       return FALSE;
587   }
588
589   gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, mode_str, NULL);
590   return TRUE;
591 }
592
593 /* Checks whether the supplied caps contain VA surfaces */
594 gboolean
595 gst_caps_has_vaapi_surface (GstCaps * caps)
596 {
597   gboolean found_caps = FALSE;
598   guint i, num_structures;
599
600   g_return_val_if_fail (caps != NULL, FALSE);
601
602   num_structures = gst_caps_get_size (caps);
603   if (num_structures < 1)
604     return FALSE;
605
606   for (i = 0; i < num_structures && !found_caps; i++) {
607     GstCapsFeatures *const features = gst_caps_get_features (caps, i);
608
609 #if GST_CHECK_VERSION(1,3,0)
610     /* Skip ANY features, we need an exact match for correct evaluation */
611     if (gst_caps_features_is_any (features))
612       continue;
613 #endif
614
615     found_caps = gst_caps_features_contains (features,
616         GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE);
617   }
618   return found_caps;
619 }
620
621 void
622 gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format,
623     guint width, guint height)
624 {
625   GstVideoInfo vi = *vip;
626
627   gst_video_info_set_format (vip, format, width, height);
628
629   vip->interlace_mode = vi.interlace_mode;
630   vip->flags = vi.flags;
631   vip->views = vi.views;
632   vip->par_n = vi.par_n;
633   vip->par_d = vi.par_d;
634   vip->fps_n = vi.fps_n;
635   vip->fps_d = vi.fps_d;
636 }
637
638 /**
639  * gst_vaapi_create_test_display:
640  *
641  * Creates a temporal #GstVaapiDisplay instance, just for testing the
642  * supported features.
643  *
644  * Returns: a new #GstVaapiDisplay instances. Free with
645  * gst_vaapi_display_unref () after use.
646  **/
647 GstVaapiDisplay *
648 gst_vaapi_create_test_display ()
649 {
650   return gst_vaapi_create_display (GST_VAAPI_DISPLAY_TYPE_ANY, NULL);
651 }