2 * gstvaapipluginbase.c - Base GStreamer VA-API Plugin element
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>
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.
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.
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
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>
37 GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
38 /* Default debug category is from the subclass */
39 #define GST_CAT_DEFAULT (plugin->debug_category)
41 #define BUFFER_POOL_SINK_MIN_BUFFERS 2
43 /* GstVideoContext interface */
45 plugin_set_display (GstVaapiPluginBase * plugin, GstVaapiDisplay * display)
47 const gchar *const display_name =
48 gst_vaapi_display_get_display_name (display);
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);
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);
60 gst_object_unref (display);
64 * gst_vaapi_plugin_base_set_context:
65 * @plugin: a #GstVaapiPluginBase instance
66 * @context: a #GstContext to set
68 * This is a common set_context() element's vmethod for all the
69 * GStreamer VA-API elements.
71 * It normally should be used through the macro
72 * #GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT()
75 gst_vaapi_plugin_base_set_context (GstVaapiPluginBase * plugin,
78 GstVaapiDisplay *display = NULL;
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);
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);
94 gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
99 default_has_interface (GstVaapiPluginBase * plugin, GType type)
105 default_display_changed (GstVaapiPluginBase * plugin)
109 static GstVaapiSurface *
110 _get_cached_surface (GstBuffer * buf)
112 return gst_mini_object_get_qdata (GST_MINI_OBJECT (buf),
113 g_quark_from_static_string ("GstVaapiDMABufSurface"));
117 _set_cached_surface (GstBuffer * buf, GstVaapiSurface * surface)
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);
125 plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin,
128 GstVideoInfo *const vip = &plugin->sinkpad_info;
132 vmeta = gst_buffer_get_video_meta (buf);
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)
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];
146 GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf);
151 is_dma_buffer (GstBuffer * buf)
155 if (gst_buffer_n_memory (buf) < 1)
158 mem = gst_buffer_peek_memory (buf, 0);
159 if (!mem || !gst_is_dmabuf_memory (mem))
165 plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin,
166 GstBuffer * inbuf, GstBuffer * outbuf)
168 GstVideoInfo *const vip = &plugin->sinkpad_info;
169 GstVaapiVideoMeta *meta;
170 GstVaapiSurface *surface;
171 GstVaapiSurfaceProxy *proxy;
174 fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0));
178 if (!plugin_update_sinkpad_info_from_buffer (plugin, inbuf))
179 goto error_update_sinkpad_info;
181 meta = gst_buffer_get_vaapi_video_meta (outbuf);
182 g_return_val_if_fail (meta != NULL, FALSE);
184 /* Check for a VASurface cached in the buffer */
185 surface = _get_cached_surface (inbuf);
187 /* otherwise create one and cache it */
189 gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd, vip);
191 goto error_create_surface;
192 _set_cached_surface (inbuf, surface);
195 proxy = gst_vaapi_surface_proxy_new (surface);
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);
204 error_update_sinkpad_info:
206 GST_ERROR_OBJECT (plugin,
207 "failed to update sink pad video info from video meta");
210 error_create_surface:
212 GST_ERROR_OBJECT (plugin,
213 "failed to create VA surface from dma_buf handle");
218 GST_ERROR_OBJECT (plugin,
219 "failed to create VA surface proxy from wrapped VA surface");
225 plugin_reset_texture_map (GstVaapiPluginBase * plugin)
228 gst_vaapi_display_reset_texture_map (plugin->display);
232 gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass)
234 klass->has_interface = default_has_interface;
235 klass->display_changed = default_display_changed;
239 gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
240 GstDebugCategory * debug_category)
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;
247 plugin->sinkpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "sink");
248 gst_video_info_init (&plugin->sinkpad_info);
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);
255 plugin->enable_direct_rendering =
256 (g_getenv ("GST_VAAPI_ENABLE_DIRECT_RENDERING") != NULL);
260 gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin)
262 gst_vaapi_plugin_base_close (plugin);
263 g_free (plugin->display_name);
265 gst_object_unref (plugin->sinkpad);
267 gst_object_unref (plugin->srcpad);
271 * gst_vaapi_plugin_base_open:
272 * @plugin: a #GstVaapiPluginBase
274 * Allocates any internal resources needed for correct operation from
277 * Returns: %TRUE if successful, %FALSE otherwise.
280 gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin)
286 * gst_vaapi_plugin_base_close:
287 * @plugin: a #GstVaapiPluginBase
289 * Deallocates all internal resources that were allocated so
290 * far. i.e. put the base plugin object into a clean state.
293 gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin)
295 /* Release vaapi textures first if exist, which refs display object */
296 plugin_reset_texture_map (plugin);
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);
303 gst_caps_replace (&plugin->sinkpad_caps, NULL);
304 gst_video_info_init (&plugin->sinkpad_info);
306 g_clear_object (&plugin->sinkpad_buffer_pool);
307 g_clear_object (&plugin->srcpad_buffer_pool);
309 g_clear_object (&plugin->sinkpad_allocator);
310 g_clear_object (&plugin->srcpad_allocator);
311 g_clear_object (&plugin->other_srcpad_allocator);
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);
319 * gst_vaapi_plugin_base_has_display_type:
320 * @plugin: a #GstVaapiPluginBase
321 * @display_type_req: the desired #GstVaapiDisplayType
323 * Checks whether the @plugin elements already has a #GstVaapiDisplay
324 * instance compatible with type @display_type_req.
326 * Return value: %TRUE if @plugin has a compatible display, %FALSE otherwise
329 gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin,
330 GstVaapiDisplayType display_type_req)
332 GstVaapiDisplayType display_type;
334 if (!plugin->display)
337 display_type = plugin->display_type;
338 if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
341 display_type = gst_vaapi_display_get_class_type (plugin->display);
342 if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
348 * gst_vaapi_plugin_base_set_display_type:
349 * @plugin: a #GstVaapiPluginBase
350 * @display_type: the new request #GstVaapiDisplayType
352 * Requests a new display type. The change is effective at the next
353 * call to gst_vaapi_plugin_base_ensure_display().
356 gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin,
357 GstVaapiDisplayType display_type)
359 plugin->display_type_req = display_type;
363 * gst_vaapi_plugin_base_set_display_name:
364 * @plugin: a #GstVaapiPluginBase
365 * @display_name: the new display name to match
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().
371 gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin,
372 const gchar * display_name)
374 g_free (plugin->display_name);
375 plugin->display_name = g_strdup (display_name);
379 * gst_vaapi_plugin_base_ensure_display:
380 * @plugin: a #GstVaapiPluginBase
382 * Ensures the display stored in @plugin complies with the requested
383 * display type constraints.
385 * Returns: %TRUE if the display was created to match the requested
386 * type, %FALSE otherwise.
389 gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin)
391 if (gst_vaapi_plugin_base_has_display_type (plugin, plugin->display_type_req))
393 gst_vaapi_display_replace (&plugin->display, NULL);
395 if (!gst_vaapi_ensure_display (GST_ELEMENT (plugin),
396 plugin->display_type_req))
398 plugin->display_type = gst_vaapi_display_get_display_type (plugin->display);
400 GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->display_changed (plugin);
405 gst_vaapi_buffer_pool_caps_is_equal (GstBufferPool * pool, GstCaps * newcaps)
407 GstStructure *config;
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);
421 static inline gboolean
422 reset_allocator (GstAllocator * allocator, GstVideoInfo * vinfo)
424 const GstVideoInfo *orig_vi;
429 orig_vi = gst_allocator_get_vaapi_video_info (allocator, NULL);
430 if (!gst_video_info_changed (orig_vi, vinfo))
433 gst_object_unref (allocator);
438 ensure_sinkpad_allocator (GstVaapiPluginBase * plugin, GstCaps * caps,
442 const GstVideoInfo *image_info;
443 GstVaapiImageUsageFlags usage_flag =
444 GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
446 if (!gst_video_info_from_caps (&vinfo, caps))
447 goto error_invalid_caps;
449 if (!reset_allocator (plugin->sinkpad_allocator, &vinfo))
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");
457 plugin->sinkpad_allocator =
458 gst_vaapi_video_allocator_new (plugin->display, &vinfo, 0, usage_flag);
461 if (!plugin->sinkpad_allocator)
462 goto error_create_allocator;
465 gst_allocator_get_vaapi_video_info (plugin->sinkpad_allocator, NULL);
466 g_assert (image_info); /* allocator ought set its image info */
468 /* update the size with the one generated by the allocator */
469 *size = GST_VIDEO_INFO_SIZE (image_info);
476 GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
479 error_create_allocator:
481 GST_ERROR_OBJECT (plugin, "failed to create sink pad's allocator");
487 get_dmabuf_surface_allocation_flags (void)
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;
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;
501 if (same_physical_device)
503 return GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE;
506 static inline GstAllocator *
507 create_dmabuf_srcpad_allocator (GstVaapiPluginBase * plugin,
508 GstVideoInfo * vinfo, gboolean check_for_map)
510 GstAllocator *allocator;
512 if (!GST_IS_VIDEO_DECODER (plugin) && !GST_IS_BASE_TRANSFORM (plugin))
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)
520 /* the dmabuf allocator *must* be capable to map a buffer with raw
521 * caps and the there's no evidence of downstream dmabuf
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);
532 ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstVideoInfo * vinfo,
535 const GstVideoInfo *image_info;
537 if (!reset_allocator (plugin->srcpad_allocator, vinfo))
538 goto valid_allocator;
540 plugin->srcpad_allocator = NULL;
541 if (caps && gst_caps_is_video_raw (caps)) {
542 GstAllocator *allocator = create_dmabuf_srcpad_allocator (plugin, vinfo,
543 !plugin->srcpad_can_dmabuf);
544 plugin->srcpad_allocator = allocator;
545 } else if (caps && gst_vaapi_caps_feature_contains (caps,
546 GST_VAAPI_CAPS_FEATURE_DMABUF)) {
547 plugin->srcpad_allocator =
548 create_dmabuf_srcpad_allocator (plugin, vinfo, FALSE);
549 if (!plugin->srcpad_allocator)
550 goto error_create_allocator;
553 if (!plugin->srcpad_allocator) {
554 GstVaapiImageUsageFlags usage_flag =
555 GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
557 if (plugin->enable_direct_rendering) {
558 usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
559 GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator");
562 plugin->srcpad_allocator =
563 gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag);
566 if (!plugin->srcpad_allocator)
567 goto error_create_allocator;
571 gst_allocator_get_vaapi_video_info (plugin->srcpad_allocator, NULL);
572 g_assert (image_info); /* both allocators ought set its image
575 /* update the size with the one generated by the allocator */
576 GST_VIDEO_INFO_SIZE (vinfo) = GST_VIDEO_INFO_SIZE (image_info);
578 if (GST_IS_VIDEO_DECODER (plugin)) {
579 /* the received caps are the "allocation caps" which may be
580 * different from the "negotiation caps". In this case, we should
581 * indicate the allocator to store the negotiation caps since they
582 * are the one should be used for frame mapping with GstVideoMeta */
583 gboolean different_caps = plugin->srcpad_caps &&
584 !gst_caps_is_strictly_equal (plugin->srcpad_caps, caps);
585 const GstVideoInfo *previous_negotiated =
586 gst_allocator_get_vaapi_negotiated_video_info
587 (plugin->srcpad_allocator);
589 if (different_caps) {
591 GstVideoInfo vi = plugin->srcpad_info;
593 /* update the planes and the size with the allocator image/surface
594 * info, but not the resolution */
595 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (image_info); i++) {
596 GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) =
597 GST_VIDEO_INFO_PLANE_OFFSET (image_info, i);
598 GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) =
599 GST_VIDEO_INFO_PLANE_STRIDE (image_info, i);
601 GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (image_info);
602 gst_allocator_set_vaapi_negotiated_video_info (plugin->srcpad_allocator,
604 } else if (previous_negotiated) {
605 gst_allocator_set_vaapi_negotiated_video_info (plugin->srcpad_allocator,
612 error_create_allocator:
614 GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator");
620 * gst_vaapi_plugin_base_create_pool:
621 * @plugin: a #GstVaapiPluginBase
622 * @caps: the initial #GstCaps for the resulting buffer pool
623 * @size: the size of each buffer, not including prefix and padding
624 * @options: a set of #GstVaapiVideoBufferPoolOption encoded as bit-wise
625 * @allocator: (allow-none): the #GstAllocator to use or %NULL
627 * Create an instance of #GstVaapiVideoBufferPool
629 * Returns: (transfer full): a new allocated #GstBufferPool
631 static GstBufferPool *
632 gst_vaapi_plugin_base_create_pool (GstVaapiPluginBase * plugin, GstCaps * caps,
633 gsize size, guint min_buffers, guint max_buffers, guint options,
634 GstAllocator * allocator)
637 GstStructure *config;
639 if (!(pool = gst_vaapi_video_buffer_pool_new (plugin->display)))
640 goto error_create_pool;
642 config = gst_buffer_pool_get_config (pool);
643 gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
645 gst_buffer_pool_config_add_option (config,
646 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
647 if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) {
648 gst_buffer_pool_config_add_option (config,
649 GST_BUFFER_POOL_OPTION_VIDEO_META);
651 if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT) {
652 gst_buffer_pool_config_add_option (config,
653 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
655 #if (USE_GLX || USE_EGL)
656 if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) {
657 gst_buffer_pool_config_add_option (config,
658 GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
662 gst_buffer_pool_config_set_allocator (config, allocator, NULL);
663 if (!gst_buffer_pool_set_config (pool, config)) {
664 config = gst_buffer_pool_get_config (pool);
666 if (!gst_buffer_pool_config_validate_params (config, caps, size,
667 min_buffers, max_buffers)) {
668 gst_structure_free (config);
669 goto error_pool_config;
672 if (!gst_buffer_pool_set_config (pool, config))
673 goto error_pool_config;
680 GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
685 gst_object_unref (pool);
686 GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS,
687 ("Failed to configure the buffer pool"),
688 ("Configuration is most likely invalid, please report this issue."));
694 * ensure_sinkpad_buffer_pool:
695 * @plugin: a #GstVaapiPluginBase
696 * @caps: the initial #GstCaps for the resulting buffer pool
698 * Makes sure the sink pad video buffer pool is created with the
701 * Returns: %TRUE if successful, %FALSE otherwise.
704 ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstCaps * caps)
709 /* video decoders don't use a buffer pool in the sink pad */
710 if (GST_IS_VIDEO_DECODER (plugin))
713 if (!gst_vaapi_plugin_base_ensure_display (plugin))
716 if (plugin->sinkpad_buffer_pool) {
717 if (gst_vaapi_buffer_pool_caps_is_equal (plugin->sinkpad_buffer_pool, caps))
719 gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, FALSE);
720 g_clear_object (&plugin->sinkpad_buffer_pool);
721 g_clear_object (&plugin->sinkpad_allocator);
722 plugin->sinkpad_buffer_size = 0;
725 if (!ensure_sinkpad_allocator (plugin, caps, &size))
729 gst_vaapi_plugin_base_create_pool (plugin, caps, size,
730 BUFFER_POOL_SINK_MIN_BUFFERS, 0,
731 GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META, plugin->sinkpad_allocator);
735 plugin->sinkpad_buffer_pool = pool;
736 plugin->sinkpad_buffer_size = size;
741 * gst_vaapi_plugin_base_set_caps:
742 * @plugin: a #GstVaapiPluginBase
743 * @incaps: the sink pad (input) caps
744 * @outcaps: the src pad (output) caps
746 * Notifies the base plugin object of the new input and output caps,
747 * obtained from the subclass.
749 * Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
752 gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
755 if (incaps && incaps != plugin->sinkpad_caps) {
756 if (!gst_video_info_from_caps (&plugin->sinkpad_info, incaps))
758 gst_caps_replace (&plugin->sinkpad_caps, incaps);
759 plugin->sinkpad_caps_is_raw = !gst_caps_has_vaapi_surface (incaps);
762 if (outcaps && outcaps != plugin->srcpad_caps) {
763 if (!gst_video_info_from_caps (&plugin->srcpad_info, outcaps))
765 if (plugin->srcpad_buffer_pool
766 && !gst_vaapi_buffer_pool_caps_is_equal (plugin->srcpad_buffer_pool,
768 gst_buffer_pool_set_active (plugin->srcpad_buffer_pool, FALSE);
769 g_clear_object (&plugin->srcpad_buffer_pool);
770 g_clear_object (&plugin->srcpad_allocator);
771 plugin_reset_texture_map (plugin);
773 gst_caps_replace (&plugin->srcpad_caps, outcaps);
776 if (!ensure_sinkpad_buffer_pool (plugin, plugin->sinkpad_caps))
782 * gst_vaapi_plugin_base_propose_allocation:
783 * @plugin: a #GstVaapiPluginBase
784 * @query: the allocation query to configure
786 * Proposes allocation parameters to the upstream elements.
788 * Returns: %TRUE if successful, %FALSE otherwise.
791 gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
794 GstCaps *caps = NULL;
795 GstBufferPool *pool = NULL;
797 guint size = 0, n_allocators;
799 gst_query_parse_allocation (query, &caps, &need_pool);
803 if (!ensure_sinkpad_allocator (plugin, caps, &size))
807 pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size,
808 BUFFER_POOL_SINK_MIN_BUFFERS, 0,
809 GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META,
810 plugin->sinkpad_allocator);
815 /* Set sinkpad allocator as the last allocation param.
817 * If there's none, set system's allocator first and VAAPI allocator
820 n_allocators = gst_query_get_n_allocation_params (query);
821 if (n_allocators == 0) {
822 GstAllocator *allocator;
824 allocator = gst_allocator_find (GST_ALLOCATOR_SYSMEM);
825 gst_query_add_allocation_param (query, allocator, NULL);
826 gst_object_unref (allocator);
828 gst_query_add_allocation_param (query, plugin->sinkpad_allocator, NULL);
830 gst_query_add_allocation_pool (query, pool, size,
831 BUFFER_POOL_SINK_MIN_BUFFERS, 0);
833 gst_object_unref (pool);
835 gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL);
836 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
842 GST_INFO_OBJECT (plugin, "no caps specified");
848 * gst_vaapi_plugin_base_decide_allocation:
849 * @plugin: a #GstVaapiPluginBase
850 * @query: the allocation query to parse
851 * @feature: the desired #GstVaapiCapsFeature, or zero to find the
854 * Decides allocation parameters for the downstream elements.
856 * Returns: %TRUE if successful, %FALSE otherwise.
859 gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
862 GstCaps *caps = NULL;
865 guint i, size, min, max, pool_options, num_allocators;
866 gint index_allocator;
867 gboolean update_pool = FALSE;
868 #if (USE_GLX || USE_EGL)
872 gst_query_parse_allocation (query, &caps, NULL);
877 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
878 pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
880 #if (USE_GLX || USE_EGL)
881 if (gst_query_find_allocation_meta (query,
882 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) &&
883 gst_vaapi_caps_feature_contains (caps,
884 GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META))
885 pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD;
887 #if USE_GST_GL_HELPERS
888 if (!plugin->gl_context &&
889 (pool_options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD)) {
890 const GstStructure *params;
891 GstObject *gl_context;
893 gst_query_parse_nth_allocation_meta (query, idx, ¶ms);
895 if (gst_structure_get (params, "gst.gl.GstGLContext", GST_TYPE_GL_CONTEXT,
896 &gl_context, NULL) && gl_context) {
897 gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
898 gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, gl_context);
899 gst_object_unref (gl_context);
906 /* Make sure the display we pass down to the buffer pool is actually
907 the expected one, especially when the downstream element requires
908 a GLX or EGL display */
909 if (!gst_vaapi_plugin_base_ensure_display (plugin))
910 goto error_ensure_display;
912 if (!gst_video_info_from_caps (&vi, caps))
913 goto error_invalid_caps;
914 gst_video_info_force_nv12_if_encoded (&vi);
916 index_allocator = -1;
917 num_allocators = gst_query_get_n_allocation_params (query);
918 for (i = 0; i < num_allocators; i++) {
919 GstAllocator *allocator = NULL;
920 GstAllocationParams params;
922 gst_query_parse_nth_allocation_param (query, i, &allocator, ¶ms);
926 /* Let's keep the the first allocator if it is not VA-API. It
927 * might be used if it is required to copy the output frame to a
930 && g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0) {
931 if (plugin->other_srcpad_allocator)
932 gst_object_unref (plugin->other_srcpad_allocator);
933 plugin->other_srcpad_allocator = allocator;
934 plugin->other_allocator_params = params;
938 if (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) == 0) {
939 GST_DEBUG_OBJECT (plugin, "found vaapi allocator in query %"
940 GST_PTR_FORMAT, allocator);
942 if (plugin->srcpad_allocator)
943 gst_object_unref (plugin->srcpad_allocator);
944 plugin->srcpad_allocator = allocator;
947 gst_object_unref (allocator);
950 if (gst_query_get_n_allocation_pools (query) > 0) {
951 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
953 size = MAX (size, GST_VIDEO_INFO_SIZE (&vi));
955 /* Check whether downstream element proposed a bufferpool but did
956 not provide a correct propose_allocation() implementation */
957 if (gst_buffer_pool_has_option (pool,
958 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT))
959 pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT;
961 /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
962 if (!gst_buffer_pool_has_option (pool,
963 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
964 GST_INFO_OBJECT (plugin, "ignoring non-VAAPI pool: %" GST_PTR_FORMAT,
966 g_clear_object (&pool);
971 size = GST_VIDEO_INFO_SIZE (&vi);
976 if (!ensure_srcpad_allocator (plugin, &vi, caps))
978 size = GST_VIDEO_INFO_SIZE (&vi); /* size might be updated by
980 pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size, min, max,
981 pool_options, plugin->srcpad_allocator);
987 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
989 gst_query_add_allocation_pool (query, pool, size, min, max);
991 /* allocator might be updated by ensure_srcpad_allocator() */
992 if (plugin->srcpad_allocator) {
993 if (index_allocator > 0) {
994 gst_query_set_nth_allocation_param (query, index_allocator,
995 plugin->srcpad_allocator, NULL);
997 GST_DEBUG_OBJECT (plugin, "adding allocator in query %" GST_PTR_FORMAT,
998 plugin->srcpad_allocator);
999 gst_query_add_allocation_param (query, plugin->srcpad_allocator, NULL);
1003 g_clear_object (&plugin->srcpad_buffer_pool);
1004 plugin->srcpad_buffer_pool = pool;
1006 /* if downstream doesn't support GstVideoMeta, and the negotiated
1007 * caps are raw video, and the used allocator is the VA-API one, we
1008 * should copy the VA-API frame into a dumb buffer */
1009 plugin->copy_output_frame = gst_vaapi_video_buffer_pool_copy_buffer (pool);
1016 GST_ERROR_OBJECT (plugin, "no caps specified");
1021 GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
1024 error_ensure_display:
1026 GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d",
1027 plugin->display_type_req);
1032 /* error message already sent */
1038 * gst_vaapi_plugin_base_get_input_buffer:
1039 * @plugin: a #GstVaapiPluginBase
1040 * @inbuf: the sink pad (input) buffer
1041 * @outbuf_ptr: the pointer to location to the VA surface backed buffer
1043 * Acquires the sink pad (input) buffer as a VA surface backed
1044 * buffer. This is mostly useful for raw YUV buffers, as source
1045 * buffers that are already backed as a VA surface are passed
1048 * Returns: #GST_FLOW_OK if the buffer could be acquired
1051 gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
1052 GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
1054 GstVaapiVideoMeta *meta;
1056 GstVideoFrame src_frame, out_frame;
1059 g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
1060 g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
1062 meta = gst_buffer_get_vaapi_video_meta (inbuf);
1064 *outbuf_ptr = gst_buffer_ref (inbuf);
1068 if (!plugin->sinkpad_caps_is_raw)
1069 goto error_invalid_buffer;
1071 if (!plugin->sinkpad_buffer_pool)
1074 if (!gst_buffer_pool_is_active (plugin->sinkpad_buffer_pool) &&
1075 !gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, TRUE))
1076 goto error_active_pool;
1079 if (gst_buffer_pool_acquire_buffer (plugin->sinkpad_buffer_pool,
1080 &outbuf, NULL) != GST_FLOW_OK)
1081 goto error_create_buffer;
1083 if (is_dma_buffer (inbuf)) {
1084 if (!plugin_bind_dma_to_vaapi_buffer (plugin, inbuf, outbuf))
1085 goto error_bind_dma_buffer;
1089 if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf,
1091 goto error_map_src_buffer;
1093 if (!gst_video_frame_map (&out_frame, &plugin->sinkpad_info, outbuf,
1095 goto error_map_dst_buffer;
1097 success = gst_video_frame_copy (&out_frame, &src_frame);
1098 gst_video_frame_unmap (&out_frame);
1099 gst_video_frame_unmap (&src_frame);
1101 goto error_copy_buffer;
1104 if (!gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS |
1105 GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, -1))
1106 return GST_FLOW_ERROR;
1107 *outbuf_ptr = outbuf;
1113 GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1114 ("no buffer pool was negotiated"), ("no buffer pool was negotiated"));
1115 return GST_FLOW_ERROR;
1119 GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1120 ("failed to activate buffer pool"), ("failed to activate buffer pool"));
1121 return GST_FLOW_ERROR;
1123 error_map_dst_buffer:
1125 gst_video_frame_unmap (&src_frame);
1128 error_map_src_buffer:
1130 GST_WARNING ("failed to map buffer");
1131 gst_buffer_unref (outbuf);
1132 return GST_FLOW_NOT_SUPPORTED;
1136 error_invalid_buffer:
1138 GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
1139 ("failed to validate source buffer"),
1140 ("failed to validate source buffer"));
1141 return GST_FLOW_ERROR;
1143 error_create_buffer:
1145 GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
1146 ("failed to create buffer"));
1147 return GST_FLOW_ERROR;
1149 error_bind_dma_buffer:
1151 GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
1152 ("failed to bind dma_buf to VA surface buffer"));
1153 gst_buffer_unref (outbuf);
1154 return GST_FLOW_ERROR;
1158 GST_WARNING_OBJECT (plugin, "failed to upload buffer to VA surface");
1159 gst_buffer_unref (outbuf);
1160 return GST_FLOW_NOT_SUPPORTED;
1165 * gst_vaapi_plugin_base_set_gl_context:
1166 * @plugin: a #GstVaapiPluginBase
1167 * @object: the new GL context from downstream
1169 * Registers the new GL context. The change is effective at the next
1170 * call to gst_vaapi_plugin_base_ensure_display(), where the
1171 * underlying display object could be re-allocated to fit the GL
1175 gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin,
1178 #if USE_GST_GL_HELPERS
1179 GstGLContext *const gl_context = GST_GL_CONTEXT (object);
1180 GstVaapiDisplayType display_type;
1182 if (plugin->gl_context == object)
1185 gst_object_replace (&plugin->gl_context, object);
1187 switch (gst_gl_context_get_gl_platform (gl_context)) {
1189 case GST_GL_PLATFORM_GLX:
1190 display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
1193 case GST_GL_PLATFORM_EGL:
1195 display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
1199 display_type = plugin->display_type;
1202 GST_INFO_OBJECT (plugin, "GL context: %" GST_PTR_FORMAT, plugin->gl_context);
1203 gst_vaapi_plugin_base_set_display_type (plugin, display_type);
1208 * gst_vaapi_plugin_base_create_gl_context:
1209 * @plugin: a #GstVaapiPluginBase
1211 * It queries downstream and upstream for a #GstGLDisplay and a other
1212 * #GstGLContext. If not found, a new #GstGLDisplay and #GstGLContext
1213 * are created, if it is possible.
1215 * Returns: (transfer full) a new created #GstGLContext or %NULL
1218 gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin)
1220 #if USE_GST_GL_HELPERS
1221 GstGLContext *gl_other_context = NULL, *gl_context = NULL;
1222 GstGLDisplay *gl_display = NULL;
1224 if (!plugin->gl_display)
1227 gl_display = (GstGLDisplay *) plugin->gl_display;
1228 if (gst_gl_display_get_handle_type (gl_display) == GST_GL_DISPLAY_TYPE_ANY)
1229 goto no_valid_gl_display;
1230 gl_other_context = (GstGLContext *) plugin->gl_other_context;
1232 GST_INFO_OBJECT (plugin, "creating a new GstGL context");
1234 GST_OBJECT_LOCK (gl_display);
1237 gst_object_unref (gl_context);
1238 gl_context = gst_gl_display_get_gl_context_for_thread (gl_display, NULL);
1240 if (!gst_gl_display_create_context (gl_display, gl_other_context,
1244 } while (!gst_gl_display_add_context (gl_display, gl_context));
1245 GST_OBJECT_UNLOCK (gl_display);
1247 return GST_OBJECT_CAST (gl_context);
1250 no_valid_gl_display:
1252 GST_INFO_OBJECT (plugin, "No valid GL display found");
1253 gst_object_replace (&plugin->gl_display, NULL);
1254 gst_object_replace (&plugin->gl_other_context, NULL);
1263 extract_allowed_surface_formats (GstVaapiDisplay * display,
1264 GArray * img_formats, GstVideoFormat specified_format,
1265 GstPadDirection direction)
1268 GArray *out_formats;
1269 GstVaapiSurface *surface = NULL;
1271 g_assert (direction == GST_PAD_SRC || direction == GST_PAD_SINK);
1274 g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat),
1279 for (i = 0; i < img_formats->len; i++) {
1280 const GstVideoFormat img_format =
1281 g_array_index (img_formats, GstVideoFormat, i);
1282 GstVaapiImage *image;
1284 GstVideoFormat surface_format;
1287 if (img_format == GST_VIDEO_FORMAT_UNKNOWN)
1291 (specified_format == GST_VIDEO_FORMAT_UNKNOWN) ?
1292 img_format : specified_format;
1294 gst_video_info_set_format (&vi, surface_format, 64, 64);
1295 surface = gst_vaapi_surface_new_full (display, &vi, 0);
1300 image = gst_vaapi_image_new (display, img_format, 64, 64);
1302 /* Just reuse the surface if the format is specified */
1303 if (specified_format == GST_VIDEO_FORMAT_UNKNOWN)
1304 gst_vaapi_object_replace (&surface, NULL);
1310 if (direction == GST_PAD_SRC) {
1311 res = gst_vaapi_surface_get_image (surface, image);
1313 res = gst_vaapi_surface_put_image (surface, image);
1316 g_array_append_val (out_formats, img_format);
1318 gst_vaapi_object_unref (image);
1319 /* Just reuse the surface if the format is specified */
1320 if (specified_format == GST_VIDEO_FORMAT_UNKNOWN)
1321 gst_vaapi_object_replace (&surface, NULL);
1325 gst_vaapi_object_unref (surface);
1327 if (out_formats->len == 0) {
1328 g_array_unref (out_formats);
1335 ensure_allowed_raw_caps (GstVaapiPluginBase * plugin, GstVideoFormat format,
1336 GstPadDirection direction)
1338 GArray *formats, *out_formats;
1339 GstVaapiDisplay *display;
1341 gboolean ret = FALSE;
1343 if (plugin->allowed_raw_caps)
1347 display = gst_object_ref (plugin->display);
1348 formats = gst_vaapi_display_get_image_formats (display);
1352 extract_allowed_surface_formats (display, formats, format, direction);
1355 out_caps = gst_vaapi_video_format_new_template_caps_from_list (out_formats);
1359 gst_caps_replace (&plugin->allowed_raw_caps, out_caps);
1360 gst_caps_unref (out_caps);
1365 g_array_unref (formats);
1367 g_array_unref (out_formats);
1368 gst_object_unref (display);
1374 * gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps:
1375 * @plugin: a #GstVaapiPluginBase
1377 * Returns the raw #GstCaps allowed by the element.
1379 * Returns: the allowed raw #GstCaps or %NULL
1382 gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GstVaapiPluginBase * plugin)
1384 if (!ensure_allowed_raw_caps (plugin, GST_VIDEO_FORMAT_UNKNOWN, GST_PAD_SINK))
1386 return plugin->allowed_raw_caps;
1390 * gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps:
1391 * @plugin: a #GstVaapiPluginBase
1392 * @format: a #GstVideoFormat, the format we need to check
1394 * Returns the raw #GstCaps allowed by the element.
1396 * Returns: the allowed raw #GstCaps or %NULL
1399 gst_vaapi_plugin_base_get_allowed_srcpad_raw_caps (GstVaapiPluginBase *
1400 plugin, GstVideoFormat format)
1402 if (!ensure_allowed_raw_caps (plugin, format, GST_PAD_SRC))
1404 return plugin->allowed_raw_caps;
1408 * gst_vaapi_plugin_base_set_srcpad_can_dmabuf:
1409 * @plugin: a #GstVaapiPluginBase
1410 * @object: the GL context from gst-gl
1412 * This function will determine if @object supports dmabuf
1415 * Please note that the context @object should come from downstream.
1418 gst_vaapi_plugin_base_set_srcpad_can_dmabuf (GstVaapiPluginBase * plugin,
1421 #if USE_EGL && USE_GST_GL_HELPERS
1422 GstGLContext *const gl_context = GST_GL_CONTEXT (object);
1424 plugin->srcpad_can_dmabuf =
1425 (!(gst_gl_context_get_gl_api (gl_context) & GST_GL_API_GLES1)
1426 && gst_gl_context_check_feature (gl_context,
1427 "EGL_EXT_image_dma_buf_import"));
1432 _init_performance_debug (void)
1434 #ifndef GST_DISABLE_GST_DEBUG
1435 static volatile gsize _init = 0;
1437 if (g_once_init_enter (&_init)) {
1438 GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
1439 g_once_init_leave (&_init, 1);
1445 * gst_vaapi_plugin_copy_va_buffer:
1446 * @plugin: a #GstVaapiPluginBase
1447 * @inbuf: a #GstBuffer with VA memory type
1448 * @outbuf: a #GstBuffer with system allocated memory
1450 * Copy @inbuf to @outbuf. This if required when downstream doesn't
1451 * support GstVideoMeta, and since VA memory may have custom strides a
1452 * frame copy is required.
1454 * Returns: %FALSE if the copy failed, otherwise %TRUE. Also returns
1455 * %TRUE if it is not required to do the copy
1458 gst_vaapi_plugin_copy_va_buffer (GstVaapiPluginBase * plugin,
1459 GstBuffer * inbuf, GstBuffer * outbuf)
1461 GstVideoMeta *vmeta;
1462 GstVideoFrame src_frame, dst_frame;
1465 if (!plugin->copy_output_frame)
1468 /* inbuf shall have video meta */
1469 vmeta = gst_buffer_get_video_meta (inbuf);
1473 _init_performance_debug ();
1474 GST_CAT_INFO (CAT_PERFORMANCE, "copying VA buffer to system memory buffer");
1476 if (!gst_video_frame_map (&src_frame, &plugin->srcpad_info, inbuf,
1479 if (!gst_video_frame_map (&dst_frame, &plugin->srcpad_info, outbuf,
1481 gst_video_frame_unmap (&src_frame);
1484 success = gst_video_frame_copy (&dst_frame, &src_frame);
1485 gst_video_frame_unmap (&dst_frame);
1486 gst_video_frame_unmap (&src_frame);
1489 gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS
1490 | GST_BUFFER_COPY_FLAGS, 0, -1);