mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +00:00
[725/906] x11: use GMainContext/GMainLoop
allows us to be reentrant https://bugzilla.gnome.org/show_bug.cgi?id=703445
This commit is contained in:
parent
96deb2fba3
commit
f9d46c29ca
5 changed files with 204 additions and 172 deletions
|
@ -6,10 +6,12 @@ libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@
|
|||
libgstglx11includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl/x11
|
||||
|
||||
libgstgl_x11_la_SOURCES = \
|
||||
gstglwindow_x11.c
|
||||
gstglwindow_x11.c \
|
||||
x11_event_source.c
|
||||
|
||||
libgstglx11include_HEADERS = \
|
||||
gstglwindow_x11.h
|
||||
gstglwindow_x11.h \
|
||||
x11_event_source.h
|
||||
|
||||
if USE_GLX
|
||||
libgstgl_x11_la_SOURCES += gstglwindow_x11_glx.c
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <gst/gst.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "x11_event_source.h"
|
||||
#include "gstglwindow_x11.h"
|
||||
|
||||
#if GST_GL_HAVE_PLATFORM_GLX
|
||||
|
@ -157,8 +158,6 @@ static void
|
|||
gst_gl_window_x11_init (GstGLWindowX11 * window)
|
||||
{
|
||||
window->priv = GST_GL_WINDOW_X11_GET_PRIVATE (window);
|
||||
|
||||
g_cond_init (&window->cond_send_message);
|
||||
}
|
||||
|
||||
/* Must be called in the gl thread */
|
||||
|
@ -228,7 +227,7 @@ gst_gl_window_x11_create_context (GstGLWindow * window,
|
|||
|
||||
setlocale (LC_NUMERIC, "C");
|
||||
|
||||
gst_gl_window_set_need_lock (GST_GL_WINDOW (window_x11), TRUE);
|
||||
gst_gl_window_set_need_lock (GST_GL_WINDOW (window_x11), FALSE);
|
||||
|
||||
window_x11->running = TRUE;
|
||||
window_x11->visible = FALSE;
|
||||
|
@ -253,7 +252,11 @@ gst_gl_window_x11_create_context (GstGLWindow * window,
|
|||
window_x11->device_height =
|
||||
DisplayHeight (window_x11->device, window_x11->screen_num);
|
||||
|
||||
window_x11->connection = ConnectionNumber (window_x11->device);
|
||||
window_x11->x11_source = x11_event_source_new (window_x11);
|
||||
window_x11->main_context = g_main_context_new ();
|
||||
window_x11->loop = g_main_loop_new (window_x11->main_context, FALSE);
|
||||
|
||||
g_source_attach (window_x11->x11_source, window_x11->main_context);
|
||||
|
||||
if (!window_class->choose_format (window_x11, error)) {
|
||||
goto failure;
|
||||
|
@ -286,7 +289,7 @@ gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11)
|
|||
XWMHints wm_hints;
|
||||
unsigned long mask;
|
||||
const gchar *title = "OpenGL renderer";
|
||||
Atom wm_atoms[3];
|
||||
Atom wm_atoms[1];
|
||||
|
||||
static gint x = 0;
|
||||
static gint y = 0;
|
||||
|
@ -337,16 +340,8 @@ gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11)
|
|||
if (wm_atoms[0] == None)
|
||||
GST_DEBUG ("Cannot create WM_DELETE_WINDOW");
|
||||
|
||||
wm_atoms[1] = XInternAtom (window_x11->device, "WM_GL_WINDOW", False);
|
||||
if (wm_atoms[1] == None)
|
||||
GST_DEBUG ("Cannot create WM_GL_WINDOW");
|
||||
|
||||
wm_atoms[2] = XInternAtom (window_x11->device, "WM_QUIT_LOOP", False);
|
||||
if (wm_atoms[2] == None)
|
||||
GST_DEBUG ("Cannot create WM_QUIT_LOOP");
|
||||
|
||||
XSetWMProtocols (window_x11->device, window_x11->internal_win_id, wm_atoms,
|
||||
2);
|
||||
1);
|
||||
|
||||
wm_hints.flags = StateHint;
|
||||
wm_hints.initial_state = NormalState;
|
||||
|
@ -413,8 +408,6 @@ gst_gl_window_x11_close (GstGLWindow * window)
|
|||
GST_DEBUG ("display sender closed");
|
||||
}
|
||||
|
||||
g_cond_clear (&window_x11->cond_send_message);
|
||||
|
||||
GST_GL_WINDOW_UNLOCK (window_x11);
|
||||
}
|
||||
|
||||
|
@ -577,143 +570,76 @@ gst_gl_window_x11_draw (GstGLWindow * window, guint width, guint height)
|
|||
}
|
||||
}
|
||||
|
||||
/* Called in the gl thread */
|
||||
typedef struct _GstGLMessage
|
||||
{
|
||||
GstGLWindow *window;
|
||||
GMutex lock;
|
||||
GCond cond;
|
||||
gboolean fired;
|
||||
|
||||
GstGLWindowCB callback;
|
||||
gpointer data;
|
||||
} GstGLMessage;
|
||||
|
||||
static gboolean
|
||||
_run_message (GstGLMessage * message)
|
||||
{
|
||||
g_mutex_lock (&message->lock);
|
||||
|
||||
if (message->callback)
|
||||
message->callback (message->data);
|
||||
|
||||
message->fired = TRUE;
|
||||
g_cond_signal (&message->cond);
|
||||
g_mutex_unlock (&message->lock);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_x11_run (GstGLWindow * window)
|
||||
{
|
||||
GstGLWindowX11 *window_x11;
|
||||
GstGLWindowX11Class *window_class;
|
||||
|
||||
window_x11 = GST_GL_WINDOW_X11 (window);
|
||||
|
||||
g_main_loop_run (window_x11->loop);
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11)
|
||||
{
|
||||
GstGLWindow *window;
|
||||
GstGLWindowX11Class *window_class;
|
||||
|
||||
window = GST_GL_WINDOW (window_x11);
|
||||
window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11);
|
||||
|
||||
GST_DEBUG ("begin loop");
|
||||
|
||||
while (window_x11->running) {
|
||||
if (window_x11->running && XPending (window_x11->device)) {
|
||||
XEvent event;
|
||||
XEvent pending_event;
|
||||
|
||||
GST_GL_WINDOW_UNLOCK (window);
|
||||
|
||||
/* XSendEvent (which are called in other threads) are done from another display structure */
|
||||
XNextEvent (window_x11->device, &event);
|
||||
|
||||
GST_GL_WINDOW_LOCK (window);
|
||||
|
||||
// use in generic/cube and other related uses
|
||||
window_x11->allow_extra_expose_events = XPending (window_x11->device) <= 2;
|
||||
|
||||
switch (event.type) {
|
||||
case ClientMessage:
|
||||
{
|
||||
|
||||
Atom wm_delete =
|
||||
XInternAtom (window_x11->device, "WM_DELETE_WINDOW", True);
|
||||
Atom wm_gl = XInternAtom (window_x11->device, "WM_GL_WINDOW", True);
|
||||
Atom wm_quit_loop =
|
||||
XInternAtom (window_x11->device, "WM_QUIT_LOOP", True);
|
||||
|
||||
if (wm_delete == None)
|
||||
GST_DEBUG ("Cannot create WM_DELETE_WINDOW");
|
||||
if (wm_gl == None)
|
||||
GST_DEBUG ("Cannot create WM_GL_WINDOW");
|
||||
if (wm_quit_loop == None)
|
||||
GST_DEBUG ("Cannot create WM_QUIT_LOOP");
|
||||
|
||||
/* Message sent with gst_gl_window_send_message */
|
||||
if (wm_gl != None && event.xclient.message_type == wm_gl) {
|
||||
if (window_x11->running) {
|
||||
#if SIZEOF_VOID_P == 8
|
||||
GstGLWindowCB custom_cb =
|
||||
(GstGLWindowCB) (((event.xclient.data.
|
||||
l[0] & 0xffffffff) << 32) | (event.xclient.data.
|
||||
l[1] & 0xffffffff));
|
||||
gpointer custom_data =
|
||||
(gpointer) (((event.xclient.data.
|
||||
l[2] & 0xffffffff) << 32) | (event.xclient.data.
|
||||
l[3] & 0xffffffff));
|
||||
#else
|
||||
GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0];
|
||||
gpointer custom_data = (gpointer) event.xclient.data.l[1];
|
||||
#endif
|
||||
|
||||
if (!custom_cb || !custom_data)
|
||||
GST_DEBUG ("custom cb not initialized");
|
||||
|
||||
custom_cb (custom_data);
|
||||
}
|
||||
|
||||
g_cond_signal (&window_x11->cond_send_message);
|
||||
}
|
||||
|
||||
/* User clicked on the cross */
|
||||
else if (wm_delete != None
|
||||
&& (Atom) event.xclient.data.l[0] == wm_delete) {
|
||||
if (wm_delete != None && (Atom) event.xclient.data.l[0] == wm_delete) {
|
||||
GST_DEBUG ("Close %lud", (gulong) window_x11->internal_win_id);
|
||||
|
||||
if (window->close)
|
||||
window->close (window->close_data);
|
||||
}
|
||||
|
||||
/* message sent with gst_gl_window_quit_loop */
|
||||
else if (wm_quit_loop != None
|
||||
&& event.xclient.message_type == wm_quit_loop) {
|
||||
#if SIZEOF_VOID_P == 8
|
||||
GstGLWindowCB destroy_cb =
|
||||
(GstGLWindowCB) (((event.xclient.data.
|
||||
l[0] & 0xffffffff) << 32) | (event.xclient.data.
|
||||
l[1] & 0xffffffff));
|
||||
gpointer destroy_data =
|
||||
(gpointer) (((event.xclient.data.
|
||||
l[2] & 0xffffffff) << 32) | (event.xclient.data.
|
||||
l[3] & 0xffffffff));
|
||||
#else
|
||||
GstGLWindowCB destroy_cb = (GstGLWindowCB) event.xclient.data.l[0];
|
||||
gpointer destroy_data = (gpointer) event.xclient.data.l[1];
|
||||
#endif
|
||||
|
||||
GST_DEBUG ("Quit loop message %lud",
|
||||
(gulong) window_x11->internal_win_id);
|
||||
|
||||
/* exit loop */
|
||||
window_x11->running = FALSE;
|
||||
|
||||
/* make sure last pendings send message calls are executed */
|
||||
XFlush (window_x11->device);
|
||||
while (XCheckTypedEvent (window_x11->device, ClientMessage,
|
||||
&pending_event)) {
|
||||
#if SIZEOF_VOID_P == 8
|
||||
GstGLWindowCB custom_cb =
|
||||
(GstGLWindowCB) (((event.xclient.data.
|
||||
l[0] & 0xffffffff) << 32) | (event.xclient.data.
|
||||
l[1] & 0xffffffff));
|
||||
gpointer custom_data =
|
||||
(gpointer) (((event.xclient.data.
|
||||
l[2] & 0xffffffff) << 32) | (event.xclient.data.
|
||||
l[3] & 0xffffffff));
|
||||
#else
|
||||
GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0];
|
||||
gpointer custom_data = (gpointer) event.xclient.data.l[1];
|
||||
#endif
|
||||
GST_DEBUG ("execute last pending custom x events");
|
||||
|
||||
if (!custom_cb || !custom_data)
|
||||
GST_DEBUG ("custom cb not initialized");
|
||||
|
||||
custom_cb (custom_data);
|
||||
|
||||
g_cond_signal (&window_x11->cond_send_message);
|
||||
}
|
||||
|
||||
/* Finally we can destroy opengl ressources (texture/shaders/fbo) */
|
||||
if (!destroy_cb || !destroy_data)
|
||||
GST_FIXME ("destroy cb not correctly set");
|
||||
|
||||
if (destroy_cb)
|
||||
destroy_cb (destroy_data);
|
||||
|
||||
} else
|
||||
GST_DEBUG ("client message not recognized");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -767,7 +693,6 @@ gst_gl_window_x11_run (GstGLWindow * window)
|
|||
} // switch
|
||||
} // while running
|
||||
|
||||
GST_DEBUG ("end loop");
|
||||
}
|
||||
|
||||
/* Not called by the gl thread */
|
||||
|
@ -779,32 +704,14 @@ gst_gl_window_x11_quit (GstGLWindow * window, GstGLWindowCB callback,
|
|||
|
||||
window_x11 = GST_GL_WINDOW_X11 (window);
|
||||
|
||||
GST_DEBUG ("sending quit, running:%i", window_x11->running);
|
||||
if (callback)
|
||||
gst_gl_window_x11_send_message (window, callback, data);
|
||||
|
||||
if (window_x11->running) {
|
||||
XEvent event;
|
||||
GST_LOG ("sending quit");
|
||||
|
||||
event.xclient.type = ClientMessage;
|
||||
event.xclient.send_event = TRUE;
|
||||
event.xclient.display = window_x11->disp_send;
|
||||
event.xclient.window = window_x11->internal_win_id;
|
||||
event.xclient.message_type =
|
||||
XInternAtom (window_x11->disp_send, "WM_QUIT_LOOP", True);
|
||||
event.xclient.format = 32;
|
||||
#if SIZEOF_VOID_P == 8
|
||||
event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff;
|
||||
event.xclient.data.l[1] = (((long) callback)) & 0xffffffff;
|
||||
event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff;
|
||||
event.xclient.data.l[3] = (((long) data)) & 0xffffffff;
|
||||
#else
|
||||
event.xclient.data.l[0] = (long) callback;
|
||||
event.xclient.data.l[1] = (long) data;
|
||||
#endif
|
||||
g_main_loop_quit (window_x11->loop);
|
||||
|
||||
XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE,
|
||||
NoEventMask, &event);
|
||||
XSync (window_x11->disp_send, FALSE);
|
||||
}
|
||||
GST_LOG ("quit sent");
|
||||
}
|
||||
|
||||
/* Not called by the gl thread */
|
||||
|
@ -817,32 +724,24 @@ gst_gl_window_x11_send_message (GstGLWindow * window, GstGLWindowCB callback,
|
|||
window_x11 = GST_GL_WINDOW_X11 (window);
|
||||
|
||||
if (window_x11->running) {
|
||||
XEvent event;
|
||||
GstGLMessage message;
|
||||
|
||||
event.xclient.type = ClientMessage;
|
||||
event.xclient.send_event = TRUE;
|
||||
event.xclient.display = window_x11->disp_send;
|
||||
event.xclient.window = window_x11->internal_win_id;
|
||||
event.xclient.message_type =
|
||||
XInternAtom (window_x11->disp_send, "WM_GL_WINDOW", True);
|
||||
event.xclient.format = 32;
|
||||
#if SIZEOF_VOID_P == 8
|
||||
event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff;
|
||||
event.xclient.data.l[1] = (((long) callback)) & 0xffffffff;
|
||||
event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff;
|
||||
event.xclient.data.l[3] = (((long) data)) & 0xffffffff;
|
||||
#else
|
||||
event.xclient.data.l[0] = (long) callback;
|
||||
event.xclient.data.l[1] = (long) data;
|
||||
#endif
|
||||
message.window = window;
|
||||
message.callback = callback;
|
||||
message.data = data;
|
||||
message.fired = FALSE;
|
||||
g_mutex_init (&message.lock);
|
||||
g_cond_init (&message.cond);
|
||||
|
||||
XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE,
|
||||
NoEventMask, &event);
|
||||
XSync (window_x11->disp_send, FALSE);
|
||||
g_main_context_invoke (window_x11->main_context, (GSourceFunc) _run_message,
|
||||
&message);
|
||||
|
||||
g_mutex_lock (&message.lock);
|
||||
|
||||
/* block until opengl calls have been executed in the gl thread */
|
||||
g_cond_wait (&window_x11->cond_send_message,
|
||||
GST_GL_WINDOW_GET_LOCK (window));
|
||||
while (!message.fired)
|
||||
g_cond_wait (&message.cond, &message.lock);
|
||||
g_mutex_unlock (&message.lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,7 @@ typedef struct _GstGLWindowX11Class GstGLWindowX11Class;
|
|||
struct _GstGLWindowX11 {
|
||||
/*< private >*/
|
||||
GstGLWindow parent;
|
||||
|
||||
GCond cond_send_message;
|
||||
|
||||
gboolean running;
|
||||
gboolean visible;
|
||||
gboolean allow_extra_expose_events;
|
||||
|
@ -71,6 +70,10 @@ struct _GstGLWindowX11 {
|
|||
/* X window */
|
||||
Window internal_win_id;
|
||||
|
||||
GSource *x11_source;
|
||||
GMainContext *main_context;
|
||||
GMainLoop *loop;
|
||||
|
||||
/*< private >*/
|
||||
GstGLWindowX11Private *priv;
|
||||
|
||||
|
|
98
gst-libs/gst/gl/x11/x11_event_source.c
Normal file
98
gst-libs/gst/gl/x11/x11_event_source.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "x11_event_source.h"
|
||||
|
||||
extern void gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11);
|
||||
|
||||
typedef struct _X11EventSource
|
||||
{
|
||||
GSource source;
|
||||
GPollFD pfd;
|
||||
uint32_t mask;
|
||||
GstGLWindowX11 *window;
|
||||
} X11EventSource;
|
||||
|
||||
static gboolean
|
||||
x11_event_source_prepare (GSource * base, gint * timeout)
|
||||
{
|
||||
X11EventSource *source = (X11EventSource *) base;
|
||||
gboolean retval;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
retval = XPending (source->window->device); //clutter_events_pending ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x11_event_source_check (GSource * base)
|
||||
{
|
||||
X11EventSource *source = (X11EventSource *) base;
|
||||
gboolean retval;
|
||||
|
||||
retval = source->pfd.revents; // || clutter_events_pending();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x11_event_source_dispatch (GSource * base, GSourceFunc callback, gpointer data)
|
||||
{
|
||||
X11EventSource *source = (X11EventSource *) base;
|
||||
|
||||
gst_gl_window_x11_handle_event (source->window);
|
||||
|
||||
if (callback)
|
||||
callback (data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs x11_event_source_funcs = {
|
||||
x11_event_source_prepare,
|
||||
x11_event_source_check,
|
||||
x11_event_source_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
GSource *
|
||||
x11_event_source_new (GstGLWindowX11 * window_x11)
|
||||
{
|
||||
X11EventSource *source;
|
||||
|
||||
source = (X11EventSource *)
|
||||
g_source_new (&x11_event_source_funcs, sizeof (X11EventSource));
|
||||
source->window = window_x11;
|
||||
source->pfd.fd = ConnectionNumber (window_x11->device);
|
||||
source->pfd.events = G_IO_IN | G_IO_ERR;
|
||||
g_source_add_poll (&source->source, &source->pfd);
|
||||
|
||||
return &source->source;
|
||||
}
|
30
gst-libs/gst/gl/x11/x11_event_source.h
Normal file
30
gst-libs/gst/gl/x11/x11_event_source.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __X11_EVENT_SOURCE_H__
|
||||
#define __X11_EVENT_SOURCE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "gstglwindow_x11.h"
|
||||
|
||||
GSource *
|
||||
x11_event_source_new (GstGLWindowX11 *window_x11);
|
||||
|
||||
#endif /* __WAYLAND_EVENT_SOURCE_H__ */
|
Loading…
Reference in a new issue