Remove a bunch of silly ';;' typos at the end of lines
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / egl / gsteglimagememory.c
1 /*
2  * GStreamer
3  * Copyright (C) 2012 Collabora Ltd.
4  *   @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  * Copyright (C) 2014 Julien Isorce <julien.isorce@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "gsteglimagememory.h"
28
29 GST_DEBUG_CATEGORY_STATIC (GST_CAT_EGL_IMAGE_MEMORY);
30 #define GST_CAT_DEFAULT GST_CAT_EGL_IMAGE_MEMORY
31
32 #define GST_EGL_IMAGE_MEMORY(mem) ((GstEGLImageMemory*)(mem))
33
34 gboolean
35 gst_is_egl_image_memory (GstMemory * mem)
36 {
37   g_return_val_if_fail (mem != NULL, FALSE);
38   g_return_val_if_fail (mem->allocator != NULL, FALSE);
39
40   return g_strcmp0 (mem->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0;
41 }
42
43 EGLImageKHR
44 gst_egl_image_memory_get_image (GstMemory * mem)
45 {
46   g_return_val_if_fail (gst_is_egl_image_memory (mem), EGL_NO_IMAGE_KHR);
47
48   if (mem->parent)
49     mem = mem->parent;
50
51   return GST_EGL_IMAGE_MEMORY (mem)->image;
52 }
53
54 EGLDisplay
55 gst_egl_image_memory_get_display (GstMemory * mem)
56 {
57   g_return_val_if_fail (gst_is_egl_image_memory (mem), NULL);
58
59   if (mem->parent)
60     mem = mem->parent;
61
62   return GST_EGL_IMAGE_MEMORY (mem)->context->egl_display;
63 }
64
65 GstVideoGLTextureOrientation
66 gst_egl_image_memory_get_orientation (GstMemory * mem)
67 {
68   g_return_val_if_fail (gst_is_egl_image_memory (mem),
69       GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL);
70
71   if (mem->parent)
72     mem = mem->parent;
73
74   return GST_EGL_IMAGE_MEMORY (mem)->orientation;
75 }
76
77 void
78 gst_egl_image_memory_set_orientation (GstMemory * mem,
79     GstVideoGLTextureOrientation orientation)
80 {
81   g_return_if_fail (gst_is_egl_image_memory (mem));
82
83   if (mem->parent)
84     mem = mem->parent;
85
86   GST_EGL_IMAGE_MEMORY (mem)->orientation = orientation;
87 }
88
89 static GstMemory *
90 gst_egl_image_allocator_alloc_vfunc (GstAllocator * allocator, gsize size,
91     GstAllocationParams * params)
92 {
93   g_warning
94       ("Use gst_egl_image_allocator_alloc() to allocate from this allocator");
95
96   return NULL;
97 }
98
99 static void
100 gst_egl_image_allocator_free_vfunc (GstAllocator * allocator, GstMemory * mem)
101 {
102   GstEGLImageMemory *emem = (GstEGLImageMemory *) mem;
103
104   g_return_if_fail (gst_is_egl_image_memory (mem));
105
106   /* Shared memory should not destroy all the data */
107   if (!mem->parent) {
108     emem->context->eglDestroyImage (emem->context->egl_display, emem->image);
109
110     if (emem->user_data_destroy)
111       emem->user_data_destroy (emem->context, emem->user_data);
112
113     gst_object_unref (emem->context);
114     emem->context = NULL;
115   }
116
117   g_slice_free (GstEGLImageMemory, emem);
118 }
119
120 static gpointer
121 gst_egl_image_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
122 {
123   return NULL;
124 }
125
126 static void
127 gst_egl_image_mem_unmap (GstMemory * mem)
128 {
129 }
130
131 static GstMemory *
132 gst_egl_image_mem_share (GstMemory * mem, gssize offset, gssize size)
133 {
134   return NULL;
135 }
136
137 static GstMemory *
138 gst_egl_image_mem_copy (GstMemory * mem, gssize offset, gssize size)
139 {
140   return NULL;
141 }
142
143 static gboolean
144 gst_egl_image_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
145 {
146   return FALSE;
147 }
148
149 typedef struct _GstEGLImageAllocator GstEGLImageAllocator;
150 typedef struct _GstEGLImageAllocatorClass GstEGLImageAllocatorClass;
151
152 struct _GstEGLImageAllocator
153 {
154   GstAllocator parent;
155 };
156
157 struct _GstEGLImageAllocatorClass
158 {
159   GstAllocatorClass parent_class;
160 };
161
162 GType gst_egl_image_allocator_get_type (void);
163 G_DEFINE_TYPE (GstEGLImageAllocator, gst_egl_image_allocator,
164     GST_TYPE_ALLOCATOR);
165
166 #define GST_TYPE_EGL_IMAGE_ALLOCATOR   (gst_egl_image_mem_allocator_get_type())
167 #define GST_IS_EGL_IMAGE_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EGL_IMAGE_ALLOCATOR))
168
169 static void
170 gst_egl_image_allocator_class_init (GstEGLImageAllocatorClass * klass)
171 {
172   GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
173
174   allocator_class->alloc = gst_egl_image_allocator_alloc_vfunc;
175   allocator_class->free = gst_egl_image_allocator_free_vfunc;
176 }
177
178 static void
179 gst_egl_image_allocator_init (GstEGLImageAllocator * allocator)
180 {
181   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
182
183   alloc->mem_type = GST_EGL_IMAGE_MEMORY_TYPE;
184   alloc->mem_map = gst_egl_image_mem_map;
185   alloc->mem_unmap = gst_egl_image_mem_unmap;
186   alloc->mem_share = gst_egl_image_mem_share;
187   alloc->mem_copy = gst_egl_image_mem_copy;
188   alloc->mem_is_span = gst_egl_image_mem_is_span;
189
190   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
191 }
192
193 static gpointer
194 gst_egl_image_allocator_init_instance (gpointer data)
195 {
196   GstAllocator *allocator =
197       g_object_new (gst_egl_image_allocator_get_type (), NULL);
198
199   GST_DEBUG_CATEGORY_INIT (GST_CAT_EGL_IMAGE_MEMORY, "eglimagememory", 0,
200       "EGLImage Memory");
201
202   gst_allocator_register (GST_EGL_IMAGE_MEMORY_TYPE,
203       gst_object_ref (allocator));
204
205   return allocator;
206 }
207
208 static GstEGLImageAllocator *
209 gst_egl_image_allocator_obtain (void)
210 {
211   static GOnce once = G_ONCE_INIT;
212
213   g_once (&once, gst_egl_image_allocator_init_instance, NULL);
214
215   g_return_val_if_fail (once.retval != NULL, NULL);
216
217   return (GstEGLImageAllocator *) (g_object_ref (once.retval));
218 }
219
220 void
221 gst_egl_image_memory_init (void)
222 {
223   gst_egl_image_allocator_obtain ();
224 }
225
226 static void
227 gst_egl_image_memory_del_gl_texture (GstGLContext * context, gpointer tex)
228 {
229   GLuint textures[1] = { GPOINTER_TO_UINT (tex) };
230
231   gst_gl_context_del_texture (context, textures);
232 }
233
234 static GstMemory *
235 gst_egl_image_allocator_wrap (GstEGLImageAllocator * allocator,
236     GstGLContextEGL * context, EGLImageKHR image, GstVideoGLTextureType type,
237     GstMemoryFlags flags, gsize size, gpointer user_data,
238     GstEGLImageDestroyNotify user_data_destroy)
239 {
240   GstEGLImageMemory *mem = NULL;
241
242   g_return_val_if_fail (context != NULL, NULL);
243   g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
244
245   if (!allocator) {
246     allocator = gst_egl_image_allocator_obtain ();
247   }
248
249   mem = g_slice_new (GstEGLImageMemory);
250   gst_memory_init (GST_MEMORY_CAST (mem), flags,
251       GST_ALLOCATOR (allocator), NULL, size, 0, 0, size);
252
253   gst_object_unref (allocator);
254
255   mem->context = gst_object_ref (context);
256   mem->image = image;
257   mem->type = type;
258   mem->orientation = GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL;
259
260   mem->user_data = user_data;
261   mem->user_data_destroy = user_data_destroy;
262
263   return GST_MEMORY_CAST (mem);
264 }
265
266 #if 0
267 static GstMemory *
268 gst_egl_image_allocator_alloc (GstAllocator * allocator,
269     GstGLContextEGL * context, GstVideoGLTextureType type, gint width,
270     gint height, gsize size)
271 {
272   /* EGL_NO_CONTEXT */
273   return NULL;
274 }
275 #endif
276
277 static gboolean
278 gst_eglimage_to_gl_texture_upload_meta (GstVideoGLTextureUploadMeta *
279     meta, guint texture_id[4])
280 {
281   gint i = 0;
282   gint n = 0;
283
284   g_return_val_if_fail (meta != NULL, FALSE);
285   g_return_val_if_fail (texture_id != NULL, FALSE);
286
287   GST_DEBUG ("Uploading for meta with textures %i,%i,%i,%i", texture_id[0],
288       texture_id[1], texture_id[2], texture_id[3]);
289
290   n = gst_buffer_n_memory (meta->buffer);
291
292   for (i = 0; i < n; i++) {
293     GstMemory *mem = gst_buffer_peek_memory (meta->buffer, i);
294     const GstGLFuncs *gl = NULL;
295
296     if (!gst_is_egl_image_memory (mem)) {
297       GST_WARNING ("memory %p does not hold an EGLImage", mem);
298       return FALSE;
299     }
300
301     gl = GST_GL_CONTEXT (GST_EGL_IMAGE_MEMORY (mem)->context)->gl_vtable;
302
303     gl->ActiveTexture (GL_TEXTURE0 + i);
304     gl->BindTexture (GL_TEXTURE_2D, texture_id[i]);
305     gl->EGLImageTargetTexture2D (GL_TEXTURE_2D,
306         gst_egl_image_memory_get_image (mem));
307   }
308
309   if (GST_IS_GL_BUFFER_POOL (meta->buffer->pool))
310     gst_gl_buffer_pool_replace_last_buffer (GST_GL_BUFFER_POOL (meta->
311             buffer->pool), meta->buffer);
312
313   return TRUE;
314 }
315
316 gboolean
317 gst_egl_image_memory_setup_buffer (GstGLContext * ctx, GstVideoInfo * info,
318     GstBuffer * buffer)
319 {
320   gint i = 0;
321   gint stride[3];
322   gsize offset[3];
323   GstMemory *mem[3] = { NULL, NULL, NULL };
324   guint n_mem = 0;
325   GstMemoryFlags flags = 0;
326   EGLImageKHR image = EGL_NO_IMAGE_KHR;
327   EGLClientBuffer client_buffer_tex[3] = { 0, 0, 0 };
328   GstVideoGLTextureType texture_types[] = { 0, 0, 0, 0 };
329   GstEGLImageAllocator *allocator = gst_egl_image_allocator_obtain ();
330   GstGLContextEGL *context = GST_GL_CONTEXT_EGL (ctx);
331
332   g_return_val_if_fail (ctx, FALSE);
333   g_return_val_if_fail (info, FALSE);
334   g_return_val_if_fail (buffer, FALSE);
335   g_return_val_if_fail (gst_gl_context_check_feature (ctx,
336           "EGL_KHR_image_base"), FALSE);
337
338   memset (stride, 0, sizeof (stride));
339   memset (offset, 0, sizeof (offset));
340
341   flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
342   flags |= GST_MEMORY_FLAG_NO_SHARE;
343
344   switch (GST_VIDEO_INFO_FORMAT (info)) {
345     case GST_VIDEO_FORMAT_RGB:
346     case GST_VIDEO_FORMAT_BGR:
347     case GST_VIDEO_FORMAT_RGB16:
348     case GST_VIDEO_FORMAT_RGBA:
349     case GST_VIDEO_FORMAT_BGRA:
350     case GST_VIDEO_FORMAT_ARGB:
351     case GST_VIDEO_FORMAT_ABGR:
352     case GST_VIDEO_FORMAT_RGBx:
353     case GST_VIDEO_FORMAT_BGRx:
354     case GST_VIDEO_FORMAT_xRGB:
355     case GST_VIDEO_FORMAT_xBGR:
356     case GST_VIDEO_FORMAT_AYUV:
357     {
358       gsize size = 0;
359
360       switch (GST_VIDEO_INFO_FORMAT (info)) {
361         case GST_VIDEO_FORMAT_RGB:
362         case GST_VIDEO_FORMAT_BGR:
363         case GST_VIDEO_FORMAT_RGB16:
364         {
365           texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGB;
366           break;
367         }
368         case GST_VIDEO_FORMAT_RGBA:
369         case GST_VIDEO_FORMAT_BGRA:
370         case GST_VIDEO_FORMAT_ARGB:
371         case GST_VIDEO_FORMAT_ABGR:
372         case GST_VIDEO_FORMAT_RGBx:
373         case GST_VIDEO_FORMAT_BGRx:
374         case GST_VIDEO_FORMAT_xRGB:
375         case GST_VIDEO_FORMAT_xBGR:
376         case GST_VIDEO_FORMAT_AYUV:
377         {
378           texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
379           break;
380         }
381         default:
382           g_assert_not_reached ();
383           break;
384       }
385 #if 0
386       mem[0] =
387           gst_egl_image_allocator_alloc (allocator, context,
388           texture_types[0], GST_VIDEO_INFO_WIDTH (info),
389           GST_VIDEO_INFO_HEIGHT (info), size);
390       if (mem[0]) {
391         stride[0] = size / GST_VIDEO_INFO_HEIGHT (info);
392         n_mem = 1;
393         GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
394       } else
395 #endif
396       {
397         gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, 0, stride,
398             offset, &size, (GLuint *) & client_buffer_tex[0]);
399
400         image = context->eglCreateImage (context->egl_display,
401             context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[0],
402             NULL);
403         if (eglGetError () != EGL_SUCCESS)
404           goto mem_error;
405
406         mem[0] =
407             gst_egl_image_allocator_wrap (allocator, context,
408             image, texture_types[0], flags, size, client_buffer_tex[0],
409             (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture);
410         n_mem = 1;
411       }
412       break;
413     }
414
415     case GST_VIDEO_FORMAT_NV12:
416     case GST_VIDEO_FORMAT_NV21:
417     {
418       gsize size[2];
419
420       texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
421       texture_types[1] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA;
422 #if 0
423       mem[0] =
424           gst_egl_image_allocator_alloc (allocator, context,
425           texture_types[0], GST_VIDEO_INFO_COMP_WIDTH (info,
426               0), GST_VIDEO_INFO_COMP_HEIGHT (info, 0), size[0]);
427       mem[1] =
428           gst_egl_image_allocator_alloc (allocator, context,
429           texture_types[1],
430           GST_VIDEO_INFO_COMP_WIDTH (info, 1),
431           GST_VIDEO_INFO_COMP_HEIGHT (info, 1), size[1]);
432
433       if (mem[0] && mem[1]) {
434         stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info);
435         offset[1] = size[0];
436         stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info);
437         n_mem = 2;
438         GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
439         GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
440       } else {
441         if (mem[0])
442           gst_memory_unref (mem[0]);
443         if (mem[1])
444           gst_memory_unref (mem[1]);
445         mem[0] = mem[1] = NULL;
446       }
447 #endif
448       {
449         for (i = 0; i < 2; i++) {
450           gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, 0,
451               stride, offset, size, (GLuint *) & client_buffer_tex[i]);
452
453           image = context->eglCreateImage (context->egl_display,
454               context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i],
455               NULL);
456           if (eglGetError () != EGL_SUCCESS)
457             goto mem_error;
458
459           mem[i] =
460               gst_egl_image_allocator_wrap (allocator, context,
461               image, texture_types[i], flags, size[i], client_buffer_tex[i],
462               (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture);
463         }
464
465         n_mem = 2;
466       }
467       break;
468     }
469     case GST_VIDEO_FORMAT_I420:
470     case GST_VIDEO_FORMAT_YV12:
471     case GST_VIDEO_FORMAT_Y444:
472     case GST_VIDEO_FORMAT_Y42B:
473     case GST_VIDEO_FORMAT_Y41B:
474     {
475       gsize size[3];
476
477       texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
478       texture_types[1] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
479       texture_types[2] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
480 #if 0
481       mem[0] =
482           gst_egl_image_allocator_alloc (allocator, context,
483           texture_types[0], GST_VIDEO_INFO_COMP_WIDTH (info,
484               0), GST_VIDEO_INFO_COMP_HEIGHT (info, 0), size[0]);
485       mem[1] =
486           gst_egl_image_allocator_alloc (allocator, context,
487           texture_types[1], GST_VIDEO_INFO_COMP_WIDTH (info,
488               1), GST_VIDEO_INFO_COMP_HEIGHT (info, 1), size[1]);
489       mem[2] =
490           gst_egl_image_allocator_alloc (allocator, context,
491           texture_types[2], GST_VIDEO_INFO_COMP_WIDTH (info,
492               2), GST_VIDEO_INFO_COMP_HEIGHT (info, 2), size[2]);
493
494       if (mem[0] && mem[1] && mem[2]) {
495         stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info);
496         offset[1] = size[0];
497         stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info);
498         offset[2] = size[1];
499         stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (info);
500         n_mem = 3;
501         GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
502         GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
503         GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE);
504       } else {
505         if (mem[0])
506           gst_memory_unref (mem[0]);
507         if (mem[1])
508           gst_memory_unref (mem[1]);
509         if (mem[2])
510           gst_memory_unref (mem[2]);
511         mem[0] = mem[1] = mem[2] = NULL;
512       }
513 #endif
514       {
515         for (i = 0; i < 3; i++) {
516           gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, i,
517               stride, offset, size, (GLuint *) & client_buffer_tex[i]);
518
519           image = context->eglCreateImage (context->egl_display,
520               context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i],
521               NULL);
522           if (eglGetError () != EGL_SUCCESS)
523             goto mem_error;
524
525           mem[i] =
526               gst_egl_image_allocator_wrap (allocator, context,
527               image, texture_types[i], flags, size[i], client_buffer_tex[i],
528               (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture);
529         }
530
531         n_mem = 3;
532       }
533       break;
534     }
535     default:
536       g_assert_not_reached ();
537       break;
538   }
539
540   gst_buffer_add_video_meta_full (buffer, 0, GST_VIDEO_INFO_FORMAT (info),
541       GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
542       GST_VIDEO_INFO_N_PLANES (info), offset, stride);
543
544   gst_buffer_add_video_gl_texture_upload_meta (buffer,
545       gst_egl_image_memory_get_orientation (mem[0]), n_mem, texture_types,
546       gst_eglimage_to_gl_texture_upload_meta, NULL, NULL, NULL);
547
548   for (i = 0; i < n_mem; i++)
549     gst_buffer_append_memory (buffer, mem[i]);
550
551   return TRUE;
552
553 mem_error:
554   {
555     GST_CAT_ERROR (GST_CAT_DEFAULT, "Failed to create EGLImage");
556
557     for (i = 0; i < 3; i++) {
558       if (client_buffer_tex[i])
559         gst_gl_context_del_texture (ctx, (GLuint *) & client_buffer_tex[i]);
560       if (mem[i])
561         gst_memory_unref (mem[i]);
562     }
563
564     return FALSE;
565   }
566 }