/** * gst_gl_context_new: * @display: a #GstGLDisplay * * Create a new #GstGLContext with the specified @display * * Returns: a new #GstGLContext * * Since: 1.4 */ GstGLContext * gst_gl_context_new (GstGLDisplay * display) { GstGLContext *context = NULL; const gchar *user_choice; _init_debug (); user_choice = g_getenv ("GST_GL_PLATFORM"); GST_INFO ("creating a context for display %" GST_PTR_FORMAT ", user choice:%s", display, user_choice); #if GST_GL_HAVE_PLATFORM_CGL if (!context && (!user_choice || g_strstr_len (user_choice, 5, "cgl"))) context = GST_GL_CONTEXT (gst_gl_context_cocoa_new ()); #endif #if GST_GL_HAVE_PLATFORM_GLX if (!context && (!user_choice || g_strstr_len (user_choice, 3, "glx"))) context = GST_GL_CONTEXT (gst_gl_context_glx_new ()); #endif #if GST_GL_HAVE_PLATFORM_EGL if (!context && (!user_choice || g_strstr_len (user_choice, 7, "egl"))) context = GST_GL_CONTEXT (gst_gl_context_egl_new ()); #endif #if GST_GL_HAVE_PLATFORM_WGL if (!context && (!user_choice || g_strstr_len (user_choice, 3, "wgl"))) { context = GST_GL_CONTEXT (gst_gl_context_wgl_new ()); } #endif #if GST_GL_HAVE_PLATFORM_EAGL if (!context && (!user_choice || g_strstr_len (user_choice, 5, "eagl"))) context = GST_GL_CONTEXT (gst_gl_context_eagl_new ()); #endif if (!context) { /* subclass returned a NULL context */ GST_WARNING ("Could not create context. user specified %s", user_choice ? user_choice : "(null)"); return NULL; } context->priv->display = gst_object_ref (display); GST_DEBUG_OBJECT (context, "Done creating context for display %" GST_PTR_FORMAT " (user_choice:%s)", display, user_choice); return context; }
/** * gst_vaapi_plugin_base_set_gl_context: * @plugin: a #GstVaapiPluginBase * @object: the new GL context from downstream * * Registers the new GL context. The change is effective at the next * call to gst_vaapi_plugin_base_ensure_display(), where the * underlying display object could be re-allocated to fit the GL * context needs */ void gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin, GstObject * object) { #if USE_GST_GL_HELPERS GstGLContext *const gl_context = GST_GL_CONTEXT (object); GstVaapiDisplayType display_type; gst_object_replace (&plugin->gl_context, object); switch (gst_gl_context_get_gl_platform (gl_context)) { #if USE_GLX case GST_GL_PLATFORM_GLX: display_type = GST_VAAPI_DISPLAY_TYPE_GLX; break; #endif #if USE_EGL case GST_GL_PLATFORM_EGL: display_type = GST_VAAPI_DISPLAY_TYPE_EGL; break; #endif default: display_type = plugin->display_type; break; } gst_vaapi_plugin_base_set_display_type (plugin, display_type); #endif }
static void gst_gl_context_gpu_process_finalize (GObject * object) { GstGLContext *context = GST_GL_CONTEXT (object); if (context->window) GST_GL_WINDOW_GET_CLASS (context->window)->close (context->window); G_OBJECT_CLASS (parent_class)->finalize (object); }
static void _gst_egl_image_free (GstMiniObject * object) { GstEGLImage *image = GST_EGL_IMAGE (object); if (image->context) { gst_gl_context_thread_add (GST_GL_CONTEXT (image->context), (GstGLContextThreadFunc) _gst_egl_image_free_thread, image); gst_object_unref (image->context); } }
static void gst_gl_context_finalize (GObject * object) { GstGLContext *context = GST_GL_CONTEXT (object); if (context->window) { gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL); gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL); if (context->priv->alive) { g_mutex_lock (&context->priv->render_lock); GST_INFO_OBJECT (context, "send quit gl window loop"); gst_gl_window_quit (context->window); while (context->priv->alive) { g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock); } g_mutex_unlock (&context->priv->render_lock); } gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL); if (context->priv->gl_thread) { gpointer ret = g_thread_join (context->priv->gl_thread); GST_INFO_OBJECT (context, "gl thread joined"); if (ret != NULL) GST_ERROR_OBJECT (context, "gl thread returned a non-null pointer"); context->priv->gl_thread = NULL; } gst_object_unref (context->window); } gst_object_unref (context->display); if (context->gl_vtable) { g_slice_free (GstGLFuncs, context->gl_vtable); context->gl_vtable = NULL; } g_mutex_clear (&context->priv->render_lock); g_cond_clear (&context->priv->destroy_cond); g_cond_clear (&context->priv->create_cond); g_free (context->priv->gl_exts); g_weak_ref_clear (&context->priv->other_context_ref); GST_DEBUG_OBJECT (context, "End of finalize"); G_OBJECT_CLASS (gst_gl_context_parent_class)->finalize (object); }
static GstVaapiDisplay * gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object) { #if USE_GST_GL_HELPERS GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object); GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context); GstGLDisplayType gl_display_type; GstGLPlatform gl_platform; gpointer native_display; GstVaapiDisplay *display = NULL; GstVaapiDisplayType display_type; /* Get display type and the native hanler */ gl_display_type = gst_gl_display_get_handle_type (gl_display); gl_platform = gst_gl_context_get_gl_platform (gl_context); display_type = gst_vaapi_get_display_type_from_gl (gl_display_type, gl_platform); native_display = GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display)); if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY) { /* derive type and native_display from the active window */ GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context); if (gl_window) native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window)); display_type = gst_vaapi_get_display_type_from_gl_env (); } if (gl_platform == GST_GL_PLATFORM_EGL) { display = gst_vaapi_create_display_from_egl (gl_display, gl_context, display_type, native_display); } /* Non-EGL and fallback */ if (!display) { display = gst_vaapi_create_display_from_handle (display_type, native_display); } gst_object_unref (gl_display); return display; #endif GST_ERROR ("No GstGL support"); return NULL; }
static gboolean _gl_mem_create (GstGLMemoryEGL * gl_mem, GError ** error) { GstGLContext *context = gl_mem->mem.mem.context; GstGLContextEGL *ctx_egl = GST_GL_CONTEXT_EGL (context); const GstGLFuncs *gl = context->gl_vtable; GstGLBaseMemoryAllocatorClass *alloc_class; if (!gst_gl_context_check_feature (GST_GL_CONTEXT (context), "EGL_KHR_image_base")) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "EGL_KHR_image_base is not supported"); return FALSE; } alloc_class = GST_GL_BASE_MEMORY_ALLOCATOR_CLASS (parent_class); if (!alloc_class->create ((GstGLBaseMemory *) gl_mem, error)) return FALSE; if (gl_mem->image == NULL) { EGLImageKHR image = ctx_egl->eglCreateImageKHR (ctx_egl->egl_display, ctx_egl->egl_context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) (guintptr) gl_mem->mem.tex_id, NULL); GST_TRACE ("Generating EGLImage handle:%p from a texture:%u", gl_mem->image, gl_mem->mem.tex_id); if (eglGetError () != EGL_SUCCESS) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to create EGLImage"); return FALSE; } gl_mem->image = gst_egl_image_new_wrapped (context, image, 0, 0, NULL, (GstEGLImageDestroyNotify) _destroy_egl_image); } else { gl->ActiveTexture (GL_TEXTURE0 + gl_mem->mem.plane); gl->BindTexture (GL_TEXTURE_2D, gl_mem->mem.tex_id); gl->EGLImageTargetTexture2D (GL_TEXTURE_2D, gst_egl_image_get_image (GST_EGL_IMAGE (gl_mem->image))); } return TRUE; }
GstGLContext * gst_gl_context_gpu_process_new (GstGLDisplay * display, GstGLAPI gl_api, GstGLProcAddrFunc proc_addr) { GstGLContext *context = NULL; GstGLContextGPUProcess *gpu_context = NULL; GstGLContextClass *context_class = NULL; GstGLWindow *window = NULL; GError *error = NULL; g_return_val_if_fail ((gst_gl_display_get_gl_api (display) & gl_api) != GST_GL_API_NONE, NULL); gpu_context = g_object_new (GST_GL_TYPE_CONTEXT_GPU_PROCESS, NULL); gpu_context->priv->gl_api = gl_api; context = GST_GL_CONTEXT (gpu_context); context->display = display; gst_gl_display_add_context (display, context); context_class = GST_GL_CONTEXT_GET_CLASS (context); context_class->get_current_context = NULL; context_class->get_proc_address = GST_DEBUG_FUNCPTR (proc_addr); gst_gl_context_activate (context, TRUE); gst_gl_context_fill_info (context, &error); if (error) { GST_ERROR_OBJECT (context, "Failed to create gpu process context: %s", error->message); g_error_free (error); gst_object_unref (context); return NULL; } window = GST_GL_WINDOW (gst_gl_window_gpu_process_new (display)); gst_gl_context_set_window (context, window); GST_GL_WINDOW_GET_CLASS (window)->open (window, NULL); gst_object_unref (window); return context; }
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; }
/** * gst_vaapi_plugin_base_set_gl_context: * @plugin: a #GstVaapiPluginBase * @object: the new GL context from downstream * * Registers the new GL context. The change is effective at the next * call to gst_vaapi_plugin_base_ensure_display(), where the * underlying display object could be re-allocated to fit the GL * context needs */ void gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin, GstObject * object) { #if USE_GST_GL_HELPERS GstGLContext *const gl_context = GST_GL_CONTEXT (object); GstVaapiDisplayType display_type; if (plugin->gl_context == object) return; gst_object_replace (&plugin->gl_context, object); switch (gst_gl_context_get_gl_platform (gl_context)) { #if USE_GLX case GST_GL_PLATFORM_GLX: display_type = GST_VAAPI_DISPLAY_TYPE_GLX; break; #endif case GST_GL_PLATFORM_EGL: #if VA_CHECK_VERSION (0,36,0) && USE_GST_GL_HELPERS plugin->srcpad_can_dmabuf = (!(gst_gl_context_get_gl_api (gl_context) & GST_GL_API_GLES1) && gst_gl_context_check_feature (gl_context, "EGL_EXT_image_dma_buf_import")); #endif #if USE_EGL display_type = GST_VAAPI_DISPLAY_TYPE_EGL; break; #endif default: display_type = plugin->display_type; break; } GST_INFO_OBJECT (plugin, "GL context: %" GST_PTR_FORMAT, plugin->gl_context); gst_vaapi_plugin_base_set_display_type (plugin, display_type); #endif }
static GstVaapiDisplay * gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object) { #if USE_GST_GL_HELPERS GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object); GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context); gpointer native_display = GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display)); GstVaapiDisplay *display, *out_display; GstVaapiDisplayType display_type; switch (gst_gl_display_get_handle_type (gl_display)) { #if USE_X11 case GST_GL_DISPLAY_TYPE_X11: display_type = GST_VAAPI_DISPLAY_TYPE_X11; break; #endif #if USE_WAYLAND case GST_GL_DISPLAY_TYPE_WAYLAND: display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND; break; #endif case GST_GL_DISPLAY_TYPE_ANY:{ /* Derive from the active window */ GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context); const gchar *const gl_window_type = g_getenv ("GST_GL_WINDOW"); display_type = GST_VAAPI_DISPLAY_TYPE_ANY; if (!gl_window) break; native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window)); if (gl_window_type) { #if USE_X11 if (!display_type && g_strcmp0 (gl_window_type, "x11") == 0) display_type = GST_VAAPI_DISPLAY_TYPE_X11; #endif #if USE_WAYLAND if (!display_type && g_strcmp0 (gl_window_type, "wayland") == 0) display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND; #endif } else { #if USE_X11 if (!display_type && GST_GL_HAVE_WINDOW_X11) display_type = GST_VAAPI_DISPLAY_TYPE_X11; #endif #if USE_WAYLAND if (!display_type && GST_GL_HAVE_WINDOW_WAYLAND) display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND; #endif } break; } default: display_type = GST_VAAPI_DISPLAY_TYPE_ANY; break; } if (!display_type) return NULL; display = gst_vaapi_create_display_from_handle (display_type, native_display); if (!display) return NULL; switch (gst_gl_context_get_gl_platform (gl_context)) { #if USE_EGL case GST_GL_PLATFORM_EGL:{ guint gles_version; switch (gst_gl_context_get_gl_api (gl_context)) { case GST_GL_API_GLES1: gles_version = 1; goto create_egl_display; case GST_GL_API_GLES2: gles_version = 2; goto create_egl_display; case GST_GL_API_OPENGL: case GST_GL_API_OPENGL3: gles_version = 0; create_egl_display: out_display = gst_vaapi_display_egl_new (display, gles_version); break; default: out_display = NULL; break; } if (!out_display) return NULL; gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (out_display), GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context))); break; } #endif default: out_display = gst_vaapi_display_ref (display); break; } gst_vaapi_display_unref (display); return out_display; #endif GST_ERROR ("unsupported GStreamer version %s", GST_API_VERSION_S); return NULL; }
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; } }