taglist, plugins: fix compiler warnings with GLib >= 2.76
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / msdk / gstmsdkvideomemory.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 #ifndef _WIN32
34 #include <unistd.h>
35 #include <va/va.h>
36 #endif
37 #include <stdlib.h>
38 #include "gstmsdkvideomemory.h"
39 #include "gstmsdkallocator.h"
40
41 #define GST_MSDK_BUFFER_SURFACE gst_msdk_buffer_surface_quark_get ()
42 static GQuark
43 gst_msdk_buffer_surface_quark_get (void)
44 {
45   static gsize g_quark;
46
47   if (g_once_init_enter (&g_quark)) {
48     gsize quark = (gsize) g_quark_from_static_string ("GstMsdkBufferSurface");
49     g_once_init_leave (&g_quark, quark);
50   }
51   return g_quark;
52 }
53
54 static mfxFrameSurface1 *
55 gst_msdk_video_allocator_get_surface (GstAllocator * allocator)
56 {
57   mfxFrameInfo frame_info = { {0,}, 0, };
58   mfxFrameSurface1 *surface;
59   GstMsdkContext *context = NULL;
60   mfxFrameAllocResponse *resp = NULL;
61   GstVideoInfo *vinfo = NULL;
62
63   if (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
64     context = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator)->context;
65     resp = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator)->alloc_response;
66     vinfo = &GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator)->image_info;
67   } else if (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator)) {
68     context = GST_MSDK_DMABUF_ALLOCATOR_CAST (allocator)->context;
69     resp = GST_MSDK_DMABUF_ALLOCATOR_CAST (allocator)->alloc_response;
70     vinfo = &GST_MSDK_DMABUF_ALLOCATOR_CAST (allocator)->image_info;
71   } else {
72     return NULL;
73   }
74
75   surface = gst_msdk_context_get_surface_available (context, resp);
76   if (!surface) {
77     GST_ERROR ("failed to get surface available");
78     return NULL;
79   }
80
81   gst_msdk_set_mfx_frame_info_from_video_info (&frame_info, vinfo);
82   surface->Info = frame_info;
83
84   return surface;
85 }
86
87 gboolean
88 gst_msdk_video_memory_get_surface_available (GstMemory * mem)
89 {
90   GstAllocator *allocator;
91   mfxFrameSurface1 *surface;
92
93   g_return_val_if_fail (mem, FALSE);
94
95   allocator = mem->allocator;
96   surface = gst_msdk_video_allocator_get_surface (allocator);
97
98   if (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
99     GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface = surface;
100   } else if (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator)) {
101     gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
102         GST_MSDK_BUFFER_SURFACE, surface, NULL);
103   }
104
105   return surface ? TRUE : FALSE;
106 }
107
108 /*
109  * Every time releasing a gst buffer, we need to check the status of surface's lock,
110  * so that we could manage locked surfaces separately in the context.
111  * Otherwise, we put the surface to the available list.
112  */
113 void
114 gst_msdk_video_memory_release_surface (GstMemory * mem)
115 {
116   mfxFrameSurface1 *surface = NULL;
117   GstMsdkContext *context = NULL;
118   mfxFrameAllocResponse *alloc_response = NULL;
119
120   g_return_if_fail (mem);
121
122   if (GST_IS_MSDK_VIDEO_ALLOCATOR (mem->allocator)) {
123     surface = GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface;
124     context = GST_MSDK_VIDEO_ALLOCATOR_CAST (mem->allocator)->context;
125     alloc_response =
126         GST_MSDK_VIDEO_ALLOCATOR_CAST (mem->allocator)->alloc_response;
127   } else if (GST_IS_MSDK_DMABUF_ALLOCATOR (mem->allocator)) {
128     surface =
129         gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
130         GST_MSDK_BUFFER_SURFACE);
131     context = GST_MSDK_DMABUF_ALLOCATOR_CAST (mem->allocator)->context;
132     alloc_response =
133         GST_MSDK_DMABUF_ALLOCATOR_CAST (mem->allocator)->alloc_response;
134   } else {
135     return;
136   }
137
138   if (surface->Data.Locked > 0)
139     gst_msdk_context_put_surface_locked (context, alloc_response, surface);
140   else
141     gst_msdk_context_put_surface_available (context, alloc_response, surface);
142
143   if (GST_IS_MSDK_VIDEO_ALLOCATOR (mem->allocator))
144     GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface = NULL;
145   else if (GST_IS_MSDK_DMABUF_ALLOCATOR (mem->allocator))
146     gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
147         GST_MSDK_BUFFER_SURFACE, NULL, NULL);
148
149   return;
150 }
151
152 GstMemory *
153 gst_msdk_video_memory_new (GstAllocator * base_allocator)
154 {
155   GstMsdkVideoAllocator *allocator;
156   GstVideoInfo *vip;
157   GstMsdkVideoMemory *mem;
158
159   g_return_val_if_fail (base_allocator, NULL);
160   g_return_val_if_fail (GST_IS_MSDK_VIDEO_ALLOCATOR (base_allocator), NULL);
161
162   allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (base_allocator);
163
164   mem = g_slice_new0 (GstMsdkVideoMemory);
165   if (!mem)
166     return NULL;
167
168   mem->surface = gst_msdk_video_allocator_get_surface (base_allocator);
169   if (!mem->surface) {
170     g_slice_free (GstMsdkVideoMemory, mem);
171     return NULL;
172   }
173
174   vip = &allocator->image_info;
175   gst_memory_init (&mem->parent_instance, 0,
176       base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0, 0,
177       GST_VIDEO_INFO_SIZE (vip));
178
179   return GST_MEMORY_CAST (mem);
180 }
181
182 gboolean
183 gst_video_meta_map_msdk_memory (GstVideoMeta * meta, guint plane,
184     GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
185 {
186   gboolean ret = FALSE;
187   GstAllocator *allocator;
188   GstMsdkVideoAllocator *msdk_video_allocator;
189   GstMsdkVideoMemory *mem =
190       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
191   GstMsdkMemoryID *mem_id;
192   guint offset = 0;
193   gint pitch = 0;
194   guint plane_id = plane;
195
196   g_return_val_if_fail (mem, FALSE);
197
198   allocator = GST_MEMORY_CAST (mem)->allocator;
199   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
200
201   if (!GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
202     GST_WARNING ("The allocator is not MSDK video allocator");
203     return FALSE;
204   }
205
206   if (!mem->surface) {
207     GST_WARNING ("The surface is not allocated");
208     return FALSE;
209   }
210
211   if ((flags & GST_MAP_WRITE) && mem->surface && mem->surface->Data.Locked) {
212     GST_WARNING ("The surface in memory %p is not still available", mem);
213     return FALSE;
214   }
215
216   if (!mem->mapped) {
217     gst_msdk_frame_lock (msdk_video_allocator->context,
218         mem->surface->Data.MemId, &mem->surface->Data);
219   }
220
221   mem->mapped++;
222   mem_id = mem->surface->Data.MemId;
223
224   /* msdk doesn't support I420 format and we used YV12 internally
225    * So we need to swap U/V planes for mapping */
226   if (meta->format == GST_VIDEO_FORMAT_I420)
227     plane_id = plane ? (plane == 1 ? 2 : 1) : plane;
228
229 #ifndef _WIN32
230   offset = mem_id->image.offsets[plane_id];
231   pitch = mem_id->image.pitches[plane_id];
232 #else
233   /* TODO: This is just to avoid compile errors on Windows.
234    * Implement handling Windows-specific video-memory.
235    */
236   offset = mem_id->offset;
237   pitch = mem_id->pitch;
238 #endif
239
240   switch (meta->format) {
241     case GST_VIDEO_FORMAT_BGRA:
242     case GST_VIDEO_FORMAT_BGRx:
243       *data = mem->surface->Data.B + offset;
244       break;
245
246       /* The first channel in memory is V for GST_VIDEO_FORMAT_VUYA */
247     case GST_VIDEO_FORMAT_VUYA:
248       *data = mem->surface->Data.V + offset;
249       break;
250
251     case GST_VIDEO_FORMAT_Y410:
252     case GST_VIDEO_FORMAT_Y412_LE:
253       *data = mem->surface->Data.U + offset;
254       break;
255
256     default:
257       *data = mem->surface->Data.Y + offset;
258       break;
259   }
260
261   *stride = pitch;
262   info->flags = flags;
263   ret = (*data != NULL);
264
265   return ret;
266 }
267
268 gboolean
269 gst_video_meta_unmap_msdk_memory (GstVideoMeta * meta, guint plane,
270     GstMapInfo * info)
271 {
272   GstAllocator *allocator;
273   GstMsdkVideoAllocator *msdk_video_allocator;
274   GstMsdkVideoMemory *mem =
275       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
276
277   g_return_val_if_fail (mem, FALSE);
278
279   allocator = GST_MEMORY_CAST (mem)->allocator;
280   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
281
282   if (mem->mapped == 1)
283     gst_msdk_frame_unlock (msdk_video_allocator->context,
284         mem->surface->Data.MemId, &mem->surface->Data);
285
286   mem->mapped--;
287
288   return TRUE;
289 }
290
291
292 static gpointer
293 gst_msdk_video_memory_map_full (GstMemory * base_mem, GstMapInfo * info,
294     gsize maxsize)
295 {
296   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
297   GstAllocator *allocator = base_mem->allocator;
298   GstMsdkVideoAllocator *msdk_video_allocator =
299       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
300
301   g_return_val_if_fail (mem, NULL);
302
303   if (!mem->surface) {
304     GST_WARNING ("The surface is not allocated");
305     return NULL;
306   }
307
308   if ((info->flags & GST_MAP_WRITE) && mem->surface
309       && mem->surface->Data.Locked) {
310     GST_WARNING ("The surface in memory %p is not still available", mem);
311     return NULL;
312   }
313
314   gst_msdk_frame_lock (msdk_video_allocator->context, mem->surface->Data.MemId,
315       &mem->surface->Data);
316
317   switch (mem->surface->Info.FourCC) {
318     case MFX_FOURCC_RGB4:
319       return mem->surface->Data.B;      /* The first channel is B */
320
321       /* The first channel in memory is V for MFX_FOURCC_AYUV (GST_VIDEO_FORMAT_VUYA) format */
322     case MFX_FOURCC_AYUV:
323       return mem->surface->Data.V;
324
325 #if (MFX_VERSION >= 1027)
326     case MFX_FOURCC_Y410:
327       return mem->surface->Data.U;      /* Data.Y410 */
328 #endif
329
330 #if (MFX_VERSION >= 1031)
331     case MFX_FOURCC_Y416:
332       return mem->surface->Data.U;
333 #endif
334
335 #if (MFX_VERSION >= 2004)
336     case MFX_FOURCC_RGBP:
337       return mem->surface->Data.R;
338
339     case MFX_FOURCC_BGRP:
340       return mem->surface->Data.B;
341 #endif
342
343     default:
344       return mem->surface->Data.Y;
345   }
346 }
347
348 static void
349 gst_msdk_video_memory_unmap (GstMemory * base_mem)
350 {
351   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
352   GstAllocator *allocator = base_mem->allocator;
353   GstMsdkVideoAllocator *msdk_video_allocator =
354       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
355
356   gst_msdk_frame_unlock (msdk_video_allocator->context,
357       mem->surface->Data.MemId, &mem->surface->Data);
358 }
359
360 static GstMemory *
361 gst_msdk_video_memory_copy (GstMemory * base_mem, gssize offset, gssize size)
362 {
363   GstMemory *copy;
364   GstVideoInfo *info;
365   GstMsdkVideoAllocator *msdk_video_allocator;
366   gsize mem_size;
367   GstMapInfo src_map, dst_map;
368
369   /* FIXME: can we consider offset and size here ? */
370   copy = gst_msdk_video_memory_new (base_mem->allocator);
371
372   if (!copy) {
373     GST_ERROR_OBJECT (base_mem->allocator, "Failed to create new video memory");
374     return NULL;
375   }
376
377   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (base_mem->allocator);
378
379   info = &msdk_video_allocator->image_info;
380   mem_size = GST_VIDEO_INFO_SIZE (info);
381
382   gst_memory_map (base_mem, &src_map, GST_MAP_READ);
383   gst_memory_map (copy, &dst_map, GST_MAP_WRITE);
384
385   memcpy (dst_map.data, src_map.data, mem_size);
386   gst_memory_unmap (copy, &dst_map);
387   gst_memory_unmap (base_mem, &src_map);
388
389   return copy;
390 }
391
392 /* GstMsdkVideoAllocator */
393 G_DEFINE_TYPE (GstMsdkVideoAllocator, gst_msdk_video_allocator,
394     GST_TYPE_ALLOCATOR);
395
396 static GstMemory *
397 gst_msdk_video_allocator_alloc (GstAllocator * allocator, gsize size,
398     GstAllocationParams * params)
399 {
400   return gst_msdk_video_memory_new (allocator);
401 }
402
403 static void
404 gst_msdk_video_allocator_finalize (GObject * object)
405 {
406   GstMsdkVideoAllocator *allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (object);
407
408   gst_msdk_frame_free (allocator->context, allocator->alloc_response);
409
410   gst_object_unref (allocator->context);
411   G_OBJECT_CLASS (gst_msdk_video_allocator_parent_class)->finalize (object);
412 }
413
414 static void
415 gst_msdk_video_allocator_free (GstAllocator * allocator, GstMemory * base_mem)
416 {
417   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
418
419   g_slice_free (GstMsdkVideoMemory, mem);
420 }
421
422 static void
423 gst_msdk_video_allocator_class_init (GstMsdkVideoAllocatorClass * klass)
424 {
425   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
426   GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass);
427
428   object_class->finalize = gst_msdk_video_allocator_finalize;
429
430   allocator_class->alloc = gst_msdk_video_allocator_alloc;
431   allocator_class->free = gst_msdk_video_allocator_free;
432 }
433
434 static void
435 gst_msdk_video_allocator_init (GstMsdkVideoAllocator * allocator)
436 {
437   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
438
439   base_allocator->mem_type = GST_MSDK_VIDEO_MEMORY_NAME;
440   base_allocator->mem_map_full = gst_msdk_video_memory_map_full;
441   base_allocator->mem_unmap = gst_msdk_video_memory_unmap;
442   base_allocator->mem_copy = gst_msdk_video_memory_copy;
443
444   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
445 }
446
447 GstAllocator *
448 gst_msdk_video_allocator_new (GstMsdkContext * context,
449     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
450 {
451   GstMsdkVideoAllocator *allocator;
452   GstMsdkAllocResponse *cached = NULL;
453
454   g_return_val_if_fail (context != NULL, NULL);
455   g_return_val_if_fail (image_info != NULL, NULL);
456
457   cached = gst_msdk_context_get_cached_alloc_responses (context, alloc_resp);
458
459   if (!cached) {
460     GST_ERROR ("Failed to get the cached alloc response");
461     return NULL;
462   }
463
464   allocator = g_object_new (GST_TYPE_MSDK_VIDEO_ALLOCATOR, NULL);
465   if (!allocator)
466     return NULL;
467
468   g_atomic_int_inc (&cached->refcount);
469   allocator->context = gst_object_ref (context);
470   allocator->image_info = *image_info;
471   allocator->mfx_response = *alloc_resp;
472   allocator->alloc_response = &allocator->mfx_response;
473
474   return GST_ALLOCATOR_CAST (allocator);
475 }
476
477 /* GstMsdkDmaBufMemory */
478 GstMemory *
479 gst_msdk_dmabuf_memory_new (GstAllocator * base_allocator)
480 {
481 #ifndef _WIN32
482   mfxFrameSurface1 *surface;
483
484   g_return_val_if_fail (base_allocator, NULL);
485   g_return_val_if_fail (GST_IS_MSDK_DMABUF_ALLOCATOR (base_allocator), NULL);
486
487   surface = gst_msdk_video_allocator_get_surface (base_allocator);
488   if (!surface)
489     return NULL;
490
491   return gst_msdk_dmabuf_memory_new_with_surface (base_allocator, surface);
492 #else
493   return NULL;
494 #endif
495 }
496
497 GstMemory *
498 gst_msdk_dmabuf_memory_new_with_surface (GstAllocator * allocator,
499     mfxFrameSurface1 * surface)
500 {
501 #ifndef _WIN32
502   GstMemory *mem;
503   GstMsdkMemoryID *mem_id;
504   gint fd;
505   gsize size;
506
507   g_return_val_if_fail (allocator, NULL);
508   g_return_val_if_fail (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator), NULL);
509
510   mem_id = surface->Data.MemId;
511
512   g_assert (mem_id->desc.num_objects == 1);
513
514   fd = mem_id->desc.objects[0].fd;
515   size = mem_id->desc.objects[0].size;
516
517   if (fd < 0) {
518     GST_ERROR ("Failed to get dmabuf handle");
519     return NULL;
520   }
521
522   mem = gst_fd_allocator_alloc (allocator, fd, size,
523       GST_FD_MEMORY_FLAG_DONT_CLOSE);
524
525   if (!mem) {
526     GST_ERROR ("failed ! dmabuf fd: %d", fd);
527     return NULL;
528   }
529
530   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
531       GST_MSDK_BUFFER_SURFACE, surface, NULL);
532
533   return mem;
534 #else
535   return NULL;
536 #endif
537 }
538
539 /* GstMsdkDmaBufAllocator */
540 G_DEFINE_TYPE (GstMsdkDmaBufAllocator, gst_msdk_dmabuf_allocator,
541     GST_TYPE_DMABUF_ALLOCATOR);
542
543 static void
544 gst_msdk_dmabuf_allocator_finalize (GObject * object)
545 {
546   GstMsdkDmaBufAllocator *allocator = GST_MSDK_DMABUF_ALLOCATOR_CAST (object);
547
548   gst_msdk_frame_free (allocator->context, allocator->alloc_response);
549
550   gst_object_unref (allocator->context);
551   G_OBJECT_CLASS (gst_msdk_dmabuf_allocator_parent_class)->finalize (object);
552 }
553
554 static void
555 gst_msdk_dmabuf_allocator_class_init (GstMsdkDmaBufAllocatorClass * klass)
556 {
557   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
558
559   object_class->finalize = gst_msdk_dmabuf_allocator_finalize;
560 }
561
562 static void
563 gst_msdk_dmabuf_allocator_init (GstMsdkDmaBufAllocator * allocator)
564 {
565   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
566   base_allocator->mem_type = GST_MSDK_DMABUF_MEMORY_NAME;
567 }
568
569 GstAllocator *
570 gst_msdk_dmabuf_allocator_new (GstMsdkContext * context,
571     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
572 {
573   GstMsdkDmaBufAllocator *allocator;
574   GstMsdkAllocResponse *cached = NULL;
575
576   g_return_val_if_fail (context != NULL, NULL);
577   g_return_val_if_fail (image_info != NULL, NULL);
578
579   cached = gst_msdk_context_get_cached_alloc_responses (context, alloc_resp);
580
581   if (!cached) {
582     GST_ERROR ("Failed to get the cached alloc response");
583     return NULL;
584   }
585
586   allocator = g_object_new (GST_TYPE_MSDK_DMABUF_ALLOCATOR, NULL);
587   if (!allocator)
588     return NULL;
589
590   g_atomic_int_inc (&cached->refcount);
591   allocator->context = gst_object_ref (context);
592   allocator->image_info = *image_info;
593   allocator->mfx_response = *alloc_resp;
594   allocator->alloc_response = &allocator->mfx_response;
595
596   return GST_ALLOCATOR_CAST (allocator);
597 }