diff --git a/gst/vaapi/gstvaapipluginbase.c b/gst/vaapi/gstvaapipluginbase.c index 1a254060a1..ca681aa3f9 100644 --- a/gst/vaapi/gstvaapipluginbase.c +++ b/gst/vaapi/gstvaapipluginbase.c @@ -24,6 +24,7 @@ #include "gst/vaapi/sysdeps.h" #include +#include #include "gstvaapipluginbase.h" #include "gstvaapipluginutil.h" #include "gstvaapivideocontext.h" @@ -392,6 +393,42 @@ gst_vaapi_plugin_base_ensure_uploader (GstVaapiPluginBase * plugin) return TRUE; } +/* Checks whether the supplied pad peer element supports DMABUF sharing */ +/* XXX: this is a workaround to the absence of any proposer way to + specify DMABUF memory capsfeatures or bufferpool option to downstream */ +static gboolean +has_dmabuf_capable_peer (GstVaapiPluginBase * plugin, GstPad * pad) +{ + GstPad *other_pad = NULL; + GstElement *element = NULL; + gchar *element_name = NULL; + gboolean is_dmabuf_capable = FALSE; + gint v; + + do { + other_pad = gst_pad_get_peer (pad); + if (!other_pad) + break; + + element = gst_pad_get_parent_element (other_pad); + if (!element || !GST_IS_PUSH_SRC (element)) + break; + + element_name = gst_element_get_name (element); + if (!element_name || sscanf (element_name, "v4l2src%d", &v) != 1) + break; + + v = 0; + g_object_get (element, "io-mode", &v, NULL); + is_dmabuf_capable = v == 5; /* "dmabuf-import" enum value */ + } while (0); + + g_free (element_name); + g_clear_object (&element); + g_clear_object (&other_pad); + return is_dmabuf_capable; +} + /** * ensure_sinkpad_buffer_pool: * @plugin: a #GstVaapiPluginBase @@ -536,6 +573,16 @@ gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin, return FALSE; gst_query_add_allocation_pool (query, plugin->sinkpad_buffer_pool, plugin->sinkpad_buffer_size, 0, 0); + + if (has_dmabuf_capable_peer (plugin, plugin->sinkpad)) { + GstStructure *const config = + gst_buffer_pool_get_config (plugin->sinkpad_buffer_pool); + + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_DMABUF_MEMORY); + if (!gst_buffer_pool_set_config (plugin->sinkpad_buffer_pool, config)) + goto error_pool_config; + } } gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL); @@ -548,6 +595,11 @@ error_no_caps: GST_ERROR ("no caps specified"); return FALSE; } +error_pool_config: + { + GST_ERROR ("failed to reset buffer pool config"); + return FALSE; + } } #endif diff --git a/gst/vaapi/gstvaapivideobufferpool.c b/gst/vaapi/gstvaapivideobufferpool.c index 84be8e3058..56295ba3b7 100644 --- a/gst/vaapi/gstvaapivideobufferpool.c +++ b/gst/vaapi/gstvaapivideobufferpool.c @@ -46,10 +46,12 @@ struct _GstVaapiVideoBufferPoolPrivate GstVideoInfo video_info[2]; guint video_info_index; GstAllocator *allocator; + GstVideoInfo alloc_info; GstVaapiDisplay *display; guint has_video_meta:1; guint has_video_alignment:1; guint has_texture_upload_meta:1; + guint use_dmabuf_memory:1; }; #define GST_VAAPI_VIDEO_BUFFER_POOL_GET_PRIVATE(obj) \ @@ -105,8 +107,7 @@ gst_vaapi_video_buffer_pool_get_property (GObject * object, guint prop_id, static void fill_video_alignment (GstVaapiVideoBufferPool * pool, GstVideoAlignment * align) { - GstVideoInfo *const vip = - &GST_VAAPI_VIDEO_ALLOCATOR_CAST (pool->priv->allocator)->image_info; + GstVideoInfo *const vip = &pool->priv->alloc_info; guint i; gst_video_alignment_reset (align); @@ -140,26 +141,48 @@ gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool, GstVideoInfo *const new_vip = &priv->video_info[!priv->video_info_index]; GstVideoAlignment align; GstAllocator *allocator; - gboolean changed_caps; + gboolean changed_caps, use_dmabuf_memory; if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) goto error_invalid_config; if (!caps || !gst_video_info_from_caps (new_vip, caps)) goto error_no_caps; + use_dmabuf_memory = gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_DMABUF_MEMORY); + if (priv->use_dmabuf_memory != use_dmabuf_memory) { + priv->use_dmabuf_memory = use_dmabuf_memory; + g_clear_object (&priv->allocator); + } + changed_caps = !priv->allocator || GST_VIDEO_INFO_FORMAT (cur_vip) != GST_VIDEO_INFO_FORMAT (new_vip) || GST_VIDEO_INFO_WIDTH (cur_vip) != GST_VIDEO_INFO_WIDTH (new_vip) || GST_VIDEO_INFO_HEIGHT (cur_vip) != GST_VIDEO_INFO_HEIGHT (new_vip); if (changed_caps) { - allocator = gst_vaapi_video_allocator_new (priv->display, new_vip, 0); + const GstVideoInfo *alloc_vip; + guint flags = 0; + + if (use_dmabuf_memory) { + /* XXX: also needs fixed strides/offsets */ + flags |= GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE; + allocator = + gst_vaapi_dmabuf_allocator_new (priv->display, new_vip, flags); + } else { + allocator = gst_vaapi_video_allocator_new (priv->display, new_vip, 0); + } if (!allocator) goto error_create_allocator; gst_object_replace ((GstObject **) & priv->allocator, GST_OBJECT_CAST (allocator)); gst_object_unref (allocator); priv->video_info_index ^= 1; + + alloc_vip = gst_allocator_get_vaapi_video_info (allocator, NULL); + if (!alloc_vip) + goto error_create_allocator_info; + priv->alloc_info = *alloc_vip; } if (!gst_buffer_pool_config_has_option (config, @@ -199,6 +222,11 @@ error_create_allocator: GST_ERROR ("failed to create GstVaapiVideoAllocator object"); return FALSE; } +error_create_allocator_info: + { + GST_ERROR ("failed to create GstVaapiVideoAllocator `video-info'"); + return FALSE; + } error_no_vaapi_video_meta_option: { GST_ERROR ("no GstVaapiVideoMeta option"); @@ -235,15 +263,17 @@ gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool, if (!buffer) goto error_create_buffer; - mem = gst_vaapi_video_memory_new (priv->allocator, meta); + if (priv->use_dmabuf_memory) + mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); + else + mem = gst_vaapi_video_memory_new (priv->allocator, meta); if (!mem) goto error_create_memory; gst_vaapi_video_meta_replace (&meta, NULL); gst_buffer_append_memory (buffer, mem); if (priv->has_video_meta) { - GstVideoInfo *const vip = - &GST_VAAPI_VIDEO_ALLOCATOR_CAST (priv->allocator)->image_info; + GstVideoInfo *const vip = &priv->alloc_info; GstVideoMeta *vmeta; vmeta = gst_buffer_add_video_meta_full (buffer, 0, @@ -251,9 +281,13 @@ gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool, GST_VIDEO_INFO_HEIGHT (vip), GST_VIDEO_INFO_N_PLANES (vip), &GST_VIDEO_INFO_PLANE_OFFSET (vip, 0), &GST_VIDEO_INFO_PLANE_STRIDE (vip, 0)); - vmeta->map = gst_video_meta_map_vaapi_memory; - vmeta->unmap = gst_video_meta_unmap_vaapi_memory; + + if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) { + vmeta->map = gst_video_meta_map_vaapi_memory; + vmeta->unmap = gst_video_meta_unmap_vaapi_memory; + } } + #if GST_CHECK_VERSION(1,1,0) && USE_GLX if (priv->has_texture_upload_meta) gst_buffer_add_texture_upload_meta (buffer); @@ -295,7 +329,8 @@ gst_vaapi_video_buffer_pool_reset_buffer (GstBufferPool * pool, GstMemory *const mem = gst_buffer_peek_memory (buffer, 0); /* Release the underlying surface proxy */ - gst_vaapi_video_memory_reset_surface (GST_VAAPI_VIDEO_MEMORY_CAST (mem)); + if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) + gst_vaapi_video_memory_reset_surface (GST_VAAPI_VIDEO_MEMORY_CAST (mem)); GST_BUFFER_POOL_CLASS (gst_vaapi_video_buffer_pool_parent_class)->reset_buffer (pool, buffer); @@ -344,6 +379,7 @@ gst_vaapi_video_buffer_pool_init (GstVaapiVideoBufferPool * pool) gst_video_info_init (&priv->video_info[0]); gst_video_info_init (&priv->video_info[1]); + gst_video_info_init (&priv->alloc_info); } GstBufferPool * diff --git a/gst/vaapi/gstvaapivideobufferpool.h b/gst/vaapi/gstvaapivideobufferpool.h index 7ced82bade..1ff3f57b7a 100644 --- a/gst/vaapi/gstvaapivideobufferpool.h +++ b/gst/vaapi/gstvaapivideobufferpool.h @@ -69,6 +69,17 @@ typedef struct _GstVaapiVideoBufferPoolPrivate GstVaapiVideoBufferPoolPrivate; "GstBufferPoolOptionVideoGLTextureUploadMeta" #endif +/** + * GST_BUFFER_POOL_OPTION_DMABUF_MEMORY: + * + * An option that can be activated on bufferpool to request dmabuf + * handles on buffers from the pool. + */ +#ifndef GST_BUFFER_POOL_OPTION_DMABUF_MEMORY +#define GST_BUFFER_POOL_OPTION_DMABUF_MEMORY \ + "GstBufferPoolOptionDMABUFMemory" +#endif + /** * GstVaapiVideoBufferPoolAcquireFlags: * @GST_VAAPI_VIDEO_BUFFER_POOL_ACQUIRE_FLAG_NO_ALLOC: option to diff --git a/gst/vaapi/gstvaapivideomemory.c b/gst/vaapi/gstvaapivideomemory.c index 33674f5e8a..04b49f247e 100644 --- a/gst/vaapi/gstvaapivideomemory.c +++ b/gst/vaapi/gstvaapivideomemory.c @@ -21,6 +21,7 @@ */ #include "gst/vaapi/sysdeps.h" +#include #include #include #include "gstvaapivideomemory.h" @@ -298,6 +299,8 @@ gst_vaapi_video_memory_new (GstAllocator * base_allocator, const GstVideoInfo *vip; GstVaapiVideoMemory *mem; + g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), NULL); + mem = g_slice_new (GstVaapiVideoMemory); if (!mem) return NULL; @@ -725,6 +728,9 @@ gst_vaapi_video_allocator_new (GstVaapiDisplay * display, &allocator->image_info); if (!allocator->image_pool) goto error_create_image_pool; + + gst_allocator_set_vaapi_video_info (GST_ALLOCATOR_CAST (allocator), + &allocator->image_info, 0); return GST_ALLOCATOR_CAST (allocator); /* ERRORS */ @@ -741,3 +747,260 @@ error_create_image_pool: return NULL; } } + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufMemory --- */ +/* ------------------------------------------------------------------------ */ + +#define GST_VAAPI_BUFFER_PROXY_QUARK gst_vaapi_buffer_proxy_quark_get () +static GQuark +gst_vaapi_buffer_proxy_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("GstVaapiBufferProxy"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +GstMemory * +gst_vaapi_dmabuf_memory_new (GstAllocator * allocator, GstVaapiVideoMeta * meta) +{ + GstMemory *mem; + GstVaapiDisplay *display; + GstVaapiSurface *surface; + GstVaapiSurfaceProxy *proxy; + GstVaapiBufferProxy *dmabuf_proxy; + const GstVideoInfo *vip; + guint flags; + + g_return_val_if_fail (allocator != NULL, NULL); + g_return_val_if_fail (meta != NULL, NULL); + + vip = gst_allocator_get_vaapi_video_info (allocator, &flags); + if (!vip) + return NULL; + + display = gst_vaapi_video_meta_get_display (meta); + if (!meta) + return NULL; + + surface = gst_vaapi_surface_new_full (display, vip, flags); + if (!surface) + goto error_create_surface; + + proxy = gst_vaapi_surface_proxy_new (surface); + if (!proxy) + goto error_create_surface_proxy; + + dmabuf_proxy = gst_vaapi_surface_get_dma_buf_handle (surface); + gst_vaapi_object_unref (surface); + if (!dmabuf_proxy) + goto error_create_dmabuf_proxy; + + gst_vaapi_video_meta_set_surface_proxy (meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + + mem = gst_dmabuf_allocator_alloc (allocator, + gst_vaapi_buffer_proxy_get_handle (dmabuf_proxy), + gst_vaapi_buffer_proxy_get_size (dmabuf_proxy)); + if (!mem) + goto error_create_dmabuf_memory; + + gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem), + GST_VAAPI_BUFFER_PROXY_QUARK, dmabuf_proxy, + (GDestroyNotify) gst_vaapi_buffer_proxy_unref); + return mem; + + /* ERRORS */ +error_create_surface: + { + GST_ERROR ("failed to create VA surface (format:%s size:%ux%u)", + gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (vip)), + GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip)); + return NULL; + } +error_create_surface_proxy: + { + GST_ERROR ("failed to create VA surface proxy"); + gst_vaapi_object_unref (surface); + return NULL; + } +error_create_dmabuf_proxy: + { + GST_ERROR ("failed to export VA surface to DMABUF"); + gst_vaapi_surface_proxy_unref (proxy); + return NULL; + } +error_create_dmabuf_memory: + { + GST_ERROR ("failed to create DMABUF memory"); + gst_vaapi_buffer_proxy_unref (dmabuf_proxy); + return NULL; + } +} + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufAllocator --- */ +/* ------------------------------------------------------------------------ */ + +GstAllocator * +gst_vaapi_dmabuf_allocator_new (GstVaapiDisplay * display, + const GstVideoInfo * vip, guint flags) +{ + GstAllocator *allocator = NULL; + GstVaapiSurface *surface = NULL; + GstVaapiImage *image = NULL; + GstVideoInfo alloc_info; + + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (vip != NULL, NULL); + + do { + surface = gst_vaapi_surface_new_full (display, vip, flags); + if (!surface) + break; + + image = gst_vaapi_surface_derive_image (surface); + if (!image || !gst_vaapi_image_map (image)) + break; + + gst_video_info_set_format (&alloc_info, GST_VIDEO_INFO_FORMAT (vip), + GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip)); + gst_video_info_update_from_image (&alloc_info, image); + gst_vaapi_image_unmap (image); + + allocator = gst_dmabuf_allocator_new (); + if (!allocator) + break; + gst_allocator_set_vaapi_video_info (allocator, &alloc_info, flags); + } while (0); + + gst_vaapi_object_replace (&image, NULL); + gst_vaapi_object_replace (&surface, NULL); + return allocator; +} + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiVideoInfo = { GstVideoInfo, flags } --- */ +/* ------------------------------------------------------------------------ */ + +static GstVideoInfo * +gst_vaapi_video_info_copy (const GstVideoInfo * vip) +{ + GstVideoInfo *out_vip; + + out_vip = g_slice_new (GstVideoInfo); + if (!out_vip) + return NULL; + + gst_video_info_init (out_vip); + *out_vip = *vip; + return out_vip; +} + +static void +gst_vaapi_video_info_free (GstVideoInfo * vip) +{ + g_slice_free (GstVideoInfo, vip); +} + +#define GST_VAAPI_TYPE_VIDEO_INFO gst_vaapi_video_info_get_type () +static GType +gst_vaapi_video_info_get_type (void) +{ + static gsize g_type; + + if (g_once_init_enter (&g_type)) { + GType type; + type = g_boxed_type_register_static ("GstVaapiVideoInfo", + (GBoxedCopyFunc) gst_vaapi_video_info_copy, + (GBoxedFreeFunc) gst_vaapi_video_info_free); + g_once_init_leave (&g_type, type); + } + return (GType) g_type; +} + +#define GST_VAAPI_VIDEO_INFO_QUARK gst_vaapi_video_info_quark_get () +static GQuark +gst_vaapi_video_info_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("GstVaapiVideoInfo"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +#define INFO_QUARK info_quark_get () +static GQuark +info_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("info"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +#define FLAGS_QUARK flags_quark_get () +static GQuark +flags_quark_get (void) +{ + static gsize g_quark; + + if (g_once_init_enter (&g_quark)) { + gsize quark = (gsize) g_quark_from_static_string ("flags"); + g_once_init_leave (&g_quark, quark); + } + return g_quark; +} + +const GstVideoInfo * +gst_allocator_get_vaapi_video_info (GstAllocator * allocator, + guint * out_flags_ptr) +{ + const GstStructure *structure; + const GValue *value; + + g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), NULL); + + structure = + g_object_get_qdata (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK); + if (!structure) + return NULL; + + if (out_flags_ptr) { + value = gst_structure_id_get_value (structure, FLAGS_QUARK); + if (!value) + return NULL; + *out_flags_ptr = g_value_get_uint (value); + } + + value = gst_structure_id_get_value (structure, INFO_QUARK); + if (!value) + return NULL; + return g_value_get_boxed (value); +} + +gboolean +gst_allocator_set_vaapi_video_info (GstAllocator * allocator, + const GstVideoInfo * vip, guint flags) +{ + g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), FALSE); + g_return_val_if_fail (vip != NULL, FALSE); + + g_object_set_qdata_full (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK, + gst_structure_new_id (GST_VAAPI_VIDEO_INFO_QUARK, + INFO_QUARK, GST_VAAPI_TYPE_VIDEO_INFO, vip, + FLAGS_QUARK, G_TYPE_UINT, flags, NULL), + (GDestroyNotify) gst_structure_free); + + return TRUE; +} diff --git a/gst/vaapi/gstvaapivideomemory.h b/gst/vaapi/gstvaapivideomemory.h index ba29564a25..d3c6151a55 100644 --- a/gst/vaapi/gstvaapivideomemory.h +++ b/gst/vaapi/gstvaapivideomemory.h @@ -28,6 +28,9 @@ #include #include #include "gstvaapivideometa.h" +#if GST_CHECK_VERSION(1,1,0) +#include +#endif G_BEGIN_DECLS @@ -113,6 +116,10 @@ struct _GstVaapiVideoMemory gboolean use_direct_rendering; }; +G_GNUC_INTERNAL +GQuark +gst_vaapi_video_memory_quark_get (void); + G_GNUC_INTERNAL GstMemory * gst_vaapi_video_memory_new (GstAllocator * allocator, GstVaapiVideoMeta * meta); @@ -189,6 +196,32 @@ GstAllocator * gst_vaapi_video_allocator_new (GstVaapiDisplay * display, const GstVideoInfo * vip, guint flags); +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufMemory --- */ +/* ------------------------------------------------------------------------ */ + +G_GNUC_INTERNAL +GstMemory * +gst_vaapi_dmabuf_memory_new (GstAllocator * allocator, + GstVaapiVideoMeta * meta); + +/* ------------------------------------------------------------------------ */ +/* --- GstVaapiDmaBufAllocator --- */ +/* ------------------------------------------------------------------------ */ + +G_GNUC_INTERNAL +GstAllocator * +gst_vaapi_dmabuf_allocator_new (GstVaapiDisplay * display, + const GstVideoInfo * vip, guint flags); + +const GstVideoInfo * +gst_allocator_get_vaapi_video_info (GstAllocator * allocator, + guint * out_flags_ptr); + +gboolean +gst_allocator_set_vaapi_video_info (GstAllocator * allocator, + const GstVideoInfo * vip, guint flags); + G_END_DECLS #endif /* GST_VAAPI_VIDEO_MEMORY_H */