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