static gboolean gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error) { #if GST_GL_HAVE_WINDOW_X11 if (GST_GL_IS_WINDOW_X11 (context->window)) { GstGLWindow *window = gst_gl_context_get_window (context); GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window); gint ret; window_x11->visual_info = g_new0 (XVisualInfo, 1); ret = XMatchVisualInfo (window_x11->device, window_x11->screen_num, window_x11->depth, TrueColor, window_x11->visual_info); gst_object_unref (window); if (ret == 0) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to match XVisualInfo"); return FALSE; } } #endif return TRUE; }
/** * gst_gl_context_thread_add: * @context: a #GstGLContext * @func: a #GstGLContextThreadFunc * @data: (closure): user data to call @func with * * Execute @func in the OpenGL thread of @context with @data * * MT-safe * * Since: 1.4 */ void gst_gl_context_thread_add (GstGLContext * context, GstGLContextThreadFunc func, gpointer data) { GstGLWindow *window; RunGenericData rdata; g_return_if_fail (GST_IS_GL_CONTEXT (context)); g_return_if_fail (func != NULL); if (GST_IS_GL_WRAPPED_CONTEXT (context)) { g_return_if_fail (context->priv->active_thread == g_thread_self ()); func (context, data); return; } rdata.context = context; rdata.data = data; rdata.func = func; window = gst_gl_context_get_window (context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_gst_gl_context_thread_run_generic), &rdata); gst_object_unref (window); }
static gboolean gst_glimage_sink_redisplay (GstGLImageSink * gl_sink) { GstGLWindow *window; gboolean alive; window = gst_gl_context_get_window (gl_sink->context); if (window && gst_gl_window_is_running (window)) { #if GST_GL_HAVE_GLES2 if (USING_GLES2 (gl_sink->context)) { if (!gl_sink->redisplay_shader) { gst_gl_window_send_message (window, GST_GL_WINDOW_CB (gst_glimage_sink_thread_init_redisplay), gl_sink); } } #endif /* Drawing is asynchrone: gst_gl_window_draw is not blocking * It means that it does not wait for stuff being executed in other threads */ gst_gl_window_draw (window, GST_VIDEO_SINK_WIDTH (gl_sink), GST_VIDEO_SINK_HEIGHT (gl_sink)); } alive = gst_gl_window_is_running (window); gst_object_unref (window); return alive; }
static gboolean gst_gl_context_egl_activate (GstGLContext * context, gboolean activate) { GstGLContextEGL *egl; gboolean result; egl = GST_GL_CONTEXT_EGL (context); if (activate) { GstGLWindow *window = gst_gl_context_get_window (context); EGLNativeWindowType handle = 0; /* Check if the backing handle changed */ if (window) { handle = (EGLNativeWindowType) gst_gl_window_get_window_handle (window); gst_object_unref (window); } if (handle && handle != egl->window_handle) { GST_DEBUG_OBJECT (context, "Handle changed (have:%p, now:%p), switching surface", (void *) egl->window_handle, (void *) handle); if (egl->egl_surface) { result = eglDestroySurface (egl->egl_display, egl->egl_surface); egl->egl_surface = EGL_NO_SURFACE; if (!result) { GST_ERROR_OBJECT (context, "Failed to destroy old window surface: %s", gst_egl_get_error_string (eglGetError ())); goto done; } } egl->egl_surface = eglCreateWindowSurface (egl->egl_display, egl->egl_config, handle, NULL); egl->window_handle = handle; if (egl->egl_surface == EGL_NO_SURFACE) { GST_ERROR_OBJECT (context, "Failed to create window surface: %s", gst_egl_get_error_string (eglGetError ())); result = FALSE; goto done; } } result = eglMakeCurrent (egl->egl_display, egl->egl_surface, egl->egl_surface, egl->egl_context); } else { result = eglMakeCurrent (egl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } if (!result) { GST_ERROR_OBJECT (context, "Failed to bind context to the current rendering thread: %s", gst_egl_get_error_string (eglGetError ())); } done: return result; }
static gboolean gst_gl_context_wgl_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLWindow *window; GstGLContextWGL *context_wgl; GstGLContextWGL *other_wgl = NULL; HDC device; context_wgl = GST_GL_CONTEXT_WGL (context); window = gst_gl_context_get_window (context); device = (HDC) gst_gl_window_get_display (window); if (other_context) { if (!GST_GL_IS_CONTEXT_WGL (other_context)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with a non-WGL context"); goto failure; } other_wgl = (GstGLContextWGL *) other_context; } context_wgl->wgl_context = wglCreateContext (device); if (context_wgl->wgl_context) GST_DEBUG ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) context_wgl->wgl_context); else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to create glcontext:0x%x", (unsigned int) GetLastError ()); goto failure; } g_assert (context_wgl->wgl_context); GST_LOG ("gl context id: %" G_GUINTPTR_FORMAT, (guintptr) context_wgl->wgl_context); if (other_wgl) { if (!wglShareLists (other_wgl->wgl_context, context_wgl->wgl_context)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to share contexts 0x%x", (unsigned int) GetLastError ()); goto failure; } } gst_object_unref (window); return TRUE; failure: gst_object_unref (window); return FALSE; }
static void gst_gl_context_wgl_swap_buffers (GstGLContext * context) { GstGLWindow *window = gst_gl_context_get_window (context); HDC device = (HDC) gst_gl_window_get_display (window); SwapBuffers (device); gst_object_unref (window); }
static gboolean gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error) { GstGLWindow *window; PIXELFORMATDESCRIPTOR pfd; gint pixelformat = 0; gboolean res = FALSE; HDC device; window = gst_gl_context_get_window (context); gst_gl_window_win32_create_window (GST_GL_WINDOW_WIN32 (window), error); device = (HDC) gst_gl_window_get_display (window); gst_object_unref (window); pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cRedBits = 8; pfd.cRedShift = 0; pfd.cGreenBits = 8; pfd.cGreenShift = 0; pfd.cBlueBits = 8; pfd.cBlueShift = 0; pfd.cAlphaBits = 0; pfd.cAlphaShift = 0; pfd.cAccumBits = 0; pfd.cAccumRedBits = 0; pfd.cAccumGreenBits = 0; pfd.cAccumBlueBits = 0; pfd.cAccumAlphaBits = 0; pfd.cDepthBits = 24; pfd.cStencilBits = 8; pfd.cAuxBuffers = 0; pfd.iLayerType = PFD_MAIN_PLANE; pfd.bReserved = 0; pfd.dwLayerMask = 0; pfd.dwVisibleMask = 0; pfd.dwDamageMask = 0; pfd.cColorBits = (BYTE) GetDeviceCaps (device, BITSPIXEL); pixelformat = ChoosePixelFormat (device, &pfd); if (!pixelformat) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to choose a pixel format"); return FALSE; } res = SetPixelFormat (device, pixelformat, &pfd); return res; }
static void gst_gl_context_glx_swap_buffers (GstGLContext * context) { GstGLWindow *window = gst_gl_context_get_window (context); Display *device = (Display *) gst_gl_display_get_handle (window->display); Window window_handle = (Window) gst_gl_window_get_window_handle (window); glXSwapBuffers (device, window_handle); gst_object_unref (window); }
static void gst_glimage_sink_on_close (GstGLImageSink * gl_sink) { GstGLWindow *window; gst_gl_context_set_error (gl_sink->context, "Output window was closed"); window = gst_gl_context_get_window (gl_sink->context); g_signal_handler_disconnect (window, gl_sink->key_sig_id); g_signal_handler_disconnect (window, gl_sink->mouse_sig_id); g_atomic_int_set (&gl_sink->to_quit, 1); gst_object_unref (window); }
static void setup (void) { GError *error = NULL; display = gst_gl_display_new (); context = gst_gl_context_new (display); gst_gl_context_create (context, 0, &error); window = gst_gl_context_get_window (context); fail_if (error != NULL, "Error creating context: %s\n", error ? error->message : "Unknown Error"); upload = gst_gl_upload_new (context); }
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 void gst_gl_context_glx_destroy_context (GstGLContext * context) { GstGLWindow *window; GstGLContextGLX *context_glx; Display *device; context_glx = GST_GL_CONTEXT_GLX (context); window = gst_gl_context_get_window (context); device = (Display *) gst_gl_display_get_handle (window->display); glXDestroyContext (device, context_glx->glx_context); context_glx->glx_context = 0; gst_object_unref (window); }
static gboolean gst_gl_context_glx_activate (GstGLContext * context, gboolean activate) { GstGLWindow *window = gst_gl_context_get_window (context); Display *device = (Display *) gst_gl_display_get_handle (window->display); Window window_handle = (Window) gst_gl_window_get_window_handle (window); gboolean result; if (activate) { result = glXMakeCurrent (device, window_handle, GST_GL_CONTEXT_GLX (context)->glx_context); } else { result = glXMakeCurrent (device, None, NULL); } gst_object_unref (window); return result; }
static void gst_glimage_sink_expose (GstVideoOverlay * overlay) { GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (overlay); /* redisplay opengl scene */ if (glimage_sink->display && glimage_sink->window_id) { if (glimage_sink->window_id != glimage_sink->new_window_id) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); gst_object_unref (window); } gst_glimage_sink_redisplay (glimage_sink); } }
static void gst_glimage_sink_navigation_send_event (GstNavigation * navigation, GstStructure * structure) { GstGLImageSink *sink = GST_GLIMAGE_SINK (navigation); GstEvent *event = NULL; GstPad *pad = NULL; GstGLWindow *window = gst_gl_context_get_window (sink->context); guint width, height; gdouble x, y, xscale, yscale; g_return_if_fail (GST_GL_IS_WINDOW (window)); width = GST_VIDEO_SINK_WIDTH (sink); height = GST_VIDEO_SINK_HEIGHT (sink); gst_gl_window_get_surface_dimensions (window, &width, &height); event = gst_event_new_navigation (structure); pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink)); /* Converting pointer coordinates to the non scaled geometry */ if (width != GST_VIDEO_SINK_WIDTH (sink) && width != 0 && gst_structure_get_double (structure, "pointer_x", &x)) { xscale = (gdouble) GST_VIDEO_SINK_WIDTH (sink) / width; gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, (gdouble) x * xscale, NULL); } if (height != GST_VIDEO_SINK_HEIGHT (sink) && height != 0 && gst_structure_get_double (structure, "pointer_y", &y)) { yscale = (gdouble) GST_VIDEO_SINK_HEIGHT (sink) / height; gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, (gdouble) y * yscale, NULL); } if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) gst_pad_send_event (pad, event); gst_object_unref (pad); gst_object_unref (window); }
static GstFlowReturn gst_glimage_sink_prepare (GstBaseSink * bsink, GstBuffer * buf) { GstGLImageSink *glimage_sink; glimage_sink = GST_GLIMAGE_SINK (bsink); GST_TRACE ("preparing buffer:%p", buf); if (GST_VIDEO_SINK_WIDTH (glimage_sink) < 1 || GST_VIDEO_SINK_HEIGHT (glimage_sink) < 1) { return GST_FLOW_NOT_NEGOTIATED; } if (!_ensure_gl_setup (glimage_sink)) return GST_FLOW_NOT_NEGOTIATED; if (!gst_gl_upload_perform_with_buffer (glimage_sink->upload, buf, &glimage_sink->next_tex)) goto upload_failed; if (glimage_sink->window_id != glimage_sink->new_window_id) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); gst_object_unref (window); } return GST_FLOW_OK; upload_failed: { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", "Failed to upload buffer"), (NULL)); return GST_FLOW_ERROR; } }
static gboolean gst_gl_context_wgl_activate (GstGLContext * context, gboolean activate) { GstGLWindow *window; GstGLContextWGL *context_wgl; HDC device; gboolean result; window = gst_gl_context_get_window (context); context_wgl = GST_GL_CONTEXT_WGL (context); device = (HDC) gst_gl_window_get_display (window); if (activate) { result = wglMakeCurrent (device, context_wgl->wgl_context); } else { result = wglMakeCurrent (NULL, NULL); } gst_object_unref (window); return result; }
static gboolean gst_glimage_sink_redisplay (GstGLImageSink * gl_sink) { GstGLWindow *window; gboolean alive; window = gst_gl_context_get_window (gl_sink->context); if (!window) return FALSE; if (gst_gl_window_is_running (window)) { #if GST_GL_HAVE_GLES2 if (USING_GLES2 (gl_sink->context)) { if (G_UNLIKELY (!gl_sink->redisplay_shader)) { gst_gl_window_send_message (window, GST_GL_WINDOW_CB (gst_glimage_sink_thread_init_redisplay), gl_sink); /* if the shader is still null it means it failed to be useable */ if (G_UNLIKELY (!gl_sink->redisplay_shader)) { gst_object_unref (window); return FALSE; } } } #endif /* Drawing is asynchronous: gst_gl_window_draw is not blocking * It means that it does not wait for stuff to be executed in other threads */ gst_gl_window_draw (window, GST_VIDEO_SINK_WIDTH (gl_sink), GST_VIDEO_SINK_HEIGHT (gl_sink)); } alive = gst_gl_window_is_running (window); gst_object_unref (window); return alive; }
static void gst_glimage_sink_on_draw (const GstGLImageSink * gl_sink) { /* Here gl_sink members (ex:gl_sink->info) have a life time of set_caps. * It means that they cannot not change between two set_caps as well as * for the redisplay_texture size. * Whereas redisplay_texture id changes every sink_render */ const GstGLFuncs *gl = NULL; GstGLWindow *window = NULL; g_return_if_fail (GST_IS_GLIMAGE_SINK (gl_sink)); gl = gl_sink->context->gl_vtable; GST_GLIMAGE_SINK_LOCK (gl_sink); /* check if texture is ready for being drawn */ if (!gl_sink->redisplay_texture) { GST_GLIMAGE_SINK_UNLOCK (gl_sink); return; } window = gst_gl_context_get_window (gl_sink->context); window->is_drawing = TRUE; /* opengl scene */ GST_TRACE ("redrawing texture:%u", gl_sink->redisplay_texture); /* make sure that the environnement is clean */ gst_gl_context_clear_shader (gl_sink->context); #if GST_GL_HAVE_OPENGL if (USING_OPENGL (gl_sink->context)) gl->Disable (GL_TEXTURE_2D); #endif gl->BindTexture (GL_TEXTURE_2D, 0); /* check if a client draw callback is registered */ if (gl_sink->clientDrawCallback) { gboolean doRedisplay = gl_sink->clientDrawCallback (gl_sink->redisplay_texture, GST_VIDEO_INFO_WIDTH (&gl_sink->info), GST_VIDEO_INFO_HEIGHT (&gl_sink->info), gl_sink->client_data); if (doRedisplay) gst_gl_window_draw_unlocked (window, GST_VIDEO_INFO_WIDTH (&gl_sink->info), GST_VIDEO_INFO_HEIGHT (&gl_sink->info)); } /* default opengl scene */ else { #if GST_GL_HAVE_OPENGL if (USING_OPENGL (gl_sink->context)) { GLfloat verts[8] = { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f }; GLfloat texcoords[8] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }; gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, gl_sink->redisplay_texture); gl->EnableClientState (GL_VERTEX_ARRAY); gl->EnableClientState (GL_TEXTURE_COORD_ARRAY); gl->VertexPointer (2, GL_FLOAT, 0, &verts); gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords); gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4); gl->DisableClientState (GL_VERTEX_ARRAY); gl->DisableClientState (GL_TEXTURE_COORD_ARRAY); gl->Disable (GL_TEXTURE_2D); } #endif #if GST_GL_HAVE_GLES2 if (USING_GLES2 (gl_sink->context)) { const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f }; GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; gl->Clear (GL_COLOR_BUFFER_BIT); gst_gl_shader_use (gl_sink->redisplay_shader); /* Load the vertex position */ gl->VertexAttribPointer (gl_sink->redisplay_attr_position_loc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); /* Load the texture coordinate */ gl->VertexAttribPointer (gl_sink->redisplay_attr_texture_loc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); gl->EnableVertexAttribArray (gl_sink->redisplay_attr_position_loc); gl->EnableVertexAttribArray (gl_sink->redisplay_attr_texture_loc); gl->ActiveTexture (GL_TEXTURE0); gl->BindTexture (GL_TEXTURE_2D, gl_sink->redisplay_texture); gst_gl_shader_set_uniform_1i (gl_sink->redisplay_shader, "s_texture", 0); gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); } #endif } /* end default opengl scene */ window->is_drawing = FALSE; gst_object_unref (window); GST_GLIMAGE_SINK_UNLOCK (gl_sink); }
static gboolean gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error) { GstGLContextGLX *context_glx; GstGLWindow *window; GstGLWindowX11 *window_x11; gint error_base; gint event_base; Display *device; context_glx = GST_GL_CONTEXT_GLX (context); window = gst_gl_context_get_window (context); window_x11 = GST_GL_WINDOW_X11 (window); device = (Display *) gst_gl_display_get_handle (window->display); if (!glXQueryExtension (device, &error_base, &event_base)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "No GLX extension"); goto failure; } if (!glXQueryVersion (device, &context_glx->priv->glx_major, &context_glx->priv->glx_minor)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to query GLX version (glXQueryVersion failed)"); goto failure; } GST_INFO ("GLX Version: %d.%d", context_glx->priv->glx_major, context_glx->priv->glx_minor); /* legacy case */ if (context_glx->priv->glx_major < 1 || (context_glx->priv->glx_major == 1 && context_glx->priv->glx_minor < 3)) { gint attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None }; window_x11->visual_info = glXChooseVisual (device, window_x11->screen_num, attribs); if (!window_x11->visual_info) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Bad attributes in glXChooseVisual"); goto failure; } } else { gint attribs[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, True, None }; int fbcount; context_glx->priv->fbconfigs = glXChooseFBConfig (device, DefaultScreen (device), attribs, &fbcount); if (!context_glx->priv->fbconfigs) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Could not find any FBConfig's to use (check attributes?)"); goto failure; } _describe_fbconfig (device, context_glx->priv->fbconfigs[0]); window_x11->visual_info = glXGetVisualFromFBConfig (device, context_glx->priv->fbconfigs[0]); if (!window_x11->visual_info) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Bad attributes in FBConfig"); goto failure; } } gst_gl_window_x11_create_window ((GstGLWindowX11 *) window); gst_object_unref (window); return TRUE; failure: if (window) gst_object_unref (window); return FALSE; }
static gboolean gst_gl_context_egl_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextEGL *egl; GstGLWindow *window = NULL; EGLNativeWindowType window_handle; gint i = 0; EGLint context_attrib[3]; EGLint majorVersion; EGLint minorVersion; const gchar *egl_exts; gboolean need_surface = TRUE; guintptr external_gl_context = 0; egl = GST_GL_CONTEXT_EGL (context); window = gst_gl_context_get_window (context); if (other_context) { if (!GST_GL_IS_CONTEXT_EGL (other_context)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with non-EGL context"); goto failure; } external_gl_context = gst_gl_context_get_gl_context (other_context); } if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_GLES2)) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "EGL supports opengl or gles2"); goto failure; } if (other_context) { GstGLContextEGL *other_egl = (GstGLContextEGL *) other_context; egl->egl_display = other_egl->egl_display; } else { egl->egl_display = eglGetDisplay ((EGLNativeDisplayType) gst_gl_window_get_display (window)); } if (eglInitialize (egl->egl_display, &majorVersion, &minorVersion)) { GST_INFO ("egl initialized, version: %d.%d", majorVersion, minorVersion); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to initialize egl: %s", gst_gl_context_egl_get_error_string ()); goto failure; } if (gl_api & GST_GL_API_OPENGL) { /* egl + opengl only available with EGL 1.4+ */ if (majorVersion == 1 && minorVersion <= 3) { if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS, "EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); goto failure; } else { GST_WARNING ("EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); if (gl_api & GST_GL_API_GLES2) { goto try_gles2; } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to choose a suitable OpenGL API"); goto failure; } } } if (!eglBindAPI (EGL_OPENGL_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL API: %s", gst_gl_context_egl_get_error_string ()); goto failure; } GST_INFO ("Using OpenGL"); egl->gl_api = GST_GL_API_OPENGL; } else if (gl_api & GST_GL_API_GLES2) { try_gles2: if (!eglBindAPI (EGL_OPENGL_ES_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL|ES API: %s", gst_gl_context_egl_get_error_string ()); goto failure; } GST_INFO ("Using OpenGL|ES 2.0"); egl->gl_api = GST_GL_API_GLES2; } if (!gst_gl_context_egl_choose_config (egl, other_context, error)) { g_assert (error == NULL || *error != NULL); goto failure; } GST_DEBUG ("about to create gl context\n"); if (egl->gl_api & GST_GL_API_GLES2) { context_attrib[i++] = EGL_CONTEXT_CLIENT_VERSION; context_attrib[i++] = 2; } context_attrib[i++] = EGL_NONE; egl->egl_context = eglCreateContext (egl->egl_display, egl->egl_config, (EGLContext) external_gl_context, context_attrib); if (egl->egl_context != EGL_NO_CONTEXT) { GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) egl->egl_context); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create a OpenGL context: %s", gst_gl_context_egl_get_error_string ()); goto failure; } egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS); if (other_context == NULL) { /* FIXME do we want a window vfunc ? */ #if GST_GL_HAVE_WINDOW_X11 if (GST_GL_IS_WINDOW_X11 (context->window)) { gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window); } #endif #if GST_GL_HAVE_WINDOW_WIN32 if (GST_GL_IS_WINDOW_WIN32 (context->window)) { gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); } #endif } window_handle = (EGLNativeWindowType) gst_gl_window_get_window_handle (window); if (window_handle) { egl->egl_surface = eglCreateWindowSurface (egl->egl_display, egl->egl_config, window_handle, NULL); } else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context", egl_exts)) { EGLint surface_attrib[7]; gint j = 0; /* FIXME: Width/height doesn't seem to matter but we can't leave them * at 0, otherwise X11 complains about BadValue */ surface_attrib[j++] = EGL_WIDTH; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_HEIGHT; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_LARGEST_PBUFFER; surface_attrib[j++] = EGL_TRUE; surface_attrib[j++] = EGL_NONE; egl->egl_surface = eglCreatePbufferSurface (egl->egl_display, egl->egl_config, surface_attrib); } else { egl->egl_surface = EGL_NO_SURFACE; need_surface = FALSE; } if (need_surface) { if (egl->egl_surface != EGL_NO_SURFACE) { GST_INFO ("surface created"); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to create window surface: %s", gst_gl_context_egl_get_error_string ()); goto failure; } } gst_object_unref (window); return TRUE; failure: if (window) gst_object_unref (window); return FALSE; }
static GstFlowReturn gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstGLImageSink *glimage_sink; guint tex_id; GST_TRACE ("rendering buffer:%p", buf); glimage_sink = GST_GLIMAGE_SINK (bsink); if (GST_VIDEO_SINK_WIDTH (glimage_sink) < 1 || GST_VIDEO_SINK_HEIGHT (glimage_sink) < 1) { return GST_FLOW_NOT_NEGOTIATED; } if (!_ensure_gl_setup (glimage_sink)) return GST_FLOW_NOT_NEGOTIATED; if (!gst_gl_upload_perform_with_buffer (glimage_sink->upload, buf, &tex_id)) goto upload_failed; if (glimage_sink->window_id != glimage_sink->new_window_id) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); gst_object_unref (window); } GST_TRACE ("redisplay texture:%u of size:%ux%u, window size:%ux%u", tex_id, GST_VIDEO_INFO_WIDTH (&glimage_sink->info), GST_VIDEO_INFO_HEIGHT (&glimage_sink->info), GST_VIDEO_SINK_WIDTH (glimage_sink), GST_VIDEO_SINK_HEIGHT (glimage_sink)); /* Avoid to release the texture while drawing */ GST_GLIMAGE_SINK_LOCK (glimage_sink); glimage_sink->redisplay_texture = tex_id; GST_GLIMAGE_SINK_UNLOCK (glimage_sink); /* Ask the underlying window to redraw its content */ if (!gst_glimage_sink_redisplay (glimage_sink)) goto redisplay_failed; GST_TRACE ("post redisplay"); if (g_atomic_int_get (&glimage_sink->to_quit) != 0) { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); gst_gl_upload_release_buffer (glimage_sink->upload); return GST_FLOW_ERROR; } gst_gl_upload_release_buffer (glimage_sink->upload); return GST_FLOW_OK; /* ERRORS */ redisplay_failed: { gst_gl_upload_release_buffer (glimage_sink->upload); GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return GST_FLOW_ERROR; } upload_failed: { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", "Failed to upload format"), (NULL)); return FALSE; } }
static GstStateChangeReturn gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) { GstGLImageSink *glimage_sink; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GST_DEBUG ("changing state: %s => %s", gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); glimage_sink = GST_GLIMAGE_SINK (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: g_atomic_int_set (&glimage_sink->to_quit, 0); if (!glimage_sink->display) { if (!gst_gl_ensure_display (glimage_sink, &glimage_sink->display)) return GST_STATE_CHANGE_FAILURE; } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: { /* mark the redisplay_texture as unavailable (=0) * to avoid drawing */ GST_GLIMAGE_SINK_LOCK (glimage_sink); glimage_sink->redisplay_texture = 0; if (glimage_sink->stored_buffer) { gst_buffer_unref (glimage_sink->stored_buffer); glimage_sink->stored_buffer = NULL; } GST_GLIMAGE_SINK_UNLOCK (glimage_sink); if (glimage_sink->upload) { gst_object_unref (glimage_sink->upload); glimage_sink->upload = NULL; } glimage_sink->window_id = 0; //but do not reset glimage_sink->new_window_id if (glimage_sink->pool) { gst_buffer_pool_set_active (glimage_sink->pool, FALSE); gst_object_unref (glimage_sink->pool); glimage_sink->pool = NULL; } GST_VIDEO_SINK_WIDTH (glimage_sink) = 1; GST_VIDEO_SINK_HEIGHT (glimage_sink) = 1; if (glimage_sink->context) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (gst_glimage_sink_cleanup_glthread), glimage_sink); gst_gl_window_set_resize_callback (window, NULL, NULL, NULL); gst_gl_window_set_draw_callback (window, NULL, NULL, NULL); gst_gl_window_set_close_callback (window, NULL, NULL, NULL); gst_object_unref (window); gst_object_unref (glimage_sink->context); glimage_sink->context = NULL; } if (glimage_sink->display) { gst_object_unref (glimage_sink->display); glimage_sink->display = NULL; } break; } case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
static gboolean gst_gl_context_egl_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextEGL *egl; GstGLWindow *window = NULL; EGLNativeWindowType window_handle = (EGLNativeWindowType) 0; EGLint egl_major; EGLint egl_minor; gboolean need_surface = TRUE; guintptr external_gl_context = 0; guintptr egl_display; egl = GST_GL_CONTEXT_EGL (context); window = gst_gl_context_get_window (context); GST_DEBUG_OBJECT (context, "Creating EGL context"); if (other_context) { if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with non-EGL context"); goto failure; } external_gl_context = gst_gl_context_get_gl_context (other_context); } if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "EGL supports opengl or gles2"); goto failure; } if (!egl->display_egl) { GstGLDisplay *display = gst_gl_context_get_display (context); egl->display_egl = gst_gl_display_egl_from_gl_display (display); if (!egl->display_egl) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to create EGLDisplay from native display"); goto failure; } gst_object_unref (display); } egl_display = gst_gl_display_get_handle (GST_GL_DISPLAY (egl->display_egl)); egl->egl_display = (EGLDisplay) egl_display; if (eglInitialize (egl->egl_display, &egl_major, &egl_minor)) { GST_INFO ("egl initialized, version: %d.%d", egl_major, egl_minor); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to initialize egl: %s", gst_egl_get_error_string (eglGetError ())); goto failure; } egl->egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS); if (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) { GstGLAPI chosen_gl_api = 0; gint i; /* egl + opengl only available with EGL 1.4+ */ if (egl_major == 1 && egl_minor <= 3) { if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS, "EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", egl_major, egl_minor); goto failure; } else { GST_WARNING ("EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", egl_major, egl_minor); if (gl_api & GST_GL_API_GLES2) { goto try_gles2; } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to choose a suitable OpenGL API"); goto failure; } } } if (!eglBindAPI (EGL_OPENGL_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL API: %s", gst_egl_get_error_string (eglGetError ())); goto failure; } GST_INFO ("Bound OpenGL"); /* api, version only matters for gles */ if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_OPENGL, 0, error)) { g_assert (error == NULL || *error != NULL); goto failure; } for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) { gint profileMask = 0; gint contextFlags = 0; if (GST_GL_CHECK_GL_VERSION (opengl_versions[i].major, opengl_versions[i].minor, 3, 2)) { /* skip gl3 contexts if requested */ if ((gl_api & GST_GL_API_OPENGL3) == 0) continue; chosen_gl_api = GST_GL_API_OPENGL3; #if defined(EGL_KHR_create_context) profileMask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; #endif } else if (opengl_versions[i].major == 3 && opengl_versions[i].minor == 1) { /* skip 3.1, the implementation is free to give us either a core or a * compatibility context (we have no say) */ continue; } else { /* skip legacy contexts if requested */ if ((gl_api & GST_GL_API_OPENGL) == 0) continue; chosen_gl_api = GST_GL_API_OPENGL; } egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, chosen_gl_api, opengl_versions[i].major, opengl_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; #if defined(EGL_KHR_create_context) profileMask &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, chosen_gl_api, opengl_versions[i].major, opengl_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; #endif } egl->gl_api = chosen_gl_api; } else if (gl_api & GST_GL_API_GLES2) { gint i; try_gles2: if (!eglBindAPI (EGL_OPENGL_ES_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL|ES API: %s", gst_egl_get_error_string (eglGetError ())); goto failure; } GST_INFO ("Bound OpenGL|ES"); for (i = 0; i < G_N_ELEMENTS (gles2_versions); i++) { gint profileMask = 0; gint contextFlags = 0; if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_GLES2, gles2_versions[i].major, error)) { continue; } #if defined(EGL_KHR_create_context) /* try a debug context */ contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, GST_GL_API_GLES2, gles2_versions[i].major, gles2_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; /* try without a debug context */ contextFlags &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; #endif egl->egl_context = _create_context_with_flags (egl, (EGLContext) external_gl_context, GST_GL_API_GLES2, gles2_versions[i].major, gles2_versions[i].minor, contextFlags, profileMask); if (egl->egl_context) break; } egl->gl_api = GST_GL_API_GLES2; } if (egl->egl_context != EGL_NO_CONTEXT) { GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) egl->egl_context); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create a OpenGL context: %s", gst_egl_get_error_string (eglGetError ())); goto failure; } /* FIXME do we want a window vfunc ? */ #if GST_GL_HAVE_WINDOW_X11 if (GST_IS_GL_WINDOW_X11 (context->window)) { gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window); } #endif if (other_context == NULL) { /* FIXME: fails to show two outputs at all. We need a property/option for * glimagesink to say its a visible context */ #if GST_GL_HAVE_WINDOW_WAYLAND if (GST_IS_GL_WINDOW_WAYLAND_EGL (context->window)) { gst_gl_window_wayland_egl_create_window ((GstGLWindowWaylandEGL *) context->window); } #endif #if GST_GL_HAVE_WINDOW_WIN32 if (GST_IS_GL_WINDOW_WIN32 (context->window)) { gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); } #endif #if GST_GL_HAVE_WINDOW_DISPMANX if (GST_IS_GL_WINDOW_DISPMANX_EGL (context->window)) { gst_gl_window_dispmanx_egl_create_window ((GstGLWindowDispmanxEGL *) context->window); } #endif } if (window) window_handle = (EGLNativeWindowType) gst_gl_window_get_window_handle (window); if (window_handle) { GST_DEBUG ("Creating EGLSurface from window_handle %p", (void *) window_handle); egl->egl_surface = eglCreateWindowSurface (egl->egl_display, egl->egl_config, window_handle, NULL); /* Store window handle for later comparision */ egl->window_handle = window_handle; } else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context", egl->egl_exts)) { EGLint surface_attrib[7]; gint j = 0; GST_DEBUG ("Surfaceless context, creating PBufferSurface"); /* FIXME: Width/height doesn't seem to matter but we can't leave them * at 0, otherwise X11 complains about BadValue */ surface_attrib[j++] = EGL_WIDTH; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_HEIGHT; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_LARGEST_PBUFFER; surface_attrib[j++] = EGL_TRUE; surface_attrib[j++] = EGL_NONE; egl->egl_surface = eglCreatePbufferSurface (egl->egl_display, egl->egl_config, surface_attrib); } else { GST_DEBUG ("No surface/handle !"); egl->egl_surface = EGL_NO_SURFACE; need_surface = FALSE; } if (need_surface) { if (egl->egl_surface != EGL_NO_SURFACE) { GST_INFO ("surface created"); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to create window surface: %s", gst_egl_get_error_string (eglGetError ())); goto failure; } } egl->egl_major = egl_major; egl->egl_minor = egl_minor; if (window) gst_object_unref (window); return TRUE; failure: if (window) gst_object_unref (window); return FALSE; }
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; }
static gboolean gst_gl_context_glx_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextGLX *context_glx; GstGLWindow *window; GstGLWindowX11 *window_x11; GstGLDisplay *display = NULL; gboolean create_context; const char *glx_exts; Display *device; guintptr external_gl_context = 0; context_glx = GST_GL_CONTEXT_GLX (context); window = gst_gl_context_get_window (context); if (!GST_IS_GL_WINDOW_X11 (window)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot create an GLX context from a non-X11 window"); goto failure; } window_x11 = GST_GL_WINDOW_X11 (window); display = gst_gl_context_get_display (context); if (other_context) { if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_GLX) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with non-GLX context"); goto failure; } external_gl_context = gst_gl_context_get_gl_context (other_context); } device = (Display *) gst_gl_display_get_handle (display); if (!device) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Invalid Display handle"); goto failure; } glx_exts = glXQueryExtensionsString (device, DefaultScreen (device)); create_context = gst_gl_check_extension ("GLX_ARB_create_context", glx_exts); context_glx->priv->glXCreateContextAttribsARB = (gpointer) glXGetProcAddressARB ((const GLubyte *) "glXCreateContextAttribsARB"); if (!context_glx->glx_context && gl_api & GST_GL_API_OPENGL3 && create_context && context_glx->priv->glXCreateContextAttribsARB) { gint i; for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) { gint profileMask = 0; gint contextFlags = 0; if ((opengl_versions[i].major > 3 || (opengl_versions[i].major == 3 && opengl_versions[i].minor >= 2))) { profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; contextFlags |= GLX_CONTEXT_DEBUG_BIT_ARB; } else { break; } GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context", opengl_versions[i].major, opengl_versions[i].minor); context_glx->glx_context = _create_context_with_flags (context_glx, device, context_glx->priv->fbconfigs[0], (GLXContext) external_gl_context, opengl_versions[i].major, opengl_versions[i].minor, contextFlags, profileMask); if (context_glx->glx_context) { context_glx->priv->context_api = GST_GL_API_OPENGL3; break; } } } if (!context_glx->glx_context && gl_api & GST_GL_API_OPENGL) { context_glx->glx_context = glXCreateContext (device, window_x11->visual_info, (GLXContext) external_gl_context, TRUE); context_glx->priv->context_api = GST_GL_API_OPENGL; } if (context_glx->priv->fbconfigs) XFree (context_glx->priv->fbconfigs); if (!context_glx->glx_context) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create opengl context"); goto failure; } GST_LOG ("gl context id: %ld", (gulong) context_glx->glx_context); gst_object_unref (window); gst_object_unref (display); return TRUE; failure: if (window) gst_object_unref (window); if (display) gst_object_unref (display); return FALSE; }
static GstStateChangeReturn gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) { GstGLImageSink *glimage_sink; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GST_DEBUG ("change state"); glimage_sink = GST_GLIMAGE_SINK (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: g_atomic_int_set (&glimage_sink->to_quit, 0); if (!glimage_sink->display) { GstGLWindow *window; GError *error = NULL; if (!gst_gl_ensure_display (glimage_sink, &glimage_sink->display)) return GST_STATE_CHANGE_FAILURE; glimage_sink->context = gst_gl_context_new (glimage_sink->display); window = gst_gl_context_get_window (glimage_sink->context); if (!glimage_sink->window_id && !glimage_sink->new_window_id) gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (glimage_sink)); if (glimage_sink->window_id != glimage_sink->new_window_id) { glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); } if (!gst_gl_context_create (glimage_sink->context, glimage_sink->other_context, &error)) { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); if (glimage_sink->display) { gst_object_unref (glimage_sink->display); glimage_sink->display = NULL; } gst_object_unref (glimage_sink->context); gst_object_unref (window); return GST_STATE_CHANGE_FAILURE; } /* setup callbacks */ gst_gl_window_set_resize_callback (window, GST_GL_WINDOW_RESIZE_CB (gst_glimage_sink_on_resize), gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref); gst_gl_window_set_draw_callback (window, GST_GL_WINDOW_CB (gst_glimage_sink_on_draw), gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref); gst_gl_window_set_close_callback (window, GST_GL_WINDOW_CB (gst_glimage_sink_on_close), gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref); gst_object_unref (window); } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: { /* mark the redisplay_texture as unavailable (=0) * to avoid drawing */ GST_GLIMAGE_SINK_LOCK (glimage_sink); glimage_sink->redisplay_texture = 0; GST_GLIMAGE_SINK_UNLOCK (glimage_sink); if (glimage_sink->upload) { gst_object_unref (glimage_sink->upload); glimage_sink->upload = NULL; } glimage_sink->window_id = 0; //but do not reset glimage_sink->new_window_id if (glimage_sink->pool) { gst_buffer_pool_set_active (glimage_sink->pool, FALSE); gst_object_unref (glimage_sink->pool); glimage_sink->pool = NULL; } GST_VIDEO_SINK_WIDTH (glimage_sink) = 1; GST_VIDEO_SINK_HEIGHT (glimage_sink) = 1; if (glimage_sink->context) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (gst_glimage_sink_cleanup_glthread), glimage_sink); gst_gl_window_set_resize_callback (window, NULL, NULL, NULL); gst_gl_window_set_draw_callback (window, NULL, NULL, NULL); gst_gl_window_set_close_callback (window, NULL, NULL, NULL); gst_object_unref (window); gst_object_unref (glimage_sink->context); glimage_sink->context = NULL; gst_object_unref (glimage_sink->display); glimage_sink->display = NULL; } break; } case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
static gboolean gst_gl_context_egl_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextEGL *egl; GstGLWindow *window = NULL; EGLNativeWindowType window_handle = (EGLNativeWindowType) 0; gint i = 0; EGLint context_attrib[5]; EGLint majorVersion; EGLint minorVersion; const gchar *egl_exts; gboolean need_surface = TRUE; guintptr external_gl_context = 0; GstGLDisplay *display; egl = GST_GL_CONTEXT_EGL (context); window = gst_gl_context_get_window (context); if (other_context) { if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with non-EGL context"); goto failure; } external_gl_context = gst_gl_context_get_gl_context (other_context); } if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_GLES2)) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "EGL supports opengl or gles2"); goto failure; } display = gst_gl_context_get_display (context); if (display->type == GST_GL_DISPLAY_TYPE_EGL) { egl->egl_display = (EGLDisplay) gst_gl_display_get_handle (display); } else { guintptr native_display = gst_gl_display_get_handle (display); if (!native_display) { GstGLWindow *window = NULL; GST_WARNING ("Failed to get a global display handle, falling back to " "per-window display handles. Context sharing may not work"); if (other_context) window = gst_gl_context_get_window (other_context); if (!window) window = gst_gl_context_get_window (context); if (window) { native_display = gst_gl_window_get_display (window); gst_object_unref (window); } } egl->egl_display = eglGetDisplay ((EGLNativeDisplayType) native_display); } gst_object_unref (display); if (eglInitialize (egl->egl_display, &majorVersion, &minorVersion)) { GST_INFO ("egl initialized, version: %d.%d", majorVersion, minorVersion); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to initialize egl: %s", gst_gl_context_egl_get_error_string ()); goto failure; } if (gl_api & GST_GL_API_OPENGL) { /* egl + opengl only available with EGL 1.4+ */ if (majorVersion == 1 && minorVersion <= 3) { if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS, "EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); goto failure; } else { GST_WARNING ("EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)", majorVersion, minorVersion); if (gl_api & GST_GL_API_GLES2) { goto try_gles2; } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to choose a suitable OpenGL API"); goto failure; } } } if (!eglBindAPI (EGL_OPENGL_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL API: %s", gst_gl_context_egl_get_error_string ()); goto failure; } GST_INFO ("Using OpenGL"); egl->gl_api = GST_GL_API_OPENGL; } else if (gl_api & GST_GL_API_GLES2) { try_gles2: if (!eglBindAPI (EGL_OPENGL_ES_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to bind OpenGL|ES API: %s", gst_gl_context_egl_get_error_string ()); goto failure; } GST_INFO ("Using OpenGL|ES 2.0"); egl->gl_api = GST_GL_API_GLES2; } if (!gst_gl_context_egl_choose_config (egl, other_context, error)) { g_assert (error == NULL || *error != NULL); goto failure; } egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS); GST_DEBUG ("about to create gl context\n"); if (egl->gl_api & GST_GL_API_GLES2) { context_attrib[i++] = EGL_CONTEXT_CLIENT_VERSION; context_attrib[i++] = 2; } #if !defined(GST_DISABLE_GST_DEBUG) && defined(EGL_KHR_create_context) if (gst_gl_check_extension ("EGL_KHR_create_context", egl_exts)) { context_attrib[i++] = EGL_CONTEXT_FLAGS_KHR; context_attrib[i++] = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; } #endif context_attrib[i++] = EGL_NONE; egl->egl_context = eglCreateContext (egl->egl_display, egl->egl_config, (EGLContext) external_gl_context, context_attrib); #ifdef EGL_KHR_create_context if (egl->egl_context == EGL_NO_CONTEXT && egl->gl_api & GST_GL_API_GLES2 && eglGetError () != EGL_SUCCESS) { /* try without EGL_CONTEXT_FLAGS flags as it was added to * EGL_KHR_create_context for gles contexts */ int i; for (i = 0; i < G_N_ELEMENTS (context_attrib); i++) { if (context_attrib[i] == EGL_CONTEXT_FLAGS_KHR || context_attrib[i] == EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) context_attrib[i] = EGL_NONE; } egl->egl_context = eglCreateContext (egl->egl_display, egl->egl_config, (EGLContext) external_gl_context, context_attrib); } #endif if (egl->egl_context != EGL_NO_CONTEXT) { GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) egl->egl_context); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create a OpenGL context: %s", gst_gl_context_egl_get_error_string ()); goto failure; } if (other_context == NULL) { /* FIXME do we want a window vfunc ? */ #if GST_GL_HAVE_WINDOW_X11 if (GST_GL_IS_WINDOW_X11 (context->window)) { gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window); } #endif #if GST_GL_HAVE_WINDOW_WIN32 if (GST_GL_IS_WINDOW_WIN32 (context->window)) { gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); } #endif } if (window) window_handle = (EGLNativeWindowType) gst_gl_window_get_window_handle (window); if (window_handle) { egl->egl_surface = eglCreateWindowSurface (egl->egl_display, egl->egl_config, window_handle, NULL); } else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context", egl_exts)) { EGLint surface_attrib[7]; gint j = 0; /* FIXME: Width/height doesn't seem to matter but we can't leave them * at 0, otherwise X11 complains about BadValue */ surface_attrib[j++] = EGL_WIDTH; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_HEIGHT; surface_attrib[j++] = 1; surface_attrib[j++] = EGL_LARGEST_PBUFFER; surface_attrib[j++] = EGL_TRUE; surface_attrib[j++] = EGL_NONE; egl->egl_surface = eglCreatePbufferSurface (egl->egl_display, egl->egl_config, surface_attrib); } else { egl->egl_surface = EGL_NO_SURFACE; need_surface = FALSE; } if (need_surface) { if (egl->egl_surface != EGL_NO_SURFACE) { GST_INFO ("surface created"); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "Failed to create window surface: %s", gst_gl_context_egl_get_error_string ()); goto failure; } } /* EGLImage functions */ if (GST_GL_CHECK_GL_VERSION (majorVersion, minorVersion, 1, 5)) { egl->eglCreateImage = gst_gl_context_get_proc_address (context, "eglCreateImage"); egl->eglDestroyImage = gst_gl_context_get_proc_address (context, "eglDestroyImage"); } else if (gst_gl_check_extension ("EGL_KHR_image_base", egl_exts)) { egl->eglCreateImage = gst_gl_context_get_proc_address (context, "eglCreateImageKHR"); egl->eglDestroyImage = gst_gl_context_get_proc_address (context, "eglDestroyImageKHR"); } if (egl->eglCreateImage == NULL || egl->eglDestroyImage == NULL) { egl->eglCreateImage = NULL; egl->eglDestroyImage = NULL; } if (window) gst_object_unref (window); return TRUE; failure: if (window) gst_object_unref (window); return FALSE; }
static gboolean gst_gl_context_glx_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextGLX *context_glx; GstGLWindow *window; GstGLWindowX11 *window_x11; GstGLDisplay *display; gboolean create_context; const char *glx_exts; int x_error; Display *device; guintptr external_gl_context = 0; context_glx = GST_GL_CONTEXT_GLX (context); window = gst_gl_context_get_window (context); window_x11 = GST_GL_WINDOW_X11 (window); display = gst_gl_context_get_display (context); if (other_context) { if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_GLX) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with non-GLX context"); goto failure; } external_gl_context = gst_gl_context_get_gl_context (other_context); } device = (Display *) gst_gl_display_get_handle (display); glx_exts = glXQueryExtensionsString (device, DefaultScreen (device)); create_context = gst_gl_check_extension ("GLX_ARB_create_context", glx_exts); context_glx->priv->glXCreateContextAttribsARB = (gpointer) glXGetProcAddressARB ((const GLubyte *) "glXCreateContextAttribsARB"); if (create_context && context_glx->priv->glXCreateContextAttribsARB) { int context_attribs_3[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 0, //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, #if !defined(GST_DISABLE_GST_DEBUG) GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, #endif None }; int context_attribs_pre_3[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 1, GLX_CONTEXT_MINOR_VERSION_ARB, 4, None }; gst_gl_window_x11_trap_x_errors (); context_glx->glx_context = context_glx->priv->glXCreateContextAttribsARB (device, context_glx->priv->fbconfigs[0], (GLXContext) external_gl_context, True, context_attribs_3); x_error = gst_gl_window_x11_untrap_x_errors (); context_glx->priv->context_api = GST_GL_API_OPENGL; if (!context_glx->glx_context || x_error != 0) { GST_DEBUG ("Failed to create an Opengl 3 context. trying a legacy one"); gst_gl_window_x11_trap_x_errors (); context_glx->glx_context = context_glx->priv->glXCreateContextAttribsARB (device, context_glx->priv->fbconfigs[0], (GLXContext) external_gl_context, True, context_attribs_pre_3); x_error = gst_gl_window_x11_untrap_x_errors (); if (x_error != 0) context_glx->glx_context = NULL; context_glx->priv->context_api = GST_GL_API_OPENGL; } } else { context_glx->glx_context = glXCreateContext (device, window_x11->visual_info, (GLXContext) external_gl_context, TRUE); context_glx->priv->context_api = GST_GL_API_OPENGL; } if (context_glx->priv->fbconfigs) XFree (context_glx->priv->fbconfigs); if (!context_glx->glx_context) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create opengl context"); goto failure; } GST_LOG ("gl context id: %ld", (gulong) context_glx->glx_context); gst_object_unref (window); gst_object_unref (display); return TRUE; failure: if (window) gst_object_unref (window); gst_object_unref (display); return FALSE; }
static gboolean gst_gl_context_wgl_create_context (GstGLContext * context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLWindow *window; GstGLContextWGL *context_wgl; HGLRC external_gl_context = NULL; HGLRC trampoline; HDC device; context_wgl = GST_GL_CONTEXT_WGL (context); window = gst_gl_context_get_window (context); device = (HDC) gst_gl_window_get_display (window); if (other_context) { if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_WGL) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Cannot share context with a non-WGL context"); goto failure; } external_gl_context = (HGLRC) gst_gl_context_get_gl_context (other_context); } trampoline = wglCreateContext (device); if (trampoline) GST_DEBUG ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) trampoline); else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to create glcontext:0x%x", (unsigned int) GetLastError ()); goto failure; } g_assert (trampoline); /* get extension functions */ wglMakeCurrent (device, trampoline); context_wgl->priv->wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress ("wglCreateContextAttribsARB"); wglMakeCurrent (device, 0); wglDeleteContext (trampoline); trampoline = NULL; if (context_wgl->priv->wglCreateContextAttribsARB != NULL && gl_api & GST_GL_API_OPENGL3) { gint i; for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) { gint profileMask = 0; gint contextFlags = 0; if ((opengl_versions[i].major > 3 || (opengl_versions[i].major == 3 && opengl_versions[i].minor >= 2))) { profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; contextFlags |= WGL_CONTEXT_DEBUG_BIT_ARB; } else { break; } GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context", opengl_versions[i].major, opengl_versions[i].minor); context_wgl->wgl_context = _create_context_with_flags (context_wgl, device, external_gl_context, opengl_versions[i].major, opengl_versions[i].minor, contextFlags, profileMask); if (context_wgl->wgl_context) { context_wgl->priv->context_api = GST_GL_API_OPENGL3; break; } } } if (!context_wgl->wgl_context) { if (context_wgl->priv->wglCreateContextAttribsARB && external_gl_context) { context_wgl->wgl_context = context_wgl->priv->wglCreateContextAttribsARB (device, external_gl_context, 0); } if (!context_wgl->wgl_context) { context_wgl->wgl_context = wglCreateContext (device); if (!context_wgl->wgl_context) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create WGL context 0x%x", (unsigned int) GetLastError ()); goto failure; } if (external_gl_context) { if (!wglShareLists (external_gl_context, context_wgl->wgl_context)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to share contexts through wglShareLists 0x%x", (unsigned int) GetLastError ()); goto failure; } } } context_wgl->priv->context_api = GST_GL_API_OPENGL; } GST_LOG ("gl context id: %" G_GUINTPTR_FORMAT, (guintptr) context_wgl->wgl_context); gst_object_unref (window); return TRUE; failure: gst_object_unref (window); return FALSE; }