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
plugin_set_display(GstVaapiPluginBase * plugin,GstVaapiDisplay * display)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
gst_vaapi_plugin_base_set_context(GstVaapiPluginBase * plugin,GstContext * context)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
gst_vaapi_plugin_base_init_interfaces(GType g_define_type_id)94 gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
95 {
96 }
97
98 static gboolean
default_has_interface(GstVaapiPluginBase * plugin,GType type)99 default_has_interface (GstVaapiPluginBase * plugin, GType type)
100 {
101 return FALSE;
102 }
103
104 static void
default_display_changed(GstVaapiPluginBase * plugin)105 default_display_changed (GstVaapiPluginBase * plugin)
106 {
107 }
108
109 static GstVaapiSurface *
_get_cached_surface(GstBuffer * buf)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
_set_cached_surface(GstBuffer * buf,GstVaapiSurface * surface)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
plugin_update_sinkpad_info_from_buffer(GstVaapiPluginBase * plugin,GstBuffer * buf)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
is_dma_buffer(GstBuffer * buf)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
plugin_bind_dma_to_vaapi_buffer(GstVaapiPluginBase * plugin,GstBuffer * inbuf,GstBuffer * outbuf)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
plugin_reset_texture_map(GstVaapiPluginBase * plugin)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
gst_vaapi_plugin_base_class_init(GstVaapiPluginBaseClass * klass)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
gst_vaapi_plugin_base_init(GstVaapiPluginBase * plugin,GstDebugCategory * debug_category)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
gst_vaapi_plugin_base_finalize(GstVaapiPluginBase * plugin)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
gst_vaapi_plugin_base_open(GstVaapiPluginBase * plugin)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
gst_vaapi_plugin_base_close(GstVaapiPluginBase * plugin)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
gst_vaapi_plugin_base_has_display_type(GstVaapiPluginBase * plugin,GstVaapiDisplayType display_type_req)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
gst_vaapi_plugin_base_set_display_type(GstVaapiPluginBase * plugin,GstVaapiDisplayType display_type)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
gst_vaapi_plugin_base_set_display_name(GstVaapiPluginBase * plugin,const gchar * display_name)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
gst_vaapi_plugin_base_ensure_display(GstVaapiPluginBase * plugin)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
gst_vaapi_buffer_pool_caps_is_equal(GstBufferPool * pool,GstCaps * newcaps)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
reset_allocator(GstAllocator * allocator,GstVideoInfo * vinfo)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
ensure_sinkpad_allocator(GstVaapiPluginBase * plugin,GstCaps * caps,guint * size)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
get_dmabuf_surface_allocation_flags(void)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 *
create_dmabuf_srcpad_allocator(GstVaapiPluginBase * plugin,GstVideoInfo * vinfo,gboolean check_for_map)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
ensure_srcpad_allocator(GstVaapiPluginBase * plugin,GstVideoInfo * vinfo,GstCaps * caps)532 ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstVideoInfo * vinfo,
533 GstCaps * caps)
534 {
535 gboolean different_caps;
536 const GstVideoInfo *image_info;
537
538 if (!reset_allocator (plugin->srcpad_allocator, vinfo))
539 goto valid_allocator;
540
541 plugin->srcpad_allocator = NULL;
542 if (caps && gst_caps_is_video_raw (caps)) {
543 GstAllocator *allocator = create_dmabuf_srcpad_allocator (plugin, vinfo,
544 !plugin->srcpad_can_dmabuf);
545 plugin->srcpad_allocator = allocator;
546 } else if (caps && gst_vaapi_caps_feature_contains (caps,
547 GST_VAAPI_CAPS_FEATURE_DMABUF)) {
548 plugin->srcpad_allocator =
549 create_dmabuf_srcpad_allocator (plugin, vinfo, FALSE);
550 if (!plugin->srcpad_allocator)
551 goto error_create_allocator;
552 }
553
554 if (!plugin->srcpad_allocator) {
555 GstVaapiImageUsageFlags usage_flag =
556 GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
557
558 if (plugin->enable_direct_rendering) {
559 usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
560 GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator");
561 }
562
563 plugin->srcpad_allocator =
564 gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag);
565 }
566
567 if (!plugin->srcpad_allocator)
568 goto error_create_allocator;
569
570 valid_allocator:
571 image_info =
572 gst_allocator_get_vaapi_video_info (plugin->srcpad_allocator, NULL);
573 g_assert (image_info); /* both allocators ought set its image
574 * info */
575
576 /* update the size with the one generated by the allocator */
577 GST_VIDEO_INFO_SIZE (vinfo) = GST_VIDEO_INFO_SIZE (image_info);
578
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 different_caps = GST_IS_VIDEO_DECODER (plugin) && plugin->srcpad_caps &&
584 !gst_caps_is_strictly_equal (plugin->srcpad_caps, caps);
585
586 if (different_caps) {
587 guint i;
588 GstVideoInfo vi = plugin->srcpad_info;
589
590 /* update the planes and the size with the allocator image/surface
591 * info, but not the resolution */
592 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (image_info); i++) {
593 GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) =
594 GST_VIDEO_INFO_PLANE_OFFSET (image_info, i);
595 GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) =
596 GST_VIDEO_INFO_PLANE_STRIDE (image_info, i);
597 }
598 GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (image_info);
599 gst_allocator_set_vaapi_negotiated_video_info (plugin->srcpad_allocator,
600 &vi);
601 }
602
603 return TRUE;
604
605 /* ERRORS */
606 error_create_allocator:
607 {
608 GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator");
609 return FALSE;
610 }
611 }
612
613 /**
614 * gst_vaapi_plugin_base_create_pool:
615 * @plugin: a #GstVaapiPluginBase
616 * @caps: the initial #GstCaps for the resulting buffer pool
617 * @size: the size of each buffer, not including prefix and padding
618 * @options: a set of #GstVaapiVideoBufferPoolOption encoded as bit-wise
619 * @allocator: (allow-none): the #GstAllocator to use or %NULL
620 *
621 * Create an instance of #GstVaapiVideoBufferPool
622 *
623 * Returns: (transfer full): a new allocated #GstBufferPool
624 **/
625 static GstBufferPool *
gst_vaapi_plugin_base_create_pool(GstVaapiPluginBase * plugin,GstCaps * caps,gsize size,guint min_buffers,guint max_buffers,guint options,GstAllocator * allocator)626 gst_vaapi_plugin_base_create_pool (GstVaapiPluginBase * plugin, GstCaps * caps,
627 gsize size, guint min_buffers, guint max_buffers, guint options,
628 GstAllocator * allocator)
629 {
630 GstBufferPool *pool;
631 GstStructure *config;
632
633 if (!(pool = gst_vaapi_video_buffer_pool_new (plugin->display)))
634 goto error_create_pool;
635
636 config = gst_buffer_pool_get_config (pool);
637 gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
638 max_buffers);
639 gst_buffer_pool_config_add_option (config,
640 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
641 if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) {
642 gst_buffer_pool_config_add_option (config,
643 GST_BUFFER_POOL_OPTION_VIDEO_META);
644 }
645 if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT) {
646 gst_buffer_pool_config_add_option (config,
647 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
648 }
649 #if (USE_GLX || USE_EGL)
650 if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) {
651 gst_buffer_pool_config_add_option (config,
652 GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
653 }
654 #endif
655 if (allocator)
656 gst_buffer_pool_config_set_allocator (config, allocator, NULL);
657 if (!gst_buffer_pool_set_config (pool, config)) {
658 config = gst_buffer_pool_get_config (pool);
659
660 if (!gst_buffer_pool_config_validate_params (config, caps, size,
661 min_buffers, max_buffers)) {
662 gst_structure_free (config);
663 goto error_pool_config;
664 }
665
666 if (!gst_buffer_pool_set_config (pool, config))
667 goto error_pool_config;
668 }
669 return pool;
670
671 /* ERRORS */
672 error_create_pool:
673 {
674 GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
675 return NULL;
676 }
677 error_pool_config:
678 {
679 gst_object_unref (pool);
680 GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS,
681 ("Failed to configure the buffer pool"),
682 ("Configuration is most likely invalid, please report this issue."));
683 return NULL;
684 }
685 }
686
687 /**
688 * ensure_sinkpad_buffer_pool:
689 * @plugin: a #GstVaapiPluginBase
690 * @caps: the initial #GstCaps for the resulting buffer pool
691 *
692 * Makes sure the sink pad video buffer pool is created with the
693 * appropriate @caps.
694 *
695 * Returns: %TRUE if successful, %FALSE otherwise.
696 */
697 static gboolean
ensure_sinkpad_buffer_pool(GstVaapiPluginBase * plugin,GstCaps * caps)698 ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstCaps * caps)
699 {
700 GstBufferPool *pool;
701 guint size;
702
703 /* video decoders don't use a buffer pool in the sink pad */
704 if (GST_IS_VIDEO_DECODER (plugin))
705 return TRUE;
706
707 if (!gst_vaapi_plugin_base_ensure_display (plugin))
708 return FALSE;
709
710 if (plugin->sinkpad_buffer_pool) {
711 if (gst_vaapi_buffer_pool_caps_is_equal (plugin->sinkpad_buffer_pool, caps))
712 return TRUE;
713 gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, FALSE);
714 g_clear_object (&plugin->sinkpad_buffer_pool);
715 g_clear_object (&plugin->sinkpad_allocator);
716 plugin->sinkpad_buffer_size = 0;
717 }
718
719 if (!ensure_sinkpad_allocator (plugin, caps, &size))
720 return FALSE;
721
722 pool =
723 gst_vaapi_plugin_base_create_pool (plugin, caps, size,
724 BUFFER_POOL_SINK_MIN_BUFFERS, 0,
725 GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META, plugin->sinkpad_allocator);
726 if (!pool)
727 return FALSE;
728
729 plugin->sinkpad_buffer_pool = pool;
730 plugin->sinkpad_buffer_size = size;
731 return TRUE;
732 }
733
734 /**
735 * gst_vaapi_plugin_base_set_caps:
736 * @plugin: a #GstVaapiPluginBase
737 * @incaps: the sink pad (input) caps
738 * @outcaps: the src pad (output) caps
739 *
740 * Notifies the base plugin object of the new input and output caps,
741 * obtained from the subclass.
742 *
743 * Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
744 */
745 gboolean
gst_vaapi_plugin_base_set_caps(GstVaapiPluginBase * plugin,GstCaps * incaps,GstCaps * outcaps)746 gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
747 GstCaps * outcaps)
748 {
749 if (incaps && incaps != plugin->sinkpad_caps) {
750 if (!gst_video_info_from_caps (&plugin->sinkpad_info, incaps))
751 return FALSE;
752 gst_caps_replace (&plugin->sinkpad_caps, incaps);
753 plugin->sinkpad_caps_is_raw = !gst_caps_has_vaapi_surface (incaps);
754 }
755
756 if (outcaps && outcaps != plugin->srcpad_caps) {
757 if (!gst_video_info_from_caps (&plugin->srcpad_info, outcaps))
758 return FALSE;
759 if (plugin->srcpad_buffer_pool
760 && !gst_vaapi_buffer_pool_caps_is_equal (plugin->srcpad_buffer_pool,
761 outcaps)) {
762 gst_buffer_pool_set_active (plugin->srcpad_buffer_pool, FALSE);
763 g_clear_object (&plugin->srcpad_buffer_pool);
764 g_clear_object (&plugin->srcpad_allocator);
765 plugin_reset_texture_map (plugin);
766 }
767 gst_caps_replace (&plugin->srcpad_caps, outcaps);
768 }
769
770 if (!ensure_sinkpad_buffer_pool (plugin, plugin->sinkpad_caps))
771 return FALSE;
772 return TRUE;
773 }
774
775 /**
776 * gst_vaapi_plugin_base_propose_allocation:
777 * @plugin: a #GstVaapiPluginBase
778 * @query: the allocation query to configure
779 *
780 * Proposes allocation parameters to the upstream elements.
781 *
782 * Returns: %TRUE if successful, %FALSE otherwise.
783 */
784 gboolean
gst_vaapi_plugin_base_propose_allocation(GstVaapiPluginBase * plugin,GstQuery * query)785 gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
786 GstQuery * query)
787 {
788 GstCaps *caps = NULL;
789 GstBufferPool *pool = NULL;
790 gboolean need_pool;
791 guint size = 0, n_allocators;
792
793 gst_query_parse_allocation (query, &caps, &need_pool);
794 if (!caps)
795 goto error_no_caps;
796
797 if (!ensure_sinkpad_allocator (plugin, caps, &size))
798 return FALSE;
799
800 if (need_pool) {
801 pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size,
802 BUFFER_POOL_SINK_MIN_BUFFERS, 0,
803 GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META,
804 plugin->sinkpad_allocator);
805 if (!pool)
806 return FALSE;
807 }
808
809 /* Set sinkpad allocator as the last allocation param.
810 *
811 * If there's none, set system's allocator first and VAAPI allocator
812 * second
813 */
814 n_allocators = gst_query_get_n_allocation_params (query);
815 if (n_allocators == 0) {
816 GstAllocator *allocator;
817
818 allocator = gst_allocator_find (GST_ALLOCATOR_SYSMEM);
819 gst_query_add_allocation_param (query, allocator, NULL);
820 gst_object_unref (allocator);
821 }
822 gst_query_add_allocation_param (query, plugin->sinkpad_allocator, NULL);
823
824 gst_query_add_allocation_pool (query, pool, size,
825 BUFFER_POOL_SINK_MIN_BUFFERS, 0);
826 if (pool)
827 gst_object_unref (pool);
828
829 gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL);
830 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
831 return TRUE;
832
833 /* ERRORS */
834 error_no_caps:
835 {
836 GST_INFO_OBJECT (plugin, "no caps specified");
837 return FALSE;
838 }
839 }
840
841 /**
842 * gst_vaapi_plugin_base_decide_allocation:
843 * @plugin: a #GstVaapiPluginBase
844 * @query: the allocation query to parse
845 * @feature: the desired #GstVaapiCapsFeature, or zero to find the
846 * preferred one
847 *
848 * Decides allocation parameters for the downstream elements.
849 *
850 * Returns: %TRUE if successful, %FALSE otherwise.
851 */
852 gboolean
gst_vaapi_plugin_base_decide_allocation(GstVaapiPluginBase * plugin,GstQuery * query)853 gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
854 GstQuery * query)
855 {
856 GstCaps *caps = NULL;
857 GstBufferPool *pool;
858 GstVideoInfo vi;
859 guint i, size, min, max, pool_options, num_allocators;
860 gint index_allocator;
861 gboolean update_pool = FALSE;
862 #if (USE_GLX || USE_EGL)
863 guint idx;
864 #endif
865
866 gst_query_parse_allocation (query, &caps, NULL);
867 if (!caps)
868 goto error_no_caps;
869
870 pool_options = 0;
871 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
872 pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
873
874 #if (USE_GLX || USE_EGL)
875 if (gst_query_find_allocation_meta (query,
876 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) &&
877 gst_vaapi_caps_feature_contains (caps,
878 GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META))
879 pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD;
880
881 #if USE_GST_GL_HELPERS
882 if (!plugin->gl_context &&
883 (pool_options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD)) {
884 const GstStructure *params;
885 GstObject *gl_context;
886
887 gst_query_parse_nth_allocation_meta (query, idx, ¶ms);
888 if (params) {
889 if (gst_structure_get (params, "gst.gl.GstGLContext", GST_TYPE_GL_CONTEXT,
890 &gl_context, NULL) && gl_context) {
891 gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
892 gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, gl_context);
893 gst_object_unref (gl_context);
894 }
895 }
896 }
897 #endif
898 #endif
899
900 /* Make sure the display we pass down to the buffer pool is actually
901 the expected one, especially when the downstream element requires
902 a GLX or EGL display */
903 if (!gst_vaapi_plugin_base_ensure_display (plugin))
904 goto error_ensure_display;
905
906 if (!gst_video_info_from_caps (&vi, caps))
907 goto error_invalid_caps;
908 gst_video_info_force_nv12_if_encoded (&vi);
909
910 index_allocator = -1;
911 num_allocators = gst_query_get_n_allocation_params (query);
912 for (i = 0; i < num_allocators; i++) {
913 GstAllocator *allocator = NULL;
914 GstAllocationParams params;
915
916 gst_query_parse_nth_allocation_param (query, i, &allocator, ¶ms);
917 if (!allocator)
918 continue;
919
920 /* Let's keep the the first allocator if it is not VA-API. It
921 * might be used if it is required to copy the output frame to a
922 * new buffer */
923 if (i == 0
924 && g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0) {
925 if (plugin->other_srcpad_allocator)
926 gst_object_unref (plugin->other_srcpad_allocator);
927 plugin->other_srcpad_allocator = allocator;
928 plugin->other_allocator_params = params;
929 continue;
930 }
931
932 if (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) == 0) {
933 GST_DEBUG_OBJECT (plugin, "found vaapi allocator in query %"
934 GST_PTR_FORMAT, allocator);
935 index_allocator = i;
936 if (plugin->srcpad_allocator)
937 gst_object_unref (plugin->srcpad_allocator);
938 plugin->srcpad_allocator = allocator;
939 break;
940 }
941 gst_object_unref (allocator);
942 }
943
944 if (gst_query_get_n_allocation_pools (query) > 0) {
945 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
946 update_pool = TRUE;
947 size = MAX (size, GST_VIDEO_INFO_SIZE (&vi));
948 if (pool) {
949 /* Check whether downstream element proposed a bufferpool but did
950 not provide a correct propose_allocation() implementation */
951 if (gst_buffer_pool_has_option (pool,
952 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT))
953 pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT;
954
955 /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
956 if (!gst_buffer_pool_has_option (pool,
957 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
958 GST_INFO_OBJECT (plugin, "ignoring non-VAAPI pool: %" GST_PTR_FORMAT,
959 pool);
960 g_clear_object (&pool);
961 }
962 }
963 } else {
964 pool = NULL;
965 size = GST_VIDEO_INFO_SIZE (&vi);
966 min = max = 0;
967 }
968
969 if (!pool) {
970 if (!ensure_srcpad_allocator (plugin, &vi, caps))
971 goto error;
972 size = GST_VIDEO_INFO_SIZE (&vi); /* size might be updated by
973 * allocator */
974 pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size, min, max,
975 pool_options, plugin->srcpad_allocator);
976 if (!pool)
977 goto error;
978 }
979
980 if (update_pool)
981 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
982 else
983 gst_query_add_allocation_pool (query, pool, size, min, max);
984
985 /* allocator might be updated by ensure_srcpad_allocator() */
986 if (plugin->srcpad_allocator) {
987 if (index_allocator > 0) {
988 gst_query_set_nth_allocation_param (query, index_allocator,
989 plugin->srcpad_allocator, NULL);
990 } else {
991 GST_DEBUG_OBJECT (plugin, "adding allocator in query %" GST_PTR_FORMAT,
992 plugin->srcpad_allocator);
993 gst_query_add_allocation_param (query, plugin->srcpad_allocator, NULL);
994 }
995 }
996
997 g_clear_object (&plugin->srcpad_buffer_pool);
998 plugin->srcpad_buffer_pool = pool;
999
1000 /* if downstream doesn't support GstVideoMeta, and the negotiated
1001 * caps are raw video, and the used allocator is the VA-API one, we
1002 * should copy the VA-API frame into a dumb buffer */
1003 plugin->copy_output_frame = gst_vaapi_video_buffer_pool_copy_buffer (pool);
1004
1005 return TRUE;
1006
1007 /* ERRORS */
1008 error_no_caps:
1009 {
1010 GST_ERROR_OBJECT (plugin, "no caps specified");
1011 return FALSE;
1012 }
1013 error_invalid_caps:
1014 {
1015 GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
1016 return FALSE;
1017 }
1018 error_ensure_display:
1019 {
1020 GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d",
1021 plugin->display_type_req);
1022 return FALSE;
1023 }
1024 error:
1025 {
1026 /* error message already sent */
1027 return FALSE;
1028 }
1029 }
1030
1031 /**
1032 * gst_vaapi_plugin_base_get_input_buffer:
1033 * @plugin: a #GstVaapiPluginBase
1034 * @inbuf: the sink pad (input) buffer
1035 * @outbuf_ptr: the pointer to location to the VA surface backed buffer
1036 *
1037 * Acquires the sink pad (input) buffer as a VA surface backed
1038 * buffer. This is mostly useful for raw YUV buffers, as source
1039 * buffers that are already backed as a VA surface are passed
1040 * verbatim.
1041 *
1042 * Returns: #GST_FLOW_OK if the buffer could be acquired
1043 */
1044 GstFlowReturn
gst_vaapi_plugin_base_get_input_buffer(GstVaapiPluginBase * plugin,GstBuffer * inbuf,GstBuffer ** outbuf_ptr)1045 gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
1046 GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
1047 {
1048 GstVaapiVideoMeta *meta;
1049 GstBuffer *outbuf;
1050 GstVideoFrame src_frame, out_frame;
1051 gboolean success;
1052
1053 g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
1054 g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
1055
1056 meta = gst_buffer_get_vaapi_video_meta (inbuf);
1057 if (meta) {
1058 *outbuf_ptr = gst_buffer_ref (inbuf);
1059 return GST_FLOW_OK;
1060 }
1061
1062 if (!plugin->sinkpad_caps_is_raw)
1063 goto error_invalid_buffer;
1064
1065 if (!plugin->sinkpad_buffer_pool)
1066 goto error_no_pool;
1067
1068 if (!gst_buffer_pool_is_active (plugin->sinkpad_buffer_pool) &&
1069 !gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, TRUE))
1070 goto error_active_pool;
1071
1072 outbuf = NULL;
1073 if (gst_buffer_pool_acquire_buffer (plugin->sinkpad_buffer_pool,
1074 &outbuf, NULL) != GST_FLOW_OK)
1075 goto error_create_buffer;
1076
1077 if (is_dma_buffer (inbuf)) {
1078 if (!plugin_bind_dma_to_vaapi_buffer (plugin, inbuf, outbuf))
1079 goto error_bind_dma_buffer;
1080 goto done;
1081 }
1082
1083 if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf,
1084 GST_MAP_READ))
1085 goto error_map_src_buffer;
1086
1087 if (!gst_video_frame_map (&out_frame, &plugin->sinkpad_info, outbuf,
1088 GST_MAP_WRITE))
1089 goto error_map_dst_buffer;
1090
1091 success = gst_video_frame_copy (&out_frame, &src_frame);
1092 gst_video_frame_unmap (&out_frame);
1093 gst_video_frame_unmap (&src_frame);
1094 if (!success)
1095 goto error_copy_buffer;
1096
1097 done:
1098 if (!gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS |
1099 GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, -1))
1100 return GST_FLOW_ERROR;
1101 *outbuf_ptr = outbuf;
1102 return GST_FLOW_OK;
1103
1104 /* ERRORS */
1105 error_no_pool:
1106 {
1107 GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1108 ("no buffer pool was negotiated"), ("no buffer pool was negotiated"));
1109 return GST_FLOW_ERROR;
1110 }
1111 error_active_pool:
1112 {
1113 GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1114 ("failed to activate buffer pool"), ("failed to activate buffer pool"));
1115 return GST_FLOW_ERROR;
1116 }
1117 error_map_dst_buffer:
1118 {
1119 gst_video_frame_unmap (&src_frame);
1120 // fall-through
1121 }
1122 error_map_src_buffer:
1123 {
1124 GST_WARNING ("failed to map buffer");
1125 gst_buffer_unref (outbuf);
1126 return GST_FLOW_NOT_SUPPORTED;
1127 }
1128
1129 /* ERRORS */
1130 error_invalid_buffer:
1131 {
1132 GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1133 ("failed to validate source buffer"),
1134 ("failed to validate source buffer"));
1135 return GST_FLOW_ERROR;
1136 }
1137 error_create_buffer:
1138 {
1139 GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
1140 ("failed to create buffer"));
1141 return GST_FLOW_ERROR;
1142 }
1143 error_bind_dma_buffer:
1144 {
1145 GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
1146 ("failed to bind dma_buf to VA surface buffer"));
1147 gst_buffer_unref (outbuf);
1148 return GST_FLOW_ERROR;
1149 }
1150 error_copy_buffer:
1151 {
1152 GST_WARNING_OBJECT (plugin, "failed to upload buffer to VA surface");
1153 gst_buffer_unref (outbuf);
1154 return GST_FLOW_NOT_SUPPORTED;
1155 }
1156 }
1157
1158 /**
1159 * gst_vaapi_plugin_base_set_gl_context:
1160 * @plugin: a #GstVaapiPluginBase
1161 * @object: the new GL context from downstream
1162 *
1163 * Registers the new GL context. The change is effective at the next
1164 * call to gst_vaapi_plugin_base_ensure_display(), where the
1165 * underlying display object could be re-allocated to fit the GL
1166 * context needs
1167 */
1168 void
gst_vaapi_plugin_base_set_gl_context(GstVaapiPluginBase * plugin,GstObject * object)1169 gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin,
1170 GstObject * object)
1171 {
1172 #if USE_GST_GL_HELPERS
1173 GstGLContext *const gl_context = GST_GL_CONTEXT (object);
1174 GstVaapiDisplayType display_type;
1175
1176 if (plugin->gl_context == object)
1177 return;
1178
1179 gst_object_replace (&plugin->gl_context, object);
1180
1181 switch (gst_gl_context_get_gl_platform (gl_context)) {
1182 #if USE_GLX
1183 case GST_GL_PLATFORM_GLX:
1184 display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
1185 break;
1186 #endif
1187 case GST_GL_PLATFORM_EGL:
1188 #if USE_EGL
1189 display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
1190 break;
1191 #endif
1192 default:
1193 display_type = plugin->display_type;
1194 break;
1195 }
1196 GST_INFO_OBJECT (plugin, "GL context: %" GST_PTR_FORMAT, plugin->gl_context);
1197 gst_vaapi_plugin_base_set_display_type (plugin, display_type);
1198 #endif
1199 }
1200
1201 /**
1202 * gst_vaapi_plugin_base_create_gl_context:
1203 * @plugin: a #GstVaapiPluginBase
1204 *
1205 * It queries downstream and upstream for a #GstGLDisplay and a other
1206 * #GstGLContext. If not found, a new #GstGLDisplay and #GstGLContext
1207 * are created, if it is possible.
1208 *
1209 * Returns: (transfer full) a new created #GstGLContext or %NULL
1210 **/
1211 GstObject *
gst_vaapi_plugin_base_create_gl_context(GstVaapiPluginBase * plugin)1212 gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin)
1213 {
1214 #if USE_GST_GL_HELPERS
1215 GstGLContext *gl_other_context = NULL, *gl_context = NULL;
1216 GstGLDisplay *gl_display = NULL;
1217
1218 if (!plugin->gl_display)
1219 return NULL;
1220
1221 gl_display = (GstGLDisplay *) plugin->gl_display;
1222 if (gst_gl_display_get_handle_type (gl_display) == GST_GL_DISPLAY_TYPE_ANY)
1223 goto no_valid_gl_display;
1224 gl_other_context = (GstGLContext *) plugin->gl_other_context;
1225
1226 GST_INFO_OBJECT (plugin, "creating a new GstGL context");
1227
1228 GST_OBJECT_LOCK (gl_display);
1229 do {
1230 if (gl_context)
1231 gst_object_unref (gl_context);
1232 gl_context = gst_gl_display_get_gl_context_for_thread (gl_display, NULL);
1233 if (!gl_context) {
1234 if (!gst_gl_display_create_context (gl_display, gl_other_context,
1235 &gl_context, NULL))
1236 break;
1237 }
1238 } while (!gst_gl_display_add_context (gl_display, gl_context));
1239 GST_OBJECT_UNLOCK (gl_display);
1240
1241 return GST_OBJECT_CAST (gl_context);
1242
1243 /* ERRORS */
1244 no_valid_gl_display:
1245 {
1246 GST_INFO_OBJECT (plugin, "No valid GL display found");
1247 gst_object_replace (&plugin->gl_display, NULL);
1248 gst_object_replace (&plugin->gl_other_context, NULL);
1249 return NULL;
1250 }
1251 #else
1252 return NULL;
1253 #endif
1254 }
1255
1256 static GArray *
extract_allowed_surface_formats(GstVaapiDisplay * display,GArray * img_formats,GstVideoFormat specified_format,GstPadDirection direction)1257 extract_allowed_surface_formats (GstVaapiDisplay * display,
1258 GArray * img_formats, GstVideoFormat specified_format,
1259 GstPadDirection direction)
1260 {
1261 guint i;
1262 GArray *out_formats;
1263 GstVaapiSurface *surface = NULL;
1264
1265 g_assert (direction == GST_PAD_SRC || direction == GST_PAD_SINK);
1266
1267 out_formats =
1268 g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat),
1269 img_formats->len);
1270 if (!out_formats)
1271 return NULL;
1272
1273 for (i = 0; i < img_formats->len; i++) {
1274 const GstVideoFormat img_format =
1275 g_array_index (img_formats, GstVideoFormat, i);
1276 GstVaapiImage *image;
1277 GstVideoInfo vi;
1278 GstVideoFormat surface_format;
1279 gboolean res;
1280
1281 if (img_format == GST_VIDEO_FORMAT_UNKNOWN)
1282 continue;
1283
1284 surface_format =
1285 (specified_format == GST_VIDEO_FORMAT_UNKNOWN) ?
1286 img_format : specified_format;
1287 if (!surface) {
1288 gst_video_info_set_format (&vi, surface_format, 64, 64);
1289 surface = gst_vaapi_surface_new_full (display, &vi, 0);
1290 if (!surface)
1291 continue;
1292 }
1293
1294 image = gst_vaapi_image_new (display, img_format, 64, 64);
1295 if (!image) {
1296 /* Just reuse the surface if the format is specified */
1297 if (specified_format == GST_VIDEO_FORMAT_UNKNOWN)
1298 gst_vaapi_object_replace (&surface, NULL);
1299
1300 continue;
1301 }
1302
1303 res = FALSE;
1304 if (direction == GST_PAD_SRC) {
1305 res = gst_vaapi_surface_get_image (surface, image);
1306 } else {
1307 res = gst_vaapi_surface_put_image (surface, image);
1308 }
1309 if (res)
1310 g_array_append_val (out_formats, img_format);
1311
1312 gst_vaapi_object_unref (image);
1313 /* Just reuse the surface if the format is specified */
1314 if (specified_format == GST_VIDEO_FORMAT_UNKNOWN)
1315 gst_vaapi_object_replace (&surface, NULL);
1316 }
1317
1318 if (surface)
1319 gst_vaapi_object_unref (surface);
1320
1321 if (out_formats->len == 0) {
1322 g_array_unref (out_formats);
1323 return NULL;
1324 }
1325 return out_formats;
1326 }
1327
1328 static gboolean
ensure_allowed_raw_caps(GstVaapiPluginBase * plugin,GstVideoFormat format,GstPadDirection direction)1329 ensure_allowed_raw_caps (GstVaapiPluginBase * plugin, GstVideoFormat format,
1330 GstPadDirection direction)
1331 {
1332 GArray *formats, *out_formats;
1333 GstVaapiDisplay *display;
1334 GstCaps *out_caps;
1335 gboolean ret = FALSE;
1336
1337 if (plugin->allowed_raw_caps)
1338 return TRUE;
1339
1340 out_formats = NULL;
1341 display = gst_object_ref (plugin->display);
1342 formats = gst_vaapi_display_get_image_formats (display);
1343 if (!formats)
1344 goto bail;
1345 out_formats =
1346 extract_allowed_surface_formats (display, formats, format, direction);
1347 if (!out_formats)
1348 goto bail;
1349 out_caps = gst_vaapi_video_format_new_template_caps_from_list (out_formats);
1350 if (!out_caps)
1351 goto bail;
1352
1353 gst_caps_replace (&plugin->allowed_raw_caps, out_caps);
1354 gst_caps_unref (out_caps);
1355 ret = TRUE;
1356
1357 bail:
1358 if (formats)
1359 g_array_unref (formats);
1360 if (out_formats)
1361 g_array_unref (out_formats);
1362 gst_object_unref (display);
1363
1364 return ret;
1365 }
1366
1367 /**
1368 * gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps:
1369 * @plugin: a #GstVaapiPluginBase
1370 *
1371 * Returns the raw #GstCaps allowed by the element.
1372 *
1373 * Returns: the allowed raw #GstCaps or %NULL
1374 **/
1375 GstCaps *
gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps(GstVaapiPluginBase * plugin)1376 gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GstVaapiPluginBase * plugin)
1377 {
1378 if (!ensure_allowed_raw_caps (plugin, GST_VIDEO_FORMAT_UNKNOWN, GST_PAD_SINK))
1379 return NULL;
1380 return plugin->allowed_raw_caps;
1381 }
1382
1383 /**
1384 * gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps:
1385 * @plugin: a #GstVaapiPluginBase
1386 * @format: a #GstVideoFormat, the format we need to check
1387 *
1388 * Returns the raw #GstCaps allowed by the element.
1389 *
1390 * Returns: the allowed raw #GstCaps or %NULL
1391 **/
1392 GstCaps *
gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps(GstVaapiPluginBase * plugin,GstVideoFormat format)1393 gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps (GstVaapiPluginBase *
1394 plugin, GstVideoFormat format)
1395 {
1396 if (!ensure_allowed_raw_caps (plugin, format, GST_PAD_SRC))
1397 return NULL;
1398 return plugin->allowed_raw_caps;
1399 }
1400
1401 /**
1402 * gst_vaapi_plugin_base_set_srcpad_can_dmabuf:
1403 * @plugin: a #GstVaapiPluginBase
1404 * @object: the GL context from gst-gl
1405 *
1406 * This function will determine if @object supports dmabuf
1407 * importing.
1408 *
1409 * Please note that the context @object should come from downstream.
1410 **/
1411 void
gst_vaapi_plugin_base_set_srcpad_can_dmabuf(GstVaapiPluginBase * plugin,GstObject * object)1412 gst_vaapi_plugin_base_set_srcpad_can_dmabuf (GstVaapiPluginBase * plugin,
1413 GstObject * object)
1414 {
1415 #if USE_EGL && USE_GST_GL_HELPERS
1416 GstGLContext *const gl_context = GST_GL_CONTEXT (object);
1417
1418 plugin->srcpad_can_dmabuf =
1419 (!(gst_gl_context_get_gl_api (gl_context) & GST_GL_API_GLES1)
1420 && gst_gl_context_check_feature (gl_context,
1421 "EGL_EXT_image_dma_buf_import"));
1422 #endif
1423 }
1424
1425 static void
_init_performance_debug(void)1426 _init_performance_debug (void)
1427 {
1428 #ifndef GST_DISABLE_GST_DEBUG
1429 static volatile gsize _init = 0;
1430
1431 if (g_once_init_enter (&_init)) {
1432 GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
1433 g_once_init_leave (&_init, 1);
1434 }
1435 #endif
1436 }
1437
1438 /**
1439 * gst_vaapi_plugin_copy_va_buffer:
1440 * @plugin: a #GstVaapiPluginBase
1441 * @inbuf: a #GstBuffer with VA memory type
1442 * @outbuf: a #GstBuffer with system allocated memory
1443 *
1444 * Copy @inbuf to @outbuf. This if required when downstream doesn't
1445 * support GstVideoMeta, and since VA memory may have custom strides a
1446 * frame copy is required.
1447 *
1448 * Returns: %FALSE if the copy failed, otherwise %TRUE. Also returns
1449 * %TRUE if it is not required to do the copy
1450 **/
1451 gboolean
gst_vaapi_plugin_copy_va_buffer(GstVaapiPluginBase * plugin,GstBuffer * inbuf,GstBuffer * outbuf)1452 gst_vaapi_plugin_copy_va_buffer (GstVaapiPluginBase * plugin,
1453 GstBuffer * inbuf, GstBuffer * outbuf)
1454 {
1455 GstVideoMeta *vmeta;
1456 GstVideoFrame src_frame, dst_frame;
1457 gboolean success;
1458
1459 if (!plugin->copy_output_frame)
1460 return TRUE;
1461
1462 /* inbuf shall have video meta */
1463 vmeta = gst_buffer_get_video_meta (inbuf);
1464 if (!vmeta)
1465 return FALSE;
1466
1467 _init_performance_debug ();
1468 GST_CAT_INFO (CAT_PERFORMANCE, "copying VA buffer to system memory buffer");
1469
1470 if (!gst_video_frame_map (&src_frame, &plugin->srcpad_info, inbuf,
1471 GST_MAP_READ))
1472 return FALSE;
1473 if (!gst_video_frame_map (&dst_frame, &plugin->srcpad_info, outbuf,
1474 GST_MAP_WRITE)) {
1475 gst_video_frame_unmap (&src_frame);
1476 return FALSE;
1477 }
1478 success = gst_video_frame_copy (&dst_frame, &src_frame);
1479 gst_video_frame_unmap (&dst_frame);
1480 gst_video_frame_unmap (&src_frame);
1481
1482 if (success) {
1483 gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS
1484 | GST_BUFFER_COPY_FLAGS, 0, -1);
1485 }
1486
1487 return success;
1488 }
1489