1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2018, Intel Corporation
3 * Copyright (c) 2018, Igalia S.L.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * 3. Neither the name of the copyright holder nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGDECE
29 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <va/va_drmcommon.h>
36 #include "gstmsdkallocator.h"
37 #include "gstmsdkallocator_libva.h"
38 #include "msdk_libva.h"
40 #include <gst/va/gstvaallocator.h>
42 #define GST_MSDK_FRAME_SURFACE gst_msdk_frame_surface_quark_get ()
44 gst_msdk_frame_surface_quark_get (void)
48 if (g_once_init_enter (&g_quark)) {
49 gsize quark = (gsize) g_quark_from_static_string ("GstMsdkFrameSurface");
50 g_once_init_leave (&g_quark, quark);
56 gst_msdk_frame_alloc (mfxHDL pthis, mfxFrameAllocRequest * req,
57 mfxFrameAllocResponse * resp)
60 mfxStatus status = MFX_ERR_NONE;
64 VASurfaceID *surfaces = NULL;
65 VASurfaceAttrib attribs[2];
66 guint num_attribs = 0;
67 mfxMemId *mids = NULL;
68 GstMsdkContext *context = (GstMsdkContext *) pthis;
69 GstMsdkMemoryID *msdk_mids = NULL;
70 GstMsdkAllocResponse *msdk_resp = NULL;
71 mfxU32 fourcc = req->Info.FourCC;
72 mfxU16 surfaces_num = req->NumFrameSuggested;
74 /* MFX_MAKEFOURCC('V','P','8','S') is used for MFX_FOURCC_VP9_SEGMAP surface
75 * in MSDK and this surface is an internal surface. The external allocator
76 * shouldn't be used for this surface allocation
78 * See https://github.com/Intel-Media-SDK/MediaSDK/issues/762
80 if (req->Type & MFX_MEMTYPE_INTERNAL_FRAME
81 && fourcc == MFX_MAKEFOURCC ('V', 'P', '8', 'S'))
82 return MFX_ERR_UNSUPPORTED;
84 if (req->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
85 GstMsdkAllocResponse *cached =
86 gst_msdk_context_get_cached_alloc_responses_by_request (context, req);
88 /* check if enough frames were allocated */
89 if (req->NumFrameSuggested > cached->response.NumFrameActual)
90 return MFX_ERR_MEMORY_ALLOC;
92 *resp = cached->response;
93 g_atomic_int_inc (&cached->refcount);
98 /* The VA API does not define any surface types and the application can use either
99 * MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET or
100 * MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET to indicate data in video memory.
102 if (!(req->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET |
103 MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)))
104 return MFX_ERR_UNSUPPORTED;
106 va_fourcc = gst_msdk_get_va_fourcc_from_mfx_fourcc (fourcc);
109 (GstMsdkMemoryID *) g_slice_alloc0 (surfaces_num *
110 sizeof (GstMsdkMemoryID));
111 mids = (mfxMemId *) g_slice_alloc0 (surfaces_num * sizeof (mfxMemId));
113 (VASurfaceID *) g_slice_alloc0 (surfaces_num * sizeof (VASurfaceID));
115 (GstMsdkAllocResponse *) g_slice_alloc0 (sizeof (GstMsdkAllocResponse));
117 if (va_fourcc != VA_FOURCC_P208) {
118 attribs[0].type = VASurfaceAttribPixelFormat;
119 attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
120 attribs[0].value.type = VAGenericValueTypeInteger;
121 attribs[0].value.value.i = va_fourcc;
124 /* set VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER flag for encoding */
125 #if (MFX_VERSION >= 1025)
126 if ((req->Type & MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET) &&
127 (req->Type & MFX_MEMTYPE_FROM_ENCODE)) {
128 attribs[1].type = VASurfaceAttribUsageHint;
129 attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
130 attribs[1].value.type = VAGenericValueTypeInteger;
131 attribs[1].value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
137 gst_msdk_get_va_rt_format_from_mfx_rt_format (req->Info.ChromaFormat);
139 if (format == VA_RT_FORMAT_YUV420 && va_fourcc == VA_FOURCC_P010)
140 #if VA_CHECK_VERSION(1, 2, 0)
141 format = VA_RT_FORMAT_YUV420_10;
143 format = VA_RT_FORMAT_YUV420_10BPP;
146 #if VA_CHECK_VERSION(1, 4, 1)
147 if (format == VA_RT_FORMAT_YUV444 && va_fourcc == VA_FOURCC_A2R10G10B10)
148 format = VA_RT_FORMAT_RGB32_10;
151 #if ((MFX_VERSION >= 1027) && VA_CHECK_VERSION(1, 2, 0))
152 if (format == VA_RT_FORMAT_YUV422 && va_fourcc == VA_FOURCC_Y210)
153 format = VA_RT_FORMAT_YUV422_10;
154 else if (format == VA_RT_FORMAT_YUV444 && va_fourcc == VA_FOURCC_Y410)
155 format = VA_RT_FORMAT_YUV444_10;
158 #if ((MFX_VERSION >= 1031) && VA_CHECK_VERSION(1, 2, 0))
159 if (format == VA_RT_FORMAT_YUV420 && va_fourcc == VA_FOURCC_P016)
160 format = VA_RT_FORMAT_YUV420_12;
162 if (format == VA_RT_FORMAT_YUV422 && va_fourcc == VA_FOURCC_Y216)
163 format = VA_RT_FORMAT_YUV422_12;
165 if (format == VA_RT_FORMAT_YUV444 && va_fourcc == VA_FOURCC_Y416)
166 format = VA_RT_FORMAT_YUV444_12;
169 #if (MFX_VERSION >= 2004)
170 if (format == VA_RT_FORMAT_YUV444 && (va_fourcc == VA_FOURCC_RGBP
171 || va_fourcc == VA_FOURCC_BGRP))
172 format = VA_RT_FORMAT_RGBP;
175 va_status = vaCreateSurfaces (gst_msdk_context_get_handle (context),
177 req->Info.Width, req->Info.Height, surfaces, surfaces_num, attribs,
180 status = gst_msdk_get_mfx_status_from_va_status (va_status);
181 if (status != MFX_ERR_NONE) {
182 GST_WARNING ("failed to create VA surface");
186 for (i = 0; i < surfaces_num; i++) {
187 /* Get dmabuf handle if MFX_MEMTYPE_EXPORT_FRAME */
188 if (req->Type & MFX_MEMTYPE_EXPORT_FRAME) {
189 VADRMPRIMESurfaceDescriptor va_desc = { 0 };
190 uint32_t export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS |
191 VA_EXPORT_SURFACE_READ_WRITE;
194 vaExportSurfaceHandle (gst_msdk_context_get_handle (context),
195 surfaces[i], VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, export_flags,
198 status = gst_msdk_get_mfx_status_from_va_status (va_status);
200 if (MFX_ERR_NONE != status) {
201 GST_ERROR ("Failed to export surface");
205 g_assert (va_desc.num_objects);
207 /* This plugin supports single object only */
208 if (va_desc.num_objects > 1) {
209 GST_ERROR ("Can not support multiple objects");
210 return MFX_ERR_UNSUPPORTED;
213 msdk_mids[i].desc = va_desc;
216 /* Don't use image for DMABuf */
217 msdk_mids[i].image.image_id = VA_INVALID_ID;
218 msdk_mids[i].image.buf = VA_INVALID_ID;
220 msdk_mids[i].surface = &surfaces[i];
221 mids[i] = (mfxMemId *) & msdk_mids[i];
224 /* This is requested from the driver when h265 encoding.
225 * These buffers will be used inside the driver and released by
226 * gst_msdk_frame_free functions. Application doesn't need to handle these buffers.
228 * See https://github.com/Intel-Media-SDK/samples/issues/13 for more details.
230 VAContextID context_id = req->AllocId;
231 gint width32 = 32 * ((req->Info.Width + 31) >> 5);
232 gint height32 = 32 * ((req->Info.Height + 31) >> 5);
233 guint64 codedbuf_size = (width32 * height32) * 400LL / (16 * 16);
235 for (i = 0; i < surfaces_num; i++) {
236 VABufferID coded_buf;
238 va_status = vaCreateBuffer (gst_msdk_context_get_handle (context),
239 context_id, VAEncCodedBufferType, codedbuf_size, 1, NULL, &coded_buf);
241 status = gst_msdk_get_mfx_status_from_va_status (va_status);
242 if (status < MFX_ERR_NONE) {
243 GST_ERROR ("failed to create buffer");
247 surfaces[i] = coded_buf;
248 msdk_mids[i].surface = &surfaces[i];
249 msdk_mids[i].fourcc = fourcc;
251 /* Don't use image for P208 */
252 msdk_mids[i].image.image_id = VA_INVALID_ID;
253 msdk_mids[i].image.buf = VA_INVALID_ID;
255 mids[i] = (mfxMemId *) & msdk_mids[i];
260 resp->NumFrameActual = surfaces_num;
262 msdk_resp->response = *resp;
263 msdk_resp->request = *req;
264 msdk_resp->refcount = 1;
266 gst_msdk_context_add_alloc_response (context, msdk_resp);
272 gst_msdk_frame_free (mfxHDL pthis, mfxFrameAllocResponse * resp)
274 GstMsdkContext *context = (GstMsdkContext *) pthis;
275 VAStatus va_status = VA_STATUS_SUCCESS;
277 GstMsdkMemoryID *mem_id;
280 GstMsdkAllocResponse *cached = NULL;
282 cached = gst_msdk_context_get_cached_alloc_responses (context, resp);
285 if (!g_atomic_int_dec_and_test (&cached->refcount))
290 if (!gst_msdk_context_remove_alloc_response (context, resp))
293 mem_id = resp->mids[0];
294 dpy = gst_msdk_context_get_handle (context);
296 if (mem_id->fourcc != MFX_FOURCC_P8) {
297 /* Make sure that all the vaImages are destroyed */
298 for (i = 0; i < resp->NumFrameActual; i++) {
299 GstMsdkMemoryID *mem = resp->mids[i];
301 /* Release prime fd if used */
302 if (mem->desc.num_objects) {
303 g_assert (mem->desc.num_objects == 1);
304 close (mem->desc.objects[0].fd);
305 mem->desc.num_objects = 0;
308 if (mem->image.image_id != VA_INVALID_ID &&
309 vaDestroyImage (dpy, mem->image.image_id) == VA_STATUS_SUCCESS) {
310 mem_id->image.image_id = VA_INVALID_ID;
311 mem_id->image.buf = VA_INVALID_ID;
316 vaDestroySurfaces (dpy, (VASurfaceID *) mem_id->surface,
317 resp->NumFrameActual);
319 VASurfaceID *surfaces = mem_id->surface;
321 for (i = 0; i < resp->NumFrameActual; i++) {
322 va_status = vaDestroyBuffer (dpy, surfaces[i]);
326 g_slice_free1 (resp->NumFrameActual * sizeof (VASurfaceID), mem_id->surface);
327 g_slice_free1 (resp->NumFrameActual * sizeof (GstMsdkMemoryID), mem_id);
328 g_slice_free1 (resp->NumFrameActual * sizeof (mfxMemId), resp->mids);
330 status = gst_msdk_get_mfx_status_from_va_status (va_status);
335 gst_msdk_frame_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * data)
337 GstMsdkContext *context = (GstMsdkContext *) pthis;
341 VASurfaceID *va_surface;
343 GstMsdkMemoryID *mem_id;
345 mem_id = (GstMsdkMemoryID *) mid;
346 va_surface = mem_id->surface;
347 dpy = gst_msdk_context_get_handle (context);
349 if (mem_id->desc.num_objects) {
350 GST_WARNING ("Couldn't map the buffer since dmabuf is already in use");
351 return MFX_ERR_LOCK_MEMORY;
354 if (mem_id->fourcc != MFX_FOURCC_P8) {
355 va_status = vaDeriveImage (dpy, *va_surface, &mem_id->image);
356 status = gst_msdk_get_mfx_status_from_va_status (va_status);
358 if (status != MFX_ERR_NONE) {
359 GST_WARNING ("failed to derive image");
363 va_status = vaMapBuffer (dpy, mem_id->image.buf, (void **) &buf);
364 status = gst_msdk_get_mfx_status_from_va_status (va_status);
366 if (status != MFX_ERR_NONE) {
367 GST_WARNING ("failed to map");
368 if (vaDestroyImage (dpy, mem_id->image.image_id) == VA_STATUS_SUCCESS) {
369 mem_id->image.image_id = VA_INVALID_ID;
370 mem_id->image.buf = VA_INVALID_ID;
375 switch (mem_id->image.format.fourcc) {
379 data->Pitch = mem_id->image.pitches[0];
380 data->Y = buf + mem_id->image.offsets[0];
381 data->UV = buf + mem_id->image.offsets[1];
384 data->Pitch = mem_id->image.pitches[0];
385 data->Y = buf + mem_id->image.offsets[0];
386 data->U = buf + mem_id->image.offsets[2];
387 data->V = buf + mem_id->image.offsets[1];
390 data->Pitch = mem_id->image.pitches[0];
391 data->Y = buf + mem_id->image.offsets[0];
392 data->U = data->Y + 1;
393 data->V = data->Y + 3;
396 data->Pitch = mem_id->image.pitches[0];
397 data->Y = buf + mem_id->image.offsets[0];
398 data->U = data->U + 1;
399 data->V = data->U + 2;
402 data->Pitch = mem_id->image.pitches[0];
403 data->B = buf + mem_id->image.offsets[0];
404 data->G = data->B + 1;
405 data->R = data->B + 2;
406 data->A = data->B + 3;
408 #if (MFX_VERSION >= 1028)
409 case VA_FOURCC_RGB565:
410 data->Pitch = mem_id->image.pitches[0];
411 data->R = buf + mem_id->image.offsets[0];
417 data->PitchHigh = (mfxU16) (mem_id->image.pitches[0] / (1 << 16));
418 data->PitchLow = (mfxU16) (mem_id->image.pitches[0] % (1 << 16));
419 data->V = buf + mem_id->image.offsets[0];
420 data->U = data->V + 1;
421 data->Y = data->V + 2;
422 data->A = data->V + 3;
424 #if VA_CHECK_VERSION(1, 4, 1)
425 case VA_FOURCC_A2R10G10B10:
426 data->Pitch = mem_id->image.pitches[0];
427 data->R = buf + mem_id->image.offsets[0];
433 #if VA_CHECK_VERSION(1, 2, 0)
436 data->Pitch = mem_id->image.pitches[0];
437 data->Y = buf + mem_id->image.offsets[0];
438 data->U = data->Y + 2;
439 data->V = data->Y + 6;
442 data->Pitch = mem_id->image.pitches[0];
443 data->U = buf + mem_id->image.offsets[0]; /* data->Y410 */
446 data->Pitch = mem_id->image.pitches[0];
447 data->U = buf + mem_id->image.offsets[0];
448 data->Y = data->U + 2;
449 data->V = data->U + 4;
450 data->A = data->U + 6;
454 data->Pitch = mem_id->image.pitches[0];
455 data->R = buf + mem_id->image.offsets[0];
456 data->G = data->R + 1;
457 data->B = data->R + 2;
458 data->A = data->R + 3;
461 #if (MFX_VERSION >= 2004)
463 data->Pitch = mem_id->image.pitches[0];
464 data->R = buf + mem_id->image.offsets[0];
465 data->G = buf + mem_id->image.offsets[1];
466 data->B = buf + mem_id->image.offsets[2];
469 data->Pitch = mem_id->image.pitches[0];
470 data->B = buf + mem_id->image.offsets[0];
471 data->G = buf + mem_id->image.offsets[1];
472 data->R = buf + mem_id->image.offsets[2];
477 g_assert_not_reached ();
481 VACodedBufferSegment *coded_buffer_segment;
483 vaMapBuffer (dpy, *va_surface, (void **) (&coded_buffer_segment));
484 status = gst_msdk_get_mfx_status_from_va_status (va_status);
485 if (MFX_ERR_NONE == status)
486 data->Y = (mfxU8 *) coded_buffer_segment->buf;
493 gst_msdk_frame_unlock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
495 GstMsdkContext *context = (GstMsdkContext *) pthis;
499 GstMsdkMemoryID *mem_id;
501 mem_id = (GstMsdkMemoryID *) mid;
502 dpy = gst_msdk_context_get_handle (context);
504 g_assert (mem_id->desc.num_objects == 0);
506 if (mem_id->fourcc != MFX_FOURCC_P8) {
507 vaUnmapBuffer (dpy, mem_id->image.buf);
508 va_status = vaDestroyImage (dpy, mem_id->image.image_id);
510 if (va_status == VA_STATUS_SUCCESS) {
511 mem_id->image.image_id = VA_INVALID_ID;
512 mem_id->image.buf = VA_INVALID_ID;
515 va_status = vaUnmapBuffer (dpy, *(mem_id->surface));
518 status = gst_msdk_get_mfx_status_from_va_status (va_status);
524 gst_msdk_frame_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * hdl)
526 GstMsdkMemoryID *mem_id;
529 return MFX_ERR_INVALID_HANDLE;
532 *hdl = mem_id->surface;
538 gst_msdk_set_frame_allocator (GstMsdkContext * context)
540 mfxFrameAllocator gst_msdk_frame_allocator = {
542 .Alloc = gst_msdk_frame_alloc,
543 .Lock = gst_msdk_frame_lock,
544 .Unlock = gst_msdk_frame_unlock,
545 .GetHDL = gst_msdk_frame_get_hdl,
546 .Free = gst_msdk_frame_free,
549 gst_msdk_context_set_frame_allocator (context, &gst_msdk_frame_allocator);
553 gst_msdk_get_dmabuf_info_from_surface (mfxFrameSurface1 * surface,
554 gint * handle, gsize * size)
556 GstMsdkMemoryID *mem_id;
557 g_return_val_if_fail (surface, FALSE);
559 mem_id = (GstMsdkMemoryID *) surface->Data.MemId;
561 g_assert (mem_id->desc.num_objects == 1);
564 *handle = mem_id->desc.objects[0].fd;
566 *size = mem_id->desc.objects[0].size;
572 gst_msdk_export_dmabuf_to_vasurface (GstMsdkContext * context,
573 GstVideoInfo * vinfo, gint fd, VASurfaceID * surface_id)
575 GstVideoFormat format;
576 guint width, height, size, i;
577 unsigned long extbuf_handle;
578 guint va_fourcc = 0, va_chroma = 0;
579 VASurfaceAttrib attribs[2], *attrib;
580 VASurfaceAttribExternalBuffers extbuf;
582 mfxStatus status = MFX_ERR_NONE;
584 g_return_val_if_fail (context != NULL, FALSE);
585 g_return_val_if_fail (vinfo != NULL, FALSE);
586 g_return_val_if_fail (fd >= 0, FALSE);
588 extbuf_handle = (guintptr) (fd);
590 format = GST_VIDEO_INFO_FORMAT (vinfo);
591 width = GST_VIDEO_INFO_WIDTH (vinfo);
592 height = GST_VIDEO_INFO_HEIGHT (vinfo);
593 size = GST_VIDEO_INFO_SIZE (vinfo);
595 /* Fixme: Move to common format handling util */
597 case GST_VIDEO_FORMAT_NV12:
598 va_chroma = VA_RT_FORMAT_YUV420;
599 va_fourcc = VA_FOURCC_NV12;
601 case GST_VIDEO_FORMAT_BGRA:
602 va_chroma = VA_RT_FORMAT_YUV444;
603 va_fourcc = VA_FOURCC_BGRA;
605 case GST_VIDEO_FORMAT_YUY2:
606 va_chroma = VA_RT_FORMAT_YUV422;
607 va_fourcc = VA_FOURCC_YUY2;
609 case GST_VIDEO_FORMAT_P010_10LE:
610 #if VA_CHECK_VERSION(1, 2, 0)
611 va_chroma = VA_RT_FORMAT_YUV420_10;
613 va_chroma = VA_RT_FORMAT_YUV420_10BPP;
615 va_fourcc = VA_FOURCC_P010;
617 case GST_VIDEO_FORMAT_UYVY:
618 va_chroma = VA_RT_FORMAT_YUV422;
619 va_fourcc = VA_FOURCC_UYVY;
621 #if (MFX_VERSION >= 1028)
622 case GST_VIDEO_FORMAT_RGB16:
623 va_chroma = VA_RT_FORMAT_RGB16;
624 va_fourcc = VA_FOURCC_RGB565;
627 case GST_VIDEO_FORMAT_VUYA:
628 va_chroma = VA_RT_FORMAT_YUV444;
629 va_fourcc = VA_FOURCC_AYUV;
631 #if VA_CHECK_VERSION(1, 4, 1)
632 case GST_VIDEO_FORMAT_BGR10A2_LE:
633 va_chroma = VA_RT_FORMAT_RGB32_10;
634 va_fourcc = VA_FOURCC_A2R10G10B10;
637 #if VA_CHECK_VERSION(1, 2, 0)
638 case GST_VIDEO_FORMAT_Y210:
639 va_chroma = VA_RT_FORMAT_YUV422_10;
640 va_fourcc = VA_FOURCC_Y210;
642 case GST_VIDEO_FORMAT_Y410:
643 va_chroma = VA_RT_FORMAT_YUV444_10;
644 va_fourcc = VA_FOURCC_Y410;
646 case GST_VIDEO_FORMAT_P012_LE:
647 va_chroma = VA_RT_FORMAT_YUV420_12;
648 va_fourcc = VA_FOURCC_P016;
650 case GST_VIDEO_FORMAT_Y212_LE:
651 va_chroma = VA_RT_FORMAT_YUV422_12;
652 va_fourcc = VA_FOURCC_Y216;
654 case GST_VIDEO_FORMAT_Y412_LE:
655 va_chroma = VA_RT_FORMAT_YUV444_12;
656 va_fourcc = VA_FOURCC_Y416;
659 #if (MFX_VERSION >= 2004)
660 case GST_VIDEO_FORMAT_RGBP:
661 va_chroma = VA_RT_FORMAT_RGBP;
662 va_fourcc = VA_FOURCC_RGBP;
664 case GST_VIDEO_FORMAT_BGRP:
665 va_chroma = VA_RT_FORMAT_RGBP;
666 va_fourcc = VA_FOURCC_BGRP;
670 goto error_unsupported_format;
673 /* Fill the VASurfaceAttribExternalBuffers */
674 extbuf.pixel_format = va_fourcc;
675 extbuf.width = width;
676 extbuf.height = height;
677 extbuf.data_size = size;
678 extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vinfo);
679 for (i = 0; i < extbuf.num_planes; i++) {
680 extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i);
681 extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i);
683 extbuf.buffers = (uintptr_t *) & extbuf_handle;
684 extbuf.num_buffers = 1;
686 extbuf.private_data = NULL;
688 /* Fill the Surface Attributes */
690 attrib->type = VASurfaceAttribMemoryType;
691 attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
692 attrib->value.type = VAGenericValueTypeInteger;
693 attrib->value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
695 attrib->type = VASurfaceAttribExternalBufferDescriptor;
696 attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
697 attrib->value.type = VAGenericValueTypePointer;
698 attrib->value.value.p = &extbuf;
701 va_status = vaCreateSurfaces (gst_msdk_context_get_handle (context),
702 va_chroma, width, height, surface_id, 1, attribs, attrib - attribs);
703 status = gst_msdk_get_mfx_status_from_va_status (va_status);
704 if (status != MFX_ERR_NONE)
705 goto error_create_surface;
709 error_unsupported_format:
711 GST_ERROR ("Unsupported Video format %s, Can't export dmabuf to vaSurface",
712 gst_video_format_to_string (format));
715 error_create_surface:
717 GST_ERROR ("Failed to create the VASurface from DRM_PRIME FD");
723 _get_va_surface (GstBuffer * buf, GstVideoInfo * info,
724 GstMsdkContext * msdk_context)
726 VASurfaceID va_surface = VA_INVALID_ID;
729 va_surface = gst_va_buffer_get_surface (buf);
731 /* Update offset/stride/size if there is VideoMeta attached to
732 * the dma buffer, which is then used to get vasurface */
737 vmeta = gst_buffer_get_video_meta (buf);
739 if (GST_VIDEO_INFO_FORMAT (info) != vmeta->format ||
740 GST_VIDEO_INFO_WIDTH (info) != vmeta->width ||
741 GST_VIDEO_INFO_HEIGHT (info) != vmeta->height ||
742 GST_VIDEO_INFO_N_PLANES (info) != vmeta->n_planes) {
743 GST_ERROR ("VideoMeta attached to buffer is not matching"
744 "the negotiated width/height/format");
747 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); ++i) {
748 GST_VIDEO_INFO_PLANE_OFFSET (info, i) = vmeta->offset[i];
749 GST_VIDEO_INFO_PLANE_STRIDE (info, i) = vmeta->stride[i];
751 GST_VIDEO_INFO_SIZE (info) = gst_buffer_get_size (buf);
754 mem = gst_buffer_peek_memory (buf, 0);
755 fd = gst_dmabuf_memory_get_fd (mem);
758 /* export dmabuf to vasurface */
759 if (!gst_msdk_export_dmabuf_to_vasurface (msdk_context, info, fd,
761 return VA_INVALID_ID;
768 gst_msdk_import_to_msdk_surface (GstBuffer * buf, GstMsdkContext * msdk_context,
769 GstVideoInfo * vinfo)
771 VASurfaceID va_surface = VA_INVALID_ID;
772 GstMemory *mem = NULL;
773 mfxFrameInfo frame_info = { 0, };
774 GstMsdkSurface *msdk_surface = NULL;
775 mfxFrameSurface1 *mfx_surface = NULL;
776 GstMsdkMemoryID *msdk_mid = NULL;
778 mem = gst_buffer_peek_memory (buf, 0);
779 msdk_surface = g_slice_new0 (GstMsdkSurface);
781 /* If buffer has qdata pointing to mfxFrameSurface1, directly extract it */
782 if ((mfx_surface = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem),
783 GST_MSDK_FRAME_SURFACE))) {
784 msdk_surface->surface = mfx_surface;
788 if (gst_msdk_is_va_mem (mem)) {
789 va_surface = _get_va_surface (buf, NULL, NULL);
790 } else if (gst_is_dmabuf_memory (mem)) {
791 /* For dma memory, videoinfo is used with dma fd to create va surface. */
792 GstVideoInfo info = *vinfo;
793 va_surface = _get_va_surface (buf, &info, msdk_context);
796 if (va_surface == VA_INVALID_ID) {
797 g_slice_free (GstMsdkSurface, msdk_surface);
801 mfx_surface = g_slice_new0 (mfxFrameSurface1);
802 msdk_mid = g_slice_new0 (GstMsdkMemoryID);
804 msdk_mid->surface = g_slice_new0 (VASurfaceID);
805 *msdk_mid->surface = va_surface;
807 mfx_surface->Data.MemId = (mfxMemId) msdk_mid;
809 gst_msdk_set_mfx_frame_info_from_video_info (&frame_info, vinfo);
810 mfx_surface->Info = frame_info;
812 /* Set mfxFrameSurface1 as qdata in buffer */
813 gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
814 GST_MSDK_FRAME_SURFACE, mfx_surface, NULL);
816 msdk_surface->surface = mfx_surface;
822 * gst_msdk_replace_mfx_memid:
823 * This method replace the internal VA Suface in mfxSurface with a new one
825 * Caution: Not a thread-safe routine, this method is here to work around
826 * the dmabuf-import use case with dynamic memID replacement where msdk
827 * originally Inited with fake memIDs.
829 * Don't use anywhere else unless you really know what you are doing!
832 gst_msdk_replace_mfx_memid (GstMsdkContext * context,
833 mfxFrameSurface1 * mfx_surface, VASurfaceID surface_id)
835 GstMsdkMemoryID *msdk_mid = NULL;
837 VASurfaceID *old_surface_id;
839 mfxStatus status = MFX_ERR_NONE;
841 g_return_val_if_fail (mfx_surface != NULL, FALSE);
842 g_return_val_if_fail (context != NULL, FALSE);
844 msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
845 dpy = gst_msdk_context_get_handle (context);
847 /* Destroy the underlined VAImage if already mapped */
848 if (msdk_mid->image.image_id != VA_INVALID_ID
849 && msdk_mid->image.buf != VA_INVALID_ID) {
851 gst_msdk_frame_unlock ((mfxHDL) context, (mfxMemId) msdk_mid, NULL);
852 if (status != MFX_ERR_NONE)
853 goto error_destroy_va_image;
856 /* Destroy the associated VASurface */
857 old_surface_id = msdk_mid->surface;
858 if (*old_surface_id != VA_INVALID_ID) {
859 va_status = vaDestroySurfaces (dpy, old_surface_id, 1);
860 status = gst_msdk_get_mfx_status_from_va_status (va_status);
861 if (status != MFX_ERR_NONE)
862 goto error_destroy_va_surface;
865 *msdk_mid->surface = surface_id;
869 error_destroy_va_image:
871 GST_ERROR ("Failed to Destroy the VAImage");
874 error_destroy_va_surface:
876 GST_ERROR ("Failed to Destroy the VASurfaceID %x", *old_surface_id);