1753ad09d283a878c65bedfc2a1534b6108f35ae
[platform/upstream/gstreamer.git] / gst / vaapi / gstvaapipluginbase.c
1 /*
2  *  gstvaapipluginbase.c - Base GStreamer VA-API Plugin element
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
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 <gst/vaapi/gstvaapisurface_drm.h>
27 #include <gst/base/gstpushsrc.h>
28 #include "gstvaapipluginbase.h"
29 #include "gstvaapipluginutil.h"
30 #include "gstvaapivideocontext.h"
31 #include "gstvaapivideometa.h"
32 #include "gstvaapivideobufferpool.h"
33 #if USE_GST_GL_HELPERS
34 # include <gst/gl/gl.h>
35 #endif
36
37 GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
38 /* Default debug category is from the subclass */
39 #define GST_CAT_DEFAULT (plugin->debug_category)
40
41 #define BUFFER_POOL_SINK_MIN_BUFFERS 2
42
43 /* GstVideoContext interface */
44 static void
45 plugin_set_display (GstVaapiPluginBase * plugin, GstVaapiDisplay * display)
46 {
47   const gchar *const display_name =
48       gst_vaapi_display_get_display_name (display);
49
50   if (plugin->display_name && g_strcmp0 (plugin->display_name, display_name)) {
51     GST_DEBUG_OBJECT (plugin, "incompatible display name '%s', requested '%s'",
52         display_name, plugin->display_name);
53     gst_vaapi_display_replace (&plugin->display, NULL);
54   } else {
55     GST_INFO_OBJECT (plugin, "set display %" GST_PTR_FORMAT, display);
56     gst_vaapi_display_replace (&plugin->display, display);
57     plugin->display_type = gst_vaapi_display_get_display_type (display);
58     gst_vaapi_plugin_base_set_display_name (plugin, display_name);
59   }
60   gst_object_unref (display);
61 }
62
63 /**
64  * gst_vaapi_plugin_base_set_context:
65  * @plugin: a #GstVaapiPluginBase instance
66  * @context: a #GstContext to set
67  *
68  * This is a common set_context() element's vmethod for all the
69  * GStreamer VA-API elements.
70  *
71  * It normally should be used through the macro
72  * #GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT()
73  **/
74 void
75 gst_vaapi_plugin_base_set_context (GstVaapiPluginBase * plugin,
76     GstContext * context)
77 {
78   GstVaapiDisplay *display = NULL;
79
80   /* gst.vaapi.app.Display is only attended _if_ the element is
81    * vaapisink and it doesn't have a display set yet */
82   if (gst_vaapi_video_context_get_display (context,
83           GST_IS_VIDEO_SINK (plugin) && !plugin->display, &display)) {
84     plugin_set_display (plugin, display);
85   }
86 #if USE_GST_GL_HELPERS
87   gst_gl_handle_set_context (GST_ELEMENT_CAST (plugin), context,
88       (GstGLDisplay **) & plugin->gl_display,
89       (GstGLContext **) & plugin->gl_other_context);
90 #endif
91 }
92
93 void
94 gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
95 {
96 }
97
98 static gboolean
99 default_has_interface (GstVaapiPluginBase * plugin, GType type)
100 {
101   return FALSE;
102 }
103
104 static void
105 default_display_changed (GstVaapiPluginBase * plugin)
106 {
107 }
108
109 static GstVaapiSurface *
110 _get_cached_surface (GstBuffer * buf)
111 {
112   return gst_mini_object_get_qdata (GST_MINI_OBJECT (buf),
113       g_quark_from_static_string ("GstVaapiDMABufSurface"));
114 }
115
116 static void
117 _set_cached_surface (GstBuffer * buf, GstVaapiSurface * surface)
118 {
119   return gst_mini_object_set_qdata (GST_MINI_OBJECT (buf),
120       g_quark_from_static_string ("GstVaapiDMABufSurface"), surface,
121       (GDestroyNotify) gst_vaapi_object_unref);
122 }
123
124 static gboolean
125 plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin,
126     GstBuffer * buf)
127 {
128   GstVideoInfo *const vip = &plugin->sinkpad_info;
129   GstVideoMeta *vmeta;
130   guint i;
131
132   vmeta = gst_buffer_get_video_meta (buf);
133   if (!vmeta)
134     return TRUE;
135
136   if (GST_VIDEO_INFO_FORMAT (vip) != vmeta->format ||
137       GST_VIDEO_INFO_WIDTH (vip) != vmeta->width ||
138       GST_VIDEO_INFO_HEIGHT (vip) != vmeta->height ||
139       GST_VIDEO_INFO_N_PLANES (vip) != vmeta->n_planes)
140     return FALSE;
141
142   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); ++i) {
143     GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = vmeta->offset[i];
144     GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = vmeta->stride[i];
145   }
146   GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf);
147   return TRUE;
148 }
149
150 static gboolean
151 is_dma_buffer (GstBuffer * buf)
152 {
153   GstMemory *mem;
154
155   if (gst_buffer_n_memory (buf) < 1)
156     return FALSE;
157
158   mem = gst_buffer_peek_memory (buf, 0);
159   if (!mem || !gst_is_dmabuf_memory (mem))
160     return FALSE;
161   return TRUE;
162 }
163
164 static gboolean
165 plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin,
166     GstBuffer * inbuf, GstBuffer * outbuf)
167 {
168   GstVideoInfo *const vip = &plugin->sinkpad_info;
169   GstVaapiVideoMeta *meta;
170   GstVaapiSurface *surface;
171   GstVaapiSurfaceProxy *proxy;
172   gint fd;
173
174   fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0));
175   if (fd < 0)
176     return FALSE;
177
178   if (!plugin_update_sinkpad_info_from_buffer (plugin, inbuf))
179     goto error_update_sinkpad_info;
180
181   meta = gst_buffer_get_vaapi_video_meta (outbuf);
182   g_return_val_if_fail (meta != NULL, FALSE);
183
184   /* Check for a VASurface cached in the buffer */
185   surface = _get_cached_surface (inbuf);
186   if (!surface) {
187     /* otherwise create one and cache it */
188     surface =
189         gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd, vip);
190     if (!surface)
191       goto error_create_surface;
192     _set_cached_surface (inbuf, surface);
193   }
194
195   proxy = gst_vaapi_surface_proxy_new (surface);
196   if (!proxy)
197     goto error_create_proxy;
198   gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
199   gst_vaapi_surface_proxy_unref (proxy);
200   gst_buffer_add_parent_buffer_meta (outbuf, inbuf);
201   return TRUE;
202
203   /* ERRORS */
204 error_update_sinkpad_info:
205   {
206     GST_ERROR_OBJECT (plugin,
207         "failed to update sink pad video info from video meta");
208     return FALSE;
209   }
210 error_create_surface:
211   {
212     GST_ERROR_OBJECT (plugin,
213         "failed to create VA surface from dma_buf handle");
214     return FALSE;
215   }
216 error_create_proxy:
217   {
218     GST_ERROR_OBJECT (plugin,
219         "failed to create VA surface proxy from wrapped VA surface");
220     return FALSE;
221   }
222 }
223
224 static void
225 plugin_reset_texture_map (GstVaapiPluginBase * plugin)
226 {
227   if (plugin->display)
228     gst_vaapi_display_reset_texture_map (plugin->display);
229 }
230
231 void
232 gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass)
233 {
234   klass->has_interface = default_has_interface;
235   klass->display_changed = default_display_changed;
236 }
237
238 void
239 gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
240     GstDebugCategory * debug_category)
241 {
242   plugin->debug_category = debug_category;
243   plugin->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
244   plugin->display_type_req = GST_VAAPI_DISPLAY_TYPE_ANY;
245
246   /* sink pad */
247   plugin->sinkpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "sink");
248   gst_video_info_init (&plugin->sinkpad_info);
249
250   /* src pad */
251   if (!(GST_OBJECT_FLAGS (plugin) & GST_ELEMENT_FLAG_SINK))
252     plugin->srcpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "src");
253   gst_video_info_init (&plugin->srcpad_info);
254
255   plugin->enable_direct_rendering =
256       (g_getenv ("GST_VAAPI_ENABLE_DIRECT_RENDERING") != NULL);
257 }
258
259 void
260 gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin)
261 {
262   gst_vaapi_plugin_base_close (plugin);
263   g_free (plugin->display_name);
264   if (plugin->sinkpad)
265     gst_object_unref (plugin->sinkpad);
266   if (plugin->srcpad)
267     gst_object_unref (plugin->srcpad);
268 }
269
270 /**
271  * gst_vaapi_plugin_base_open:
272  * @plugin: a #GstVaapiPluginBase
273  *
274  * Allocates any internal resources needed for correct operation from
275  * the subclass.
276  *
277  * Returns: %TRUE if successful, %FALSE otherwise.
278  */
279 gboolean
280 gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin)
281 {
282   return TRUE;
283 }
284
285 /**
286  * gst_vaapi_plugin_base_close:
287  * @plugin: a #GstVaapiPluginBase
288  *
289  * Deallocates all internal resources that were allocated so
290  * far. i.e. put the base plugin object into a clean state.
291  */
292 void
293 gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin)
294 {
295   /* Release vaapi textures first if exist, which refs display object */
296   plugin_reset_texture_map (plugin);
297
298   gst_vaapi_display_replace (&plugin->display, NULL);
299   gst_object_replace (&plugin->gl_context, NULL);
300   gst_object_replace (&plugin->gl_display, NULL);
301   gst_object_replace (&plugin->gl_other_context, NULL);
302
303   gst_caps_replace (&plugin->sinkpad_caps, NULL);
304   gst_video_info_init (&plugin->sinkpad_info);
305
306   g_clear_object (&plugin->sinkpad_buffer_pool);
307   g_clear_object (&plugin->srcpad_buffer_pool);
308
309   g_clear_object (&plugin->sinkpad_allocator);
310   g_clear_object (&plugin->srcpad_allocator);
311   g_clear_object (&plugin->other_srcpad_allocator);
312
313   gst_caps_replace (&plugin->srcpad_caps, NULL);
314   gst_video_info_init (&plugin->srcpad_info);
315   gst_caps_replace (&plugin->allowed_raw_caps, NULL);
316 }
317
318 /**
319  * gst_vaapi_plugin_base_has_display_type:
320  * @plugin: a #GstVaapiPluginBase
321  * @display_type_req: the desired #GstVaapiDisplayType
322  *
323  * Checks whether the @plugin elements already has a #GstVaapiDisplay
324  * instance compatible with type @display_type_req.
325  *
326  * Return value: %TRUE if @plugin has a compatible display, %FALSE otherwise
327  */
328 gboolean
329 gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin,
330     GstVaapiDisplayType display_type_req)
331 {
332   GstVaapiDisplayType display_type;
333
334   if (!plugin->display)
335     return FALSE;
336
337   display_type = plugin->display_type;
338   if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
339     return TRUE;
340
341   display_type = gst_vaapi_display_get_class_type (plugin->display);
342   if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
343     return TRUE;
344   return FALSE;
345 }
346
347 /**
348  * gst_vaapi_plugin_base_set_display_type:
349  * @plugin: a #GstVaapiPluginBase
350  * @display_type: the new request #GstVaapiDisplayType
351  *
352  * Requests a new display type. The change is effective at the next
353  * call to gst_vaapi_plugin_base_ensure_display().
354  */
355 void
356 gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin,
357     GstVaapiDisplayType display_type)
358 {
359   plugin->display_type_req = display_type;
360 }
361
362 /**
363  * gst_vaapi_plugin_base_set_display_name:
364  * @plugin: a #GstVaapiPluginBase
365  * @display_name: the new display name to match
366  *
367  * Sets the name of the display to look for. The change is effective
368  * at the next call to gst_vaapi_plugin_base_ensure_display().
369  */
370 void
371 gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin,
372     const gchar * display_name)
373 {
374   g_free (plugin->display_name);
375   plugin->display_name = g_strdup (display_name);
376 }
377
378 /**
379  * gst_vaapi_plugin_base_ensure_display:
380  * @plugin: a #GstVaapiPluginBase
381  *
382  * Ensures the display stored in @plugin complies with the requested
383  * display type constraints.
384  *
385  * Returns: %TRUE if the display was created to match the requested
386  *   type, %FALSE otherwise.
387  */
388 gboolean
389 gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin)
390 {
391   if (gst_vaapi_plugin_base_has_display_type (plugin, plugin->display_type_req))
392     return TRUE;
393   gst_vaapi_display_replace (&plugin->display, NULL);
394
395   if (!gst_vaapi_ensure_display (GST_ELEMENT (plugin),
396           plugin->display_type_req))
397     return FALSE;
398   plugin->display_type = gst_vaapi_display_get_display_type (plugin->display);
399
400   GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->display_changed (plugin);
401   return TRUE;
402 }
403
404 static gboolean
405 gst_vaapi_buffer_pool_caps_is_equal (GstBufferPool * pool, GstCaps * newcaps)
406 {
407   GstStructure *config;
408   GstCaps *caps;
409   gboolean ret;
410
411   caps = NULL;
412   ret = FALSE;
413   config = gst_buffer_pool_get_config (pool);
414   if (gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
415     ret = gst_caps_is_equal (newcaps, caps);
416   gst_structure_free (config);
417
418   return ret;
419 }
420
421 static inline gboolean
422 reset_allocator (GstAllocator * allocator, GstVideoInfo * vinfo)
423 {
424   const GstVideoInfo *orig_vi;
425
426   if (!allocator)
427     return TRUE;
428
429   orig_vi = gst_allocator_get_vaapi_video_info (allocator, NULL);
430   if (!gst_video_info_changed (orig_vi, vinfo))
431     return FALSE;
432
433   gst_object_unref (allocator);
434   return TRUE;
435 }
436
437 static gboolean
438 ensure_sinkpad_allocator (GstVaapiPluginBase * plugin, GstCaps * caps,
439     guint * size)
440 {
441   GstVideoInfo vinfo;
442   const GstVideoInfo *image_info;
443   GstVaapiImageUsageFlags usage_flag =
444       GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
445
446   if (!gst_video_info_from_caps (&vinfo, caps))
447     goto error_invalid_caps;
448
449   if (!reset_allocator (plugin->sinkpad_allocator, &vinfo))
450     goto bail;
451
452   /* enable direct upload if upstream requests raw video */
453   if (gst_caps_is_video_raw (caps)) {
454     usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD;
455     GST_INFO_OBJECT (plugin, "enabling direct upload in sink allocator");
456   }
457   plugin->sinkpad_allocator =
458       gst_vaapi_video_allocator_new (plugin->display, &vinfo, 0, usage_flag);
459
460 bail:
461   if (!plugin->sinkpad_allocator)
462     goto error_create_allocator;
463
464   image_info =
465       gst_allocator_get_vaapi_video_info (plugin->sinkpad_allocator, NULL);
466   g_assert (image_info);        /* allocator ought set its image info */
467
468   /* update the size with the one generated by the allocator */
469   *size = GST_VIDEO_INFO_SIZE (image_info);
470
471   return TRUE;
472
473   /* ERRORS */
474 error_invalid_caps:
475   {
476     GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
477     return FALSE;
478   }
479 error_create_allocator:
480   {
481     GST_ERROR_OBJECT (plugin, "failed to create sink pad's allocator");
482     return FALSE;
483   }
484 }
485
486 static inline guint
487 get_dmabuf_surface_allocation_flags (void)
488 {
489   /* @FIXME: fetch the real devices ids */
490   /* Pair vendor/device identifies an unique physical device. */
491   guint va_vendor_id = 0x00;
492   guint va_device_id = 0x00;
493   guint gl_vendor_id = 0x00;
494   guint gl_device_id = 0x00;
495
496   /* Requires linear memory only if fd export is done on a different
497    * device than the device where the fd is imported. */
498   gboolean same_physical_device = va_vendor_id == gl_vendor_id
499       && va_device_id == gl_device_id;
500
501   if (same_physical_device)
502     return 0;
503   return GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE;
504 }
505
506 static inline GstAllocator *
507 create_dmabuf_srcpad_allocator (GstVaapiPluginBase * plugin,
508     GstVideoInfo * vinfo, gboolean check_for_map)
509 {
510   GstAllocator *allocator;
511
512   if (!GST_IS_VIDEO_DECODER (plugin) && !GST_IS_BASE_TRANSFORM (plugin))
513     return NULL;
514
515   allocator = gst_vaapi_dmabuf_allocator_new (plugin->display, vinfo,
516       get_dmabuf_surface_allocation_flags (), GST_PAD_SRC);
517   if (!allocator || !check_for_map)
518     return allocator;
519
520   /* the dmabuf allocator *must* be capable to map a buffer with raw
521    * caps and the there's no evidence of downstream dmabuf
522    * importation */
523   if (!gst_vaapi_dmabuf_can_map (plugin->display, allocator)) {
524     GST_INFO_OBJECT (plugin, "dmabuf allocator generates unmappable buffers");
525     gst_object_replace ((GstObject **) & allocator, NULL);
526   }
527
528   return allocator;
529 }
530
531 static gboolean
532 ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstVideoInfo * vinfo,
533     GstCaps * caps)
534 {
535   const GstVideoInfo *image_info;
536
537   if (!reset_allocator (plugin->srcpad_allocator, vinfo))
538     goto valid_allocator;
539
540   plugin->srcpad_allocator = NULL;
541   if (caps && gst_caps_is_video_raw (caps)) {
542     GstAllocator *allocator = create_dmabuf_srcpad_allocator (plugin, vinfo,
543         !plugin->srcpad_can_dmabuf);
544     plugin->srcpad_allocator = allocator;
545   } else if (caps && gst_vaapi_caps_feature_contains (caps,
546           GST_VAAPI_CAPS_FEATURE_DMABUF)) {
547     plugin->srcpad_allocator =
548         create_dmabuf_srcpad_allocator (plugin, vinfo, FALSE);
549     if (!plugin->srcpad_allocator)
550       goto error_create_allocator;
551   }
552
553   if (!plugin->srcpad_allocator) {
554     GstVaapiImageUsageFlags usage_flag =
555         GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
556
557     if (plugin->enable_direct_rendering) {
558       usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
559       GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator");
560     }
561
562     plugin->srcpad_allocator =
563         gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag);
564   }
565
566   if (!plugin->srcpad_allocator)
567     goto error_create_allocator;
568
569 valid_allocator:
570   image_info =
571       gst_allocator_get_vaapi_video_info (plugin->srcpad_allocator, NULL);
572   g_assert (image_info);        /* both allocators ought set its image
573                                  * info */
574
575   /* update the size with the one generated by the allocator */
576   GST_VIDEO_INFO_SIZE (vinfo) = GST_VIDEO_INFO_SIZE (image_info);
577
578   if (GST_IS_VIDEO_DECODER (plugin)) {
579     /* the received caps are the "allocation caps" which may be
580      * different from the "negotiation caps". In this case, we should
581      * indicate the allocator to store the negotiation caps since they
582      * are the one should be used for frame mapping with GstVideoMeta */
583     gboolean different_caps = plugin->srcpad_caps &&
584         !gst_caps_is_strictly_equal (plugin->srcpad_caps, caps);
585     const GstVideoInfo *previous_negotiated =
586         gst_allocator_get_vaapi_negotiated_video_info
587         (plugin->srcpad_allocator);
588
589     if (different_caps) {
590       guint i;
591       GstVideoInfo vi = plugin->srcpad_info;
592
593       /* update the planes and the size with the allocator image/surface
594        * info, but not the resolution */
595       for (i = 0; i < GST_VIDEO_INFO_N_PLANES (image_info); i++) {
596         GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) =
597             GST_VIDEO_INFO_PLANE_OFFSET (image_info, i);
598         GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) =
599             GST_VIDEO_INFO_PLANE_STRIDE (image_info, i);
600       }
601       GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (image_info);
602       gst_allocator_set_vaapi_negotiated_video_info (plugin->srcpad_allocator,
603           &vi);
604     } else if (previous_negotiated) {
605       gst_allocator_set_vaapi_negotiated_video_info (plugin->srcpad_allocator,
606           NULL);
607     }
608   }
609   return TRUE;
610
611   /* ERRORS */
612 error_create_allocator:
613   {
614     GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator");
615     return FALSE;
616   }
617 }
618
619 /**
620  * gst_vaapi_plugin_base_create_pool:
621  * @plugin: a #GstVaapiPluginBase
622  * @caps: the initial #GstCaps for the resulting buffer pool
623  * @size: the size of each buffer, not including prefix and padding
624  * @options: a set of #GstVaapiVideoBufferPoolOption encoded as bit-wise
625  * @allocator: (allow-none): the #GstAllocator to use or %NULL
626  *
627  * Create an instance of #GstVaapiVideoBufferPool
628  *
629  * Returns: (transfer full): a new allocated #GstBufferPool
630  **/
631 static GstBufferPool *
632 gst_vaapi_plugin_base_create_pool (GstVaapiPluginBase * plugin, GstCaps * caps,
633     gsize size, guint min_buffers, guint max_buffers, guint options,
634     GstAllocator * allocator)
635 {
636   GstBufferPool *pool;
637   GstStructure *config;
638
639   if (!(pool = gst_vaapi_video_buffer_pool_new (plugin->display)))
640     goto error_create_pool;
641
642   config = gst_buffer_pool_get_config (pool);
643   gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
644       max_buffers);
645   gst_buffer_pool_config_add_option (config,
646       GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
647   if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) {
648     gst_buffer_pool_config_add_option (config,
649         GST_BUFFER_POOL_OPTION_VIDEO_META);
650   }
651   if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT) {
652     gst_buffer_pool_config_add_option (config,
653         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
654   }
655 #if (USE_GLX || USE_EGL)
656   if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) {
657     gst_buffer_pool_config_add_option (config,
658         GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
659   }
660 #endif
661   if (allocator)
662     gst_buffer_pool_config_set_allocator (config, allocator, NULL);
663   if (!gst_buffer_pool_set_config (pool, config)) {
664     config = gst_buffer_pool_get_config (pool);
665
666     if (!gst_buffer_pool_config_validate_params (config, caps, size,
667             min_buffers, max_buffers)) {
668       gst_structure_free (config);
669       goto error_pool_config;
670     }
671
672     if (!gst_buffer_pool_set_config (pool, config))
673       goto error_pool_config;
674   }
675   return pool;
676
677   /* ERRORS */
678 error_create_pool:
679   {
680     GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
681     return NULL;
682   }
683 error_pool_config:
684   {
685     gst_object_unref (pool);
686     GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS,
687         ("Failed to configure the buffer pool"),
688         ("Configuration is most likely invalid, please report this issue."));
689     return NULL;
690   }
691 }
692
693 /**
694  * ensure_sinkpad_buffer_pool:
695  * @plugin: a #GstVaapiPluginBase
696  * @caps: the initial #GstCaps for the resulting buffer pool
697  *
698  * Makes sure the sink pad video buffer pool is created with the
699  * appropriate @caps.
700  *
701  * Returns: %TRUE if successful, %FALSE otherwise.
702  */
703 static gboolean
704 ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstCaps * caps)
705 {
706   GstBufferPool *pool;
707   guint size;
708
709   /* video decoders don't use a buffer pool in the sink pad */
710   if (GST_IS_VIDEO_DECODER (plugin))
711     return TRUE;
712
713   if (!gst_vaapi_plugin_base_ensure_display (plugin))
714     return FALSE;
715
716   if (plugin->sinkpad_buffer_pool) {
717     if (gst_vaapi_buffer_pool_caps_is_equal (plugin->sinkpad_buffer_pool, caps))
718       return TRUE;
719     gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, FALSE);
720     g_clear_object (&plugin->sinkpad_buffer_pool);
721     g_clear_object (&plugin->sinkpad_allocator);
722     plugin->sinkpad_buffer_size = 0;
723   }
724
725   if (!ensure_sinkpad_allocator (plugin, caps, &size))
726     return FALSE;
727
728   pool =
729       gst_vaapi_plugin_base_create_pool (plugin, caps, size,
730       BUFFER_POOL_SINK_MIN_BUFFERS, 0,
731       GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META, plugin->sinkpad_allocator);
732   if (!pool)
733     return FALSE;
734
735   plugin->sinkpad_buffer_pool = pool;
736   plugin->sinkpad_buffer_size = size;
737   return TRUE;
738 }
739
740 /**
741  * gst_vaapi_plugin_base_set_caps:
742  * @plugin: a #GstVaapiPluginBase
743  * @incaps: the sink pad (input) caps
744  * @outcaps: the src pad (output) caps
745  *
746  * Notifies the base plugin object of the new input and output caps,
747  * obtained from the subclass.
748  *
749  * Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
750  */
751 gboolean
752 gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
753     GstCaps * outcaps)
754 {
755   if (incaps && incaps != plugin->sinkpad_caps) {
756     if (!gst_video_info_from_caps (&plugin->sinkpad_info, incaps))
757       return FALSE;
758     gst_caps_replace (&plugin->sinkpad_caps, incaps);
759     plugin->sinkpad_caps_is_raw = !gst_caps_has_vaapi_surface (incaps);
760   }
761
762   if (outcaps && outcaps != plugin->srcpad_caps) {
763     if (!gst_video_info_from_caps (&plugin->srcpad_info, outcaps))
764       return FALSE;
765     if (plugin->srcpad_buffer_pool
766         && !gst_vaapi_buffer_pool_caps_is_equal (plugin->srcpad_buffer_pool,
767             outcaps)) {
768       gst_buffer_pool_set_active (plugin->srcpad_buffer_pool, FALSE);
769       g_clear_object (&plugin->srcpad_buffer_pool);
770       g_clear_object (&plugin->srcpad_allocator);
771       plugin_reset_texture_map (plugin);
772     }
773     gst_caps_replace (&plugin->srcpad_caps, outcaps);
774   }
775
776   if (!ensure_sinkpad_buffer_pool (plugin, plugin->sinkpad_caps))
777     return FALSE;
778   return TRUE;
779 }
780
781 /**
782  * gst_vaapi_plugin_base_propose_allocation:
783  * @plugin: a #GstVaapiPluginBase
784  * @query: the allocation query to configure
785  *
786  * Proposes allocation parameters to the upstream elements.
787  *
788  * Returns: %TRUE if successful, %FALSE otherwise.
789  */
790 gboolean
791 gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
792     GstQuery * query)
793 {
794   GstCaps *caps = NULL;
795   GstBufferPool *pool = NULL;
796   gboolean need_pool;
797   guint size = 0, n_allocators;
798
799   gst_query_parse_allocation (query, &caps, &need_pool);
800   if (!caps)
801     goto error_no_caps;
802
803   if (!ensure_sinkpad_allocator (plugin, caps, &size))
804     return FALSE;
805
806   if (need_pool) {
807     pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size,
808         BUFFER_POOL_SINK_MIN_BUFFERS, 0,
809         GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META,
810         plugin->sinkpad_allocator);
811     if (!pool)
812       return FALSE;
813   }
814
815   /* Set sinkpad allocator as the last allocation param.
816    *
817    * If there's none, set system's allocator first and VAAPI allocator
818    * second
819    */
820   n_allocators = gst_query_get_n_allocation_params (query);
821   if (n_allocators == 0) {
822     GstAllocator *allocator;
823
824     allocator = gst_allocator_find (GST_ALLOCATOR_SYSMEM);
825     gst_query_add_allocation_param (query, allocator, NULL);
826     gst_object_unref (allocator);
827   }
828   gst_query_add_allocation_param (query, plugin->sinkpad_allocator, NULL);
829
830   gst_query_add_allocation_pool (query, pool, size,
831       BUFFER_POOL_SINK_MIN_BUFFERS, 0);
832   if (pool)
833     gst_object_unref (pool);
834
835   gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL);
836   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
837   return TRUE;
838
839   /* ERRORS */
840 error_no_caps:
841   {
842     GST_INFO_OBJECT (plugin, "no caps specified");
843     return FALSE;
844   }
845 }
846
847 /**
848  * gst_vaapi_plugin_base_decide_allocation:
849  * @plugin: a #GstVaapiPluginBase
850  * @query: the allocation query to parse
851  * @feature: the desired #GstVaapiCapsFeature, or zero to find the
852  *   preferred one
853  *
854  * Decides allocation parameters for the downstream elements.
855  *
856  * Returns: %TRUE if successful, %FALSE otherwise.
857  */
858 gboolean
859 gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
860     GstQuery * query)
861 {
862   GstCaps *caps = NULL;
863   GstBufferPool *pool;
864   GstVideoInfo vi;
865   guint i, size, min, max, pool_options, num_allocators;
866   gint index_allocator;
867   gboolean update_pool = FALSE;
868 #if (USE_GLX || USE_EGL)
869   guint idx;
870 #endif
871
872   gst_query_parse_allocation (query, &caps, NULL);
873   if (!caps)
874     goto error_no_caps;
875
876   pool_options = 0;
877   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
878     pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
879
880 #if (USE_GLX || USE_EGL)
881   if (gst_query_find_allocation_meta (query,
882           GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) &&
883       gst_vaapi_caps_feature_contains (caps,
884           GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META))
885     pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD;
886
887 #if USE_GST_GL_HELPERS
888   if (!plugin->gl_context &&
889       (pool_options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD)) {
890     const GstStructure *params;
891     GstObject *gl_context;
892
893     gst_query_parse_nth_allocation_meta (query, idx, &params);
894     if (params) {
895       if (gst_structure_get (params, "gst.gl.GstGLContext", GST_TYPE_GL_CONTEXT,
896               &gl_context, NULL) && gl_context) {
897         gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
898         gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, gl_context);
899         gst_object_unref (gl_context);
900       }
901     }
902   }
903 #endif
904 #endif
905
906   /* Make sure the display we pass down to the buffer pool is actually
907      the expected one, especially when the downstream element requires
908      a GLX or EGL display */
909   if (!gst_vaapi_plugin_base_ensure_display (plugin))
910     goto error_ensure_display;
911
912   if (!gst_video_info_from_caps (&vi, caps))
913     goto error_invalid_caps;
914   gst_video_info_force_nv12_if_encoded (&vi);
915
916   index_allocator = -1;
917   num_allocators = gst_query_get_n_allocation_params (query);
918   for (i = 0; i < num_allocators; i++) {
919     GstAllocator *allocator = NULL;
920     GstAllocationParams params;
921
922     gst_query_parse_nth_allocation_param (query, i, &allocator, &params);
923     if (!allocator)
924       continue;
925
926     /* Let's keep the the first allocator if it is not VA-API. It
927      * might be used if it is required to copy the output frame to a
928      * new buffer */
929     if (i == 0
930         && g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0) {
931       if (plugin->other_srcpad_allocator)
932         gst_object_unref (plugin->other_srcpad_allocator);
933       plugin->other_srcpad_allocator = allocator;
934       plugin->other_allocator_params = params;
935       continue;
936     }
937
938     if (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) == 0) {
939       GST_DEBUG_OBJECT (plugin, "found vaapi allocator in query %"
940           GST_PTR_FORMAT, allocator);
941       index_allocator = i;
942       if (plugin->srcpad_allocator)
943         gst_object_unref (plugin->srcpad_allocator);
944       plugin->srcpad_allocator = allocator;
945       break;
946     }
947     gst_object_unref (allocator);
948   }
949
950   if (gst_query_get_n_allocation_pools (query) > 0) {
951     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
952     update_pool = TRUE;
953     size = MAX (size, GST_VIDEO_INFO_SIZE (&vi));
954     if (pool) {
955       /* Check whether downstream element proposed a bufferpool but did
956          not provide a correct propose_allocation() implementation */
957       if (gst_buffer_pool_has_option (pool,
958               GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT))
959         pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT;
960
961       /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
962       if (!gst_buffer_pool_has_option (pool,
963               GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
964         GST_INFO_OBJECT (plugin, "ignoring non-VAAPI pool: %" GST_PTR_FORMAT,
965             pool);
966         g_clear_object (&pool);
967       }
968     }
969   } else {
970     pool = NULL;
971     size = GST_VIDEO_INFO_SIZE (&vi);
972     min = max = 0;
973   }
974
975   if (!pool) {
976     if (!ensure_srcpad_allocator (plugin, &vi, caps))
977       goto error;
978     size = GST_VIDEO_INFO_SIZE (&vi);   /* size might be updated by
979                                          * allocator */
980     pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size, min, max,
981         pool_options, plugin->srcpad_allocator);
982     if (!pool)
983       goto error;
984   }
985
986   if (update_pool)
987     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
988   else
989     gst_query_add_allocation_pool (query, pool, size, min, max);
990
991   /* allocator might be updated by ensure_srcpad_allocator() */
992   if (plugin->srcpad_allocator) {
993     if (index_allocator > 0) {
994       gst_query_set_nth_allocation_param (query, index_allocator,
995           plugin->srcpad_allocator, NULL);
996     } else {
997       GST_DEBUG_OBJECT (plugin, "adding allocator in query %" GST_PTR_FORMAT,
998           plugin->srcpad_allocator);
999       gst_query_add_allocation_param (query, plugin->srcpad_allocator, NULL);
1000     }
1001   }
1002
1003   g_clear_object (&plugin->srcpad_buffer_pool);
1004   plugin->srcpad_buffer_pool = pool;
1005
1006   /* if downstream doesn't support GstVideoMeta, and the negotiated
1007    * caps are raw video, and the used allocator is the VA-API one, we
1008    * should copy the VA-API frame into a dumb buffer */
1009   plugin->copy_output_frame = gst_vaapi_video_buffer_pool_copy_buffer (pool);
1010
1011   return TRUE;
1012
1013   /* ERRORS */
1014 error_no_caps:
1015   {
1016     GST_ERROR_OBJECT (plugin, "no caps specified");
1017     return FALSE;
1018   }
1019 error_invalid_caps:
1020   {
1021     GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
1022     return FALSE;
1023   }
1024 error_ensure_display:
1025   {
1026     GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d",
1027         plugin->display_type_req);
1028     return FALSE;
1029   }
1030 error:
1031   {
1032     /* error message already sent */
1033     return FALSE;
1034   }
1035 }
1036
1037 /**
1038  * gst_vaapi_plugin_base_get_input_buffer:
1039  * @plugin: a #GstVaapiPluginBase
1040  * @inbuf: the sink pad (input) buffer
1041  * @outbuf_ptr: the pointer to location to the VA surface backed buffer
1042  *
1043  * Acquires the sink pad (input) buffer as a VA surface backed
1044  * buffer. This is mostly useful for raw YUV buffers, as source
1045  * buffers that are already backed as a VA surface are passed
1046  * verbatim.
1047  *
1048  * Returns: #GST_FLOW_OK if the buffer could be acquired
1049  */
1050 GstFlowReturn
1051 gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
1052     GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
1053 {
1054   GstVaapiVideoMeta *meta;
1055   GstBuffer *outbuf;
1056   GstVideoFrame src_frame, out_frame;
1057   gboolean success;
1058
1059   g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
1060   g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
1061
1062   meta = gst_buffer_get_vaapi_video_meta (inbuf);
1063   if (meta) {
1064     *outbuf_ptr = gst_buffer_ref (inbuf);
1065     return GST_FLOW_OK;
1066   }
1067
1068   if (!plugin->sinkpad_caps_is_raw)
1069     goto error_invalid_buffer;
1070
1071   if (!plugin->sinkpad_buffer_pool)
1072     goto error_no_pool;
1073
1074   if (!gst_buffer_pool_is_active (plugin->sinkpad_buffer_pool) &&
1075       !gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, TRUE))
1076     goto error_active_pool;
1077
1078   outbuf = NULL;
1079   if (gst_buffer_pool_acquire_buffer (plugin->sinkpad_buffer_pool,
1080           &outbuf, NULL) != GST_FLOW_OK)
1081     goto error_create_buffer;
1082
1083   if (is_dma_buffer (inbuf)) {
1084     if (!plugin_bind_dma_to_vaapi_buffer (plugin, inbuf, outbuf))
1085       goto error_bind_dma_buffer;
1086     goto done;
1087   }
1088
1089   if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf,
1090           GST_MAP_READ))
1091     goto error_map_src_buffer;
1092
1093   if (!gst_video_frame_map (&out_frame, &plugin->sinkpad_info, outbuf,
1094           GST_MAP_WRITE))
1095     goto error_map_dst_buffer;
1096
1097   success = gst_video_frame_copy (&out_frame, &src_frame);
1098   gst_video_frame_unmap (&out_frame);
1099   gst_video_frame_unmap (&src_frame);
1100   if (!success)
1101     goto error_copy_buffer;
1102
1103 done:
1104   if (!gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS |
1105           GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, -1))
1106     return GST_FLOW_ERROR;
1107   *outbuf_ptr = outbuf;
1108   return GST_FLOW_OK;
1109
1110   /* ERRORS */
1111 error_no_pool:
1112   {
1113     GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1114         ("no buffer pool was negotiated"), ("no buffer pool was negotiated"));
1115     return GST_FLOW_ERROR;
1116   }
1117 error_active_pool:
1118   {
1119     GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1120         ("failed to activate buffer pool"), ("failed to activate buffer pool"));
1121     return GST_FLOW_ERROR;
1122   }
1123 error_map_dst_buffer:
1124   {
1125     gst_video_frame_unmap (&src_frame);
1126     // fall-through
1127   }
1128 error_map_src_buffer:
1129   {
1130     GST_WARNING ("failed to map buffer");
1131     gst_buffer_unref (outbuf);
1132     return GST_FLOW_NOT_SUPPORTED;
1133   }
1134
1135   /* ERRORS */
1136 error_invalid_buffer:
1137   {
1138     GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1139         ("failed to validate source buffer"),
1140         ("failed to validate source buffer"));
1141     return GST_FLOW_ERROR;
1142   }
1143 error_create_buffer:
1144   {
1145     GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
1146         ("failed to create buffer"));
1147     return GST_FLOW_ERROR;
1148   }
1149 error_bind_dma_buffer:
1150   {
1151     GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
1152         ("failed to bind dma_buf to VA surface buffer"));
1153     gst_buffer_unref (outbuf);
1154     return GST_FLOW_ERROR;
1155   }
1156 error_copy_buffer:
1157   {
1158     GST_WARNING_OBJECT (plugin, "failed to upload buffer to VA surface");
1159     gst_buffer_unref (outbuf);
1160     return GST_FLOW_NOT_SUPPORTED;
1161   }
1162 }
1163
1164 /**
1165  * gst_vaapi_plugin_base_set_gl_context:
1166  * @plugin: a #GstVaapiPluginBase
1167  * @object: the new GL context from downstream
1168  *
1169  * Registers the new GL context. The change is effective at the next
1170  * call to gst_vaapi_plugin_base_ensure_display(), where the
1171  * underlying display object could be re-allocated to fit the GL
1172  * context needs
1173  */
1174 void
1175 gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin,
1176     GstObject * object)
1177 {
1178 #if USE_GST_GL_HELPERS
1179   GstGLContext *const gl_context = GST_GL_CONTEXT (object);
1180   GstVaapiDisplayType display_type;
1181
1182   if (plugin->gl_context == object)
1183     return;
1184
1185   gst_object_replace (&plugin->gl_context, object);
1186
1187   switch (gst_gl_context_get_gl_platform (gl_context)) {
1188 #if USE_GLX
1189     case GST_GL_PLATFORM_GLX:
1190       display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
1191       break;
1192 #endif
1193     case GST_GL_PLATFORM_EGL:
1194 #if USE_EGL
1195       display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
1196       break;
1197 #endif
1198     default:
1199       display_type = plugin->display_type;
1200       break;
1201   }
1202   GST_INFO_OBJECT (plugin, "GL context: %" GST_PTR_FORMAT, plugin->gl_context);
1203   gst_vaapi_plugin_base_set_display_type (plugin, display_type);
1204 #endif
1205 }
1206
1207 /**
1208  * gst_vaapi_plugin_base_create_gl_context:
1209  * @plugin: a #GstVaapiPluginBase
1210  *
1211  * It queries downstream and upstream for a #GstGLDisplay and a other
1212  * #GstGLContext. If not found, a new #GstGLDisplay and #GstGLContext
1213  * are created, if it is possible.
1214  *
1215  * Returns: (transfer full) a new created #GstGLContext or %NULL
1216  **/
1217 GstObject *
1218 gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin)
1219 {
1220 #if USE_GST_GL_HELPERS
1221   GstGLContext *gl_other_context = NULL, *gl_context = NULL;
1222   GstGLDisplay *gl_display = NULL;
1223
1224   if (!plugin->gl_display)
1225     return NULL;
1226
1227   gl_display = (GstGLDisplay *) plugin->gl_display;
1228   if (gst_gl_display_get_handle_type (gl_display) == GST_GL_DISPLAY_TYPE_ANY)
1229     goto no_valid_gl_display;
1230   gl_other_context = (GstGLContext *) plugin->gl_other_context;
1231
1232   GST_INFO_OBJECT (plugin, "creating a new GstGL context");
1233
1234   GST_OBJECT_LOCK (gl_display);
1235   do {
1236     if (gl_context)
1237       gst_object_unref (gl_context);
1238     gl_context = gst_gl_display_get_gl_context_for_thread (gl_display, NULL);
1239     if (!gl_context) {
1240       if (!gst_gl_display_create_context (gl_display, gl_other_context,
1241               &gl_context, NULL))
1242         break;
1243     }
1244   } while (!gst_gl_display_add_context (gl_display, gl_context));
1245   GST_OBJECT_UNLOCK (gl_display);
1246
1247   return GST_OBJECT_CAST (gl_context);
1248
1249   /* ERRORS */
1250 no_valid_gl_display:
1251   {
1252     GST_INFO_OBJECT (plugin, "No valid GL display found");
1253     gst_object_replace (&plugin->gl_display, NULL);
1254     gst_object_replace (&plugin->gl_other_context, NULL);
1255     return NULL;
1256   }
1257 #else
1258   return NULL;
1259 #endif
1260 }
1261
1262 static GArray *
1263 extract_allowed_surface_formats (GstVaapiDisplay * display,
1264     GArray * img_formats, GstVideoFormat specified_format,
1265     GstPadDirection direction)
1266 {
1267   guint i;
1268   GArray *out_formats;
1269   GstVaapiSurface *surface = NULL;
1270
1271   g_assert (direction == GST_PAD_SRC || direction == GST_PAD_SINK);
1272
1273   out_formats =
1274       g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat),
1275       img_formats->len);
1276   if (!out_formats)
1277     return NULL;
1278
1279   for (i = 0; i < img_formats->len; i++) {
1280     const GstVideoFormat img_format =
1281         g_array_index (img_formats, GstVideoFormat, i);
1282     GstVaapiImage *image;
1283     GstVideoInfo vi;
1284     GstVideoFormat surface_format;
1285     gboolean res;
1286
1287     if (img_format == GST_VIDEO_FORMAT_UNKNOWN)
1288       continue;
1289
1290     surface_format =
1291         (specified_format == GST_VIDEO_FORMAT_UNKNOWN) ?
1292         img_format : specified_format;
1293     if (!surface) {
1294       gst_video_info_set_format (&vi, surface_format, 64, 64);
1295       surface = gst_vaapi_surface_new_full (display, &vi, 0);
1296       if (!surface)
1297         continue;
1298     }
1299
1300     image = gst_vaapi_image_new (display, img_format, 64, 64);
1301     if (!image) {
1302       /* Just reuse the surface if the format is specified */
1303       if (specified_format == GST_VIDEO_FORMAT_UNKNOWN)
1304         gst_vaapi_object_replace (&surface, NULL);
1305
1306       continue;
1307     }
1308
1309     res = FALSE;
1310     if (direction == GST_PAD_SRC) {
1311       res = gst_vaapi_surface_get_image (surface, image);
1312     } else {
1313       res = gst_vaapi_surface_put_image (surface, image);
1314     }
1315     if (res)
1316       g_array_append_val (out_formats, img_format);
1317
1318     gst_vaapi_object_unref (image);
1319     /* Just reuse the surface if the format is specified */
1320     if (specified_format == GST_VIDEO_FORMAT_UNKNOWN)
1321       gst_vaapi_object_replace (&surface, NULL);
1322   }
1323
1324   if (surface)
1325     gst_vaapi_object_unref (surface);
1326
1327   if (out_formats->len == 0) {
1328     g_array_unref (out_formats);
1329     return NULL;
1330   }
1331   return out_formats;
1332 }
1333
1334 static gboolean
1335 ensure_allowed_raw_caps (GstVaapiPluginBase * plugin, GstVideoFormat format,
1336     GstPadDirection direction)
1337 {
1338   GArray *formats, *out_formats;
1339   GstVaapiDisplay *display;
1340   GstCaps *out_caps;
1341   gboolean ret = FALSE;
1342
1343   if (plugin->allowed_raw_caps)
1344     return TRUE;
1345
1346   out_formats = NULL;
1347   display = gst_object_ref (plugin->display);
1348   formats = gst_vaapi_display_get_image_formats (display);
1349   if (!formats)
1350     goto bail;
1351   out_formats =
1352       extract_allowed_surface_formats (display, formats, format, direction);
1353   if (!out_formats)
1354     goto bail;
1355   out_caps = gst_vaapi_video_format_new_template_caps_from_list (out_formats);
1356   if (!out_caps)
1357     goto bail;
1358
1359   gst_caps_replace (&plugin->allowed_raw_caps, out_caps);
1360   gst_caps_unref (out_caps);
1361   ret = TRUE;
1362
1363 bail:
1364   if (formats)
1365     g_array_unref (formats);
1366   if (out_formats)
1367     g_array_unref (out_formats);
1368   gst_object_unref (display);
1369
1370   return ret;
1371 }
1372
1373 /**
1374  * gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps:
1375  * @plugin: a #GstVaapiPluginBase
1376  *
1377  * Returns the raw #GstCaps allowed by the element.
1378  *
1379  * Returns: the allowed raw #GstCaps or %NULL
1380  **/
1381 GstCaps *
1382 gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GstVaapiPluginBase * plugin)
1383 {
1384   if (!ensure_allowed_raw_caps (plugin, GST_VIDEO_FORMAT_UNKNOWN, GST_PAD_SINK))
1385     return NULL;
1386   return plugin->allowed_raw_caps;
1387 }
1388
1389 /**
1390  * gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps:
1391  * @plugin: a #GstVaapiPluginBase
1392  * @format: a #GstVideoFormat, the format we need to check
1393  *
1394  * Returns the raw #GstCaps allowed by the element.
1395  *
1396  * Returns: the allowed raw #GstCaps or %NULL
1397  **/
1398 GstCaps *
1399 gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps (GstVaapiPluginBase *
1400     plugin, GstVideoFormat format)
1401 {
1402   if (!ensure_allowed_raw_caps (plugin, format, GST_PAD_SRC))
1403     return NULL;
1404   return plugin->allowed_raw_caps;
1405 }
1406
1407 /**
1408  * gst_vaapi_plugin_base_set_srcpad_can_dmabuf:
1409  * @plugin: a #GstVaapiPluginBase
1410  * @object: the GL context from gst-gl
1411  *
1412  * This function will determine if @object supports dmabuf
1413  * importing.
1414  *
1415  * Please note that the context @object should come from downstream.
1416  **/
1417 void
1418 gst_vaapi_plugin_base_set_srcpad_can_dmabuf (GstVaapiPluginBase * plugin,
1419     GstObject * object)
1420 {
1421 #if USE_EGL && USE_GST_GL_HELPERS
1422   GstGLContext *const gl_context = GST_GL_CONTEXT (object);
1423
1424   plugin->srcpad_can_dmabuf =
1425       (!(gst_gl_context_get_gl_api (gl_context) & GST_GL_API_GLES1)
1426       && gst_gl_context_check_feature (gl_context,
1427           "EGL_EXT_image_dma_buf_import"));
1428 #endif
1429 }
1430
1431 static void
1432 _init_performance_debug (void)
1433 {
1434 #ifndef GST_DISABLE_GST_DEBUG
1435   static volatile gsize _init = 0;
1436
1437   if (g_once_init_enter (&_init)) {
1438     GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
1439     g_once_init_leave (&_init, 1);
1440   }
1441 #endif
1442 }
1443
1444 /**
1445  * gst_vaapi_plugin_copy_va_buffer:
1446  * @plugin: a #GstVaapiPluginBase
1447  * @inbuf: a #GstBuffer with VA memory type
1448  * @outbuf: a #GstBuffer with system allocated memory
1449  *
1450  * Copy @inbuf to @outbuf. This if required when downstream doesn't
1451  * support GstVideoMeta, and since VA memory may have custom strides a
1452  * frame copy is required.
1453  *
1454  * Returns: %FALSE if the copy failed, otherwise %TRUE. Also returns
1455  *          %TRUE if it is not required to do the copy
1456  **/
1457 gboolean
1458 gst_vaapi_plugin_copy_va_buffer (GstVaapiPluginBase * plugin,
1459     GstBuffer * inbuf, GstBuffer * outbuf)
1460 {
1461   GstVideoMeta *vmeta;
1462   GstVideoFrame src_frame, dst_frame;
1463   gboolean success;
1464
1465   if (!plugin->copy_output_frame)
1466     return TRUE;
1467
1468   /* inbuf shall have video meta */
1469   vmeta = gst_buffer_get_video_meta (inbuf);
1470   if (!vmeta)
1471     return FALSE;
1472
1473   _init_performance_debug ();
1474   GST_CAT_INFO (CAT_PERFORMANCE, "copying VA buffer to system memory buffer");
1475
1476   if (!gst_video_frame_map (&src_frame, &plugin->srcpad_info, inbuf,
1477           GST_MAP_READ))
1478     return FALSE;
1479   if (!gst_video_frame_map (&dst_frame, &plugin->srcpad_info, outbuf,
1480           GST_MAP_WRITE)) {
1481     gst_video_frame_unmap (&src_frame);
1482     return FALSE;
1483   }
1484   success = gst_video_frame_copy (&dst_frame, &src_frame);
1485   gst_video_frame_unmap (&dst_frame);
1486   gst_video_frame_unmap (&src_frame);
1487
1488   if (success) {
1489     gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS
1490         | GST_BUFFER_COPY_FLAGS, 0, -1);
1491   }
1492
1493   return success;
1494 }