msdk: supports bufferpool
[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 gboolean
40 ensure_data (GstMsdkVideoMemory * mem, GstMsdkVideoAllocator * allocator)
41 {
42   GstMsdkMemoryID *mem_id;
43   GstMsdkAllocResponse *resp =
44       gst_msdk_context_get_cached_alloc_responses (allocator->context,
45       allocator->alloc_response);
46
47   if (!resp) {
48     GST_WARNING ("failed to get allocation response");
49     return FALSE;
50   }
51
52   mem_id = (GstMsdkMemoryID *) resp->mem_ids[resp->num_used_memory++];
53   mem->surface->Data.MemId = mem_id;
54
55   return TRUE;
56 }
57
58 static mfxFrameSurface1 *
59 gst_msdk_video_allocator_create_surface (GstAllocator * allocator)
60 {
61   mfxFrameInfo frame_info = { {0,}, 0, };
62   mfxFrameSurface1 *surface;
63   GstMsdkVideoAllocator *msdk_video_allocator =
64       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
65
66   surface = (mfxFrameSurface1 *) g_slice_new0 (mfxFrameSurface1);
67
68   if (!surface) {
69     GST_ERROR ("failed to allocate surface");
70     return NULL;
71   }
72
73   gst_msdk_set_mfx_frame_info_from_video_info (&frame_info,
74       &msdk_video_allocator->image_info);
75
76   surface->Info = frame_info;
77
78   return surface;
79 }
80
81 GstMemory *
82 gst_msdk_video_memory_new (GstAllocator * base_allocator)
83 {
84   GstMsdkVideoAllocator *allocator;
85   GstVideoInfo *vip;
86   GstMsdkVideoMemory *mem;
87
88   g_return_val_if_fail (base_allocator, NULL);
89   g_return_val_if_fail (GST_IS_MSDK_VIDEO_ALLOCATOR (base_allocator), NULL);
90
91   allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (base_allocator);
92
93   mem = g_slice_new0 (GstMsdkVideoMemory);
94   if (!mem)
95     return NULL;
96
97   mem->surface = gst_msdk_video_allocator_create_surface (base_allocator);
98
99   vip = &allocator->image_info;
100   gst_memory_init (&mem->parent_instance, GST_MEMORY_FLAG_NO_SHARE,
101       base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0, 0,
102       GST_VIDEO_INFO_SIZE (vip));
103
104   if (!ensure_data (mem, allocator))
105     return FALSE;
106
107   return GST_MEMORY_CAST (mem);
108 }
109
110 gboolean
111 gst_video_meta_map_msdk_memory (GstVideoMeta * meta, guint plane,
112     GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
113 {
114   gboolean ret = FALSE;
115   GstAllocator *allocator;
116   GstMsdkVideoAllocator *msdk_video_allocator;
117   GstMsdkVideoMemory *mem =
118       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
119   GstMsdkMemoryID *mem_id;
120
121   g_return_val_if_fail (mem, FALSE);
122
123   allocator = GST_MEMORY_CAST (mem)->allocator;
124   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
125
126   if (!GST_IS_MSDK_VIDEO_ALLOCATOR (allocator)) {
127     GST_WARNING ("The allocator is not MSDK video allocator");
128     return FALSE;
129   }
130
131   if (!mem->surface) {
132     GST_WARNING ("The surface is not allocated");
133     return FALSE;
134   }
135
136   if ((flags & GST_MAP_WRITE) && mem->surface && mem->surface->Data.Locked) {
137     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
138     return FALSE;
139   }
140
141   if (!mem->mapped) {
142     gst_msdk_frame_lock (msdk_video_allocator->context,
143         mem->surface->Data.MemId, &mem->surface->Data);
144   }
145
146   mem->mapped++;
147   mem_id = mem->surface->Data.MemId;
148
149   *data = mem->surface->Data.Y + mem_id->image.offsets[plane];
150   *stride = mem_id->image.pitches[plane];
151
152   info->flags = flags;
153   ret = (*data != NULL);
154
155   return ret;
156 }
157
158 gboolean
159 gst_video_meta_unmap_msdk_memory (GstVideoMeta * meta, guint plane,
160     GstMapInfo * info)
161 {
162   GstAllocator *allocator;
163   GstMsdkVideoAllocator *msdk_video_allocator;
164   GstMsdkVideoMemory *mem =
165       GST_MSDK_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
166
167   g_return_val_if_fail (mem, FALSE);
168
169   allocator = GST_MEMORY_CAST (mem)->allocator;
170   msdk_video_allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
171
172   if (mem->mapped == 1)
173     gst_msdk_frame_unlock (msdk_video_allocator->context,
174         mem->surface->Data.MemId, &mem->surface->Data);
175
176   mem->mapped--;
177
178   return TRUE;
179 }
180
181
182 static gpointer
183 gst_msdk_video_memory_map_full (GstMemory * base_mem, GstMapInfo * info,
184     gsize maxsize)
185 {
186   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
187   GstAllocator *allocator = base_mem->allocator;
188   GstMsdkVideoAllocator *msdk_video_allocator =
189       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
190
191   g_return_val_if_fail (mem, NULL);
192
193   if (!mem->surface) {
194     GST_WARNING ("The surface is not allocated");
195     return FALSE;
196   }
197
198   if ((info->flags & GST_MAP_WRITE) && mem->surface
199       && mem->surface->Data.Locked) {
200     GST_WARNING ("The surface in memory %p is not still avaliable", mem);
201     return FALSE;
202   }
203
204   gst_msdk_frame_lock (msdk_video_allocator->context, mem->surface->Data.MemId,
205       &mem->surface->Data);
206   return mem->surface->Data.Y;
207 }
208
209 static void
210 gst_msdk_video_memory_unmap (GstMemory * base_mem)
211 {
212   GstMsdkVideoMemory *const mem = GST_MSDK_VIDEO_MEMORY_CAST (base_mem);
213   GstAllocator *allocator = base_mem->allocator;
214   GstMsdkVideoAllocator *msdk_video_allocator =
215       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
216
217   gst_msdk_frame_unlock (msdk_video_allocator->context,
218       mem->surface->Data.MemId, &mem->surface->Data);
219 }
220
221 /* GstMsdkVideoAllocator */
222 G_DEFINE_TYPE (GstMsdkVideoAllocator, gst_msdk_video_allocator,
223     GST_TYPE_ALLOCATOR);
224
225 static GstMemory *
226 gst_msdk_video_allocator_alloc (GstAllocator * allocator, gsize size,
227     GstAllocationParams * params)
228 {
229   return gst_msdk_video_memory_new (allocator);
230 }
231
232 static void
233 gst_msdk_video_allocator_free (GstAllocator * allocator, GstMemory * memory)
234 {
235   GstMsdkVideoAllocator *msdk_video_allocator =
236       GST_MSDK_VIDEO_ALLOCATOR_CAST (allocator);
237   GstMsdkAllocResponse *resp =
238       gst_msdk_context_get_cached_alloc_responses
239       (msdk_video_allocator->context, msdk_video_allocator->alloc_response);
240
241   if (resp)
242     resp->num_used_memory--;
243 }
244
245 static void
246 gst_msdk_video_allocator_finalize (GObject * object)
247 {
248   GstMsdkVideoAllocator *allocator = GST_MSDK_VIDEO_ALLOCATOR_CAST (object);
249
250   gst_object_unref (allocator->context);
251   G_OBJECT_CLASS (gst_msdk_video_allocator_parent_class)->finalize (object);
252 }
253
254 static void
255 gst_msdk_video_allocator_class_init (GstMsdkVideoAllocatorClass * klass)
256 {
257   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
258   GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass);
259
260   object_class->finalize = gst_msdk_video_allocator_finalize;
261
262   allocator_class->alloc = gst_msdk_video_allocator_alloc;
263   allocator_class->free = gst_msdk_video_allocator_free;
264 }
265
266 static void
267 gst_msdk_video_allocator_init (GstMsdkVideoAllocator * allocator)
268 {
269   GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
270
271   base_allocator->mem_type = GST_MSDK_VIDEO_MEMORY_NAME;
272   base_allocator->mem_map_full = gst_msdk_video_memory_map_full;
273   base_allocator->mem_unmap = gst_msdk_video_memory_unmap;
274
275   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
276 }
277
278 GstAllocator *
279 gst_msdk_video_allocator_new (GstMsdkContext * context,
280     GstVideoInfo * image_info, mfxFrameAllocResponse * alloc_resp)
281 {
282   GstMsdkVideoAllocator *allocator;
283
284   g_return_val_if_fail (context != NULL, NULL);
285   g_return_val_if_fail (image_info != NULL, NULL);
286
287   allocator = g_object_new (GST_TYPE_MSDK_VIDEO_ALLOCATOR, NULL);
288   if (!allocator)
289     return NULL;
290
291   allocator->context = gst_object_ref (context);
292   allocator->image_info = *image_info;
293   allocator->alloc_response = alloc_resp;
294
295   return GST_ALLOCATOR_CAST (allocator);
296 }