diff --git a/configure.ac b/configure.ac index cbe9962f1b..92e25a6d05 100644 --- a/configure.ac +++ b/configure.ac @@ -305,6 +305,10 @@ PKG_CHECK_MODULES([GST_INTERFACES], [gstreamer-interfaces-$GST_PKG_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED]) fi +dnl ... gst_dmabuf_memory_get_fd (gstreamer-allocators) +PKG_CHECK_MODULES([GST_ALLOCATORS], + [gstreamer-allocators-$GST_PKG_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED]) + dnl ... GstVideoOverlayComposition (gstreamer-video) PKG_CHECK_MODULES([GST_VIDEO], [gstreamer-video-$GST_PKG_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED]) diff --git a/gst/vaapi/Makefile.am b/gst/vaapi/Makefile.am index 58800db59c..ffaa26bac4 100644 --- a/gst/vaapi/Makefile.am +++ b/gst/vaapi/Makefile.am @@ -150,7 +150,8 @@ libgstvaapi_la_CFLAGS = \ $(GST_VIDEO_CFLAGS) \ $(GST_INTERFACES_CFLAGS) \ $(GST_BASEVIDEO_CFLAGS) \ - $(GST_PLUGINS_BASE_CFLAGS) + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_ALLOCATORS_CFLAGS) libgstvaapi_la_LIBADD = \ $(libgstvaapi_LIBS) \ @@ -160,6 +161,7 @@ libgstvaapi_la_LIBADD = \ $(GST_INTERFACES_LIBS) \ $(GST_BASEVIDEO_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \ + $(GST_ALLOCATORS_LIBS) \ $(top_builddir)/gst-libs/gst/video/libgstvaapi-videoutils.la libgstvaapi_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/gst/vaapi/gstvaapipluginbase.c b/gst/vaapi/gstvaapipluginbase.c index 922260fa61..1a254060a1 100644 --- a/gst/vaapi/gstvaapipluginbase.c +++ b/gst/vaapi/gstvaapipluginbase.c @@ -23,6 +23,7 @@ */ #include "gst/vaapi/sysdeps.h" +#include #include "gstvaapipluginbase.h" #include "gstvaapipluginutil.h" #include "gstvaapivideocontext.h" @@ -30,6 +31,9 @@ #if GST_CHECK_VERSION(1,0,0) #include "gstvaapivideobufferpool.h" #endif +#if GST_CHECK_VERSION(1,1,0) +#include +#endif /* Default debug category is from the subclass */ #define GST_CAT_DEFAULT (plugin->debug_category) @@ -127,6 +131,98 @@ default_display_changed (GstVaapiPluginBase * plugin) { } +static gboolean +plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin, + GstBuffer * buf) +{ + GstVideoInfo *const vip = &plugin->sinkpad_info; + GstVideoMeta *vmeta; + guint i; + + vmeta = gst_buffer_get_video_meta (buf); + if (!vmeta) + return TRUE; + + if (GST_VIDEO_INFO_FORMAT (vip) != vmeta->format || + GST_VIDEO_INFO_WIDTH (vip) != vmeta->width || + GST_VIDEO_INFO_HEIGHT (vip) != vmeta->height || + GST_VIDEO_INFO_N_PLANES (vip) != vmeta->n_planes) + return FALSE; + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); ++i) { + GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = vmeta->offset[i]; + GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = vmeta->stride[i]; + } + GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf); + return TRUE; +} + +#if GST_CHECK_VERSION(1,1,0) +static gboolean +is_dma_buffer (GstBuffer * buf) +{ + GstMemory *mem; + + if (gst_buffer_n_memory (buf) < 1) + return FALSE; + + mem = gst_buffer_peek_memory (buf, 0); + if (!mem || !gst_is_dmabuf_memory (mem)) + return FALSE; + return TRUE; +} + +static gboolean +plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin, + GstBuffer * inbuf, GstBuffer * outbuf) +{ + GstVideoInfo *const vip = &plugin->sinkpad_info; + GstVaapiVideoMeta *meta; + GstVaapiSurface *surface; + GstVaapiSurfaceProxy *proxy; + gint fd; + + fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0)); + if (fd < 0) + return FALSE; + + if (!plugin_update_sinkpad_info_from_buffer (plugin, inbuf)) + goto error_update_sinkpad_info; + + meta = gst_buffer_get_vaapi_video_meta (outbuf); + g_return_val_if_fail (meta != NULL, FALSE); + + surface = gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd, + GST_VIDEO_INFO_SIZE (vip), GST_VIDEO_INFO_FORMAT (vip), + GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip), + vip->offset, vip->stride); + if (!surface) + goto error_create_surface; + + proxy = gst_vaapi_surface_proxy_new (surface); + gst_vaapi_object_unref (surface); + if (!proxy) + goto error_create_proxy; + + gst_vaapi_surface_proxy_set_destroy_notify (proxy, + (GDestroyNotify) gst_buffer_unref, (gpointer) gst_buffer_ref (inbuf)); + gst_vaapi_video_meta_set_surface_proxy (meta, proxy); + gst_vaapi_surface_proxy_unref (proxy); + return TRUE; + + /* ERRORS */ +error_update_sinkpad_info: + GST_ERROR ("failed to update sink pad video info from video meta"); + return FALSE; +error_create_surface: + GST_ERROR ("failed to create VA surface from dma_buf handle"); + return FALSE; +error_create_proxy: + GST_ERROR ("failed to create VA surface proxy from wrapped VA surface"); + return FALSE; +} +#endif + void gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass) { @@ -686,6 +782,14 @@ gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin, &outbuf, NULL) != GST_FLOW_OK) goto error_create_buffer; +#if GST_CHECK_VERSION(1,1,0) + if (is_dma_buffer (inbuf)) { + if (!plugin_bind_dma_to_vaapi_buffer (plugin, inbuf, outbuf)) + goto error_bind_dma_buffer; + goto done; + } +#endif + if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf, GST_MAP_READ)) goto error_map_src_buffer; @@ -700,6 +804,7 @@ gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin, if (!success) goto error_copy_buffer; +done: gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); *outbuf_ptr = outbuf; @@ -758,6 +863,12 @@ error_create_buffer: GST_ERROR ("failed to create buffer"); return GST_FLOW_ERROR; } +error_bind_dma_buffer: + { + GST_ERROR ("failed to bind dma_buf to VA surface buffer"); + gst_buffer_unref (outbuf); + return GST_FLOW_ERROR; + } error_copy_buffer: { GST_WARNING ("failed to upload buffer to VA surface");