forked from AuroraMiddleware/gtk
Merge branch 'gst.gl.win32' into 'master'
media/gstreamer: Support using GL for video for Windows See merge request GNOME/gtk!3506
This commit is contained in:
commit
f1f225c6b3
@ -674,7 +674,7 @@ _create_gl_context (HDC hdc,
|
||||
}
|
||||
else
|
||||
{
|
||||
HGLRC hglrc;
|
||||
HGLRC hglrc = NULL;
|
||||
|
||||
if (!wglMakeCurrent (hdc, hglrc_base))
|
||||
{
|
||||
@ -682,13 +682,33 @@ _create_gl_context (HDC hdc,
|
||||
goto gl_fail;
|
||||
}
|
||||
|
||||
hglrc = _create_gl_context_with_attribs (hdc,
|
||||
hglrc_base,
|
||||
share,
|
||||
flags,
|
||||
major,
|
||||
minor,
|
||||
is_legacy);
|
||||
/*
|
||||
* We need a Core GL 4.1 context in order to use the GL support in
|
||||
* the GStreamer media widget backend, but wglCreateContextAttribsARB()
|
||||
* may only give us the GL context version that we ask for here, and
|
||||
* nothing more. So, if we are asking for a pre-GL 4.1 context,
|
||||
* try to ask for a 4.1 context explicitly first. If that is not supported,
|
||||
* then we fall back to whatever version that we were asking for (or, even a
|
||||
* legacy context if that fails), at a price of not able to have GL support
|
||||
* for the media GStreamer backend.
|
||||
*/
|
||||
if (major < 4 || (major == 4 && minor < 1))
|
||||
hglrc = _create_gl_context_with_attribs (hdc,
|
||||
hglrc_base,
|
||||
share,
|
||||
flags,
|
||||
4,
|
||||
1,
|
||||
is_legacy);
|
||||
|
||||
if (hglrc == NULL)
|
||||
hglrc = _create_gl_context_with_attribs (hdc,
|
||||
hglrc_base,
|
||||
share,
|
||||
flags,
|
||||
major,
|
||||
minor,
|
||||
is_legacy);
|
||||
|
||||
/* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation failed */
|
||||
if (hglrc == NULL)
|
||||
|
@ -117,33 +117,39 @@ gtk_gst_paintable_video_renderer_create_video_sink (GstPlayerVideoRenderer *rend
|
||||
{
|
||||
GtkGstPaintable *self = GTK_GST_PAINTABLE (renderer);
|
||||
GstElement *sink, *glsinkbin;
|
||||
GdkGLContext *ctx;
|
||||
|
||||
#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (GDK_WINDOWING_WIN32)
|
||||
/*
|
||||
* Unfortunately, we can't connect the GstGLContext with our GDKGLContext,
|
||||
* since gdk_gl_context_make_current(), which calls wglMakeCurrent(), does not
|
||||
* allow us to share WGL contexts across threads, which will cause a crash.
|
||||
* See MR !3034, so no WGL in the gstreamer media backend :(
|
||||
*/
|
||||
sink = g_object_new (GTK_TYPE_GST_SINK,
|
||||
"paintable", self,
|
||||
NULL);
|
||||
return sink;
|
||||
#else
|
||||
sink = g_object_new (GTK_TYPE_GST_SINK,
|
||||
"paintable", self,
|
||||
"gl-context", self->context,
|
||||
NULL);
|
||||
|
||||
if (self->context == NULL)
|
||||
return sink;
|
||||
if (self->context != NULL)
|
||||
g_object_get (GTK_GST_SINK (sink), "gl-context", &ctx, NULL);
|
||||
|
||||
glsinkbin = gst_element_factory_make ("glsinkbin", NULL);
|
||||
if (self->context != NULL && ctx != NULL)
|
||||
{
|
||||
glsinkbin = gst_element_factory_make ("glsinkbin", NULL);
|
||||
|
||||
g_object_set (glsinkbin, "sink", sink, NULL);
|
||||
g_object_set (glsinkbin, "sink", sink, NULL);
|
||||
g_object_unref (ctx);
|
||||
|
||||
return glsinkbin;
|
||||
#endif
|
||||
return glsinkbin;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->context != NULL)
|
||||
{
|
||||
g_warning ("GstGL context creation failed, falling back to non-GL playback");
|
||||
|
||||
g_object_unref (sink);
|
||||
sink = g_object_new (GTK_TYPE_GST_SINK,
|
||||
"paintable", self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return sink;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -31,9 +31,6 @@
|
||||
#if GST_GL_HAVE_PLATFORM_GLX
|
||||
#include <gst/gl/x11/gstgldisplay_x11.h>
|
||||
#endif
|
||||
#if GST_GL_HAVE_PLATFORM_EGL
|
||||
#include <gst/gl/egl/gstgldisplay_egl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND)
|
||||
@ -42,6 +39,15 @@
|
||||
#include <gst/gl/wayland/gstgldisplay_wayland.h>
|
||||
#endif
|
||||
|
||||
#if GST_GL_HAVE_WINDOW_WIN32 && (GST_GL_HAVE_PLATFORM_WGL || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_WIN32)
|
||||
#include <gdk/win32/gdkwin32.h>
|
||||
#include <epoxy/wgl.h>
|
||||
#endif
|
||||
|
||||
#if GST_GL_HAVE_PLATFORM_EGL && (GST_GL_HAVE_WINDOW_WIN32 || GST_GL_HAVE_WINDOW_X11)
|
||||
#include <gst/gl/egl/gstgldisplay_egl.h>
|
||||
#endif
|
||||
|
||||
#include <gst/gl/gstglfuncs.h>
|
||||
|
||||
enum {
|
||||
@ -348,22 +354,87 @@ gtk_gst_sink_show_frame (GstVideoSink *vsink,
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
#if GST_GL_HAVE_WINDOW_WIN32 && (GST_GL_HAVE_PLATFORM_WGL || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_WIN32)
|
||||
#define HANDLE_EXTERNAL_WGL_MAKE_CURRENT(ctx) handle_wgl_makecurrent(ctx)
|
||||
#define DEACTIVATE_WGL_CONTEXT(ctx) deactivate_gdk_wgl_context(ctx)
|
||||
#define REACTIVATE_WGL_CONTEXT(ctx) reactivate_gdk_wgl_context(ctx)
|
||||
|
||||
static void
|
||||
handle_wgl_makecurrent (GdkGLContext *ctx)
|
||||
{
|
||||
if (!gdk_gl_context_get_use_es (ctx))
|
||||
epoxy_handle_external_wglMakeCurrent();
|
||||
}
|
||||
|
||||
static void
|
||||
deactivate_gdk_wgl_context (GdkGLContext *ctx)
|
||||
{
|
||||
if (!gdk_gl_context_get_use_es (ctx))
|
||||
{
|
||||
HDC hdc = GetDC (GDK_SURFACE_HWND (gdk_gl_context_get_surface (ctx)));
|
||||
wglMakeCurrent (hdc, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reactivate_gdk_wgl_context (GdkGLContext *ctx)
|
||||
{
|
||||
if (!gdk_gl_context_get_use_es (ctx))
|
||||
gdk_gl_context_make_current (ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately, libepoxy does not offer a way to allow us to safely call
|
||||
* gst_gl_context_get_current_gl_api() on a WGL context that underlies a
|
||||
* GdkGLContext after we notify libepoxy an external wglMakeCurrent() has
|
||||
* been called (which is required for the first gdk_gl_context_make_current()
|
||||
* call in gtk_gst_sink_initialize_gl(), for instance), so we can't do
|
||||
* gst_gl_context_get_current_gl_api() directly on WGL contexts that underlies
|
||||
* GdkGLContext's. So, we just ask GDK about our WGL context, since it already
|
||||
* knows what kind of WGL context we have there...
|
||||
*/
|
||||
static gboolean
|
||||
check_win32_gst_gl_api (GdkGLContext *ctx,
|
||||
GstGLPlatform *platform,
|
||||
GstGLAPI *gl_api)
|
||||
{
|
||||
gboolean is_gles = gdk_gl_context_get_use_es (ctx);
|
||||
|
||||
g_return_val_if_fail (*gl_api == GST_GL_API_NONE, FALSE);
|
||||
|
||||
*platform = is_gles ? GST_GL_PLATFORM_EGL : GST_GL_PLATFORM_WGL;
|
||||
|
||||
if (is_gles)
|
||||
*gl_api = gst_gl_context_get_current_gl_api (*platform, NULL, NULL);
|
||||
else
|
||||
*gl_api = gdk_gl_context_is_legacy (ctx) ? GST_GL_API_OPENGL : GST_GL_API_OPENGL3;
|
||||
|
||||
return is_gles;
|
||||
}
|
||||
#else
|
||||
#define HANDLE_EXTERNAL_WGL_MAKE_CURRENT(ctx)
|
||||
#define DEACTIVATE_WGL_CONTEXT(ctx)
|
||||
#define REACTIVATE_WGL_CONTEXT(ctx)
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
gtk_gst_sink_initialize_gl (GtkGstSink *self)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GError *error = NULL;
|
||||
GstGLPlatform platform = GST_GL_PLATFORM_NONE;
|
||||
GstGLAPI gl_api = GST_GL_API_NONE;
|
||||
guintptr gl_handle = 0;
|
||||
gboolean succeeded = FALSE;
|
||||
|
||||
display = gdk_gl_context_get_display (self->gdk_context);
|
||||
|
||||
HANDLE_EXTERNAL_WGL_MAKE_CURRENT (self->gdk_context);
|
||||
gdk_gl_context_make_current (self->gdk_context);
|
||||
|
||||
#ifdef HAVE_GST_X11_SUPPORT
|
||||
if (GDK_IS_X11_DISPLAY (display))
|
||||
{
|
||||
GstGLPlatform platform;
|
||||
GstGLAPI gl_api;
|
||||
guintptr gl_handle;
|
||||
gpointer display_ptr;
|
||||
|
||||
#if GST_GL_HAVE_PLATFORM_EGL
|
||||
@ -387,6 +458,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
|
||||
|
||||
gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
|
||||
gl_handle = gst_gl_context_get_current_gl_context (platform);
|
||||
|
||||
if (gl_handle)
|
||||
{
|
||||
self->gst_app_context = gst_gl_context_new_wrapped (self->gst_display, gl_handle, platform, gl_api);
|
||||
@ -394,7 +466,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
|
||||
else
|
||||
{
|
||||
GST_ERROR_OBJECT (self, "Failed to get handle from GdkGLContext");
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -402,13 +474,10 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
|
||||
#ifdef HAVE_GST_WAYLAND_SUPPORT
|
||||
if (GDK_IS_WAYLAND_DISPLAY (display))
|
||||
{
|
||||
GstGLPlatform platform = GST_GL_PLATFORM_GLX;
|
||||
GstGLAPI gl_api;
|
||||
guintptr gl_handle;
|
||||
platform = GST_GL_PLATFORM_EGL;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "got EGL on Wayland!");
|
||||
|
||||
platform = GST_GL_PLATFORM_EGL;
|
||||
gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
|
||||
gl_handle = gst_gl_context_get_current_gl_context (platform);
|
||||
|
||||
@ -423,40 +492,104 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
|
||||
else
|
||||
{
|
||||
GST_ERROR_OBJECT (self, "Failed to get handle from GdkGLContext, not using Wayland EGL");
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if GST_GL_HAVE_WINDOW_WIN32 && (GST_GL_HAVE_PLATFORM_WGL || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_WIN32)
|
||||
if (GDK_IS_WIN32_DISPLAY (display))
|
||||
{
|
||||
gboolean is_gles = check_win32_gst_gl_api (self->gdk_context, &platform, &gl_api);
|
||||
const gchar *gl_type = is_gles ? "EGL" : "WGL";
|
||||
|
||||
GST_DEBUG_OBJECT (self, "got %s on Win32!", gl_type);
|
||||
|
||||
gl_handle = gst_gl_context_get_current_gl_context (platform);
|
||||
|
||||
if (gl_handle)
|
||||
{
|
||||
/*
|
||||
* We must force a win32 GstGL display type and if using desktop GL, the GL_Platform to be WGL
|
||||
* and an appropriate GstGL API depending on the gl_api we receive. We also ensure that we use
|
||||
* an EGL GstGL API if we are using EGL in GDK. Envvars are required, unless
|
||||
* gst_gl_display_new_with_type() is available, unfortunately, so that gst_gl_display_new() does
|
||||
* things correctly if we have GstGL built with both EGL and WGL support for the WGL case,
|
||||
* otherwise gst_gl_display_new() will assume an EGL display, which won't work for us
|
||||
*/
|
||||
|
||||
if (gl_api & (GST_GL_API_OPENGL3 | GST_GL_API_OPENGL))
|
||||
{
|
||||
#ifdef HAVE_GST_GL_DISPLAY_NEW_WITH_TYPE
|
||||
self->gst_display = gst_gl_display_new_with_type (GST_GL_DISPLAY_TYPE_WIN32);
|
||||
#else
|
||||
#if GST_GL_HAVE_PLATFORM_EGL
|
||||
g_message ("If media fails to play, set the envvar `GST_DEBUG=1`, and if GstGL context creation fails");
|
||||
g_message ("due to \"Couldn't create GL context: Cannot share context with non-EGL context\",");
|
||||
g_message ("set in the environment `GST_GL_PLATFORM=wgl` and `GST_GL_WINDOW=win32`,");
|
||||
g_message ("and restart the GTK application");
|
||||
#endif
|
||||
|
||||
self->gst_display = gst_gl_display_new ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if GST_GL_HAVE_PLATFORM_EGL
|
||||
else
|
||||
{
|
||||
gpointer display_ptr = gdk_win32_display_get_egl_display (display);
|
||||
self->gst_display = GST_GL_DISPLAY (gst_gl_display_egl_new_with_egl_display (display_ptr));
|
||||
}
|
||||
#endif
|
||||
|
||||
gst_gl_display_filter_gl_api (self->gst_display, gl_api);
|
||||
self->gst_app_context = gst_gl_context_new_wrapped (self->gst_display, gl_handle, platform, gl_api);
|
||||
}
|
||||
else
|
||||
{
|
||||
GST_ERROR_OBJECT (self, "Failed to get handle from GdkGLContext, not using %s", gl_type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
GST_INFO_OBJECT (self, "Unsupported GDK display %s for GL", G_OBJECT_TYPE_NAME (display));
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_assert (self->gst_app_context != NULL);
|
||||
|
||||
gst_gl_context_activate (self->gst_app_context, TRUE);
|
||||
|
||||
if (!gst_gl_context_fill_info (self->gst_app_context, &error))
|
||||
{
|
||||
GST_ERROR_OBJECT (self, "failed to retrieve GDK context info: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
g_clear_object (&self->gst_app_context);
|
||||
g_clear_object (&self->gst_display);
|
||||
return;
|
||||
HANDLE_EXTERNAL_WGL_MAKE_CURRENT (self->gdk_context);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEACTIVATE_WGL_CONTEXT (self->gdk_context);
|
||||
gst_gl_context_activate (self->gst_app_context, FALSE);
|
||||
}
|
||||
|
||||
if (!gst_gl_display_create_context (self->gst_display, self->gst_app_context, &self->gst_context, &error))
|
||||
succeeded = gst_gl_display_create_context (self->gst_display, self->gst_app_context, &self->gst_context, &error);
|
||||
|
||||
if (!succeeded)
|
||||
{
|
||||
GST_ERROR_OBJECT (self, "Couldn't create GL context: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_clear_object (&self->gst_app_context);
|
||||
g_clear_object (&self->gst_display);
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE_EXTERNAL_WGL_MAKE_CURRENT (self->gdk_context);
|
||||
REACTIVATE_WGL_CONTEXT (self->gdk_context);
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -478,8 +611,8 @@ gtk_gst_sink_set_property (GObject *object,
|
||||
|
||||
case PROP_GL_CONTEXT:
|
||||
self->gdk_context = g_value_dup_object (value);
|
||||
if (self->gdk_context != NULL)
|
||||
gtk_gst_sink_initialize_gl (self);
|
||||
if (self->gdk_context != NULL && !gtk_gst_sink_initialize_gl (self))
|
||||
g_clear_object (&self->gdk_context);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -501,6 +634,9 @@ gtk_gst_sink_get_property (GObject *object,
|
||||
case PROP_PAINTABLE:
|
||||
g_value_set_object (value, self->paintable);
|
||||
break;
|
||||
case PROP_GL_CONTEXT:
|
||||
g_value_set_object (value, self->gdk_context);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
@ -563,7 +699,7 @@ gtk_gst_sink_class_init (GtkGstSinkClass * klass)
|
||||
P_("gl-context"),
|
||||
P_("GL context to use for rendering"),
|
||||
GDK_TYPE_GL_CONTEXT,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
|
@ -47,6 +47,21 @@ gstgl_dep = dependency('gstreamer-gl-1.0', version: '>= 1.12.3',
|
||||
required: get_option('media-gstreamer'))
|
||||
|
||||
if gstplayer_dep.found() and gstgl_dep.found()
|
||||
extra_win_cflags = []
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
new_gst_gl_display_code = \
|
||||
'''#include <gst/gl/gstgldisplay.h>
|
||||
int main (int a, char ** g) {
|
||||
GstGLDisplay *d = gst_gl_display_new_with_type (GST_GL_DISPLAY_TYPE_WIN32);
|
||||
return 0;
|
||||
}'''
|
||||
if cc.links(new_gst_gl_display_code, dependencies : gstgl_dep)
|
||||
message('libgstgl has gst_gl_display_new_with_type()')
|
||||
extra_win_cflags += '-DHAVE_GST_GL_DISPLAY_NEW_WITH_TYPE'
|
||||
endif
|
||||
endif
|
||||
|
||||
media_backends += 'gstreamer'
|
||||
cdata.set('HAVE_GSTREAMER', 1)
|
||||
shared_module('media-gstreamer',
|
||||
@ -55,7 +70,7 @@ if gstplayer_dep.found() and gstgl_dep.found()
|
||||
'gtkgstpaintable.c',
|
||||
'gtkgstsink.c',
|
||||
],
|
||||
c_args: extra_c_args,
|
||||
c_args: extra_c_args + extra_win_cflags,
|
||||
dependencies: [ libm, libgtk_dep, gstplayer_dep, gstgl_dep ],
|
||||
name_suffix: module_suffix,
|
||||
install_dir: media_install_dir,
|
||||
|
Loading…
Reference in New Issue
Block a user