msdk: enc: Add supprot for dmabuf-import

MediaSDK requires all the input 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 in future once we have a solution for:
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 enabling it in gst-msdk by replacing the MemID of mfxSurface
with dmabuf-backed vasurface dynamically.

Important: v4l2 ! msdkenc 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:26:27 -08:00
parent a972d76784
commit 57b9875260

View file

@ -50,6 +50,10 @@
#include "gstmsdksystemmemory.h"
#include "gstmsdkcontextutil.h"
#ifndef _WIN32
#include "gstmsdkallocator_libva.h"
#endif
static inline void *
_aligned_alloc (size_t alignment, size_t size)
{
@ -1092,6 +1096,67 @@ gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz, GstBufferPool * pool,
return msdk_surface;
}
static gboolean
import_dmabuf_to_msdk_surface (GstMsdkEnc * 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->input_state->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->aligned_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 *
gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
GstVideoCodecFrame * frame)
@ -1099,6 +1164,7 @@ gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
GstVideoFrame src_frame, out_frame;
MsdkSurface *msdk_surface;
GstBuffer *inbuf;
GstMemory *mem = NULL;
inbuf = frame->input_buffer;
if (gst_msdk_is_msdk_buffer (inbuf)) {
@ -1107,22 +1173,27 @@ gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
return msdk_surface;
}
/* If the pipeline negotiated dmabuf (use_dmabuf == TRUE) and the
* upstream rejected the pool proposed by msdkencoder, then
* we won't be able create a mappalbe buffer from the internal pool.
*
* Fixme: One possible fix could be to maintain an internal pool backed by the
* videomemory always and providee a dmabuf-backed pool in propose_allocation */
if (thiz->use_dmabuf)
goto error_copying;
/* 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 =
gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_pool, NULL)))
goto error;
#ifndef _WIN32
/************ dmabuf-import ************* */
/* if upstream provided a dmabuf backed memory, but not an msdk
* buffer, we could try to 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->input_state->info, inbuf,
GST_MAP_READ)) {
GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
@ -1157,13 +1228,7 @@ error:
if (msdk_surface->buf)
gst_buffer_unref (msdk_surface->buf);
g_slice_free (MsdkSurface, msdk_surface);
return NULL;
}
error_copying:
GST_ERROR_OBJECT (thiz,
"Upstream rejected the proposed dmabuf pool, "
"and we can't copy the incoming buffers to msdk pool!");
return NULL;
}