mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-13 12:51:16 +00:00
907aca399f
drm_fourcc.h should be picked up via the pkgconfig include, not the system includedir directly. Also consolidate the libdrm usage in va and msdk. All this allows it to be picked up consistently (via the subproject, for example). Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6932>
826 lines
25 KiB
C
826 lines
25 KiB
C
/* GStreamer Intel MSDK plugin
|
|
* Copyright (c) 2018, Intel Corporation
|
|
* Copyright (c) 2018, Igalia S.L.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGDECE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <va/va.h>
|
|
#include <va/va_drmcommon.h>
|
|
#include <drm_fourcc.h>
|
|
#include <unistd.h>
|
|
#include "gstmsdkallocator.h"
|
|
#include "gstmsdkallocator_libva.h"
|
|
#include "msdk_libva.h"
|
|
|
|
#include <gst/va/gstvaallocator.h>
|
|
|
|
#define GST_MSDK_FRAME_SURFACE gst_msdk_frame_surface_quark_get ()
|
|
|
|
static void
|
|
gst_msdk_surface_list_free (GstMsdkSurface * surface)
|
|
{
|
|
gst_buffer_unref (surface->buf);
|
|
g_slice_free (GstMsdkSurface, surface);
|
|
}
|
|
|
|
mfxStatus
|
|
gst_msdk_frame_alloc (mfxHDL pthis, mfxFrameAllocRequest * req,
|
|
mfxFrameAllocResponse * resp)
|
|
{
|
|
mfxStatus status = MFX_ERR_NONE;
|
|
gint i;
|
|
GstMsdkSurface *msdk_surface = NULL;
|
|
mfxMemId *mids = NULL;
|
|
GstMsdkContext *context = (GstMsdkContext *) pthis;
|
|
GstMsdkAllocResponse *msdk_resp = NULL;
|
|
mfxU32 fourcc = req->Info.FourCC;
|
|
mfxU16 surfaces_num = req->NumFrameSuggested;
|
|
GList *tmp_list = NULL;
|
|
VAStatus va_status;
|
|
|
|
/* MFX_MAKEFOURCC('V','P','8','S') is used for MFX_FOURCC_VP9_SEGMAP surface
|
|
* in MSDK and this surface is an internal surface. The external allocator
|
|
* shouldn't be used for this surface allocation
|
|
*
|
|
* See https://github.com/Intel-Media-SDK/MediaSDK/issues/762
|
|
*/
|
|
if (req->Type & MFX_MEMTYPE_INTERNAL_FRAME
|
|
&& fourcc == MFX_MAKEFOURCC ('V', 'P', '8', 'S'))
|
|
return MFX_ERR_UNSUPPORTED;
|
|
|
|
if (req->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
|
|
GstMsdkAllocResponse *cached =
|
|
gst_msdk_context_get_cached_alloc_responses_by_request (context, req);
|
|
if (cached) {
|
|
/* check if enough frames were allocated */
|
|
if (req->NumFrameSuggested > cached->response.NumFrameActual)
|
|
return MFX_ERR_MEMORY_ALLOC;
|
|
|
|
*resp = cached->response;
|
|
g_atomic_int_inc (&cached->refcount);
|
|
return MFX_ERR_NONE;
|
|
}
|
|
}
|
|
|
|
/* The VA API does not define any surface types and the application can use either
|
|
* MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET or
|
|
* MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET to indicate data in video memory.
|
|
*/
|
|
if (!(req->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET |
|
|
MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)))
|
|
return MFX_ERR_UNSUPPORTED;
|
|
|
|
mids = (mfxMemId *) g_slice_alloc0 (surfaces_num * sizeof (mfxMemId));
|
|
msdk_resp = g_slice_new0 (GstMsdkAllocResponse);
|
|
|
|
if (fourcc != MFX_FOURCC_P8) {
|
|
GstBufferPool *pool;
|
|
GstVideoFormat format;
|
|
GstStructure *config;
|
|
GstVideoInfo info;
|
|
GstCaps *caps;
|
|
GstVideoAlignment align;
|
|
guint min_buffers, max_buffers;
|
|
|
|
format = gst_msdk_get_video_format_from_mfx_fourcc (fourcc);
|
|
gst_video_info_set_format (&info, format, req->Info.CropW, req->Info.CropH);
|
|
|
|
gst_video_alignment_reset (&align);
|
|
gst_msdk_set_video_alignment
|
|
(&info, req->Info.Width, req->Info.Height, &align);
|
|
gst_video_info_align (&info, &align);
|
|
|
|
pool = gst_msdk_context_get_alloc_pool (context);
|
|
if (!pool) {
|
|
status = MFX_ERR_MEMORY_ALLOC;
|
|
goto error_alloc;
|
|
}
|
|
|
|
config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
|
|
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers,
|
|
&max_buffers)) {
|
|
status = MFX_ERR_MEMORY_ALLOC;
|
|
goto error_alloc;
|
|
}
|
|
|
|
max_buffers = MAX (max_buffers, surfaces_num);
|
|
gst_buffer_pool_config_set_params (config, caps,
|
|
GST_VIDEO_INFO_SIZE (&info), min_buffers, max_buffers);
|
|
gst_buffer_pool_config_add_option (config,
|
|
GST_BUFFER_POOL_OPTION_VIDEO_META);
|
|
gst_buffer_pool_config_add_option (config,
|
|
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
|
|
gst_buffer_pool_config_set_va_alignment (config, &align);
|
|
|
|
if (!gst_buffer_pool_set_config (pool, config)) {
|
|
GST_ERROR ("Failed to set pool config");
|
|
gst_object_unref (pool);
|
|
status = MFX_ERR_MEMORY_ALLOC;
|
|
goto error_alloc;
|
|
}
|
|
|
|
if (!gst_buffer_pool_set_active (pool, TRUE)) {
|
|
GST_ERROR ("Failed to activate pool");
|
|
gst_object_unref (pool);
|
|
status = MFX_ERR_MEMORY_ALLOC;
|
|
goto error_alloc;
|
|
}
|
|
|
|
for (i = 0; i < surfaces_num; i++) {
|
|
GstBuffer *buf;
|
|
|
|
if (gst_buffer_pool_acquire_buffer (pool, &buf, NULL) != GST_FLOW_OK) {
|
|
GST_ERROR ("Failed to allocate buffer");
|
|
gst_buffer_pool_set_active (pool, FALSE);
|
|
gst_object_unref (pool);
|
|
status = MFX_ERR_MEMORY_ALLOC;
|
|
goto error_alloc;
|
|
}
|
|
|
|
msdk_surface = gst_msdk_import_to_msdk_surface (buf, context, &info, 0);
|
|
|
|
if (!msdk_surface) {
|
|
GST_ERROR ("Failed to get GstMsdkSurface");
|
|
gst_buffer_pool_set_active (pool, FALSE);
|
|
gst_object_unref (pool);
|
|
status = MFX_ERR_MEMORY_ALLOC;
|
|
goto error_alloc;
|
|
}
|
|
|
|
msdk_surface->buf = buf;
|
|
mids[i] = msdk_surface->surface->Data.MemId;
|
|
tmp_list = g_list_prepend (tmp_list, msdk_surface);
|
|
}
|
|
} else {
|
|
/* This path is to handle a special case when requesting MFX_FOURCC_P208, We keep
|
|
* this to avoid failure when building gst-msdk plugins using old version of MediaSDK.
|
|
* These buffers will be used inside the driver and released by
|
|
* gst_msdk_frame_free functions. Application doesn't need to handle these buffers.
|
|
* See https://github.com/Intel-Media-SDK/samples/issues/13 for more details.
|
|
*/
|
|
VAContextID context_id = req->AllocId;
|
|
gint width32 = 32 * ((req->Info.Width + 31) >> 5);
|
|
gint height32 = 32 * ((req->Info.Height + 31) >> 5);
|
|
guint64 codedbuf_size = (width32 * height32) * 400LL / (16 * 16);
|
|
|
|
for (i = 0; i < surfaces_num; i++) {
|
|
VABufferID coded_buf;
|
|
GstMsdkMemoryID msdk_mid;
|
|
|
|
va_status = vaCreateBuffer (gst_msdk_context_get_handle (context),
|
|
context_id, VAEncCodedBufferType, codedbuf_size, 1, NULL, &coded_buf);
|
|
|
|
status = gst_msdk_get_mfx_status_from_va_status (va_status);
|
|
if (status < MFX_ERR_NONE) {
|
|
GST_ERROR ("failed to create buffer");
|
|
goto error_alloc;
|
|
}
|
|
|
|
msdk_mid.surface = coded_buf;
|
|
msdk_mid.fourcc = fourcc;
|
|
|
|
/* Don't use image for P208 */
|
|
msdk_mid.image.image_id = VA_INVALID_ID;
|
|
msdk_mid.image.buf = VA_INVALID_ID;
|
|
|
|
mids[i] = (mfxMemId *) & msdk_mid;
|
|
}
|
|
}
|
|
|
|
resp->mids = mids;
|
|
resp->NumFrameActual = surfaces_num;
|
|
|
|
msdk_resp->response = *resp;
|
|
msdk_resp->request = *req;
|
|
msdk_resp->refcount = 1;
|
|
|
|
gst_msdk_context_add_alloc_response (context, msdk_resp);
|
|
|
|
g_list_free_full (tmp_list, (GDestroyNotify) gst_msdk_surface_list_free);
|
|
|
|
return status;
|
|
|
|
error_alloc:
|
|
g_slice_free1 (surfaces_num * sizeof (mfxMemId), mids);
|
|
g_slice_free (GstMsdkAllocResponse, msdk_resp);
|
|
if (tmp_list)
|
|
g_list_free_full (tmp_list, (GDestroyNotify) gst_msdk_surface_list_free);
|
|
return status;
|
|
}
|
|
|
|
mfxStatus
|
|
gst_msdk_frame_free (mfxHDL pthis, mfxFrameAllocResponse * resp)
|
|
{
|
|
GstMsdkContext *context = (GstMsdkContext *) pthis;
|
|
GstMsdkAllocResponse *cached = NULL;
|
|
|
|
cached = gst_msdk_context_get_cached_alloc_responses (context, resp);
|
|
|
|
if (cached) {
|
|
if (!g_atomic_int_dec_and_test (&cached->refcount))
|
|
return MFX_ERR_NONE;
|
|
} else
|
|
return MFX_ERR_NONE;
|
|
|
|
if (!gst_msdk_context_remove_alloc_response (context, resp))
|
|
return MFX_ERR_NONE;
|
|
|
|
g_slice_free1 (resp->NumFrameActual * sizeof (mfxMemId), resp->mids);
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
mfxStatus
|
|
gst_msdk_frame_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * data)
|
|
{
|
|
GstMsdkContext *context = (GstMsdkContext *) pthis;
|
|
VAStatus va_status;
|
|
mfxStatus status;
|
|
mfxU8 *buf = NULL;
|
|
VASurfaceID va_surface;
|
|
VADisplay dpy;
|
|
GstMsdkMemoryID *mem_id;
|
|
|
|
mem_id = (GstMsdkMemoryID *) mid;
|
|
va_surface = mem_id->surface;
|
|
dpy = gst_msdk_context_get_handle (context);
|
|
|
|
if (mem_id->desc.num_objects) {
|
|
GST_WARNING ("Couldn't map the buffer since dmabuf is already in use");
|
|
return MFX_ERR_LOCK_MEMORY;
|
|
}
|
|
|
|
if (mem_id->fourcc != MFX_FOURCC_P8) {
|
|
va_status = vaDeriveImage (dpy, va_surface, &mem_id->image);
|
|
status = gst_msdk_get_mfx_status_from_va_status (va_status);
|
|
|
|
if (status != MFX_ERR_NONE) {
|
|
GST_WARNING ("failed to derive image");
|
|
return status;
|
|
}
|
|
|
|
va_status = vaMapBuffer (dpy, mem_id->image.buf, (void **) &buf);
|
|
status = gst_msdk_get_mfx_status_from_va_status (va_status);
|
|
|
|
if (status != MFX_ERR_NONE) {
|
|
GST_WARNING ("failed to map");
|
|
if (vaDestroyImage (dpy, mem_id->image.image_id) == VA_STATUS_SUCCESS) {
|
|
mem_id->image.image_id = VA_INVALID_ID;
|
|
mem_id->image.buf = VA_INVALID_ID;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
switch (mem_id->image.format.fourcc) {
|
|
case VA_FOURCC_NV12:
|
|
case VA_FOURCC_P010:
|
|
case VA_FOURCC_P016:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->Y = buf + mem_id->image.offsets[0];
|
|
data->UV = buf + mem_id->image.offsets[1];
|
|
break;
|
|
case VA_FOURCC_YV12:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->Y = buf + mem_id->image.offsets[0];
|
|
data->U = buf + mem_id->image.offsets[2];
|
|
data->V = buf + mem_id->image.offsets[1];
|
|
break;
|
|
case VA_FOURCC_YUY2:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->Y = buf + mem_id->image.offsets[0];
|
|
data->U = data->Y + 1;
|
|
data->V = data->Y + 3;
|
|
break;
|
|
case VA_FOURCC_UYVY:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->Y = buf + mem_id->image.offsets[0];
|
|
data->U = data->U + 1;
|
|
data->V = data->U + 2;
|
|
break;
|
|
case VA_FOURCC_ARGB:
|
|
case VA_FOURCC_XRGB:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->B = buf + mem_id->image.offsets[0];
|
|
data->G = data->B + 1;
|
|
data->R = data->B + 2;
|
|
data->A = data->B + 3;
|
|
break;
|
|
#if (MFX_VERSION >= 1028)
|
|
case VA_FOURCC_RGB565:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->R = buf + mem_id->image.offsets[0];
|
|
data->G = data->R;
|
|
data->B = data->R;
|
|
break;
|
|
#endif
|
|
case VA_FOURCC_AYUV:
|
|
data->PitchHigh = (mfxU16) (mem_id->image.pitches[0] / (1 << 16));
|
|
data->PitchLow = (mfxU16) (mem_id->image.pitches[0] % (1 << 16));
|
|
data->V = buf + mem_id->image.offsets[0];
|
|
data->U = data->V + 1;
|
|
data->Y = data->V + 2;
|
|
data->A = data->V + 3;
|
|
break;
|
|
case VA_FOURCC_A2R10G10B10:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->R = buf + mem_id->image.offsets[0];
|
|
data->G = data->R;
|
|
data->B = data->R;
|
|
data->A = data->R;
|
|
break;
|
|
case VA_FOURCC_Y210:
|
|
case VA_FOURCC_Y216:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->Y = buf + mem_id->image.offsets[0];
|
|
data->U = data->Y + 2;
|
|
data->V = data->Y + 6;
|
|
break;
|
|
case VA_FOURCC_Y410:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->U = buf + mem_id->image.offsets[0]; /* data->Y410 */
|
|
break;
|
|
case VA_FOURCC_Y416:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->U = buf + mem_id->image.offsets[0];
|
|
data->Y = data->U + 2;
|
|
data->V = data->U + 4;
|
|
data->A = data->U + 6;
|
|
break;
|
|
case VA_FOURCC_ABGR:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->R = buf + mem_id->image.offsets[0];
|
|
data->G = data->R + 1;
|
|
data->B = data->R + 2;
|
|
data->A = data->R + 3;
|
|
break;
|
|
|
|
#if (MFX_VERSION >= 2004)
|
|
case VA_FOURCC_RGBP:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->R = buf + mem_id->image.offsets[0];
|
|
data->G = buf + mem_id->image.offsets[1];
|
|
data->B = buf + mem_id->image.offsets[2];
|
|
break;
|
|
case VA_FOURCC_BGRP:
|
|
data->Pitch = mem_id->image.pitches[0];
|
|
data->B = buf + mem_id->image.offsets[0];
|
|
data->G = buf + mem_id->image.offsets[1];
|
|
data->R = buf + mem_id->image.offsets[2];
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
} else {
|
|
VACodedBufferSegment *coded_buffer_segment;
|
|
va_status =
|
|
vaMapBuffer (dpy, va_surface, (void **) (&coded_buffer_segment));
|
|
status = gst_msdk_get_mfx_status_from_va_status (va_status);
|
|
if (MFX_ERR_NONE == status)
|
|
data->Y = (mfxU8 *) coded_buffer_segment->buf;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
mfxStatus
|
|
gst_msdk_frame_unlock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
|
|
{
|
|
GstMsdkContext *context = (GstMsdkContext *) pthis;
|
|
VAStatus va_status;
|
|
mfxStatus status;
|
|
VADisplay dpy;
|
|
GstMsdkMemoryID *mem_id;
|
|
|
|
mem_id = (GstMsdkMemoryID *) mid;
|
|
dpy = gst_msdk_context_get_handle (context);
|
|
|
|
g_assert (mem_id->desc.num_objects == 0);
|
|
|
|
if (mem_id->fourcc != MFX_FOURCC_P8) {
|
|
vaUnmapBuffer (dpy, mem_id->image.buf);
|
|
va_status = vaDestroyImage (dpy, mem_id->image.image_id);
|
|
|
|
if (va_status == VA_STATUS_SUCCESS) {
|
|
mem_id->image.image_id = VA_INVALID_ID;
|
|
mem_id->image.buf = VA_INVALID_ID;
|
|
}
|
|
} else {
|
|
va_status = vaUnmapBuffer (dpy, mem_id->surface);
|
|
}
|
|
|
|
status = gst_msdk_get_mfx_status_from_va_status (va_status);
|
|
|
|
return status;
|
|
}
|
|
|
|
mfxStatus
|
|
gst_msdk_frame_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * hdl)
|
|
{
|
|
GstMsdkMemoryID *mem_id;
|
|
|
|
if (!hdl || !mid)
|
|
return MFX_ERR_INVALID_HANDLE;
|
|
|
|
mem_id = mid;
|
|
*hdl = &mem_id->surface;
|
|
|
|
return MFX_ERR_NONE;
|
|
}
|
|
|
|
void
|
|
gst_msdk_set_frame_allocator (GstMsdkContext * context)
|
|
{
|
|
mfxFrameAllocator gst_msdk_frame_allocator = {
|
|
.pthis = context,
|
|
.Alloc = gst_msdk_frame_alloc,
|
|
.Lock = gst_msdk_frame_lock,
|
|
.Unlock = gst_msdk_frame_unlock,
|
|
.GetHDL = gst_msdk_frame_get_hdl,
|
|
.Free = gst_msdk_frame_free,
|
|
};
|
|
|
|
gst_msdk_context_set_frame_allocator (context, &gst_msdk_frame_allocator);
|
|
}
|
|
|
|
gboolean
|
|
gst_msdk_get_dmabuf_info_from_surface (mfxFrameSurface1 * surface,
|
|
gint * handle, gsize * size)
|
|
{
|
|
GstMsdkMemoryID *mem_id;
|
|
g_return_val_if_fail (surface, FALSE);
|
|
|
|
mem_id = (GstMsdkMemoryID *) surface->Data.MemId;
|
|
|
|
g_assert (mem_id->desc.num_objects == 1);
|
|
|
|
if (handle)
|
|
*handle = mem_id->desc.objects[0].fd;
|
|
if (size)
|
|
*size = mem_id->desc.objects[0].size;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_msdk_export_dmabuf_to_vasurface (GstMsdkContext * context,
|
|
GstVideoInfo * vinfo, gint fd, VASurfaceID * surface_id)
|
|
{
|
|
GstVideoFormat format;
|
|
guint width, height, size, i;
|
|
unsigned long extbuf_handle;
|
|
guint va_fourcc = 0, va_chroma = 0;
|
|
VASurfaceAttrib attribs[2], *attrib;
|
|
VASurfaceAttribExternalBuffers extbuf;
|
|
VAStatus va_status;
|
|
mfxStatus status = MFX_ERR_NONE;
|
|
|
|
g_return_val_if_fail (context != NULL, FALSE);
|
|
g_return_val_if_fail (vinfo != NULL, FALSE);
|
|
g_return_val_if_fail (fd >= 0, FALSE);
|
|
|
|
extbuf_handle = (guintptr) (fd);
|
|
|
|
format = GST_VIDEO_INFO_FORMAT (vinfo);
|
|
width = GST_VIDEO_INFO_WIDTH (vinfo);
|
|
height = GST_VIDEO_INFO_HEIGHT (vinfo);
|
|
size = GST_VIDEO_INFO_SIZE (vinfo);
|
|
|
|
/* Fixme: Move to common format handling util */
|
|
switch (format) {
|
|
case GST_VIDEO_FORMAT_NV12:
|
|
va_chroma = VA_RT_FORMAT_YUV420;
|
|
va_fourcc = VA_FOURCC_NV12;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
va_chroma = VA_RT_FORMAT_YUV444;
|
|
va_fourcc = VA_FOURCC_BGRA;
|
|
break;
|
|
case GST_VIDEO_FORMAT_YUY2:
|
|
va_chroma = VA_RT_FORMAT_YUV422;
|
|
va_fourcc = VA_FOURCC_YUY2;
|
|
break;
|
|
case GST_VIDEO_FORMAT_P010_10LE:
|
|
va_chroma = VA_RT_FORMAT_YUV420_10;
|
|
va_fourcc = VA_FOURCC_P010;
|
|
break;
|
|
case GST_VIDEO_FORMAT_UYVY:
|
|
va_chroma = VA_RT_FORMAT_YUV422;
|
|
va_fourcc = VA_FOURCC_UYVY;
|
|
break;
|
|
#if (MFX_VERSION >= 1028)
|
|
case GST_VIDEO_FORMAT_RGB16:
|
|
va_chroma = VA_RT_FORMAT_RGB16;
|
|
va_fourcc = VA_FOURCC_RGB565;
|
|
break;
|
|
#endif
|
|
case GST_VIDEO_FORMAT_VUYA:
|
|
va_chroma = VA_RT_FORMAT_YUV444;
|
|
va_fourcc = VA_FOURCC_AYUV;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR10A2_LE:
|
|
va_chroma = VA_RT_FORMAT_RGB32_10;
|
|
va_fourcc = VA_FOURCC_A2R10G10B10;
|
|
break;
|
|
case GST_VIDEO_FORMAT_Y210:
|
|
va_chroma = VA_RT_FORMAT_YUV422_10;
|
|
va_fourcc = VA_FOURCC_Y210;
|
|
break;
|
|
case GST_VIDEO_FORMAT_Y410:
|
|
va_chroma = VA_RT_FORMAT_YUV444_10;
|
|
va_fourcc = VA_FOURCC_Y410;
|
|
break;
|
|
case GST_VIDEO_FORMAT_P012_LE:
|
|
va_chroma = VA_RT_FORMAT_YUV420_12;
|
|
va_fourcc = VA_FOURCC_P016;
|
|
break;
|
|
case GST_VIDEO_FORMAT_Y212_LE:
|
|
va_chroma = VA_RT_FORMAT_YUV422_12;
|
|
va_fourcc = VA_FOURCC_Y216;
|
|
break;
|
|
case GST_VIDEO_FORMAT_Y412_LE:
|
|
va_chroma = VA_RT_FORMAT_YUV444_12;
|
|
va_fourcc = VA_FOURCC_Y416;
|
|
break;
|
|
#if (MFX_VERSION >= 2004)
|
|
case GST_VIDEO_FORMAT_RGBP:
|
|
va_chroma = VA_RT_FORMAT_RGBP;
|
|
va_fourcc = VA_FOURCC_RGBP;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRP:
|
|
va_chroma = VA_RT_FORMAT_RGBP;
|
|
va_fourcc = VA_FOURCC_BGRP;
|
|
break;
|
|
#endif
|
|
default:
|
|
goto error_unsupported_format;
|
|
}
|
|
|
|
/* Fill the VASurfaceAttribExternalBuffers */
|
|
extbuf.pixel_format = va_fourcc;
|
|
extbuf.width = width;
|
|
extbuf.height = height;
|
|
extbuf.data_size = size;
|
|
extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
|
|
for (i = 0; i < extbuf.num_planes; i++) {
|
|
extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i);
|
|
extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i);
|
|
}
|
|
extbuf.buffers = (uintptr_t *) & extbuf_handle;
|
|
extbuf.num_buffers = 1;
|
|
extbuf.flags = 0;
|
|
extbuf.private_data = NULL;
|
|
|
|
/* Fill the Surface Attributes */
|
|
attrib = attribs;
|
|
attrib->type = VASurfaceAttribMemoryType;
|
|
attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
attrib->value.type = VAGenericValueTypeInteger;
|
|
attrib->value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
|
|
attrib++;
|
|
attrib->type = VASurfaceAttribExternalBufferDescriptor;
|
|
attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
attrib->value.type = VAGenericValueTypePointer;
|
|
attrib->value.value.p = &extbuf;
|
|
attrib++;
|
|
|
|
va_status = vaCreateSurfaces (gst_msdk_context_get_handle (context),
|
|
va_chroma, width, height, surface_id, 1, attribs, attrib - attribs);
|
|
status = gst_msdk_get_mfx_status_from_va_status (va_status);
|
|
if (status != MFX_ERR_NONE)
|
|
goto error_create_surface;
|
|
|
|
return TRUE;
|
|
|
|
error_unsupported_format:
|
|
{
|
|
GST_ERROR ("Unsupported Video format %s, Can't export dmabuf to vaSurface",
|
|
gst_video_format_to_string (format));
|
|
return FALSE;
|
|
}
|
|
error_create_surface:
|
|
{
|
|
GST_ERROR ("Failed to create the VASurface from DRM_PRIME FD");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_msdk_qdata_free (gpointer data)
|
|
{
|
|
mfxFrameSurface1 *mfx_surface = data;
|
|
|
|
if (mfx_surface->Data.Locked == 0) {
|
|
GstMsdkMemoryID *msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
|
|
|
|
g_slice_free (GstMsdkMemoryID, msdk_mid);
|
|
g_slice_free (mfxFrameSurface1, mfx_surface);
|
|
}
|
|
}
|
|
|
|
/* Currently parameter map_flag is not useful on Linux */
|
|
GstMsdkSurface *
|
|
gst_msdk_import_to_msdk_surface (GstBuffer * buf, GstMsdkContext * msdk_context,
|
|
GstVideoInfo * vinfo, guint map_flag)
|
|
{
|
|
VASurfaceID va_surface = VA_INVALID_ID;
|
|
GstMemory *mem = NULL;
|
|
mfxFrameInfo frame_info = { 0, };
|
|
GstMsdkSurface *msdk_surface = NULL;
|
|
mfxFrameSurface1 *mfx_surface = NULL;
|
|
GstMsdkMemoryID *msdk_mid = NULL;
|
|
GDestroyNotify qdata_destroy = NULL;
|
|
|
|
mem = gst_buffer_peek_memory (buf, 0);
|
|
msdk_surface = g_slice_new0 (GstMsdkSurface);
|
|
|
|
/* If buffer has qdata pointing to mfxFrameSurface1, directly extract it */
|
|
if ((mfx_surface = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem),
|
|
GST_MSDK_FRAME_SURFACE))) {
|
|
msdk_surface->surface = mfx_surface;
|
|
msdk_surface->from_qdata = TRUE;
|
|
return msdk_surface;
|
|
}
|
|
|
|
va_surface = gst_va_buffer_get_surface (buf);
|
|
|
|
if (va_surface == VA_INVALID_ID) {
|
|
g_slice_free (GstMsdkSurface, msdk_surface);
|
|
return NULL;
|
|
}
|
|
|
|
mfx_surface = g_slice_new0 (mfxFrameSurface1);
|
|
msdk_mid = g_slice_new0 (GstMsdkMemoryID);
|
|
|
|
msdk_mid->surface = va_surface;
|
|
|
|
mfx_surface->Data.MemId = (mfxMemId) msdk_mid;
|
|
|
|
gst_msdk_set_mfx_frame_info_from_video_info (&frame_info, vinfo);
|
|
mfx_surface->Info = frame_info;
|
|
|
|
qdata_destroy = gst_msdk_qdata_free;
|
|
/* Set mfxFrameSurface1 as qdata in buffer */
|
|
gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
|
|
GST_MSDK_FRAME_SURFACE, mfx_surface, qdata_destroy);
|
|
|
|
msdk_surface->surface = mfx_surface;
|
|
|
|
return msdk_surface;
|
|
}
|
|
|
|
/**
|
|
* gst_msdk_replace_mfx_memid:
|
|
* This method replace the internal VA Suface in mfxSurface with a new one
|
|
*
|
|
* Caution: Not a thread-safe routine, this method is here to work around
|
|
* the dmabuf-import use case with dynamic memID replacement where msdk
|
|
* originally Inited with fake memIDs.
|
|
*
|
|
* Don't use anywhere else unless you really know what you are doing!
|
|
*/
|
|
gboolean
|
|
gst_msdk_replace_mfx_memid (GstMsdkContext * context,
|
|
mfxFrameSurface1 * mfx_surface, VASurfaceID surface_id)
|
|
{
|
|
GstMsdkMemoryID *msdk_mid = NULL;
|
|
VADisplay dpy;
|
|
VASurfaceID old_surface_id;
|
|
VAStatus va_status;
|
|
mfxStatus status = MFX_ERR_NONE;
|
|
|
|
g_return_val_if_fail (mfx_surface != NULL, FALSE);
|
|
g_return_val_if_fail (context != NULL, FALSE);
|
|
|
|
msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
|
|
dpy = gst_msdk_context_get_handle (context);
|
|
|
|
/* Destroy the underlined VAImage if already mapped */
|
|
if (msdk_mid->image.image_id != VA_INVALID_ID
|
|
&& msdk_mid->image.buf != VA_INVALID_ID) {
|
|
status =
|
|
gst_msdk_frame_unlock ((mfxHDL) context, (mfxMemId) msdk_mid, NULL);
|
|
if (status != MFX_ERR_NONE)
|
|
goto error_destroy_va_image;
|
|
}
|
|
|
|
/* Destroy the associated VASurface */
|
|
old_surface_id = msdk_mid->surface;
|
|
if (old_surface_id != VA_INVALID_ID) {
|
|
va_status = vaDestroySurfaces (dpy, &old_surface_id, 1);
|
|
status = gst_msdk_get_mfx_status_from_va_status (va_status);
|
|
if (status != MFX_ERR_NONE)
|
|
goto error_destroy_va_surface;
|
|
}
|
|
|
|
msdk_mid->surface = surface_id;
|
|
|
|
return TRUE;
|
|
|
|
error_destroy_va_image:
|
|
{
|
|
GST_ERROR ("Failed to Destroy the VAImage");
|
|
return FALSE;
|
|
}
|
|
error_destroy_va_surface:
|
|
{
|
|
GST_ERROR ("Failed to Destroy the VASurfaceID %x", old_surface_id);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static guint
|
|
_get_usage_hint (GstMsdkContextJobType job_type)
|
|
{
|
|
guint hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
|
|
|
|
switch (job_type) {
|
|
case GST_MSDK_JOB_DECODER:
|
|
hint |= VA_SURFACE_ATTRIB_USAGE_HINT_DECODER;
|
|
break;
|
|
case GST_MSDK_JOB_ENCODER:
|
|
hint |= VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
|
|
break;
|
|
case GST_MSDK_JOB_VPP:
|
|
hint |= VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ |
|
|
VA_SURFACE_ATTRIB_USAGE_HINT_VPP_WRITE;
|
|
break;
|
|
default:
|
|
GST_WARNING ("Unsupported job type %d", job_type);
|
|
break;
|
|
}
|
|
|
|
return hint;
|
|
}
|
|
|
|
void
|
|
gst_msdk_get_supported_modifiers (GstMsdkContext * context,
|
|
GstMsdkContextJobType job_type, GstVideoFormat format, GValue * modifiers)
|
|
{
|
|
guint64 mod = DRM_FORMAT_MOD_INVALID;
|
|
guint64 mod_gen = DRM_FORMAT_MOD_INVALID;
|
|
GValue gmod = G_VALUE_INIT;
|
|
guint usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
|
|
GstVaDisplay *display =
|
|
(GstVaDisplay *) gst_msdk_context_get_va_display (context);
|
|
|
|
g_value_init (&gmod, G_TYPE_UINT64);
|
|
|
|
mod = gst_va_dmabuf_get_modifier_for_format (display, format, usage_hint);
|
|
if (mod != DRM_FORMAT_MOD_INVALID && mod != DRM_FORMAT_MOD_LINEAR) {
|
|
g_value_set_uint64 (&gmod, mod);
|
|
gst_value_list_append_value (modifiers, &gmod);
|
|
}
|
|
|
|
usage_hint = _get_usage_hint (job_type);
|
|
if (usage_hint != VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC) {
|
|
mod_gen =
|
|
gst_va_dmabuf_get_modifier_for_format (display, format, usage_hint);
|
|
if (mod_gen != mod && mod_gen != DRM_FORMAT_MOD_INVALID &&
|
|
mod_gen != DRM_FORMAT_MOD_LINEAR) {
|
|
g_value_set_uint64 (&gmod, mod_gen);
|
|
gst_value_list_append_value (modifiers, &gmod);
|
|
}
|
|
}
|
|
|
|
if (mod == DRM_FORMAT_MOD_LINEAR || mod_gen == DRM_FORMAT_MOD_LINEAR) {
|
|
g_value_set_uint64 (&gmod, DRM_FORMAT_MOD_LINEAR);
|
|
gst_value_list_append_value (modifiers, &gmod);
|
|
}
|
|
|
|
if (mod == DRM_FORMAT_MOD_INVALID && mod_gen == DRM_FORMAT_MOD_INVALID) {
|
|
GST_WARNING ("Failed to get modifier %s:0x%016llx",
|
|
gst_video_format_to_string (format), DRM_FORMAT_MOD_INVALID);
|
|
}
|
|
|
|
gst_object_unref (display);
|
|
g_value_unset (&gmod);
|
|
}
|