msdk: dmabuf support
[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 #include <unistd.h>
34 #include <stdlib.h>
35 #include <va/va.h>
36 #include "gstmsdkvideomemory.h"
37 #include "gstmsdkallocator.h"
38
39 #define GST_MSDK_BUFFER_SURFACE gst_msdk_buffer_surface_quark_get ()
40 static GQuark
41 gst_msdk_buffer_surface_quark_get (void)
42 {
43   static gsize g_quark;
44
45   if (g_once_init_enter (&g_quark)) {
46     gsize quark = (gsize) g_quark_from_static_string ("GstMsdkBufferSurface");
47     g_once_init_leave (&g_quark, quark);
48   }
49   return g_quark;
50 }
51
52 static mfxFrameSurface1 *
53 gst_msdk_video_allocator_get_surface (GstAllocator * allocator)
54 {
55   mfxFrameInfo frame_info = { {0,}, 0, };
56   mfxFrameSurface1 *surface;
57   GstMsdkContext *context = NULL;
58   mfxFrameAllocResponse *resp = NULL;
59   GstVideoInfo *vinfo = NULL;
60
61   if (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
62     context = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator)->context;
63     resp = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator)->alloc_response;
64     vinfo = &GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator)->image_info;
65   } else if (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator)) {
66     context = GST_MSDK_DMABUF_ALLOCATOR_CAST (allocator)->context;
67     resp = GST_MSDK_DMABUF_ALLOCATOR_CAST (allocator)->alloc_response;
68     vinfo = &GST_MSDK_DMABUF_ALLOCATOR_CAST (allocator)->image_info;
69   } else {
70     return NULL;
71   }
72
73   surface = gst_msdk_context_get_surface_available (context, resp);
74   if (!surface) {
75     GST_ERROR ("failed to get surface available");
76     return NULL;
77   }
78
79   gst_msdk_set_mfx_frame_info_from_video_info (&frame_info, vinfo);
80   surface->Info = frame_info;
81
82   return surface;
83 }
84
85 gboolean
86 gst_msdk_video_memory_get_surface_available (GstMemory * mem)
87 {
88   GstAllocator *allocator;
89   mfxFrameSurface1 *surface;
90
91   g_return_val_if_fail (mem, FALSE);
92
93   allocator = mem->allocator;
94   surface = gst_msdk_video_allocator_get_surface (allocator);
95
96   if (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
97     GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface = surface;
98   } else if (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator)) {
99     gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
100         GST_MSDK_BUFFER_SURFACE, surface, NULL);
101   }
102
103   return surface ? TRUE : FALSE;
104 }
105
106 /*
107  * Every time releasing a gst buffer, we need to check the status of surface's lock,
108  * so that we could manage locked surfaces seperatedly in the context.
109  * Otherwise, we put the surface to the available list.
110  */
111 void
112 gst_msdk_video_memory_release_surface (GstMemory * mem)
113 {
114   mfxFrameSurface1 *surface = NULL;
115   GstMsdkContext *context = NULL;
116   mfxFrameAllocResponse *alloc_response = NULL;
117
118   g_return_if_fail (mem);
119
120   if (GST_IS_MSDK_VIDEO_ALLOCATOR (mem->allocator)) {
121     surface = GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface;
122     context = GST_MSDK_VIDEO_ALLOCATOR_CAST (mem->allocator)->context;
123     alloc_response =
124         GST_MSDK_VIDEO_ALLOCATOR_CAST (mem->allocator)->alloc_response;
125   } else if (GST_IS_MSDK_DMABUF_ALLOCATOR (mem->allocator)) {
126     surface =
127         gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
128         GST_MSDK_BUFFER_SURFACE);
129     context = GST_MSDK_DMABUF_ALLOCATOR_CAST (mem->allocator)->context;
130     alloc_response =
131         GST_MSDK_DMABUF_ALLOCATOR_CAST (mem->allocator)->alloc_response;
132   } else {
133     return;
134   }
135
136   if (surface->Data.Locked > 0)
137     gst_msdk_context_put_surface_locked (context, alloc_response, surface);
138   else
139     gst_msdk_context_put_surface_available (context, alloc_response, surface);
140
141   if (GST_IS_MSDK_VIDEO_ALLOCATOR (mem->allocator))
142     GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface = NULL;
143   else if (GST_IS_MSDK_DMABUF_ALLOCATOR (mem->allocator))
144     gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
145         GST_MSDK_BUFFER_SURFACE, NULL, NULL);
146
147   return;
148 }
149
150 GstMemory *
151 gst_msdk_video_memory_new (GstAllocator * base_allocator)
152 {
153   GstMsdkVideoAllocator *allocator;
154   GstVideoInfo *vip;
155   GstMsdkVideoMemory *mem;
156
157   g_return_val_if_fail (base_allocator, NULL);
158   g_return_val_if_fail (GST_IS_MSDK_VIDEO_ALLOCATOR (base_allocator), NULL);
159
160   allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (base_allocator);
161
162   mem = g_slice_new0 (GstMsdkVideoMemory);
163   if (!mem)
164     return NULL;
165
166   mem->surface = gst_msdk_video_allocator_get_surface (base_allocator);
167   if (!mem->surface)
168     return NULL;
169
170   vip = &allocator->image_info;
171   gst_memory_init (&mem->parent_instance, GST_MEMORY_FLAG_NO_SHARE,
172       base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0, 0,
173       GST_VIDEO_INFO_SIZE (vip));
174
175   return GST_MEMORY_CAST (mem);
176 }
177
178 gboolean
179 gst_video_meta_map_msdk_memory (GstVideoMeta * meta, guint plane,
180     GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
181 {
182   gboolean ret = FALSE;
183   GstAllocator *allocator;
184   GstMsdkVideoAllocator *msdk_video_allocator;
185   GstMsdkVideoMemory *mem =
186       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
187   GstMsdkMemoryID *mem_id;
188   guint offset = 0;
189   gint pitch = 0;
190   guint plane_id = plane;
191
192   g_return_val_if_fail (mem, FALSE);
193
194   allocator = GST_MEMORY_CAST (mem)->allocator;
195   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
196
197   if (!GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
198     GST_WARNING ("The allocator is not MSDK video allocator");
199     return FALSE;
200   }
201
202   if (!mem->surface) {
203     GST_WARNING ("The surface is not allocated");
204     return FALSE;
205   }
206
207   if ((flags & GST_MAP_WRITE) && mem->surface && mem->surface->Data.Locked) {
208     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
209     return FALSE;
210   }
211
212   if (!mem->mapped) {
213     gst_msdk_frame_lock (msdk_video_allocator->context,
214         mem->surface->Data.MemId, &mem->surface->Data);
215   }
216
217   mem->mapped++;
218   mem_id = mem->surface->Data.MemId;
219
220   /* msdk doesn't support I420 format and we used YV12 internally
221    * So we need to swap U/V planes for mapping */
222   if (meta->format == GST_VIDEO_FORMAT_I420)
223     plane_id = plane ? (plane == 1 ? 2 : 1) : plane;
224
225 #ifndef _WIN32
226   offset = mem_id->image.offsets[plane_id];
227   pitch = mem_id->image.pitches[plane_id];
228 #else
229   /* TODO: This is just to avoid compile errors on Windows.
230    * Implement handling Windows-specific video-memory.
231    */
232   offset = mem_id->offset;
233   pitch = mem_id->pitch;
234 #endif
235
236   *data = mem->surface->Data.Y + offset;
237   *stride = pitch;
238
239   info->flags = flags;
240   ret = (*data != NULL);
241
242   return ret;
243 }
244
245 gboolean
246 gst_video_meta_unmap_msdk_memory (GstVideoMeta * meta, guint plane,
247     GstMapInfo * info)
248 {
249   GstAllocator *allocator;
250   GstMsdkVideoAllocator *msdk_video_allocator;
251   GstMsdkVideoMemory *mem =
252       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
253
254   g_return_val_if_fail (mem, FALSE);
255
256   allocator = GST_MEMORY_CAST (mem)->allocator;
257   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
258
259   if (mem->mapped == 1)
260     gst_msdk_frame_unlock (msdk_video_allocator->context,
261         mem->surface->Data.MemId, &mem->surface->Data);
262
263   mem->mapped--;
264
265   return TRUE;
266 }
267
268
269 static gpointer
270 gst_msdk_video_memory_map_full (GstMemory * base_mem, GstMapInfo * info,
271     gsize maxsize)
272 {
273   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
274   GstAllocator *allocator = base_mem->allocator;
275   GstMsdkVideoAllocator *msdk_video_allocator =
276       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
277
278   g_return_val_if_fail (mem, NULL);
279
280   if (!mem->surface) {
281     GST_WARNING ("The surface is not allocated");
282     return NULL;
283   }
284
285   if ((info->flags & GST_MAP_WRITE) && mem->surface
286       && mem->surface->Data.Locked) {
287     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
288     return NULL;
289   }
290
291   gst_msdk_frame_lock (msdk_video_allocator->context, mem->surface->Data.MemId,
292       &mem->surface->Data);
293   return mem->surface->Data.Y;
294 }
295
296 static void
297 gst_msdk_video_memory_unmap (GstMemory * base_mem)
298 {
299   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
300   GstAllocator *allocator = base_mem->allocator;
301   GstMsdkVideoAllocator *msdk_video_allocator =
302       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
303
304   gst_msdk_frame_unlock (msdk_video_allocator->context,
305       mem->surface->Data.MemId, &mem->surface->Data);
306 }
307
308 /* GstMsdkVideoAllocator */
309 G_DEFINE_TYPE (GstMsdkVideoAllocator, gst_msdk_video_allocator,
310     GST_TYPE_ALLOCATOR);
311
312 static GstMemory *
313 gst_msdk_video_allocator_alloc (GstAllocator * allocator, gsize size,
314     GstAllocationParams * params)
315 {
316   return gst_msdk_video_memory_new (allocator);
317 }
318
319 static void
320 gst_msdk_video_allocator_finalize (GObject * object)
321 {
322   GstMsdkVideoAllocator *allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (object);
323
324   gst_object_unref (allocator->context);
325   G_OBJECT_CLASS (gst_msdk_video_allocator_parent_class)->finalize (object);
326 }
327
328 static void
329 gst_msdk_video_allocator_class_init (GstMsdkVideoAllocatorClass * klass)
330 {
331   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
332   GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass);
333
334   object_class->finalize = gst_msdk_video_allocator_finalize;
335
336   allocator_class->alloc = gst_msdk_video_allocator_alloc;
337 }
338
339 static void
340 gst_msdk_video_allocator_init (GstMsdkVideoAllocator * allocator)
341 {
342   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
343
344   base_allocator->mem_type = GST_MSDK_VIDEO_MEMORY_NAME;
345   base_allocator->mem_map_full = gst_msdk_video_memory_map_full;
346   base_allocator->mem_unmap = gst_msdk_video_memory_unmap;
347
348   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
349 }
350
351 GstAllocator *
352 gst_msdk_video_allocator_new (GstMsdkContext * context,
353     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
354 {
355   GstMsdkVideoAllocator *allocator;
356
357   g_return_val_if_fail (context != NULL, NULL);
358   g_return_val_if_fail (image_info != NULL, NULL);
359
360   allocator = g_object_new (GST_TYPE_MSDK_VIDEO_ALLOCATOR, NULL);
361   if (!allocator)
362     return NULL;
363
364   allocator->context = gst_object_ref (context);
365   allocator->image_info = *image_info;
366   allocator->alloc_response = alloc_resp;
367
368   return GST_ALLOCATOR_CAST (allocator);
369 }
370
371 /* GstMsdkDmaBufMemory */
372 GstMemory *
373 gst_msdk_dmabuf_memory_new (GstAllocator * base_allocator)
374 {
375 #ifndef _WIN32
376   mfxFrameSurface1 *surface;
377
378   g_return_val_if_fail (base_allocator, NULL);
379   g_return_val_if_fail (GST_IS_MSDK_DMABUF_ALLOCATOR (base_allocator), NULL);
380
381   surface = gst_msdk_video_allocator_get_surface (base_allocator);
382   if (!surface)
383     return NULL;
384
385   return gst_msdk_dmabuf_memory_new_with_surface (base_allocator, surface);
386 #else
387   return NULL;
388 #endif
389 }
390
391 GstMemory *
392 gst_msdk_dmabuf_memory_new_with_surface (GstAllocator * allocator,
393     mfxFrameSurface1 * surface)
394 {
395 #ifndef _WIN32
396   GstMemory *mem;
397   GstMsdkMemoryID *mem_id;
398   gint fd;
399   gsize size;
400
401   g_return_val_if_fail (allocator, NULL);
402   g_return_val_if_fail (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator), NULL);
403
404   mem_id = surface->Data.MemId;
405   fd = mem_id->info.handle;
406   size = mem_id->info.mem_size;
407
408   if (fd < 0 || (fd = dup (fd)) < 0) {
409     GST_ERROR ("Failed to get dmabuf handle");
410     return NULL;
411   }
412
413   mem = gst_dmabuf_allocator_alloc (allocator, fd, size);
414   if (!mem) {
415     GST_ERROR ("failed ! dmabuf fd: %d", fd);
416     return NULL;
417   }
418
419   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
420       GST_MSDK_BUFFER_SURFACE, surface, NULL);
421
422   return mem;
423 #else
424   return NULL;
425 #endif
426 }
427
428 /* GstMsdkDmaBufAllocator */
429 G_DEFINE_TYPE (GstMsdkDmaBufAllocator, gst_msdk_dmabuf_allocator,
430     GST_TYPE_DMABUF_ALLOCATOR);
431
432 static void
433 gst_msdk_dmabuf_allocator_finalize (GObject * object)
434 {
435   GstMsdkDmaBufAllocator *allocator = GST_MSDK_DMABUF_ALLOCATOR_CAST (object);
436
437   gst_object_unref (allocator->context);
438   G_OBJECT_CLASS (gst_msdk_dmabuf_allocator_parent_class)->finalize (object);
439 }
440
441 static void
442 gst_msdk_dmabuf_allocator_class_init (GstMsdkDmaBufAllocatorClass * klass)
443 {
444   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
445
446   object_class->finalize = gst_msdk_dmabuf_allocator_finalize;
447 }
448
449 static void
450 gst_msdk_dmabuf_allocator_init (GstMsdkDmaBufAllocator * allocator)
451 {
452   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
453   base_allocator->mem_type = GST_MSDK_DMABUF_MEMORY_NAME;
454 }
455
456 GstAllocator *
457 gst_msdk_dmabuf_allocator_new (GstMsdkContext * context,
458     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
459 {
460   GstMsdkDmaBufAllocator *allocator;
461
462   g_return_val_if_fail (context != NULL, NULL);
463   g_return_val_if_fail (image_info != NULL, NULL);
464
465   allocator = g_object_new (GST_TYPE_MSDK_DMABUF_ALLOCATOR, NULL);
466   if (!allocator)
467     return NULL;
468
469   allocator->context = gst_object_ref (context);
470   allocator->image_info = *image_info;
471   allocator->alloc_response = alloc_resp;
472
473   return GST_ALLOCATOR_CAST (allocator);
474 }