e8079d089b4c6aaad50406b9f26f2d3bae77f0f9
[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 #include <gst/allocators/allocators.h>
34
35 /* Default debug category is from the subclass */
36 #define GST_CAT_DEFAULT (plugin->debug_category)
37
38 /* GstVideoContext interface */
39 static void
40 plugin_set_display (GstVaapiPluginBase * plugin, GstVaapiDisplay * display)
41 {
42   const gchar *const display_name =
43       gst_vaapi_display_get_display_name (display);
44
45   if (plugin->display_name && g_strcmp0 (plugin->display_name, display_name)) {
46     GST_DEBUG_OBJECT (plugin, "incompatible display name '%s', requested '%s'",
47         display_name, plugin->display_name);
48     gst_vaapi_display_replace (&plugin->display, NULL);
49   } else {
50     GST_INFO_OBJECT (plugin, "set display %p", display);
51     gst_vaapi_display_replace (&plugin->display, display);
52     plugin->display_type = gst_vaapi_display_get_display_type (display);
53     gst_vaapi_plugin_base_set_display_name (plugin, display_name);
54   }
55   gst_vaapi_display_unref (display);
56 }
57
58 static void
59 plugin_set_context (GstElement * element, GstContext * context)
60 {
61   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
62   GstVaapiDisplay *display = NULL;
63
64   if (gst_vaapi_video_context_get_display (context, &display))
65     plugin_set_display (plugin, display);
66 }
67
68 void
69 gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
70 {
71 }
72
73 static gboolean
74 default_has_interface (GstVaapiPluginBase * plugin, GType type)
75 {
76   return FALSE;
77 }
78
79 static void
80 default_display_changed (GstVaapiPluginBase * plugin)
81 {
82 }
83
84 static gboolean
85 plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin,
86     GstBuffer * buf)
87 {
88   GstVideoInfo *const vip = &plugin->sinkpad_info;
89   GstVideoMeta *vmeta;
90   guint i;
91
92   vmeta = gst_buffer_get_video_meta (buf);
93   if (!vmeta)
94     return TRUE;
95
96   if (GST_VIDEO_INFO_FORMAT (vip) != vmeta->format ||
97       GST_VIDEO_INFO_WIDTH (vip) != vmeta->width ||
98       GST_VIDEO_INFO_HEIGHT (vip) != vmeta->height ||
99       GST_VIDEO_INFO_N_PLANES (vip) != vmeta->n_planes)
100     return FALSE;
101
102   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); ++i) {
103     GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = vmeta->offset[i];
104     GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = vmeta->stride[i];
105   }
106   GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf);
107   return TRUE;
108 }
109
110 static gboolean
111 is_dma_buffer (GstBuffer * buf)
112 {
113   GstMemory *mem;
114
115   if (gst_buffer_n_memory (buf) < 1)
116     return FALSE;
117
118   mem = gst_buffer_peek_memory (buf, 0);
119   if (!mem || !gst_is_dmabuf_memory (mem))
120     return FALSE;
121   return TRUE;
122 }
123
124 static gboolean
125 plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin,
126     GstBuffer * inbuf, GstBuffer * outbuf)
127 {
128   GstVideoInfo *const vip = &plugin->sinkpad_info;
129   GstVaapiVideoMeta *meta;
130   GstVaapiSurface *surface;
131   GstVaapiSurfaceProxy *proxy;
132   gint fd;
133
134   fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0));
135   if (fd < 0)
136     return FALSE;
137
138   if (!plugin_update_sinkpad_info_from_buffer (plugin, inbuf))
139     goto error_update_sinkpad_info;
140
141   meta = gst_buffer_get_vaapi_video_meta (outbuf);
142   g_return_val_if_fail (meta != NULL, FALSE);
143
144   surface = gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd,
145       GST_VIDEO_INFO_SIZE (vip), GST_VIDEO_INFO_FORMAT (vip),
146       GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip),
147       vip->offset, vip->stride);
148   if (!surface)
149     goto error_create_surface;
150
151   proxy = gst_vaapi_surface_proxy_new (surface);
152   gst_vaapi_object_unref (surface);
153   if (!proxy)
154     goto error_create_proxy;
155
156   gst_vaapi_surface_proxy_set_destroy_notify (proxy,
157       (GDestroyNotify) gst_buffer_unref, (gpointer) gst_buffer_ref (inbuf));
158   gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
159   gst_vaapi_surface_proxy_unref (proxy);
160   return TRUE;
161
162   /* ERRORS */
163 error_update_sinkpad_info:
164   GST_ERROR ("failed to update sink pad video info from video meta");
165   return FALSE;
166 error_create_surface:
167   GST_ERROR ("failed to create VA surface from dma_buf handle");
168   return FALSE;
169 error_create_proxy:
170   GST_ERROR ("failed to create VA surface proxy from wrapped VA surface");
171   return FALSE;
172 }
173
174 void
175 gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass)
176 {
177   klass->has_interface = default_has_interface;
178   klass->display_changed = default_display_changed;
179
180   GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
181   element_class->set_context = GST_DEBUG_FUNCPTR (plugin_set_context);
182 }
183
184 void
185 gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
186     GstDebugCategory * debug_category)
187 {
188   plugin->debug_category = debug_category;
189   plugin->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
190   plugin->display_type_req = GST_VAAPI_DISPLAY_TYPE_ANY;
191
192   /* sink pad */
193   plugin->sinkpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "sink");
194   plugin->sinkpad_query = GST_PAD_QUERYFUNC (plugin->sinkpad);
195   gst_video_info_init (&plugin->sinkpad_info);
196
197   /* src pad */
198   if (!(GST_OBJECT_FLAGS (plugin) & GST_ELEMENT_FLAG_SINK)) {
199     plugin->srcpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "src");
200     plugin->srcpad_query = GST_PAD_QUERYFUNC (plugin->srcpad);
201   }
202   gst_video_info_init (&plugin->srcpad_info);
203 }
204
205 void
206 gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin)
207 {
208   gst_vaapi_plugin_base_close (plugin);
209   g_free (plugin->display_name);
210   if (plugin->sinkpad)
211     gst_object_unref (plugin->sinkpad);
212   if (plugin->srcpad)
213     gst_object_unref (plugin->srcpad);
214 }
215
216 /**
217  * gst_vaapi_plugin_base_open:
218  * @plugin: a #GstVaapiPluginBase
219  *
220  * Allocates any internal resources needed for correct operation from
221  * the subclass.
222  *
223  * Returns: %TRUE if successful, %FALSE otherwise.
224  */
225 gboolean
226 gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin)
227 {
228   return TRUE;
229 }
230
231 /**
232  * gst_vaapi_plugin_base_close:
233  * @plugin: a #GstVaapiPluginBase
234  *
235  * Deallocates all internal resources that were allocated so
236  * far. i.e. put the base plugin object into a clean state.
237  */
238 void
239 gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin)
240 {
241   g_clear_object (&plugin->uploader);
242   gst_vaapi_display_replace (&plugin->display, NULL);
243   gst_object_replace (&plugin->gl_context, NULL);
244
245   gst_caps_replace (&plugin->sinkpad_caps, NULL);
246   plugin->sinkpad_caps_changed = FALSE;
247   gst_video_info_init (&plugin->sinkpad_info);
248   if (plugin->sinkpad_buffer_pool) {
249     gst_object_unref (plugin->sinkpad_buffer_pool);
250     plugin->sinkpad_buffer_pool = NULL;
251   }
252   g_clear_object (&plugin->srcpad_buffer_pool);
253
254   gst_caps_replace (&plugin->srcpad_caps, NULL);
255   plugin->srcpad_caps_changed = FALSE;
256   gst_video_info_init (&plugin->srcpad_info);
257 }
258
259 /**
260  * gst_vaapi_plugin_base_has_display_type:
261  * @plugin: a #GstVaapiPluginBase
262  * @display_type_req: the desired #GstVaapiDisplayType
263  *
264  * Checks whether the @plugin elements already has a #GstVaapiDisplay
265  * instance compatible with type @display_type_req.
266  *
267  * Return value: %TRUE if @plugin has a compatible display, %FALSE otherwise
268  */
269 gboolean
270 gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin,
271     GstVaapiDisplayType display_type_req)
272 {
273   GstVaapiDisplayType display_type;
274
275   if (!plugin->display)
276     return FALSE;
277
278   display_type = plugin->display_type;
279   if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
280     return TRUE;
281
282   display_type = gst_vaapi_display_get_class_type (plugin->display);
283   if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
284     return TRUE;
285   return FALSE;
286 }
287
288 /**
289  * gst_vaapi_plugin_base_set_display_type:
290  * @plugin: a #GstVaapiPluginBase
291  * @display_type: the new request #GstVaapiDisplayType
292  *
293  * Requests a new display type. The change is effective at the next
294  * call to gst_vaapi_plugin_base_ensure_display().
295  */
296 void
297 gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin,
298     GstVaapiDisplayType display_type)
299 {
300   plugin->display_type_req = display_type;
301 }
302
303 /**
304  * gst_vaapi_plugin_base_set_display_name:
305  * @plugin: a #GstVaapiPluginBase
306  * @display_name: the new display name to match
307  *
308  * Sets the name of the display to look for. The change is effective
309  * at the next call to gst_vaapi_plugin_base_ensure_display().
310  */
311 void
312 gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin,
313     const gchar * display_name)
314 {
315   g_free (plugin->display_name);
316   plugin->display_name = g_strdup (display_name);
317 }
318
319 /**
320  * gst_vaapi_plugin_base_ensure_display:
321  * @plugin: a #GstVaapiPluginBase
322  *
323  * Ensures the display stored in @plugin complies with the requested
324  * display type constraints.
325  *
326  * Returns: %TRUE if the display was created to match the requested
327  *   type, %FALSE otherwise.
328  */
329 gboolean
330 gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin)
331 {
332   if (gst_vaapi_plugin_base_has_display_type (plugin, plugin->display_type_req))
333     return TRUE;
334   gst_vaapi_display_replace (&plugin->display, NULL);
335
336   if (!gst_vaapi_ensure_display (plugin, plugin->display_type_req))
337     return FALSE;
338   plugin->display_type = gst_vaapi_display_get_display_type (plugin->display);
339
340   GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->display_changed (plugin);
341   return TRUE;
342 }
343
344 /**
345  * gst_vaapi_plugin_base_ensure_uploader:
346  * @plugin: a #GstVaapiPluginBase
347  *
348  * Makes sure the built-in #GstVaapiUploader object is created, or
349  * that it was successfully notified of any VA display change.
350  *
351  * Returns: %TRUE if the uploader was successfully created, %FALSE otherwise.
352  */
353 gboolean
354 gst_vaapi_plugin_base_ensure_uploader (GstVaapiPluginBase * plugin)
355 {
356   if (plugin->uploader) {
357     if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
358       return FALSE;
359   } else {
360     plugin->uploader = gst_vaapi_uploader_new (plugin->display);
361     if (!plugin->uploader)
362       return FALSE;
363   }
364   return TRUE;
365 }
366
367 /* Checks whether the supplied pad peer element supports DMABUF sharing */
368 /* XXX: this is a workaround to the absence of any proposer way to
369    specify DMABUF memory capsfeatures or bufferpool option to downstream */
370 static gboolean
371 has_dmabuf_capable_peer (GstVaapiPluginBase * plugin, GstPad * pad)
372 {
373   GstPad *other_pad = NULL;
374   GstElement *element = NULL;
375   gchar *element_name = NULL;
376   gboolean is_dmabuf_capable = FALSE;
377   gint v;
378
379   gst_object_ref (pad);
380
381   for (;;) {
382     other_pad = gst_pad_get_peer (pad);
383     gst_object_unref (pad);
384     if (!other_pad)
385       break;
386
387     element = gst_pad_get_parent_element (other_pad);
388     gst_object_unref (other_pad);
389     if (!element)
390       break;
391
392     if (GST_IS_PUSH_SRC (element)) {
393       element_name = gst_element_get_name (element);
394       if (!element_name || sscanf (element_name, "v4l2src%d", &v) != 1)
395         break;
396
397       v = 0;
398       g_object_get (element, "io-mode", &v, NULL);
399       is_dmabuf_capable = v == 5; /* "dmabuf-import" enum value */
400       break;
401     } else if (GST_IS_BASE_TRANSFORM (element)) {
402       element_name = gst_element_get_name (element);
403       if (!element_name || sscanf (element_name, "capsfilter%d", &v) != 1)
404         break;
405
406       pad = gst_element_get_static_pad (element, "sink");
407       if (!pad)
408         break;
409     } else
410       break;
411
412     g_free (element_name);
413     element_name = NULL;
414     g_clear_object (&element);
415   }
416
417   g_free (element_name);
418   g_clear_object (&element);
419   return is_dmabuf_capable;
420 }
421
422 /**
423  * ensure_sinkpad_buffer_pool:
424  * @plugin: a #GstVaapiPluginBase
425  * @caps: the initial #GstCaps for the resulting buffer pool
426  *
427  * Makes sure the sink pad video buffer pool is created with the
428  * appropriate @caps.
429  *
430  * Returns: %TRUE if successful, %FALSE otherwise.
431  */
432 static gboolean
433 ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstCaps * caps)
434 {
435   GstBufferPool *pool;
436   GstCaps *pool_caps;
437   GstStructure *config;
438   GstVideoInfo vi;
439   gboolean need_pool;
440
441   if (!gst_vaapi_plugin_base_ensure_display (plugin))
442     return FALSE;
443
444   if (plugin->sinkpad_buffer_pool) {
445     config = gst_buffer_pool_get_config (plugin->sinkpad_buffer_pool);
446     gst_buffer_pool_config_get_params (config, &pool_caps, NULL, NULL, NULL);
447     need_pool = !gst_caps_is_equal (caps, pool_caps);
448     gst_structure_free (config);
449     if (!need_pool)
450       return TRUE;
451     g_clear_object (&plugin->sinkpad_buffer_pool);
452     plugin->sinkpad_buffer_size = 0;
453   }
454
455   pool = gst_vaapi_video_buffer_pool_new (plugin->display);
456   if (!pool)
457     goto error_create_pool;
458
459   gst_video_info_init (&vi);
460   gst_video_info_from_caps (&vi, caps);
461   if (GST_VIDEO_INFO_FORMAT (&vi) == GST_VIDEO_FORMAT_ENCODED) {
462     GST_DEBUG ("assume video buffer pool format is NV12");
463     gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_NV12,
464         GST_VIDEO_INFO_WIDTH (&vi), GST_VIDEO_INFO_HEIGHT (&vi));
465   }
466   plugin->sinkpad_buffer_size = vi.size;
467
468   config = gst_buffer_pool_get_config (pool);
469   gst_buffer_pool_config_set_params (config, caps,
470       plugin->sinkpad_buffer_size, 0, 0);
471   gst_buffer_pool_config_add_option (config,
472       GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
473   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
474   if (!gst_buffer_pool_set_config (pool, config))
475     goto error_pool_config;
476   plugin->sinkpad_buffer_pool = pool;
477   return TRUE;
478
479   /* ERRORS */
480 error_create_pool:
481   {
482     GST_ERROR ("failed to create buffer pool");
483     return FALSE;
484   }
485 error_pool_config:
486   {
487     GST_ERROR ("failed to reset buffer pool config");
488     gst_object_unref (pool);
489     return FALSE;
490   }
491 }
492
493 /**
494  * gst_vaapi_plugin_base_set_caps:
495  * @plugin: a #GstVaapiPluginBase
496  * @incaps: the sink pad (input) caps
497  * @outcaps: the src pad (output) caps
498  *
499  * Notifies the base plugin object of the new input and output caps,
500  * obtained from the subclass.
501  *
502  * Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
503  */
504 gboolean
505 gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
506     GstCaps * outcaps)
507 {
508   if (incaps && incaps != plugin->sinkpad_caps) {
509     gst_caps_replace (&plugin->sinkpad_caps, incaps);
510     if (!gst_video_info_from_caps (&plugin->sinkpad_info, incaps))
511       return FALSE;
512     plugin->sinkpad_caps_changed = TRUE;
513     plugin->sinkpad_caps_is_raw = !gst_caps_has_vaapi_surface (incaps);
514   }
515
516   if (outcaps && outcaps != plugin->srcpad_caps) {
517     gst_caps_replace (&plugin->srcpad_caps, outcaps);
518     if (!gst_video_info_from_caps (&plugin->srcpad_info, outcaps))
519       return FALSE;
520     plugin->srcpad_caps_changed = TRUE;
521   }
522
523   if (plugin->uploader && plugin->sinkpad_caps_is_raw) {
524     if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
525       return FALSE;
526     if (!gst_vaapi_uploader_ensure_caps (plugin->uploader,
527             plugin->sinkpad_caps, plugin->srcpad_caps))
528       return FALSE;
529   }
530
531   if (!ensure_sinkpad_buffer_pool (plugin, plugin->sinkpad_caps))
532     return FALSE;
533   return TRUE;
534 }
535
536 /**
537  * gst_vaapi_plugin_base_propose_allocation:
538  * @plugin: a #GstVaapiPluginBase
539  * @query: the allocation query to configure
540  *
541  * Proposes allocation parameters to the upstream elements.
542  *
543  * Returns: %TRUE if successful, %FALSE otherwise.
544  */
545 gboolean
546 gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
547     GstQuery * query)
548 {
549   GstCaps *caps = NULL;
550   gboolean need_pool;
551
552   gst_query_parse_allocation (query, &caps, &need_pool);
553
554   if (need_pool) {
555     if (!caps)
556       goto error_no_caps;
557     if (!ensure_sinkpad_buffer_pool (plugin, caps))
558       return FALSE;
559     gst_query_add_allocation_pool (query, plugin->sinkpad_buffer_pool,
560         plugin->sinkpad_buffer_size, 0, 0);
561
562     if (has_dmabuf_capable_peer (plugin, plugin->sinkpad)) {
563       GstStructure *const config =
564           gst_buffer_pool_get_config (plugin->sinkpad_buffer_pool);
565
566       gst_buffer_pool_config_add_option (config,
567           GST_BUFFER_POOL_OPTION_DMABUF_MEMORY);
568       if (!gst_buffer_pool_set_config (plugin->sinkpad_buffer_pool, config))
569         goto error_pool_config;
570     }
571   }
572
573   gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL);
574   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
575   return TRUE;
576
577   /* ERRORS */
578 error_no_caps:
579   {
580     GST_ERROR ("no caps specified");
581     return FALSE;
582   }
583 error_pool_config:
584   {
585     GST_ERROR ("failed to reset buffer pool config");
586     return FALSE;
587   }
588 }
589
590 /**
591  * gst_vaapi_plugin_base_decide_allocation:
592  * @plugin: a #GstVaapiPluginBase
593  * @query: the allocation query to parse
594  * @feature: the desired #GstVaapiCapsFeature, or zero to find the
595  *   preferred one
596  *
597  * Decides allocation parameters for the downstream elements.
598  *
599  * Returns: %TRUE if successful, %FALSE otherwise.
600  */
601 gboolean
602 gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
603     GstQuery * query, guint feature)
604 {
605   GstCaps *caps = NULL;
606   GstBufferPool *pool;
607   GstStructure *config;
608   GstVideoInfo vi;
609   guint size, min, max;
610   gboolean need_pool, update_pool;
611   gboolean has_video_meta = FALSE;
612   gboolean has_video_alignment = FALSE;
613 #if (USE_GLX || USE_EGL)
614   gboolean has_texture_upload_meta = FALSE;
615   guint idx;
616 #endif
617
618   g_return_val_if_fail (plugin->display != NULL, FALSE);
619
620   gst_query_parse_allocation (query, &caps, &need_pool);
621
622   /* We don't need any GL context beyond this point if not requested
623      so explicitly through GstVideoGLTextureUploadMeta */
624   gst_object_replace (&plugin->gl_context, NULL);
625
626   if (!caps)
627     goto error_no_caps;
628
629   if (!feature)
630     feature =
631         gst_vaapi_find_preferred_caps_feature (plugin->srcpad,
632         GST_VIDEO_FORMAT_ENCODED, NULL);
633
634   has_video_meta = gst_query_find_allocation_meta (query,
635       GST_VIDEO_META_API_TYPE, NULL);
636
637 #if (USE_GLX || USE_EGL)
638   has_texture_upload_meta = gst_query_find_allocation_meta (query,
639       GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) &&
640       (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META);
641
642 #if USE_GST_GL_HELPERS
643   if (has_texture_upload_meta) {
644     const GstStructure *params;
645     GstObject *gl_context;
646
647     gst_query_parse_nth_allocation_meta (query, idx, &params);
648     if (params) {
649       if (gst_structure_get (params, "gst.gl.GstGLContext", GST_GL_TYPE_CONTEXT,
650               &gl_context, NULL) && gl_context) {
651         gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
652         gst_object_unref (gl_context);
653       }
654     }
655   }
656 #endif
657 #endif
658
659   /* Make sure the display we pass down to the buffer pool is actually
660      the expected one, especially when the downstream element requires
661      a GLX or EGL display */
662   if (!gst_vaapi_plugin_base_ensure_display (plugin))
663     goto error_ensure_display;
664
665   gst_video_info_init (&vi);
666   gst_video_info_from_caps (&vi, caps);
667   if (GST_VIDEO_INFO_FORMAT (&vi) == GST_VIDEO_FORMAT_ENCODED)
668     gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_I420,
669         GST_VIDEO_INFO_WIDTH (&vi), GST_VIDEO_INFO_HEIGHT (&vi));
670
671   if (gst_query_get_n_allocation_pools (query) > 0) {
672     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
673     if (pool) {
674       size = MAX (size, vi.size);
675       update_pool = TRUE;
676
677       /* Check whether downstream element proposed a bufferpool but did
678          not provide a correct propose_allocation() implementation */
679       has_video_alignment = gst_buffer_pool_has_option (pool,
680           GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
681     }
682   } else {
683     pool = NULL;
684     size = vi.size;
685     min = max = 0;
686     update_pool = FALSE;
687   }
688
689   /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
690   if (!pool || !gst_buffer_pool_has_option (pool,
691           GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
692     GST_INFO_OBJECT (plugin, "no pool or doesn't support GstVaapiVideoMeta, "
693         "making new pool");
694     if (pool)
695       gst_object_unref (pool);
696     pool = gst_vaapi_video_buffer_pool_new (plugin->display);
697     if (!pool)
698       goto error_create_pool;
699
700     config = gst_buffer_pool_get_config (pool);
701     gst_buffer_pool_config_set_params (config, caps, size, min, max);
702     gst_buffer_pool_config_add_option (config,
703         GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
704     gst_buffer_pool_set_config (pool, config);
705   }
706
707   /* Check whether GstVideoMeta, or GstVideoAlignment, is needed (raw video) */
708   if (has_video_meta) {
709     config = gst_buffer_pool_get_config (pool);
710     gst_buffer_pool_config_add_option (config,
711         GST_BUFFER_POOL_OPTION_VIDEO_META);
712     gst_buffer_pool_set_config (pool, config);
713   } else if (has_video_alignment) {
714     config = gst_buffer_pool_get_config (pool);
715     gst_buffer_pool_config_add_option (config,
716         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
717     gst_buffer_pool_set_config (pool, config);
718   }
719
720   /* GstVideoGLTextureUploadMeta (OpenGL) */
721 #if (USE_GLX || USE_EGL)
722   if (has_texture_upload_meta) {
723     config = gst_buffer_pool_get_config (pool);
724     gst_buffer_pool_config_add_option (config,
725         GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
726     gst_buffer_pool_set_config (pool, config);
727   }
728 #endif
729
730   if (update_pool)
731     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
732   else
733     gst_query_add_allocation_pool (query, pool, size, min, max);
734
735   g_clear_object (&plugin->srcpad_buffer_pool);
736   plugin->srcpad_buffer_pool = pool;
737   return TRUE;
738
739   /* ERRORS */
740 error_no_caps:
741   {
742     GST_ERROR_OBJECT (plugin, "no caps specified");
743     return FALSE;
744   }
745 error_ensure_display:
746   {
747     GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d",
748         plugin->display_type_req);
749     return FALSE;
750   }
751 error_create_pool:
752   {
753     GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
754     return FALSE;
755   }
756 }
757
758 /**
759  * gst_vaapi_plugin_base_allocate_input_buffer:
760  * @plugin: a #GstVaapiPluginBase
761  * @caps: the buffer caps constraints to honour
762  * @outbuf_ptr: the pointer location to the newly allocated buffer
763  *
764  * Creates a buffer that holds a VA surface memory for the sink pad to
765  * use it as the result for buffer_alloc() impementations.
766  *
767  * Return: #GST_FLOW_OK if the buffer could be created.
768  */
769 GstFlowReturn
770 gst_vaapi_plugin_base_allocate_input_buffer (GstVaapiPluginBase * plugin,
771     GstCaps * caps, GstBuffer ** outbuf_ptr)
772 {
773   GstBuffer *outbuf;
774
775   *outbuf_ptr = NULL;
776
777   if (!plugin->sinkpad_caps_changed) {
778     if (!gst_video_info_from_caps (&plugin->sinkpad_info, caps))
779       return GST_FLOW_NOT_SUPPORTED;
780     plugin->sinkpad_caps_changed = TRUE;
781   }
782
783   if (!plugin->sinkpad_caps_is_raw)
784     return GST_FLOW_OK;
785
786   if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
787     return GST_FLOW_NOT_SUPPORTED;
788   if (!gst_vaapi_uploader_ensure_caps (plugin->uploader, caps, NULL))
789     return GST_FLOW_NOT_SUPPORTED;
790
791   outbuf = gst_vaapi_uploader_get_buffer (plugin->uploader);
792   if (!outbuf) {
793     GST_WARNING ("failed to allocate resources for raw YUV buffer");
794     return GST_FLOW_NOT_SUPPORTED;
795   }
796
797   *outbuf_ptr = outbuf;
798   return GST_FLOW_OK;
799 }
800
801 /**
802  * gst_vaapi_plugin_base_get_input_buffer:
803  * @plugin: a #GstVaapiPluginBase
804  * @incaps: the sink pad (input) buffer
805  * @outbuf_ptr: the pointer to location to the VA surface backed buffer
806  *
807  * Acquires the sink pad (input) buffer as a VA surface backed
808  * buffer. This is mostly useful for raw YUV buffers, as source
809  * buffers that are already backed as a VA surface are passed
810  * verbatim.
811  *
812  * Returns: #GST_FLOW_OK if the buffer could be acquired
813  */
814 GstFlowReturn
815 gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
816     GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
817 {
818   GstVaapiVideoMeta *meta;
819   GstBuffer *outbuf;
820   GstVideoFrame src_frame, out_frame;
821   gboolean success;
822
823   g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
824   g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
825
826   meta = gst_buffer_get_vaapi_video_meta (inbuf);
827   if (meta) {
828     *outbuf_ptr = gst_buffer_ref (inbuf);
829     return GST_FLOW_OK;
830   }
831
832   if (!plugin->sinkpad_caps_is_raw)
833     goto error_invalid_buffer;
834
835   if (!plugin->sinkpad_buffer_pool)
836     goto error_no_pool;
837
838   if (!gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, TRUE))
839     goto error_active_pool;
840
841   outbuf = NULL;
842   if (gst_buffer_pool_acquire_buffer (plugin->sinkpad_buffer_pool,
843           &outbuf, NULL) != GST_FLOW_OK)
844     goto error_create_buffer;
845
846   if (is_dma_buffer (inbuf)) {
847     if (!plugin_bind_dma_to_vaapi_buffer (plugin, inbuf, outbuf))
848       goto error_bind_dma_buffer;
849     goto done;
850   }
851
852   if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf,
853           GST_MAP_READ))
854     goto error_map_src_buffer;
855
856   if (!gst_video_frame_map (&out_frame, &plugin->sinkpad_info, outbuf,
857           GST_MAP_WRITE))
858     goto error_map_dst_buffer;
859
860   success = gst_video_frame_copy (&out_frame, &src_frame);
861   gst_video_frame_unmap (&out_frame);
862   gst_video_frame_unmap (&src_frame);
863   if (!success)
864     goto error_copy_buffer;
865
866 done:
867   gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS |
868       GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
869   *outbuf_ptr = outbuf;
870   return GST_FLOW_OK;
871
872   /* ERRORS */
873 error_no_pool:
874   {
875     GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
876         ("no buffer pool was negotiated"),
877         ("no buffer pool was negotiated"));
878     return GST_FLOW_ERROR;
879   }
880 error_active_pool:
881   {
882     GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
883         ("failed to activate buffer pool"),
884         ("failed to activate buffer pool"));
885     return GST_FLOW_ERROR;
886   }
887 error_map_dst_buffer:
888   {
889     gst_video_frame_unmap (&src_frame);
890     // fall-through
891   }
892 error_map_src_buffer:
893   {
894     GST_WARNING ("failed to map buffer");
895     gst_buffer_unref (outbuf);
896     return GST_FLOW_NOT_SUPPORTED;
897   }
898
899   /* ERRORS */
900 error_invalid_buffer:
901   {
902     GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
903         ("failed to validate source buffer"),
904         ("failed to validate source buffer"));
905     return GST_FLOW_ERROR;
906   }
907 error_create_buffer:
908   {
909     GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
910         ("failed to create buffer"));
911     return GST_FLOW_ERROR;
912   }
913 error_bind_dma_buffer:
914   {
915     GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
916         ("failed to bind dma_buf to VA surface buffer"));
917     gst_buffer_unref (outbuf);
918     return GST_FLOW_ERROR;
919   }
920 error_copy_buffer:
921   {
922     GST_WARNING ("failed to upload buffer to VA surface");
923     gst_buffer_unref (outbuf);
924     return GST_FLOW_NOT_SUPPORTED;
925   }
926 }
927
928 /**
929  * gst_vaapi_plugin_base_set_gl_context:
930  * @plugin: a #GstVaapiPluginBase
931  * @object: the new GL context from downstream
932  *
933  * Registers the new GL context. The change is effective at the next
934  * call to gst_vaapi_plugin_base_ensure_display(), where the
935  * underlying display object could be re-allocated to fit the GL
936  * context needs
937  */
938 void
939 gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin,
940     GstObject * object)
941 {
942 #if USE_GST_GL_HELPERS
943   GstGLContext *const gl_context = GST_GL_CONTEXT (object);
944   GstVaapiDisplayType display_type;
945
946   gst_object_replace (&plugin->gl_context, object);
947
948   switch (gst_gl_context_get_gl_platform (gl_context)) {
949 #if USE_GLX
950     case GST_GL_PLATFORM_GLX:
951       display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
952       break;
953 #endif
954 #if USE_EGL
955     case GST_GL_PLATFORM_EGL:
956       display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
957       break;
958 #endif
959     default:
960       display_type = plugin->display_type;
961       break;
962   }
963   gst_vaapi_plugin_base_set_display_type (plugin, display_type);
964 #endif
965 }