plugins: add support for dma_buf imports.

Allow imports of v4l2 buffers into VA surfaces for further operation
with vaapi plugins, e.g. vaapipostproc or vaapiencode_* elements.

https://bugzilla.gnome.org/show_bug.cgi?id=735362

[fixed memory leaks, ported to new dma_buf infrastructure, cleanups]
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
This commit is contained in:
Wind Yuan 2014-01-23 05:00:09 -05:00 committed by Gwenole Beauchesne
parent 797632139f
commit 667749c67e
3 changed files with 118 additions and 1 deletions

View file

@ -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])

View file

@ -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)

View file

@ -23,6 +23,7 @@
*/
#include "gst/vaapi/sysdeps.h"
#include <gst/vaapi/gstvaapisurface_drm.h>
#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 <gst/allocators/allocators.h>
#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");