msdk: vpp: Add supprot for dmabuf-import

MediaSDK requires all the input and output buffers to be
pre-allocated during init phase and this won't work with
current design of GStreamer or gst-msdk. But this can be
done with https://bugzilla.gnome.org/show_bug.cgi?id=795747

There is a workaround possible as per
https://github.com/Intel-Media-SDK/MediaSDK/issues/155#issuecomment-381790504
by faking the mem-id during MFXInit.
This patch do this in gst-msdk by replacing the MemID of mfxSurface
with dmabuf-backed vasurface dynamically.

Important: v4l2 ! msdkvpp won't work without a copy because
of the GMMLib (https://github.com/intel/gmmlib) memory restrictions.

https://bugzilla.gnome.org/show_bug.cgi?id=794817
This commit is contained in:
Sreerenj Balachandran 2018-05-30 16:24:24 -08:00
parent a7b7939dd7
commit a972d76784

View file

@ -44,6 +44,10 @@
#include "gstmsdkcontextutil.h" #include "gstmsdkcontextutil.h"
#include "gstmsdkvpputil.h" #include "gstmsdkvpputil.h"
#ifndef _WIN32
#include "gstmsdkallocator_libva.h"
#endif
GST_DEBUG_CATEGORY_EXTERN (gst_msdkvpp_debug); GST_DEBUG_CATEGORY_EXTERN (gst_msdkvpp_debug);
#define GST_CAT_DEFAULT gst_msdkvpp_debug #define GST_CAT_DEFAULT gst_msdkvpp_debug
@ -508,11 +512,76 @@ get_surface_from_pool (GstMsdkVPP * thiz, GstBufferPool * pool,
return msdk_surface; return msdk_surface;
} }
static gboolean
import_dmabuf_to_msdk_surface (GstMsdkVPP * thiz, GstBuffer * buf,
MsdkSurface * msdk_surface)
{
GstMemory *mem = NULL;
GstVideoInfo vinfo;
GstVideoMeta *vmeta;
GstMsdkMemoryID *msdk_mid = NULL;
mfxFrameSurface1 *mfx_surface = NULL;
gint fd, i;
mem = gst_buffer_peek_memory (buf, 0);
fd = gst_dmabuf_memory_get_fd (mem);
if (fd < 0)
return FALSE;
vinfo = thiz->sinkpad_info;
/* Update offset/stride/size if there is VideoMeta attached to
* the buffer */
vmeta = gst_buffer_get_video_meta (buf);
if (vmeta) {
if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
"the negotiated width/height/format");
return FALSE;
}
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
}
GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
}
/* Upstream neither accepted the msdk pool nor the msdk buffer size restrictions.
* Current media-driver and GMMLib will fail due to strict memory size restrictions.
* Ideally, media-driver should accept what ever memory coming from other drivers
* in case of dmabuf-import and this is how the intel-vaapi-driver works.
* For now, in order to avoid any crash we check the buffer size and fallback
* to copy frame method.
*
* See this: https://github.com/intel/media-driver/issues/169
* */
if (GST_VIDEO_INFO_SIZE (&vinfo) <
GST_VIDEO_INFO_SIZE (&thiz->sinkpad_buffer_pool_info))
return FALSE;
mfx_surface = msdk_surface->surface;
msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
/* release the internal memory storage of associated mfxSurface */
gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID);
/* export dmabuf to vasurface */
if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd,
msdk_mid->surface))
return FALSE;
return TRUE;
}
static MsdkSurface * static MsdkSurface *
get_msdk_surface_from_input_buffer (GstMsdkVPP * thiz, GstBuffer * inbuf) get_msdk_surface_from_input_buffer (GstMsdkVPP * thiz, GstBuffer * inbuf)
{ {
GstVideoFrame src_frame, out_frame; GstVideoFrame src_frame, out_frame;
MsdkSurface *msdk_surface; MsdkSurface *msdk_surface;
GstMemory *mem = NULL;
if (gst_msdk_is_msdk_buffer (inbuf)) { if (gst_msdk_is_msdk_buffer (inbuf)) {
msdk_surface = g_slice_new0 (MsdkSurface); msdk_surface = g_slice_new0 (MsdkSurface);
@ -522,12 +591,26 @@ get_msdk_surface_from_input_buffer (GstMsdkVPP * thiz, GstBuffer * inbuf)
} }
/* If upstream hasn't accpeted the proposed msdk bufferpool, /* If upstream hasn't accpeted the proposed msdk bufferpool,
* just copy frame to msdk buffer and take a surface from it. * just copy frame (if not dmabuf backed) to msdk buffer and
*/ * take a surface from it. */
if (!(msdk_surface = if (!(msdk_surface =
get_surface_from_pool (thiz, thiz->sinkpad_buffer_pool, NULL))) get_surface_from_pool (thiz, thiz->sinkpad_buffer_pool, NULL)))
goto error; goto error;
#ifndef _WIN32
/************ dmabuf-import ************* */
/* if upstream provided a dmabuf backed memory, but not an msdk
* buffer, we could export the dmabuf to underlined vasurface */
mem = gst_buffer_peek_memory (inbuf, 0);
if (gst_is_dmabuf_memory (mem)) {
if (import_dmabuf_to_msdk_surface (thiz, inbuf, msdk_surface))
return msdk_surface;
else
GST_INFO_OBJECT (thiz, "Upstream dmabuf-backed memory is not imported"
"to the msdk surface, fall back to the copy input frame method");
}
#endif
if (!gst_video_frame_map (&src_frame, &thiz->sinkpad_info, inbuf, if (!gst_video_frame_map (&src_frame, &thiz->sinkpad_info, inbuf,
GST_MAP_READ)) { GST_MAP_READ)) {
GST_ERROR_OBJECT (thiz, "failed to map the frame for source"); GST_ERROR_OBJECT (thiz, "failed to map the frame for source");