msdk: return a right pointer for Y410 when mapping a frame
[platform/upstream/gstreamer.git] / 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 seperatedly 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     return NULL;
171
172   vip = &allocator->image_info;
173   gst_memory_init (&mem->parent_instance, GST_MEMORY_FLAG_NO_SHARE,
174       base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0, 0,
175       GST_VIDEO_INFO_SIZE (vip));
176
177   return GST_MEMORY_CAST (mem);
178 }
179
180 gboolean
181 gst_video_meta_map_msdk_memory (GstVideoMeta * meta, guint plane,
182     GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
183 {
184   gboolean ret = FALSE;
185   GstAllocator *allocator;
186   GstMsdkVideoAllocator *msdk_video_allocator;
187   GstMsdkVideoMemory *mem =
188       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
189   GstMsdkMemoryID *mem_id;
190   guint offset = 0;
191   gint pitch = 0;
192   guint plane_id = plane;
193
194   g_return_val_if_fail (mem, FALSE);
195
196   allocator = GST_MEMORY_CAST (mem)->allocator;
197   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
198
199   if (!GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
200     GST_WARNING ("The allocator is not MSDK video allocator");
201     return FALSE;
202   }
203
204   if (!mem->surface) {
205     GST_WARNING ("The surface is not allocated");
206     return FALSE;
207   }
208
209   if ((flags & GST_MAP_WRITE) && mem->surface && mem->surface->Data.Locked) {
210     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
211     return FALSE;
212   }
213
214   if (!mem->mapped) {
215     gst_msdk_frame_lock (msdk_video_allocator->context,
216         mem->surface->Data.MemId, &mem->surface->Data);
217   }
218
219   mem->mapped++;
220   mem_id = mem->surface->Data.MemId;
221
222   /* msdk doesn't support I420 format and we used YV12 internally
223    * So we need to swap U/V planes for mapping */
224   if (meta->format == GST_VIDEO_FORMAT_I420)
225     plane_id = plane ? (plane == 1 ? 2 : 1) : plane;
226
227 #ifndef _WIN32
228   offset = mem_id->image.offsets[plane_id];
229   pitch = mem_id->image.pitches[plane_id];
230 #else
231   /* TODO: This is just to avoid compile errors on Windows.
232    * Implement handling Windows-specific video-memory.
233    */
234   offset = mem_id->offset;
235   pitch = mem_id->pitch;
236 #endif
237
238   /* The first channel in memory is V for GST_VIDEO_FORMAT_VUYA */
239   if (meta->format == GST_VIDEO_FORMAT_VUYA)
240     *data = mem->surface->Data.V + offset;
241   else if (meta->format == GST_VIDEO_FORMAT_Y410)
242     *data = mem->surface->Data.U + offset;      /* Data.Y410 */
243   else
244     *data = mem->surface->Data.Y + offset;
245   *stride = pitch;
246
247   info->flags = flags;
248   ret = (*data != NULL);
249
250   return ret;
251 }
252
253 gboolean
254 gst_video_meta_unmap_msdk_memory (GstVideoMeta * meta, guint plane,
255     GstMapInfo * info)
256 {
257   GstAllocator *allocator;
258   GstMsdkVideoAllocator *msdk_video_allocator;
259   GstMsdkVideoMemory *mem =
260       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
261
262   g_return_val_if_fail (mem, FALSE);
263
264   allocator = GST_MEMORY_CAST (mem)->allocator;
265   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
266
267   if (mem->mapped == 1)
268     gst_msdk_frame_unlock (msdk_video_allocator->context,
269         mem->surface->Data.MemId, &mem->surface->Data);
270
271   mem->mapped--;
272
273   return TRUE;
274 }
275
276
277 static gpointer
278 gst_msdk_video_memory_map_full (GstMemory * base_mem, GstMapInfo * info,
279     gsize maxsize)
280 {
281   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
282   GstAllocator *allocator = base_mem->allocator;
283   GstMsdkVideoAllocator *msdk_video_allocator =
284       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
285
286   g_return_val_if_fail (mem, NULL);
287
288   if (!mem->surface) {
289     GST_WARNING ("The surface is not allocated");
290     return NULL;
291   }
292
293   if ((info->flags & GST_MAP_WRITE) && mem->surface
294       && mem->surface->Data.Locked) {
295     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
296     return NULL;
297   }
298
299   gst_msdk_frame_lock (msdk_video_allocator->context, mem->surface->Data.MemId,
300       &mem->surface->Data);
301   return mem->surface->Data.Y;
302 }
303
304 static void
305 gst_msdk_video_memory_unmap (GstMemory * base_mem)
306 {
307   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
308   GstAllocator *allocator = base_mem->allocator;
309   GstMsdkVideoAllocator *msdk_video_allocator =
310       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
311
312   gst_msdk_frame_unlock (msdk_video_allocator->context,
313       mem->surface->Data.MemId, &mem->surface->Data);
314 }
315
316 /* GstMsdkVideoAllocator */
317 G_DEFINE_TYPE (GstMsdkVideoAllocator, gst_msdk_video_allocator,
318     GST_TYPE_ALLOCATOR);
319
320 static GstMemory *
321 gst_msdk_video_allocator_alloc (GstAllocator * allocator, gsize size,
322     GstAllocationParams * params)
323 {
324   return gst_msdk_video_memory_new (allocator);
325 }
326
327 static void
328 gst_msdk_video_allocator_finalize (GObject * object)
329 {
330   GstMsdkVideoAllocator *allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (object);
331
332   gst_object_unref (allocator->context);
333   G_OBJECT_CLASS (gst_msdk_video_allocator_parent_class)->finalize (object);
334 }
335
336 static void
337 gst_msdk_video_allocator_class_init (GstMsdkVideoAllocatorClass * klass)
338 {
339   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
340   GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass);
341
342   object_class->finalize = gst_msdk_video_allocator_finalize;
343
344   allocator_class->alloc = gst_msdk_video_allocator_alloc;
345 }
346
347 static void
348 gst_msdk_video_allocator_init (GstMsdkVideoAllocator * allocator)
349 {
350   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
351
352   base_allocator->mem_type = GST_MSDK_VIDEO_MEMORY_NAME;
353   base_allocator->mem_map_full = gst_msdk_video_memory_map_full;
354   base_allocator->mem_unmap = gst_msdk_video_memory_unmap;
355
356   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
357 }
358
359 GstAllocator *
360 gst_msdk_video_allocator_new (GstMsdkContext * context,
361     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
362 {
363   GstMsdkVideoAllocator *allocator;
364
365   g_return_val_if_fail (context != NULL, NULL);
366   g_return_val_if_fail (image_info != NULL, NULL);
367
368   allocator = g_object_new (GST_TYPE_MSDK_VIDEO_ALLOCATOR, NULL);
369   if (!allocator)
370     return NULL;
371
372   allocator->context = gst_object_ref (context);
373   allocator->image_info = *image_info;
374   allocator->alloc_response = alloc_resp;
375
376   return GST_ALLOCATOR_CAST (allocator);
377 }
378
379 /* GstMsdkDmaBufMemory */
380 GstMemory *
381 gst_msdk_dmabuf_memory_new (GstAllocator * base_allocator)
382 {
383 #ifndef _WIN32
384   mfxFrameSurface1 *surface;
385
386   g_return_val_if_fail (base_allocator, NULL);
387   g_return_val_if_fail (GST_IS_MSDK_DMABUF_ALLOCATOR (base_allocator), NULL);
388
389   surface = gst_msdk_video_allocator_get_surface (base_allocator);
390   if (!surface)
391     return NULL;
392
393   return gst_msdk_dmabuf_memory_new_with_surface (base_allocator, surface);
394 #else
395   return NULL;
396 #endif
397 }
398
399 GstMemory *
400 gst_msdk_dmabuf_memory_new_with_surface (GstAllocator * allocator,
401     mfxFrameSurface1 * surface)
402 {
403 #ifndef _WIN32
404   GstMemory *mem;
405   GstMsdkMemoryID *mem_id;
406   gint fd;
407   gsize size;
408
409   g_return_val_if_fail (allocator, NULL);
410   g_return_val_if_fail (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator), NULL);
411
412   mem_id = surface->Data.MemId;
413   fd = mem_id->info.handle;
414   size = mem_id->info.mem_size;
415
416   if (fd < 0 || (fd = dup (fd)) < 0) {
417     GST_ERROR ("Failed to get dmabuf handle");
418     return NULL;
419   }
420
421   mem = gst_dmabuf_allocator_alloc (allocator, fd, size);
422   if (!mem) {
423     GST_ERROR ("failed ! dmabuf fd: %d", fd);
424     close (fd);
425     return NULL;
426   }
427
428   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
429       GST_MSDK_BUFFER_SURFACE, surface, NULL);
430
431   return mem;
432 #else
433   return NULL;
434 #endif
435 }
436
437 /* GstMsdkDmaBufAllocator */
438 G_DEFINE_TYPE (GstMsdkDmaBufAllocator, gst_msdk_dmabuf_allocator,
439     GST_TYPE_DMABUF_ALLOCATOR);
440
441 static void
442 gst_msdk_dmabuf_allocator_finalize (GObject * object)
443 {
444   GstMsdkDmaBufAllocator *allocator = GST_MSDK_DMABUF_ALLOCATOR_CAST (object);
445
446   gst_object_unref (allocator->context);
447   G_OBJECT_CLASS (gst_msdk_dmabuf_allocator_parent_class)->finalize (object);
448 }
449
450 static void
451 gst_msdk_dmabuf_allocator_class_init (GstMsdkDmaBufAllocatorClass * klass)
452 {
453   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
454
455   object_class->finalize = gst_msdk_dmabuf_allocator_finalize;
456 }
457
458 static void
459 gst_msdk_dmabuf_allocator_init (GstMsdkDmaBufAllocator * allocator)
460 {
461   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
462   base_allocator->mem_type = GST_MSDK_DMABUF_MEMORY_NAME;
463 }
464
465 GstAllocator *
466 gst_msdk_dmabuf_allocator_new (GstMsdkContext * context,
467     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
468 {
469   GstMsdkDmaBufAllocator *allocator;
470
471   g_return_val_if_fail (context != NULL, NULL);
472   g_return_val_if_fail (image_info != NULL, NULL);
473
474   allocator = g_object_new (GST_TYPE_MSDK_DMABUF_ALLOCATOR, NULL);
475   if (!allocator)
476     return NULL;
477
478   allocator->context = gst_object_ref (context);
479   allocator->image_info = *image_info;
480   allocator->alloc_response = alloc_resp;
481
482   return GST_ALLOCATOR_CAST (allocator);
483 }