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>
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.
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.
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.
27 #include "gsteglimagememory.h"
29 GST_DEBUG_CATEGORY_STATIC (GST_CAT_EGL_IMAGE_MEMORY);
30 #define GST_CAT_DEFAULT GST_CAT_EGL_IMAGE_MEMORY
32 #define GST_EGL_IMAGE_MEMORY(mem) ((GstEGLImageMemory*)(mem))
35 gst_is_egl_image_memory (GstMemory * mem)
37 g_return_val_if_fail (mem != NULL, FALSE);
38 g_return_val_if_fail (mem->allocator != NULL, FALSE);
40 return g_strcmp0 (mem->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0;
44 gst_egl_image_memory_get_image (GstMemory * mem)
46 g_return_val_if_fail (gst_is_egl_image_memory (mem), EGL_NO_IMAGE_KHR);
51 return GST_EGL_IMAGE_MEMORY (mem)->image;
55 gst_egl_image_memory_get_display (GstMemory * mem)
57 g_return_val_if_fail (gst_is_egl_image_memory (mem), NULL);
62 return GST_EGL_IMAGE_MEMORY (mem)->context->egl_display;
65 GstVideoGLTextureOrientation
66 gst_egl_image_memory_get_orientation (GstMemory * mem)
68 g_return_val_if_fail (gst_is_egl_image_memory (mem),
69 GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL);
74 return GST_EGL_IMAGE_MEMORY (mem)->orientation;
78 gst_egl_image_memory_set_orientation (GstMemory * mem,
79 GstVideoGLTextureOrientation orientation)
81 g_return_if_fail (gst_is_egl_image_memory (mem));
86 GST_EGL_IMAGE_MEMORY (mem)->orientation = orientation;
90 gst_egl_image_allocator_alloc_vfunc (GstAllocator * allocator, gsize size,
91 GstAllocationParams * params)
94 ("Use gst_egl_image_allocator_alloc() to allocate from this allocator");
100 gst_egl_image_allocator_free_vfunc (GstAllocator * allocator, GstMemory * mem)
102 GstEGLImageMemory *emem = (GstEGLImageMemory *) mem;
104 g_return_if_fail (gst_is_egl_image_memory (mem));
106 /* Shared memory should not destroy all the data */
108 emem->context->eglDestroyImage (emem->context->egl_display, emem->image);
110 if (emem->user_data_destroy)
111 emem->user_data_destroy (emem->context, emem->user_data);
113 gst_object_unref (emem->context);
114 emem->context = NULL;
117 g_slice_free (GstEGLImageMemory, emem);
121 gst_egl_image_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
127 gst_egl_image_mem_unmap (GstMemory * mem)
132 gst_egl_image_mem_share (GstMemory * mem, gssize offset, gssize size)
138 gst_egl_image_mem_copy (GstMemory * mem, gssize offset, gssize size)
144 gst_egl_image_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
149 typedef struct _GstEGLImageAllocator GstEGLImageAllocator;
150 typedef struct _GstEGLImageAllocatorClass GstEGLImageAllocatorClass;
152 struct _GstEGLImageAllocator
157 struct _GstEGLImageAllocatorClass
159 GstAllocatorClass parent_class;
162 GType gst_egl_image_allocator_get_type (void);
163 G_DEFINE_TYPE (GstEGLImageAllocator, gst_egl_image_allocator,
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))
170 gst_egl_image_allocator_class_init (GstEGLImageAllocatorClass * klass)
172 GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
174 allocator_class->alloc = gst_egl_image_allocator_alloc_vfunc;
175 allocator_class->free = gst_egl_image_allocator_free_vfunc;
179 gst_egl_image_allocator_init (GstEGLImageAllocator * allocator)
181 GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
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;
190 GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
194 gst_egl_image_allocator_init_instance (gpointer data)
196 GstAllocator *allocator =
197 g_object_new (gst_egl_image_allocator_get_type (), NULL);;
199 GST_DEBUG_CATEGORY_INIT (GST_CAT_EGL_IMAGE_MEMORY, "eglimagememory", 0,
202 gst_allocator_register (GST_EGL_IMAGE_MEMORY_TYPE,
203 gst_object_ref (allocator));
208 static GstEGLImageAllocator *
209 gst_egl_image_allocator_obtain (void)
211 static GOnce once = G_ONCE_INIT;
213 g_once (&once, gst_egl_image_allocator_init_instance, NULL);
215 g_return_val_if_fail (once.retval != NULL, NULL);
217 return (GstEGLImageAllocator *) (g_object_ref (once.retval));
221 gst_egl_image_memory_init (void)
223 gst_egl_image_allocator_obtain ();
227 gst_egl_image_memory_del_gl_texture (GstGLContext * context, gpointer tex)
229 GLuint textures[1] = { GPOINTER_TO_UINT (tex) };
231 gst_gl_context_del_texture (context, textures);
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)
240 GstEGLImageMemory *mem = NULL;
242 g_return_val_if_fail (context != NULL, NULL);
243 g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
246 allocator = gst_egl_image_allocator_obtain ();
249 mem = g_slice_new (GstEGLImageMemory);
250 gst_memory_init (GST_MEMORY_CAST (mem), flags,
251 GST_ALLOCATOR (allocator), NULL, size, 0, 0, size);
253 gst_object_unref (allocator);
255 mem->context = gst_object_ref (context);
258 mem->orientation = GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL;
260 mem->user_data = user_data;
261 mem->user_data_destroy = user_data_destroy;
263 return GST_MEMORY_CAST (mem);
268 gst_egl_image_allocator_alloc (GstAllocator * allocator,
269 GstGLContextEGL * context, GstVideoGLTextureType type, gint width,
270 gint height, gsize size)
278 gst_eglimage_to_gl_texture_upload_meta (GstVideoGLTextureUploadMeta *
279 meta, guint texture_id[4])
284 g_return_val_if_fail (meta != NULL, FALSE);
285 g_return_val_if_fail (texture_id != NULL, FALSE);
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]);
290 n = gst_buffer_n_memory (meta->buffer);
292 for (i = 0; i < n; i++) {
293 GstMemory *mem = gst_buffer_peek_memory (meta->buffer, i);
294 const GstGLFuncs *gl = NULL;
296 if (!gst_is_egl_image_memory (mem)) {
297 GST_WARNING ("memory %p does not hold an EGLImage", mem);
301 gl = GST_GL_CONTEXT (GST_EGL_IMAGE_MEMORY (mem)->context)->gl_vtable;
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));
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);
317 gst_egl_image_memory_setup_buffer (GstGLContext * ctx, GstVideoInfo * info,
323 GstMemory *mem[3] = { NULL, NULL, NULL };
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);
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);
338 memset (stride, 0, sizeof (stride));
339 memset (offset, 0, sizeof (offset));
341 flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
342 flags |= GST_MEMORY_FLAG_NO_SHARE;
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:
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:
365 texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGB;
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:
378 texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
382 g_assert_not_reached ();
387 gst_egl_image_allocator_alloc (allocator, context,
388 texture_types[0], GST_VIDEO_INFO_WIDTH (info),
389 GST_VIDEO_INFO_HEIGHT (info), size);
391 stride[0] = size / GST_VIDEO_INFO_HEIGHT (info);
393 GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
397 gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, 0, stride,
398 offset, &size, (GLuint *) & client_buffer_tex[0]);
400 image = context->eglCreateImage (context->egl_display,
401 context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[0],
403 if (eglGetError () != EGL_SUCCESS)
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);
415 case GST_VIDEO_FORMAT_NV12:
416 case GST_VIDEO_FORMAT_NV21:
420 texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
421 texture_types[1] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA;
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]);
428 gst_egl_image_allocator_alloc (allocator, context,
430 GST_VIDEO_INFO_COMP_WIDTH (info, 1),
431 GST_VIDEO_INFO_COMP_HEIGHT (info, 1), size[1]);
433 if (mem[0] && mem[1]) {
434 stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info);
436 stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info);
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);
442 gst_memory_unref (mem[0]);
444 gst_memory_unref (mem[1]);
445 mem[0] = mem[1] = NULL;
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]);
453 image = context->eglCreateImage (context->egl_display,
454 context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i],
456 if (eglGetError () != EGL_SUCCESS)
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);
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:
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;
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]);
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]);
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]);
494 if (mem[0] && mem[1] && mem[2]) {
495 stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info);
497 stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info);
499 stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (info);
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);
506 gst_memory_unref (mem[0]);
508 gst_memory_unref (mem[1]);
510 gst_memory_unref (mem[2]);
511 mem[0] = mem[1] = mem[2] = NULL;
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]);
519 image = context->eglCreateImage (context->egl_display,
520 context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i],
522 if (eglGetError () != EGL_SUCCESS)
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);
536 g_assert_not_reached ();
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);
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);
548 for (i = 0; i < n_mem; i++)
549 gst_buffer_append_memory (buffer, mem[i]);
555 GST_CAT_ERROR (GST_CAT_DEFAULT, "Failed to create EGLImage");
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]);
561 gst_memory_unref (mem[i]);