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