taglist, plugins: fix compiler warnings with GLib >= 2.76
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / msdk / gstmsdkallocator_libva.c
1 /* GStreamer Intel MSDK plugin
2  * Copyright (c) 2018, Intel Corporation
3  * Copyright (c) 2018, Igalia S.L.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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.
31  */
32
33 #include <va/va.h>
34 #include <va/va_drmcommon.h>
35 #include <unistd.h>
36 #include "gstmsdkallocator.h"
37 #include "gstmsdkallocator_libva.h"
38 #include "msdk_libva.h"
39
40 #include <gst/va/gstvaallocator.h>
41
42 #define GST_MSDK_FRAME_SURFACE gst_msdk_frame_surface_quark_get ()
43 static GQuark
44 gst_msdk_frame_surface_quark_get (void)
45 {
46   static gsize g_quark;
47
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);
51   }
52   return g_quark;
53 }
54
55 mfxStatus
56 gst_msdk_frame_alloc (mfxHDL pthis, mfxFrameAllocRequest * req,
57     mfxFrameAllocResponse * resp)
58 {
59   VAStatus va_status;
60   mfxStatus status = MFX_ERR_NONE;
61   gint i;
62   guint format;
63   guint va_fourcc = 0;
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;
73
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
77    *
78    * See https://github.com/Intel-Media-SDK/MediaSDK/issues/762
79    */
80   if (req->Type & MFX_MEMTYPE_INTERNAL_FRAME
81       && fourcc == MFX_MAKEFOURCC ('V', 'P', '8', 'S'))
82     return MFX_ERR_UNSUPPORTED;
83
84   if (req->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
85     GstMsdkAllocResponse *cached =
86         gst_msdk_context_get_cached_alloc_responses_by_request (context, req);
87     if (cached) {
88       /* check if enough frames were allocated */
89       if (req->NumFrameSuggested > cached->response.NumFrameActual)
90         return MFX_ERR_MEMORY_ALLOC;
91
92       *resp = cached->response;
93       g_atomic_int_inc (&cached->refcount);
94       return MFX_ERR_NONE;
95     }
96   }
97
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.
101    */
102   if (!(req->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET |
103               MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)))
104     return MFX_ERR_UNSUPPORTED;
105
106   va_fourcc = gst_msdk_get_va_fourcc_from_mfx_fourcc (fourcc);
107
108   msdk_mids =
109       (GstMsdkMemoryID *) g_slice_alloc0 (surfaces_num *
110       sizeof (GstMsdkMemoryID));
111   mids = (mfxMemId *) g_slice_alloc0 (surfaces_num * sizeof (mfxMemId));
112   surfaces =
113       (VASurfaceID *) g_slice_alloc0 (surfaces_num * sizeof (VASurfaceID));
114   msdk_resp =
115       (GstMsdkAllocResponse *) g_slice_alloc0 (sizeof (GstMsdkAllocResponse));
116
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;
122     num_attribs = 1;
123
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;
132       num_attribs = 2;
133     }
134 #endif
135
136     format =
137         gst_msdk_get_va_rt_format_from_mfx_rt_format (req->Info.ChromaFormat);
138
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;
142 #else
143       format = VA_RT_FORMAT_YUV420_10BPP;
144 #endif
145
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;
149 #endif
150
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;
156 #endif
157
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;
161
162     if (format == VA_RT_FORMAT_YUV422 && va_fourcc == VA_FOURCC_Y216)
163       format = VA_RT_FORMAT_YUV422_12;
164
165     if (format == VA_RT_FORMAT_YUV444 && va_fourcc == VA_FOURCC_Y416)
166       format = VA_RT_FORMAT_YUV444_12;
167 #endif
168
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;
173 #endif
174
175     va_status = vaCreateSurfaces (gst_msdk_context_get_handle (context),
176         format,
177         req->Info.Width, req->Info.Height, surfaces, surfaces_num, attribs,
178         num_attribs);
179
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");
183       return status;
184     }
185
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;
192
193         va_status =
194             vaExportSurfaceHandle (gst_msdk_context_get_handle (context),
195             surfaces[i], VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, export_flags,
196             &va_desc);
197
198         status = gst_msdk_get_mfx_status_from_va_status (va_status);
199
200         if (MFX_ERR_NONE != status) {
201           GST_ERROR ("Failed to export surface");
202           return status;
203         }
204
205         g_assert (va_desc.num_objects);
206
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;
211         }
212
213         msdk_mids[i].desc = va_desc;
214       }
215
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;
219
220       msdk_mids[i].surface = &surfaces[i];
221       mids[i] = (mfxMemId *) & msdk_mids[i];
222     }
223   } else {
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.
227      *
228      * See https://github.com/Intel-Media-SDK/samples/issues/13 for more details.
229      */
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);
234
235     for (i = 0; i < surfaces_num; i++) {
236       VABufferID coded_buf;
237
238       va_status = vaCreateBuffer (gst_msdk_context_get_handle (context),
239           context_id, VAEncCodedBufferType, codedbuf_size, 1, NULL, &coded_buf);
240
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");
244         return status;
245       }
246
247       surfaces[i] = coded_buf;
248       msdk_mids[i].surface = &surfaces[i];
249       msdk_mids[i].fourcc = fourcc;
250
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;
254
255       mids[i] = (mfxMemId *) & msdk_mids[i];
256     }
257   }
258
259   resp->mids = mids;
260   resp->NumFrameActual = surfaces_num;
261
262   msdk_resp->response = *resp;
263   msdk_resp->request = *req;
264   msdk_resp->refcount = 1;
265
266   gst_msdk_context_add_alloc_response (context, msdk_resp);
267
268   return status;
269 }
270
271 mfxStatus
272 gst_msdk_frame_free (mfxHDL pthis, mfxFrameAllocResponse * resp)
273 {
274   GstMsdkContext *context = (GstMsdkContext *) pthis;
275   VAStatus va_status = VA_STATUS_SUCCESS;
276   mfxStatus status;
277   GstMsdkMemoryID *mem_id;
278   VADisplay dpy;
279   gint i;
280   GstMsdkAllocResponse *cached = NULL;
281
282   cached = gst_msdk_context_get_cached_alloc_responses (context, resp);
283
284   if (cached) {
285     if (!g_atomic_int_dec_and_test (&cached->refcount))
286       return MFX_ERR_NONE;
287   } else
288     return MFX_ERR_NONE;
289
290   if (!gst_msdk_context_remove_alloc_response (context, resp))
291     return MFX_ERR_NONE;
292
293   mem_id = resp->mids[0];
294   dpy = gst_msdk_context_get_handle (context);
295
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];
300
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;
306       }
307
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;
312       }
313     }
314
315     va_status =
316         vaDestroySurfaces (dpy, (VASurfaceID *) mem_id->surface,
317         resp->NumFrameActual);
318   } else {
319     VASurfaceID *surfaces = mem_id->surface;
320
321     for (i = 0; i < resp->NumFrameActual; i++) {
322       va_status = vaDestroyBuffer (dpy, surfaces[i]);
323     }
324   }
325
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);
329
330   status = gst_msdk_get_mfx_status_from_va_status (va_status);
331   return status;
332 }
333
334 mfxStatus
335 gst_msdk_frame_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * data)
336 {
337   GstMsdkContext *context = (GstMsdkContext *) pthis;
338   VAStatus va_status;
339   mfxStatus status;
340   mfxU8 *buf = NULL;
341   VASurfaceID *va_surface;
342   VADisplay dpy;
343   GstMsdkMemoryID *mem_id;
344
345   mem_id = (GstMsdkMemoryID *) mid;
346   va_surface = mem_id->surface;
347   dpy = gst_msdk_context_get_handle (context);
348
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;
352   }
353
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);
357
358     if (status != MFX_ERR_NONE) {
359       GST_WARNING ("failed to derive image");
360       return status;
361     }
362
363     va_status = vaMapBuffer (dpy, mem_id->image.buf, (void **) &buf);
364     status = gst_msdk_get_mfx_status_from_va_status (va_status);
365
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;
371       }
372       return status;
373     }
374
375     switch (mem_id->image.format.fourcc) {
376       case VA_FOURCC_NV12:
377       case VA_FOURCC_P010:
378       case VA_FOURCC_P016:
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];
382         break;
383       case VA_FOURCC_YV12:
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];
388         break;
389       case VA_FOURCC_YUY2:
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;
394         break;
395       case VA_FOURCC_UYVY:
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;
400         break;
401       case VA_FOURCC_ARGB:
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;
407         break;
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];
412         data->G = data->R;
413         data->B = data->R;
414         break;
415 #endif
416       case VA_FOURCC_AYUV:
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;
423         break;
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];
428         data->G = data->R;
429         data->B = data->R;
430         data->A = data->R;
431         break;
432 #endif
433 #if VA_CHECK_VERSION(1, 2, 0)
434       case VA_FOURCC_Y210:
435       case VA_FOURCC_Y216:
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;
440         break;
441       case VA_FOURCC_Y410:
442         data->Pitch = mem_id->image.pitches[0];
443         data->U = buf + mem_id->image.offsets[0];       /* data->Y410 */
444         break;
445       case VA_FOURCC_Y416:
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;
451         break;
452 #endif
453       case VA_FOURCC_ABGR:
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;
459         break;
460
461 #if (MFX_VERSION >= 2004)
462       case VA_FOURCC_RGBP:
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];
467         break;
468       case VA_FOURCC_BGRP:
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];
473         break;
474 #endif
475
476       default:
477         g_assert_not_reached ();
478         break;
479     }
480   } else {
481     VACodedBufferSegment *coded_buffer_segment;
482     va_status =
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;
487   }
488
489   return status;
490 }
491
492 mfxStatus
493 gst_msdk_frame_unlock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
494 {
495   GstMsdkContext *context = (GstMsdkContext *) pthis;
496   VAStatus va_status;
497   mfxStatus status;
498   VADisplay dpy;
499   GstMsdkMemoryID *mem_id;
500
501   mem_id = (GstMsdkMemoryID *) mid;
502   dpy = gst_msdk_context_get_handle (context);
503
504   g_assert (mem_id->desc.num_objects == 0);
505
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);
509
510     if (va_status == VA_STATUS_SUCCESS) {
511       mem_id->image.image_id = VA_INVALID_ID;
512       mem_id->image.buf = VA_INVALID_ID;
513     }
514   } else {
515     va_status = vaUnmapBuffer (dpy, *(mem_id->surface));
516   }
517
518   status = gst_msdk_get_mfx_status_from_va_status (va_status);
519
520   return status;
521 }
522
523 mfxStatus
524 gst_msdk_frame_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * hdl)
525 {
526   GstMsdkMemoryID *mem_id;
527
528   if (!hdl || !mid)
529     return MFX_ERR_INVALID_HANDLE;
530
531   mem_id = mid;
532   *hdl = mem_id->surface;
533
534   return MFX_ERR_NONE;
535 }
536
537 void
538 gst_msdk_set_frame_allocator (GstMsdkContext * context)
539 {
540   mfxFrameAllocator gst_msdk_frame_allocator = {
541     .pthis = context,
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,
547   };
548
549   gst_msdk_context_set_frame_allocator (context, &gst_msdk_frame_allocator);
550 }
551
552 gboolean
553 gst_msdk_get_dmabuf_info_from_surface (mfxFrameSurface1 * surface,
554     gint * handle, gsize * size)
555 {
556   GstMsdkMemoryID *mem_id;
557   g_return_val_if_fail (surface, FALSE);
558
559   mem_id = (GstMsdkMemoryID *) surface->Data.MemId;
560
561   g_assert (mem_id->desc.num_objects == 1);
562
563   if (handle)
564     *handle = mem_id->desc.objects[0].fd;
565   if (size)
566     *size = mem_id->desc.objects[0].size;
567
568   return TRUE;
569 }
570
571 gboolean
572 gst_msdk_export_dmabuf_to_vasurface (GstMsdkContext * context,
573     GstVideoInfo * vinfo, gint fd, VASurfaceID * surface_id)
574 {
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;
581   VAStatus va_status;
582   mfxStatus status = MFX_ERR_NONE;
583
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);
587
588   extbuf_handle = (guintptr) (fd);
589
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);
594
595   /* Fixme: Move to common format handling util */
596   switch (format) {
597     case GST_VIDEO_FORMAT_NV12:
598       va_chroma = VA_RT_FORMAT_YUV420;
599       va_fourcc = VA_FOURCC_NV12;
600       break;
601     case GST_VIDEO_FORMAT_BGRA:
602       va_chroma = VA_RT_FORMAT_YUV444;
603       va_fourcc = VA_FOURCC_BGRA;
604       break;
605     case GST_VIDEO_FORMAT_YUY2:
606       va_chroma = VA_RT_FORMAT_YUV422;
607       va_fourcc = VA_FOURCC_YUY2;
608       break;
609     case GST_VIDEO_FORMAT_P010_10LE:
610 #if VA_CHECK_VERSION(1, 2, 0)
611       va_chroma = VA_RT_FORMAT_YUV420_10;
612 #else
613       va_chroma = VA_RT_FORMAT_YUV420_10BPP;
614 #endif
615       va_fourcc = VA_FOURCC_P010;
616       break;
617     case GST_VIDEO_FORMAT_UYVY:
618       va_chroma = VA_RT_FORMAT_YUV422;
619       va_fourcc = VA_FOURCC_UYVY;
620       break;
621 #if (MFX_VERSION >= 1028)
622     case GST_VIDEO_FORMAT_RGB16:
623       va_chroma = VA_RT_FORMAT_RGB16;
624       va_fourcc = VA_FOURCC_RGB565;
625       break;
626 #endif
627     case GST_VIDEO_FORMAT_VUYA:
628       va_chroma = VA_RT_FORMAT_YUV444;
629       va_fourcc = VA_FOURCC_AYUV;
630       break;
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;
635       break;
636 #endif
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;
641       break;
642     case GST_VIDEO_FORMAT_Y410:
643       va_chroma = VA_RT_FORMAT_YUV444_10;
644       va_fourcc = VA_FOURCC_Y410;
645       break;
646     case GST_VIDEO_FORMAT_P012_LE:
647       va_chroma = VA_RT_FORMAT_YUV420_12;
648       va_fourcc = VA_FOURCC_P016;
649       break;
650     case GST_VIDEO_FORMAT_Y212_LE:
651       va_chroma = VA_RT_FORMAT_YUV422_12;
652       va_fourcc = VA_FOURCC_Y216;
653       break;
654     case GST_VIDEO_FORMAT_Y412_LE:
655       va_chroma = VA_RT_FORMAT_YUV444_12;
656       va_fourcc = VA_FOURCC_Y416;
657       break;
658 #endif
659 #if (MFX_VERSION >= 2004)
660     case GST_VIDEO_FORMAT_RGBP:
661       va_chroma = VA_RT_FORMAT_RGBP;
662       va_fourcc = VA_FOURCC_RGBP;
663       break;
664     case GST_VIDEO_FORMAT_BGRP:
665       va_chroma = VA_RT_FORMAT_RGBP;
666       va_fourcc = VA_FOURCC_BGRP;
667       break;
668 #endif
669     default:
670       goto error_unsupported_format;
671   }
672
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);
682   }
683   extbuf.buffers = (uintptr_t *) & extbuf_handle;
684   extbuf.num_buffers = 1;
685   extbuf.flags = 0;
686   extbuf.private_data = NULL;
687
688   /* Fill the Surface Attributes */
689   attrib = attribs;
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;
694   attrib++;
695   attrib->type = VASurfaceAttribExternalBufferDescriptor;
696   attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
697   attrib->value.type = VAGenericValueTypePointer;
698   attrib->value.value.p = &extbuf;
699   attrib++;
700
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;
706
707   return TRUE;
708
709 error_unsupported_format:
710   {
711     GST_ERROR ("Unsupported Video format %s, Can't export dmabuf to vaSurface",
712         gst_video_format_to_string (format));
713     return FALSE;
714   }
715 error_create_surface:
716   {
717     GST_ERROR ("Failed to create the VASurface from DRM_PRIME FD");
718     return FALSE;
719   }
720 }
721
722 static VASurfaceID
723 _get_va_surface (GstBuffer * buf, GstVideoInfo * info,
724     GstMsdkContext * msdk_context)
725 {
726   VASurfaceID va_surface = VA_INVALID_ID;
727
728   if (!info) {
729     va_surface = gst_va_buffer_get_surface (buf);
730   } else {
731     /* Update offset/stride/size if there is VideoMeta attached to
732      * the dma buffer, which is then used to get vasurface */
733     GstMemory *mem;
734     gint i, fd;
735     GstVideoMeta *vmeta;
736
737     vmeta = gst_buffer_get_video_meta (buf);
738     if (vmeta) {
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");
745         return va_surface;
746       }
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];
750       }
751       GST_VIDEO_INFO_SIZE (info) = gst_buffer_get_size (buf);
752     }
753
754     mem = gst_buffer_peek_memory (buf, 0);
755     fd = gst_dmabuf_memory_get_fd (mem);
756     if (fd < 0)
757       return va_surface;
758     /* export dmabuf to vasurface */
759     if (!gst_msdk_export_dmabuf_to_vasurface (msdk_context, info, fd,
760             &va_surface))
761       return VA_INVALID_ID;
762   }
763
764   return va_surface;
765 }
766
767 /* Currently parameter map_flag is not useful on Linux */
768 GstMsdkSurface *
769 gst_msdk_import_to_msdk_surface (GstBuffer * buf, GstMsdkContext * msdk_context,
770     GstVideoInfo * vinfo, guint map_flag)
771 {
772   VASurfaceID va_surface = VA_INVALID_ID;
773   GstMemory *mem = NULL;
774   mfxFrameInfo frame_info = { 0, };
775   GstMsdkSurface *msdk_surface = NULL;
776   mfxFrameSurface1 *mfx_surface = NULL;
777   GstMsdkMemoryID *msdk_mid = NULL;
778
779   mem = gst_buffer_peek_memory (buf, 0);
780   msdk_surface = g_slice_new0 (GstMsdkSurface);
781
782   /* If buffer has qdata pointing to mfxFrameSurface1, directly extract it */
783   if ((mfx_surface = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem),
784               GST_MSDK_FRAME_SURFACE))) {
785     msdk_surface->surface = mfx_surface;
786     msdk_surface->from_qdata = TRUE;
787     return msdk_surface;
788   }
789
790   if (gst_msdk_is_va_mem (mem)) {
791     va_surface = _get_va_surface (buf, NULL, NULL);
792   } else if (gst_is_dmabuf_memory (mem)) {
793     /* For dma memory, videoinfo is used with dma fd to create va surface. */
794     GstVideoInfo info = *vinfo;
795     va_surface = _get_va_surface (buf, &info, msdk_context);
796   }
797
798   if (va_surface == VA_INVALID_ID) {
799     g_slice_free (GstMsdkSurface, msdk_surface);
800     return NULL;
801   }
802
803   mfx_surface = g_slice_new0 (mfxFrameSurface1);
804   msdk_mid = g_slice_new0 (GstMsdkMemoryID);
805
806   msdk_mid->surface = g_slice_new0 (VASurfaceID);
807   *msdk_mid->surface = va_surface;
808
809   mfx_surface->Data.MemId = (mfxMemId) msdk_mid;
810
811   gst_msdk_set_mfx_frame_info_from_video_info (&frame_info, vinfo);
812   mfx_surface->Info = frame_info;
813
814   /* Set mfxFrameSurface1 as qdata in buffer */
815   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
816       GST_MSDK_FRAME_SURFACE, mfx_surface, NULL);
817
818   msdk_surface->surface = mfx_surface;
819
820   return msdk_surface;
821 }
822
823 /**
824  * gst_msdk_replace_mfx_memid:
825  * This method replace the internal VA Suface in mfxSurface with a new one
826  *
827  * Caution: Not a thread-safe routine, this method is here to work around
828  * the dmabuf-import use case with dynamic memID replacement where msdk
829  * originally Inited with fake memIDs.
830  *
831  * Don't use anywhere else unless you really know what you are doing!
832  */
833 gboolean
834 gst_msdk_replace_mfx_memid (GstMsdkContext * context,
835     mfxFrameSurface1 * mfx_surface, VASurfaceID surface_id)
836 {
837   GstMsdkMemoryID *msdk_mid = NULL;
838   VADisplay dpy;
839   VASurfaceID *old_surface_id;
840   VAStatus va_status;
841   mfxStatus status = MFX_ERR_NONE;
842
843   g_return_val_if_fail (mfx_surface != NULL, FALSE);
844   g_return_val_if_fail (context != NULL, FALSE);
845
846   msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
847   dpy = gst_msdk_context_get_handle (context);
848
849   /* Destroy the underlined VAImage if already mapped */
850   if (msdk_mid->image.image_id != VA_INVALID_ID
851       && msdk_mid->image.buf != VA_INVALID_ID) {
852     status =
853         gst_msdk_frame_unlock ((mfxHDL) context, (mfxMemId) msdk_mid, NULL);
854     if (status != MFX_ERR_NONE)
855       goto error_destroy_va_image;
856   }
857
858   /* Destroy the associated VASurface */
859   old_surface_id = msdk_mid->surface;
860   if (*old_surface_id != VA_INVALID_ID) {
861     va_status = vaDestroySurfaces (dpy, old_surface_id, 1);
862     status = gst_msdk_get_mfx_status_from_va_status (va_status);
863     if (status != MFX_ERR_NONE)
864       goto error_destroy_va_surface;
865   }
866
867   *msdk_mid->surface = surface_id;
868
869   return TRUE;
870
871 error_destroy_va_image:
872   {
873     GST_ERROR ("Failed to Destroy the VAImage");
874     return FALSE;
875   }
876 error_destroy_va_surface:
877   {
878     GST_ERROR ("Failed to Destroy the VASurfaceID %x", *old_surface_id);
879     return FALSE;
880   }
881 }