| /* |
| * GStreamer |
| * Copyright (C) 2012 Collabora Ltd. |
| * @author: Sebastian Dröge <sebastian.droege@collabora.co.uk> |
| * Copyright (C) 2014 Julien Isorce <julien.isorce@gmail.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "gsteglimagememory.h" |
| #include <string.h> |
| |
| #if GST_GL_HAVE_DMABUF |
| #include <gst/allocators/gstdmabuf.h> |
| #include <libdrm/drm_fourcc.h> |
| |
| #ifndef DRM_FORMAT_R8 |
| #define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') |
| #endif |
| |
| #ifndef DRM_FORMAT_RG88 |
| #define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') |
| #endif |
| |
| #ifndef DRM_FORMAT_GR88 |
| #define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') |
| #endif |
| #endif |
| |
| #ifndef EGL_LINUX_DMA_BUF_EXT |
| #define EGL_LINUX_DMA_BUF_EXT 0x3270 |
| #endif |
| |
| #ifndef EGL_LINUX_DRM_FOURCC_EXT |
| #define EGL_LINUX_DRM_FOURCC_EXT 0x3271 |
| #endif |
| |
| #ifndef EGL_DMA_BUF_PLANE0_FD_EXT |
| #define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 |
| #endif |
| |
| #ifndef EGL_DMA_BUF_PLANE0_OFFSET_EXT |
| #define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 |
| #endif |
| |
| #ifndef EGL_DMA_BUF_PLANE0_PITCH_EXT |
| #define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 |
| #endif |
| |
| GST_DEBUG_CATEGORY_STATIC (GST_CAT_EGL_IMAGE_MEMORY); |
| #define GST_CAT_DEFAULT GST_CAT_EGL_IMAGE_MEMORY |
| |
| #define GST_EGL_IMAGE_MEMORY(mem) ((GstEGLImageMemory*)(mem)) |
| |
| gboolean |
| gst_is_egl_image_memory (GstMemory * mem) |
| { |
| g_return_val_if_fail (mem != NULL, FALSE); |
| g_return_val_if_fail (mem->allocator != NULL, FALSE); |
| |
| return g_strcmp0 (mem->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0; |
| } |
| |
| EGLImageKHR |
| gst_egl_image_memory_get_image (GstMemory * mem) |
| { |
| g_return_val_if_fail (gst_is_egl_image_memory (mem), EGL_NO_IMAGE_KHR); |
| |
| if (mem->parent) |
| mem = mem->parent; |
| |
| return GST_EGL_IMAGE_MEMORY (mem)->image; |
| } |
| |
| EGLDisplay |
| gst_egl_image_memory_get_display (GstMemory * mem) |
| { |
| g_return_val_if_fail (gst_is_egl_image_memory (mem), NULL); |
| |
| if (mem->parent) |
| mem = mem->parent; |
| |
| return GST_EGL_IMAGE_MEMORY (mem)->context->egl_display; |
| } |
| |
| GstVideoGLTextureOrientation |
| gst_egl_image_memory_get_orientation (GstMemory * mem) |
| { |
| g_return_val_if_fail (gst_is_egl_image_memory (mem), |
| GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL); |
| |
| if (mem->parent) |
| mem = mem->parent; |
| |
| return GST_EGL_IMAGE_MEMORY (mem)->orientation; |
| } |
| |
| void |
| gst_egl_image_memory_set_orientation (GstMemory * mem, |
| GstVideoGLTextureOrientation orientation) |
| { |
| g_return_if_fail (gst_is_egl_image_memory (mem)); |
| |
| if (mem->parent) |
| mem = mem->parent; |
| |
| GST_EGL_IMAGE_MEMORY (mem)->orientation = orientation; |
| } |
| |
| static GstMemory * |
| gst_egl_image_allocator_alloc_vfunc (GstAllocator * allocator, gsize size, |
| GstAllocationParams * params) |
| { |
| g_warning |
| ("Use gst_egl_image_allocator_alloc() to allocate from this allocator"); |
| |
| return NULL; |
| } |
| |
| static void |
| gst_egl_image_allocator_free_vfunc (GstAllocator * allocator, GstMemory * mem) |
| { |
| GstEGLImageMemory *emem = (GstEGLImageMemory *) mem; |
| |
| g_return_if_fail (gst_is_egl_image_memory (mem)); |
| |
| /* Shared memory should not destroy all the data */ |
| if (!mem->parent) { |
| emem->context->eglDestroyImage (emem->context->egl_display, emem->image); |
| |
| if (emem->user_data_destroy) |
| emem->user_data_destroy (emem->context, emem->user_data); |
| |
| gst_object_unref (emem->context); |
| emem->context = NULL; |
| } |
| |
| g_slice_free (GstEGLImageMemory, emem); |
| } |
| |
| static gpointer |
| gst_egl_image_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) |
| { |
| return NULL; |
| } |
| |
| static void |
| gst_egl_image_mem_unmap (GstMemory * mem) |
| { |
| } |
| |
| static GstMemory * |
| gst_egl_image_mem_share (GstMemory * mem, gssize offset, gssize size) |
| { |
| return NULL; |
| } |
| |
| static GstMemory * |
| gst_egl_image_mem_copy (GstMemory * mem, gssize offset, gssize size) |
| { |
| return NULL; |
| } |
| |
| static gboolean |
| gst_egl_image_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset) |
| { |
| return FALSE; |
| } |
| |
| typedef struct _GstEGLImageAllocator GstEGLImageAllocator; |
| typedef struct _GstEGLImageAllocatorClass GstEGLImageAllocatorClass; |
| |
| struct _GstEGLImageAllocator |
| { |
| GstAllocator parent; |
| }; |
| |
| struct _GstEGLImageAllocatorClass |
| { |
| GstAllocatorClass parent_class; |
| }; |
| |
| GType gst_egl_image_allocator_get_type (void); |
| G_DEFINE_TYPE (GstEGLImageAllocator, gst_egl_image_allocator, |
| GST_TYPE_ALLOCATOR); |
| |
| #define GST_TYPE_EGL_IMAGE_ALLOCATOR (gst_egl_image_mem_allocator_get_type()) |
| #define GST_IS_EGL_IMAGE_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EGL_IMAGE_ALLOCATOR)) |
| |
| static void |
| gst_egl_image_allocator_class_init (GstEGLImageAllocatorClass * klass) |
| { |
| GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass; |
| |
| allocator_class->alloc = gst_egl_image_allocator_alloc_vfunc; |
| allocator_class->free = gst_egl_image_allocator_free_vfunc; |
| } |
| |
| static void |
| gst_egl_image_allocator_init (GstEGLImageAllocator * allocator) |
| { |
| GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); |
| |
| alloc->mem_type = GST_EGL_IMAGE_MEMORY_TYPE; |
| alloc->mem_map = gst_egl_image_mem_map; |
| alloc->mem_unmap = gst_egl_image_mem_unmap; |
| alloc->mem_share = gst_egl_image_mem_share; |
| alloc->mem_copy = gst_egl_image_mem_copy; |
| alloc->mem_is_span = gst_egl_image_mem_is_span; |
| |
| GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); |
| } |
| |
| static gpointer |
| gst_egl_image_allocator_init_instance (gpointer data) |
| { |
| GstAllocator *allocator = |
| g_object_new (gst_egl_image_allocator_get_type (), NULL); |
| |
| GST_DEBUG_CATEGORY_INIT (GST_CAT_EGL_IMAGE_MEMORY, "eglimagememory", 0, |
| "EGLImage Memory"); |
| |
| gst_allocator_register (GST_EGL_IMAGE_MEMORY_TYPE, |
| gst_object_ref (allocator)); |
| |
| return allocator; |
| } |
| |
| static GstEGLImageAllocator * |
| gst_egl_image_allocator_obtain (void) |
| { |
| static GOnce once = G_ONCE_INIT; |
| |
| g_once (&once, gst_egl_image_allocator_init_instance, NULL); |
| |
| g_return_val_if_fail (once.retval != NULL, NULL); |
| |
| return (GstEGLImageAllocator *) (g_object_ref (once.retval)); |
| } |
| |
| void |
| gst_egl_image_memory_init (void) |
| { |
| gst_egl_image_allocator_obtain (); |
| } |
| |
| static void |
| gst_egl_image_memory_del_gl_texture (GstGLContext * context, gpointer tex) |
| { |
| GLuint textures[1] = { GPOINTER_TO_UINT (tex) }; |
| |
| gst_gl_context_del_texture (context, textures); |
| } |
| |
| static GstMemory * |
| gst_egl_image_allocator_wrap (GstEGLImageAllocator * allocator, |
| GstGLContextEGL * context, EGLImageKHR image, GstVideoGLTextureType type, |
| GstMemoryFlags flags, gsize size, gpointer user_data, |
| GstEGLImageDestroyNotify user_data_destroy) |
| { |
| GstEGLImageMemory *mem = NULL; |
| |
| g_return_val_if_fail (context != NULL, NULL); |
| g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL); |
| |
| if (!allocator) { |
| allocator = gst_egl_image_allocator_obtain (); |
| } |
| |
| mem = g_slice_new (GstEGLImageMemory); |
| gst_memory_init (GST_MEMORY_CAST (mem), flags, |
| GST_ALLOCATOR (allocator), NULL, size, 0, 0, size); |
| |
| gst_object_unref (allocator); |
| |
| mem->context = gst_object_ref (context); |
| mem->image = image; |
| mem->type = type; |
| mem->orientation = GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL; |
| |
| mem->user_data = user_data; |
| mem->user_data_destroy = user_data_destroy; |
| |
| return GST_MEMORY_CAST (mem); |
| } |
| |
| #if 0 |
| static GstMemory * |
| gst_egl_image_allocator_alloc (GstAllocator * allocator, |
| GstGLContextEGL * context, GstVideoGLTextureType type, gint width, |
| gint height, gsize size) |
| { |
| /* EGL_NO_CONTEXT */ |
| return NULL; |
| } |
| #endif |
| |
| static gboolean |
| gst_eglimage_to_gl_texture_upload_meta (GstVideoGLTextureUploadMeta * |
| meta, guint texture_id[4]) |
| { |
| gint i = 0; |
| gint n = 0; |
| |
| g_return_val_if_fail (meta != NULL, FALSE); |
| g_return_val_if_fail (texture_id != NULL, FALSE); |
| |
| GST_DEBUG ("Uploading for meta with textures %i,%i,%i,%i", texture_id[0], |
| texture_id[1], texture_id[2], texture_id[3]); |
| |
| n = gst_buffer_n_memory (meta->buffer); |
| |
| for (i = 0; i < n; i++) { |
| GstMemory *mem = gst_buffer_peek_memory (meta->buffer, i); |
| const GstGLFuncs *gl = NULL; |
| |
| if (!gst_is_egl_image_memory (mem)) { |
| GST_WARNING ("memory %p does not hold an EGLImage", mem); |
| return FALSE; |
| } |
| |
| gl = GST_GL_CONTEXT (GST_EGL_IMAGE_MEMORY (mem)->context)->gl_vtable; |
| |
| gl->ActiveTexture (GL_TEXTURE0 + i); |
| gl->BindTexture (GL_TEXTURE_2D, texture_id[i]); |
| gl->EGLImageTargetTexture2D (GL_TEXTURE_2D, |
| gst_egl_image_memory_get_image (mem)); |
| } |
| |
| if (GST_IS_GL_BUFFER_POOL (meta->buffer->pool)) |
| gst_gl_buffer_pool_replace_last_buffer (GST_GL_BUFFER_POOL (meta-> |
| buffer->pool), meta->buffer); |
| |
| |
| return TRUE; |
| } |
| |
| #if GST_GL_HAVE_DMABUF |
| /* |
| * GStreamer format descriptions differ from DRM formats as the representation |
| * is relative to a register, hence in native endianness. To reduce the driver |
| * requirement, we only import with a subset of texture formats and use |
| * shaders to convert. This way we avoid having to use external texture |
| * target. |
| */ |
| static int |
| _drm_fourcc_from_info (GstVideoInfo * info, int plane) |
| { |
| GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info); |
| #if G_BYTE_ORDER == G_LITTLE_ENDIAN |
| const gint rgba_fourcc = DRM_FORMAT_ABGR8888; |
| const gint rgb_fourcc = DRM_FORMAT_BGR888; |
| const gint rg_fourcc = DRM_FORMAT_GR88; |
| #else |
| const gint rgba_fourcc = DRM_FORMAT_RGBA8888; |
| const gint rgb_fourcc = DRM_FORMAT_RGB888; |
| const gint rg_fourcc = DRM_FORMAT_RG88; |
| #endif |
| |
| GST_DEBUG ("Getting DRM fourcc for %s plane %i", |
| gst_video_format_to_string (format), plane); |
| |
| switch (format) { |
| case GST_VIDEO_FORMAT_RGB16: |
| case GST_VIDEO_FORMAT_BGR16: |
| return DRM_FORMAT_RGB565; |
| |
| case GST_VIDEO_FORMAT_RGB: |
| case GST_VIDEO_FORMAT_BGR: |
| return rgb_fourcc; |
| |
| case GST_VIDEO_FORMAT_RGBA: |
| case GST_VIDEO_FORMAT_RGBx: |
| case GST_VIDEO_FORMAT_BGRA: |
| case GST_VIDEO_FORMAT_BGRx: |
| case GST_VIDEO_FORMAT_ARGB: |
| case GST_VIDEO_FORMAT_xRGB: |
| case GST_VIDEO_FORMAT_ABGR: |
| case GST_VIDEO_FORMAT_xBGR: |
| case GST_VIDEO_FORMAT_AYUV: |
| return rgba_fourcc; |
| |
| case GST_VIDEO_FORMAT_GRAY8: |
| return DRM_FORMAT_R8; |
| |
| case GST_VIDEO_FORMAT_YUY2: |
| case GST_VIDEO_FORMAT_UYVY: |
| case GST_VIDEO_FORMAT_GRAY16_LE: |
| case GST_VIDEO_FORMAT_GRAY16_BE: |
| return rg_fourcc; |
| |
| case GST_VIDEO_FORMAT_NV12: |
| case GST_VIDEO_FORMAT_NV21: |
| return plane == 0 ? DRM_FORMAT_R8 : rg_fourcc; |
| |
| case GST_VIDEO_FORMAT_I420: |
| case GST_VIDEO_FORMAT_YV12: |
| case GST_VIDEO_FORMAT_Y41B: |
| case GST_VIDEO_FORMAT_Y42B: |
| case GST_VIDEO_FORMAT_Y444: |
| return DRM_FORMAT_R8; |
| |
| default: |
| GST_ERROR ("Unsupported format for DMABuf."); |
| return -1; |
| } |
| } |
| |
| GstMemory * |
| gst_egl_image_memory_from_dmabuf (GstGLContext * context, |
| gint dmabuf, GstVideoInfo * in_info, gint plane, gsize offset) |
| { |
| GstGLContextEGL *ctx_egl = GST_GL_CONTEXT_EGL (context); |
| GstEGLImageAllocator *allocator; |
| gint fourcc; |
| gint atti = 0; |
| EGLint attribs[13]; |
| EGLImageKHR img = EGL_NO_IMAGE_KHR; |
| |
| allocator = gst_egl_image_allocator_obtain (); |
| fourcc = _drm_fourcc_from_info (in_info, plane); |
| |
| GST_DEBUG ("fourcc %.4s (%d) plane %d (%dx%d)", |
| (char *) &fourcc, fourcc, plane, |
| GST_VIDEO_INFO_COMP_WIDTH (in_info, plane), |
| GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane)); |
| |
| attribs[atti++] = EGL_WIDTH; |
| attribs[atti++] = GST_VIDEO_INFO_COMP_WIDTH (in_info, plane); |
| attribs[atti++] = EGL_HEIGHT; |
| attribs[atti++] = GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane); |
| |
| attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; |
| attribs[atti++] = fourcc; |
| |
| attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; |
| attribs[atti++] = dmabuf; |
| |
| attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; |
| attribs[atti++] = offset; |
| attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; |
| attribs[atti++] = GST_VIDEO_INFO_PLANE_STRIDE (in_info, plane); |
| |
| attribs[atti] = EGL_NONE; |
| |
| for (int i = 0; i < atti; i++) |
| GST_LOG ("attr %i: %08X", i, attribs[i]); |
| |
| g_assert (atti == 12); |
| |
| img = ctx_egl->eglCreateImage (ctx_egl->egl_display, EGL_NO_CONTEXT, |
| EGL_LINUX_DMA_BUF_EXT, NULL, attribs); |
| |
| if (!img) { |
| GST_WARNING_OBJECT (allocator, "eglCreateImage failed: %s", |
| gst_gl_context_egl_get_error_string (eglGetError ())); |
| return NULL; |
| } |
| |
| return gst_egl_image_allocator_wrap (allocator, ctx_egl, img, 0, 0, |
| in_info->size, NULL, NULL); |
| } |
| #endif /* GST_GL_HAVE_DMABUF */ |
| |
| gboolean |
| gst_egl_image_memory_setup_buffer (GstGLContext * ctx, GstVideoInfo * info, |
| GstBuffer * buffer) |
| { |
| gint i = 0; |
| gint stride[3]; |
| gsize offset[3]; |
| GstMemory *mem[3] = { NULL, NULL, NULL }; |
| guint n_mem = 0; |
| GstMemoryFlags flags = 0; |
| EGLImageKHR image = EGL_NO_IMAGE_KHR; |
| EGLClientBuffer client_buffer_tex[3] = { 0, 0, 0 }; |
| GstVideoGLTextureType texture_types[] = { 0, 0, 0, 0 }; |
| GstEGLImageAllocator *allocator = gst_egl_image_allocator_obtain (); |
| GstGLContextEGL *context = GST_GL_CONTEXT_EGL (ctx); |
| |
| g_return_val_if_fail (ctx, FALSE); |
| g_return_val_if_fail (info, FALSE); |
| g_return_val_if_fail (buffer, FALSE); |
| g_return_val_if_fail (gst_gl_context_check_feature (ctx, |
| "EGL_KHR_image_base"), FALSE); |
| |
| memset (stride, 0, sizeof (stride)); |
| memset (offset, 0, sizeof (offset)); |
| |
| flags |= GST_MEMORY_FLAG_NOT_MAPPABLE; |
| flags |= GST_MEMORY_FLAG_NO_SHARE; |
| |
| switch (GST_VIDEO_INFO_FORMAT (info)) { |
| case GST_VIDEO_FORMAT_RGB: |
| case GST_VIDEO_FORMAT_BGR: |
| case GST_VIDEO_FORMAT_RGB16: |
| case GST_VIDEO_FORMAT_RGBA: |
| case GST_VIDEO_FORMAT_BGRA: |
| case GST_VIDEO_FORMAT_ARGB: |
| case GST_VIDEO_FORMAT_ABGR: |
| case GST_VIDEO_FORMAT_RGBx: |
| case GST_VIDEO_FORMAT_BGRx: |
| case GST_VIDEO_FORMAT_xRGB: |
| case GST_VIDEO_FORMAT_xBGR: |
| case GST_VIDEO_FORMAT_AYUV: |
| { |
| gsize size = 0; |
| |
| switch (GST_VIDEO_INFO_FORMAT (info)) { |
| case GST_VIDEO_FORMAT_RGB: |
| case GST_VIDEO_FORMAT_BGR: |
| case GST_VIDEO_FORMAT_RGB16: |
| { |
| texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGB; |
| break; |
| } |
| case GST_VIDEO_FORMAT_RGBA: |
| case GST_VIDEO_FORMAT_BGRA: |
| case GST_VIDEO_FORMAT_ARGB: |
| case GST_VIDEO_FORMAT_ABGR: |
| case GST_VIDEO_FORMAT_RGBx: |
| case GST_VIDEO_FORMAT_BGRx: |
| case GST_VIDEO_FORMAT_xRGB: |
| case GST_VIDEO_FORMAT_xBGR: |
| case GST_VIDEO_FORMAT_AYUV: |
| { |
| texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA; |
| break; |
| } |
| default: |
| g_assert_not_reached (); |
| break; |
| } |
| #if 0 |
| mem[0] = |
| gst_egl_image_allocator_alloc (allocator, context, |
| texture_types[0], GST_VIDEO_INFO_WIDTH (info), |
| GST_VIDEO_INFO_HEIGHT (info), size); |
| if (mem[0]) { |
| stride[0] = size / GST_VIDEO_INFO_HEIGHT (info); |
| n_mem = 1; |
| GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE); |
| } else |
| #endif |
| { |
| gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, 0, stride, |
| offset, &size, (GLuint *) & client_buffer_tex[0]); |
| |
| image = context->eglCreateImage (context->egl_display, |
| context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[0], |
| NULL); |
| if (eglGetError () != EGL_SUCCESS) |
| goto mem_error; |
| |
| mem[0] = |
| gst_egl_image_allocator_wrap (allocator, context, |
| image, texture_types[0], flags, size, client_buffer_tex[0], |
| (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture); |
| n_mem = 1; |
| } |
| break; |
| } |
| |
| case GST_VIDEO_FORMAT_NV12: |
| case GST_VIDEO_FORMAT_NV21: |
| { |
| gsize size[2]; |
| |
| texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE; |
| texture_types[1] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA; |
| #if 0 |
| mem[0] = |
| gst_egl_image_allocator_alloc (allocator, context, |
| texture_types[0], GST_VIDEO_INFO_COMP_WIDTH (info, |
| 0), GST_VIDEO_INFO_COMP_HEIGHT (info, 0), size[0]); |
| mem[1] = |
| gst_egl_image_allocator_alloc (allocator, context, |
| texture_types[1], |
| GST_VIDEO_INFO_COMP_WIDTH (info, 1), |
| GST_VIDEO_INFO_COMP_HEIGHT (info, 1), size[1]); |
| |
| if (mem[0] && mem[1]) { |
| stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info); |
| offset[1] = size[0]; |
| stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info); |
| n_mem = 2; |
| GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE); |
| GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE); |
| } else { |
| if (mem[0]) |
| gst_memory_unref (mem[0]); |
| if (mem[1]) |
| gst_memory_unref (mem[1]); |
| mem[0] = mem[1] = NULL; |
| } |
| #endif |
| { |
| for (i = 0; i < 2; i++) { |
| gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, 0, |
| stride, offset, size, (GLuint *) & client_buffer_tex[i]); |
| |
| image = context->eglCreateImage (context->egl_display, |
| context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i], |
| NULL); |
| if (eglGetError () != EGL_SUCCESS) |
| goto mem_error; |
| |
| mem[i] = |
| gst_egl_image_allocator_wrap (allocator, context, |
| image, texture_types[i], flags, size[i], client_buffer_tex[i], |
| (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture); |
| } |
| |
| n_mem = 2; |
| } |
| break; |
| } |
| case GST_VIDEO_FORMAT_I420: |
| case GST_VIDEO_FORMAT_YV12: |
| case GST_VIDEO_FORMAT_Y444: |
| case GST_VIDEO_FORMAT_Y42B: |
| case GST_VIDEO_FORMAT_Y41B: |
| { |
| gsize size[3]; |
| |
| texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE; |
| texture_types[1] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE; |
| texture_types[2] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE; |
| #if 0 |
| mem[0] = |
| gst_egl_image_allocator_alloc (allocator, context, |
| texture_types[0], GST_VIDEO_INFO_COMP_WIDTH (info, |
| 0), GST_VIDEO_INFO_COMP_HEIGHT (info, 0), size[0]); |
| mem[1] = |
| gst_egl_image_allocator_alloc (allocator, context, |
| texture_types[1], GST_VIDEO_INFO_COMP_WIDTH (info, |
| 1), GST_VIDEO_INFO_COMP_HEIGHT (info, 1), size[1]); |
| mem[2] = |
| gst_egl_image_allocator_alloc (allocator, context, |
| texture_types[2], GST_VIDEO_INFO_COMP_WIDTH (info, |
| 2), GST_VIDEO_INFO_COMP_HEIGHT (info, 2), size[2]); |
| |
| if (mem[0] && mem[1] && mem[2]) { |
| stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info); |
| offset[1] = size[0]; |
| stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info); |
| offset[2] = size[1]; |
| stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (info); |
| n_mem = 3; |
| GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE); |
| GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE); |
| GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE); |
| } else { |
| if (mem[0]) |
| gst_memory_unref (mem[0]); |
| if (mem[1]) |
| gst_memory_unref (mem[1]); |
| if (mem[2]) |
| gst_memory_unref (mem[2]); |
| mem[0] = mem[1] = mem[2] = NULL; |
| } |
| #endif |
| { |
| for (i = 0; i < 3; i++) { |
| gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, i, |
| stride, offset, size, (GLuint *) & client_buffer_tex[i]); |
| |
| image = context->eglCreateImage (context->egl_display, |
| context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i], |
| NULL); |
| if (eglGetError () != EGL_SUCCESS) |
| goto mem_error; |
| |
| mem[i] = |
| gst_egl_image_allocator_wrap (allocator, context, |
| image, texture_types[i], flags, size[i], client_buffer_tex[i], |
| (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture); |
| } |
| |
| n_mem = 3; |
| } |
| break; |
| } |
| default: |
| g_assert_not_reached (); |
| break; |
| } |
| |
| gst_buffer_add_video_meta_full (buffer, 0, GST_VIDEO_INFO_FORMAT (info), |
| GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), |
| GST_VIDEO_INFO_N_PLANES (info), offset, stride); |
| |
| gst_buffer_add_video_gl_texture_upload_meta (buffer, |
| gst_egl_image_memory_get_orientation (mem[0]), n_mem, texture_types, |
| gst_eglimage_to_gl_texture_upload_meta, NULL, NULL, NULL); |
| |
| for (i = 0; i < n_mem; i++) |
| gst_buffer_append_memory (buffer, mem[i]); |
| |
| return TRUE; |
| |
| mem_error: |
| { |
| GST_CAT_ERROR (GST_CAT_DEFAULT, "Failed to create EGLImage"); |
| |
| for (i = 0; i < 3; i++) { |
| if (client_buffer_tex[i]) |
| gst_gl_context_del_texture (ctx, (GLuint *) & client_buffer_tex[i]); |
| if (mem[i]) |
| gst_memory_unref (mem[i]); |
| } |
| |
| return FALSE; |
| } |
| } |