| /* 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 "gstmsdkallocator.h" |
| #include "msdk_libva.h" |
| |
| mfxStatus |
| gst_msdk_frame_alloc (mfxHDL pthis, mfxFrameAllocRequest * req, |
| mfxFrameAllocResponse * resp) |
| { |
| VAStatus va_status; |
| mfxStatus status = MFX_ERR_NONE; |
| gint i; |
| guint format; |
| guint va_fourcc = 0; |
| VASurfaceID *surfaces = NULL; |
| VASurfaceAttrib attrib; |
| mfxMemId *mids = NULL; |
| GstMsdkContext *context = (GstMsdkContext *) pthis; |
| GstMsdkMemoryID *msdk_mids = NULL; |
| GstMsdkAllocResponse *msdk_resp = NULL; |
| mfxU32 fourcc = req->Info.FourCC; |
| mfxU16 surfaces_num = req->NumFrameSuggested; |
| |
| if (req->Type & MFX_MEMTYPE_EXTERNAL_FRAME) { |
| GstMsdkAllocResponse *cached = |
| gst_msdk_context_get_cached_alloc_responses_by_request (context, req); |
| if (cached) { |
| *resp = *cached->response; |
| 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; |
| |
| va_fourcc = gst_msdk_get_va_fourcc_from_mfx_fourcc (fourcc); |
| |
| msdk_mids = |
| (GstMsdkMemoryID *) g_slice_alloc0 (surfaces_num * |
| sizeof (GstMsdkMemoryID)); |
| mids = (mfxMemId *) g_slice_alloc0 (surfaces_num * sizeof (mfxMemId)); |
| surfaces = |
| (VASurfaceID *) g_slice_alloc0 (surfaces_num * sizeof (VASurfaceID)); |
| msdk_resp = |
| (GstMsdkAllocResponse *) g_slice_alloc0 (sizeof (GstMsdkAllocResponse)); |
| |
| if (va_fourcc != VA_FOURCC_P208) { |
| attrib.type = VASurfaceAttribPixelFormat; |
| attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; |
| attrib.value.type = VAGenericValueTypeInteger; |
| attrib.value.value.i = va_fourcc; |
| |
| format = |
| gst_msdk_get_va_rt_format_from_mfx_rt_format (req->Info.ChromaFormat); |
| |
| va_status = vaCreateSurfaces (gst_msdk_context_get_handle (context), |
| format, |
| req->Info.Width, req->Info.Height, surfaces, surfaces_num, &attrib, 1); |
| |
| status = gst_msdk_get_mfx_status_from_va_status (va_status); |
| if (status != MFX_ERR_NONE) { |
| GST_WARNING ("failed to create VA surface"); |
| return status; |
| } |
| |
| for (i = 0; i < surfaces_num; i++) { |
| msdk_mids[i].surface = &surfaces[i]; |
| mids[i] = (mfxMemId *) & msdk_mids[i]; |
| } |
| } else { |
| /* This is requested from the driver when h265 encoding. |
| * 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; |
| |
| 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"); |
| return status; |
| } |
| |
| surfaces[i] = coded_buf; |
| msdk_mids[i].surface = &surfaces[i]; |
| msdk_mids[i].fourcc = fourcc; |
| mids[i] = (mfxMemId *) & msdk_mids[i]; |
| } |
| } |
| |
| resp->mids = mids; |
| resp->NumFrameActual = surfaces_num; |
| |
| msdk_resp->response = resp; |
| msdk_resp->mem_ids = mids; |
| msdk_resp->request = *req; |
| |
| gst_msdk_context_add_alloc_response (context, msdk_resp); |
| |
| return status; |
| } |
| |
| mfxStatus |
| gst_msdk_frame_free (mfxHDL pthis, mfxFrameAllocResponse * resp) |
| { |
| GstMsdkContext *context = (GstMsdkContext *) pthis; |
| VAStatus va_status = VA_STATUS_SUCCESS; |
| mfxStatus status; |
| GstMsdkMemoryID *mem_id; |
| VADisplay dpy; |
| gint i; |
| |
| if (!gst_msdk_context_remove_alloc_response (context, resp)) |
| return MFX_ERR_NONE; |
| |
| mem_id = resp->mids[0]; |
| dpy = gst_msdk_context_get_handle (context); |
| |
| if (mem_id->fourcc != MFX_FOURCC_P8) { |
| /* Make sure that all the vaImages are destroyed */ |
| for (i = 0; i < resp->NumFrameActual; i++) { |
| GstMsdkMemoryID *mem = resp->mids[i]; |
| vaDestroyImage (dpy, mem->image.image_id); |
| } |
| |
| va_status = |
| vaDestroySurfaces (dpy, (VASurfaceID *) mem_id->surface, |
| resp->NumFrameActual); |
| } else { |
| VASurfaceID *surfaces = mem_id->surface; |
| |
| for (i = 0; i < resp->NumFrameActual; i++) { |
| va_status = vaDestroyBuffer (dpy, surfaces[i]); |
| } |
| } |
| |
| g_slice_free1 (resp->NumFrameActual * sizeof (VASurfaceID), mem_id->surface); |
| g_slice_free1 (resp->NumFrameActual * sizeof (GstMsdkMemoryID), mem_id); |
| g_slice_free1 (resp->NumFrameActual * sizeof (mfxMemId), resp->mids); |
| |
| status = gst_msdk_get_mfx_status_from_va_status (va_status); |
| return status; |
| } |
| |
| 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->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"); |
| return status; |
| } |
| |
| switch (mem_id->image.format.fourcc) { |
| case VA_FOURCC_NV12: |
| 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: |
| 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; |
| } |
| } 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); |
| |
| if (mem_id->fourcc != MFX_FOURCC_P8) { |
| vaUnmapBuffer (dpy, mem_id->image.buf); |
| va_status = vaDestroyImage (dpy, mem_id->image.image_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, |
| }; |
| |
| MFXVideoCORE_SetFrameAllocator (gst_msdk_context_get_session (context), |
| &gst_msdk_frame_allocator); |
| } |