/** * gst_gl_display_x11_new: * @name: (allow-none): a display name * * Create a new #GstGLDisplayX11 from the x11 display name. See XOpenDisplay() * for details on what is a valid name. * * Returns: (transfer full): a new #GstGLDisplayX11 or %NULL */ GstGLDisplayX11 * gst_gl_display_x11_new (const gchar * name) { GstGLDisplayX11 *ret; GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); ret = g_object_new (GST_TYPE_GL_DISPLAY_X11, NULL); ret->name = g_strdup (name); ret->display = XOpenDisplay (ret->name); if (!ret->display) { GST_ERROR ("Failed to open X11 display connection with name, \'%s\'", name); gst_object_unref (ret); return NULL; } ret->xcb_connection = XGetXCBConnection (ret->display); if (!ret->xcb_connection) { GST_ERROR ("Failed to open retieve XCB connection from X11 Display"); gst_object_unref (ret); return NULL; } XSetEventQueueOwner (ret->display, XCBOwnsEventQueue); GST_GL_DISPLAY (ret)->event_source = xcb_event_source_new (ret); g_source_attach (GST_GL_DISPLAY (ret)->event_source, GST_GL_DISPLAY (ret)->main_context); return ret; }
bool MediaPlayerPrivateGStreamerBase::ensureGstGLContext() { if (m_glContext) return true; if (!m_glDisplay) { const auto& sharedDisplay = PlatformDisplay::sharedDisplay(); #if PLATFORM(X11) m_glDisplay = GST_GL_DISPLAY(gst_gl_display_x11_new_with_display(downcast<PlatformDisplayX11>(sharedDisplay).native())); #elif PLATFORM(WAYLAND) m_glDisplay = GST_GL_DISPLAY(gst_gl_display_egl_new_with_egl_display(downcast<PlatformDisplayWayland>(sharedDisplay).native())); #endif } GLContext* webkitContext = GLContext::sharingContext(); // EGL and GLX are mutually exclusive, no need for ifdefs here. GstGLPlatform glPlatform = webkitContext->isEGLContext() ? GST_GL_PLATFORM_EGL : GST_GL_PLATFORM_GLX; #if USE(OPENGL_ES_2) GstGLAPI glAPI = GST_GL_API_GLES2; #elif USE(OPENGL) GstGLAPI glAPI = GST_GL_API_OPENGL; #else ASSERT_NOT_REACHED(); #endif PlatformGraphicsContext3D contextHandle = webkitContext->platformContext(); if (!contextHandle) return false; m_glContext = gst_gl_context_new_wrapped(m_glDisplay.get(), reinterpret_cast<guintptr>(contextHandle), glPlatform, glAPI); return true; }
/** * gst_gl_display_new: * * Returns: (transfer full): a new #GstGLDisplay * * Since: 1.4 */ GstGLDisplay * gst_gl_display_new (void) { GstGLDisplay *display = NULL; const gchar *user_choice, *platform_choice; static volatile gsize _init = 0; if (g_once_init_enter (&_init)) { GST_DEBUG_CATEGORY_INIT (gst_gl_display_debug, "gldisplay", 0, "gldisplay element"); g_once_init_leave (&_init, 1); } user_choice = g_getenv ("GST_GL_WINDOW"); platform_choice = g_getenv ("GST_GL_PLATFORM"); GST_INFO ("creating a display, user choice:%s (platform: %s)", GST_STR_NULL (user_choice), GST_STR_NULL (platform_choice)); #if GST_GL_HAVE_WINDOW_COCOA if (!display && (!user_choice || g_strstr_len (user_choice, 5, "cocoa"))) { display = GST_GL_DISPLAY (gst_gl_display_cocoa_new ()); if (!display) return NULL; } #endif #if GST_GL_HAVE_WINDOW_X11 if (!display && (!user_choice || g_strstr_len (user_choice, 3, "x11"))) display = GST_GL_DISPLAY (gst_gl_display_x11_new (NULL)); #endif #if GST_GL_HAVE_WINDOW_WAYLAND if (!display && (!user_choice || g_strstr_len (user_choice, 7, "wayland"))) display = GST_GL_DISPLAY (gst_gl_display_wayland_new (NULL)); #endif #if GST_GL_HAVE_PLATFORM_EGL if (!display && (!platform_choice || g_strstr_len (platform_choice, 3, "egl"))) display = GST_GL_DISPLAY (gst_gl_display_egl_new ()); #endif if (!display) { /* subclass returned a NULL window */ GST_WARNING ("Could not create display. user specified %s " "(platform: %s), creating dummy", GST_STR_NULL (user_choice), GST_STR_NULL (platform_choice)); return g_object_new (GST_TYPE_GL_DISPLAY, NULL); } return display; }
static guintptr gst_vaapi_get_egl_handle_from_gl_display (GstGLDisplay * gl_display) { guintptr egl_handle = 0; GstGLDisplayEGL *egl_display; egl_display = gst_gl_display_egl_from_gl_display (gl_display); if (egl_display) { egl_handle = gst_gl_display_get_handle (GST_GL_DISPLAY (egl_display)); gst_object_unref (egl_display); } return egl_handle; }
static void gst_gl_display_finalize (GObject * object) { GstGLDisplay *display = GST_GL_DISPLAY (object); GList *l; GST_TRACE_OBJECT (object, "finalizing"); for (l = display->priv->contexts; l; l = l->next) { g_weak_ref_clear ((GWeakRef *) l->data); g_free (l->data); } g_list_free (display->priv->contexts); G_OBJECT_CLASS (gst_gl_display_parent_class)->finalize (object); }
static GstGLWindowX11 * _find_window_from_xcb_window (GstGLDisplayX11 * display_x11, xcb_window_t window_id) { GstGLDisplay *display = GST_GL_DISPLAY (display_x11); GstGLWindowX11 *ret = NULL; GList *l; if (!window_id) return NULL; GST_OBJECT_LOCK (display); l = g_list_find_custom (display->windows, &window_id, (GCompareFunc) _compare_xcb_window); if (l) ret = gst_object_ref (l->data); GST_OBJECT_UNLOCK (display); 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 GstStateChangeReturn gst_visual_gl_change_state (GstElement * element, GstStateChange transition) { GstVisualGL *visual = GST_VISUAL_GL (element); GstStateChangeReturn ret; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: { GstElement *parent = GST_ELEMENT (gst_element_get_parent (visual)); GstStructure *structure = NULL; GstQuery *query = NULL; gboolean isPerformed = FALSE; gchar *name; if (!parent) { GST_ELEMENT_ERROR (visual, CORE, STATE_CHANGE, (NULL), ("A parent bin is required")); return FALSE; } name = gst_element_get_name (visual); structure = gst_structure_new (name, NULL); query = gst_query_new_application (GST_QUERY_CUSTOM, structure); g_free (name); isPerformed = gst_element_query (parent, query); if (isPerformed) { const GValue *id_value = gst_structure_get_value (structure, "gstgldisplay"); if (G_VALUE_HOLDS_POINTER (id_value)) /* at least one gl element is after in our gl chain */ visual->display = gst_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value))); else { /* this gl filter is a sink in terms of the gl chain */ visual->display = gst_gl_display_new (); gst_gl_display_create_context (visual->display, 0); //TODO visual->external_gl_context); } gst_visual_gl_reset (visual); visual->actor = visual_actor_new (GST_VISUAL_GL_GET_CLASS (visual)->plugin->info-> plugname); visual->video = visual_video_new (); visual->audio = visual_audio_new (); if (!visual->actor || !visual->video) goto actor_setup_failed; gst_gl_display_thread_add (visual->display, (GstGLDisplayThreadFunc) actor_setup, visual); if (visual->actor_setup_result != 0) goto actor_setup_failed; else visual_actor_set_video (visual->actor, visual->video); } gst_query_unref (query); gst_object_unref (GST_OBJECT (parent)); if (!isPerformed) 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); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: { if (visual->fbo) { gst_gl_display_del_fbo (visual->display, visual->fbo, visual->depthbuffer); visual->fbo = 0; visual->depthbuffer = 0; } if (visual->midtexture) { gst_gl_display_del_texture (visual->display, visual->midtexture, visual->width, visual->height); visual->midtexture = 0; } if (visual->display) { gst_object_unref (visual->display); visual->display = NULL; } gst_visual_gl_clear_actors (visual); } break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; /* ERRORS */ actor_setup_failed: { GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL), ("could not set up actor")); gst_visual_gl_clear_actors (visual); return GST_STATE_CHANGE_FAILURE; } }