msdk: generalize the parameter of msdk video memory functions
[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 static mfxFrameSurface1 *
40 gst_msdk_video_allocator_get_surface (GstAllocator * allocator)
41 {
42   mfxFrameInfo frame_info = { {0,}, 0, };
43   mfxFrameSurface1 *surface;
44   GstMsdkVideoAllocator *msdk_video_allocator =
45       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
46
47   surface =
48       gst_msdk_context_get_surface_available (msdk_video_allocator->context,
49       msdk_video_allocator->alloc_response);
50   if (!surface) {
51     GST_ERROR ("failed to get surface available");
52     return NULL;
53   }
54
55   gst_msdk_set_mfx_frame_info_from_video_info (&frame_info,
56       &msdk_video_allocator->image_info);
57
58   surface->Info = frame_info;
59
60   return surface;
61 }
62
63 gboolean
64 gst_msdk_video_memory_get_surface_available (GstMemory * mem)
65 {
66   GstAllocator *allocator;
67   GstMsdkVideoMemory *msdk_mem;
68
69   g_return_val_if_fail (mem, FALSE);
70   g_return_val_if_fail (GST_IS_MSDK_VIDEO_MEMORY (mem), FALSE);
71
72   msdk_mem = GST_MSDK_VIDEO_MEMORY_CAST (mem);
73   allocator = mem->allocator;
74   msdk_mem->surface = gst_msdk_video_allocator_get_surface (allocator);
75   return msdk_mem->surface ? TRUE : FALSE;
76 }
77
78 /*
79  * Every time releasing a gst buffer, we need to check the status of surface's lock,
80  * so that we could manage locked surfaces seperatedly in the context.
81  * Otherwise, we put the surface to the available list.
82  */
83 void
84 gst_msdk_video_memory_release_surface (GstMemory * mem)
85 {
86   GstMsdkVideoAllocator *msdk_video_allocator;
87   GstMsdkVideoMemory *msdk_mem;
88
89   g_return_if_fail (mem);
90   g_return_if_fail (GST_IS_MSDK_VIDEO_MEMORY (mem));
91
92   msdk_mem = GST_MSDK_VIDEO_MEMORY_CAST (mem);
93   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (mem->allocator);
94
95   if (!msdk_mem->surface)
96     return;
97
98   if (msdk_mem->surface->Data.Locked > 0)
99     gst_msdk_context_put_surface_locked (msdk_video_allocator->context,
100         msdk_video_allocator->alloc_response, msdk_mem->surface);
101   else
102     gst_msdk_context_put_surface_available (msdk_video_allocator->context,
103         msdk_video_allocator->alloc_response, msdk_mem->surface);
104
105   msdk_mem->surface = NULL;
106   return;
107 }
108
109 GstMemory *
110 gst_msdk_video_memory_new (GstAllocator * base_allocator)
111 {
112   GstMsdkVideoAllocator *allocator;
113   GstVideoInfo *vip;
114   GstMsdkVideoMemory *mem;
115
116   g_return_val_if_fail (base_allocator, NULL);
117   g_return_val_if_fail (GST_IS_MSDK_VIDEO_ALLOCATOR (base_allocator), NULL);
118
119   allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (base_allocator);
120
121   mem = g_slice_new0 (GstMsdkVideoMemory);
122   if (!mem)
123     return NULL;
124
125   mem->surface = gst_msdk_video_allocator_get_surface (base_allocator);
126   if (!mem->surface)
127     return NULL;
128
129   vip = &allocator->image_info;
130   gst_memory_init (&mem->parent_instance, GST_MEMORY_FLAG_NO_SHARE,
131       base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0, 0,
132       GST_VIDEO_INFO_SIZE (vip));
133
134   return GST_MEMORY_CAST (mem);
135 }
136
137 gboolean
138 gst_video_meta_map_msdk_memory (GstVideoMeta * meta, guint plane,
139     GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
140 {
141   gboolean ret = FALSE;
142   GstAllocator *allocator;
143   GstMsdkVideoAllocator *msdk_video_allocator;
144   GstMsdkVideoMemory *mem =
145       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
146   GstMsdkMemoryID *mem_id;
147   guint offset = 0;
148   gint pitch = 0;
149   guint plane_id = plane;
150
151   g_return_val_if_fail (mem, FALSE);
152
153   allocator = GST_MEMORY_CAST (mem)->allocator;
154   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
155
156   if (!GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
157     GST_WARNING ("The allocator is not MSDK video allocator");
158     return FALSE;
159   }
160
161   if (!mem->surface) {
162     GST_WARNING ("The surface is not allocated");
163     return FALSE;
164   }
165
166   if ((flags & GST_MAP_WRITE) && mem->surface && mem->surface->Data.Locked) {
167     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
168     return FALSE;
169   }
170
171   if (!mem->mapped) {
172     gst_msdk_frame_lock (msdk_video_allocator->context,
173         mem->surface->Data.MemId, &mem->surface->Data);
174   }
175
176   mem->mapped++;
177   mem_id = mem->surface->Data.MemId;
178
179   /* msdk doesn't support I420 format and we used YV12 internally
180    * So we need to swap U/V planes for mapping */
181   if (meta->format == GST_VIDEO_FORMAT_I420)
182     plane_id = plane ? (plane == 1 ? 2 : 1) : plane;
183
184 #ifndef _WIN32
185   offset = mem_id->image.offsets[plane_id];
186   pitch = mem_id->image.pitches[plane_id];
187 #else
188   /* TODO: This is just to avoid compile errors on Windows.
189    * Implement handling Windows-specific video-memory.
190    */
191   offset = mem_id->offset;
192   pitch = mem_id->pitch;
193 #endif
194
195   *data = mem->surface->Data.Y + offset;
196   *stride = pitch;
197
198   info->flags = flags;
199   ret = (*data != NULL);
200
201   return ret;
202 }
203
204 gboolean
205 gst_video_meta_unmap_msdk_memory (GstVideoMeta * meta, guint plane,
206     GstMapInfo * info)
207 {
208   GstAllocator *allocator;
209   GstMsdkVideoAllocator *msdk_video_allocator;
210   GstMsdkVideoMemory *mem =
211       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
212
213   g_return_val_if_fail (mem, FALSE);
214
215   allocator = GST_MEMORY_CAST (mem)->allocator;
216   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
217
218   if (mem->mapped == 1)
219     gst_msdk_frame_unlock (msdk_video_allocator->context,
220         mem->surface->Data.MemId, &mem->surface->Data);
221
222   mem->mapped--;
223
224   return TRUE;
225 }
226
227
228 static gpointer
229 gst_msdk_video_memory_map_full (GstMemory * base_mem, GstMapInfo * info,
230     gsize maxsize)
231 {
232   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
233   GstAllocator *allocator = base_mem->allocator;
234   GstMsdkVideoAllocator *msdk_video_allocator =
235       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
236
237   g_return_val_if_fail (mem, NULL);
238
239   if (!mem->surface) {
240     GST_WARNING ("The surface is not allocated");
241     return NULL;
242   }
243
244   if ((info->flags & GST_MAP_WRITE) && mem->surface
245       && mem->surface->Data.Locked) {
246     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
247     return NULL;
248   }
249
250   gst_msdk_frame_lock (msdk_video_allocator->context, mem->surface->Data.MemId,
251       &mem->surface->Data);
252   return mem->surface->Data.Y;
253 }
254
255 static void
256 gst_msdk_video_memory_unmap (GstMemory * base_mem)
257 {
258   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
259   GstAllocator *allocator = base_mem->allocator;
260   GstMsdkVideoAllocator *msdk_video_allocator =
261       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
262
263   gst_msdk_frame_unlock (msdk_video_allocator->context,
264       mem->surface->Data.MemId, &mem->surface->Data);
265 }
266
267 /* GstMsdkVideoAllocator */
268 G_DEFINE_TYPE (GstMsdkVideoAllocator, gst_msdk_video_allocator,
269     GST_TYPE_ALLOCATOR);
270
271 static GstMemory *
272 gst_msdk_video_allocator_alloc (GstAllocator * allocator, gsize size,
273     GstAllocationParams * params)
274 {
275   return gst_msdk_video_memory_new (allocator);
276 }
277
278 static void
279 gst_msdk_video_allocator_finalize (GObject * object)
280 {
281   GstMsdkVideoAllocator *allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (object);
282
283   gst_object_unref (allocator->context);
284   G_OBJECT_CLASS (gst_msdk_video_allocator_parent_class)->finalize (object);
285 }
286
287 static void
288 gst_msdk_video_allocator_class_init (GstMsdkVideoAllocatorClass * klass)
289 {
290   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
291   GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass);
292
293   object_class->finalize = gst_msdk_video_allocator_finalize;
294
295   allocator_class->alloc = gst_msdk_video_allocator_alloc;
296 }
297
298 static void
299 gst_msdk_video_allocator_init (GstMsdkVideoAllocator * allocator)
300 {
301   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
302
303   base_allocator->mem_type = GST_MSDK_VIDEO_MEMORY_NAME;
304   base_allocator->mem_map_full = gst_msdk_video_memory_map_full;
305   base_allocator->mem_unmap = gst_msdk_video_memory_unmap;
306
307   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
308 }
309
310 GstAllocator *
311 gst_msdk_video_allocator_new (GstMsdkContext * context,
312     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
313 {
314   GstMsdkVideoAllocator *allocator;
315
316   g_return_val_if_fail (context != NULL, NULL);
317   g_return_val_if_fail (image_info != NULL, NULL);
318
319   allocator = g_object_new (GST_TYPE_MSDK_VIDEO_ALLOCATOR, NULL);
320   if (!allocator)
321     return NULL;
322
323   allocator->context = gst_object_ref (context);
324   allocator->image_info = *image_info;
325   allocator->alloc_response = alloc_resp;
326
327   return GST_ALLOCATOR_CAST (allocator);
328 }