gl: win32: fix crash when finalizing GstGLContext

gst_gl_context_finalize() is calling gst_gl_window_win32_quit()
which was posting a message. But then window_proc takes window's
context and get a NULL.

Now that we've got a GMainLoop we can do like other backends and
simply call g_main_loop_quit().

This also remove duplicated code to release the parent window and
potential crash there because parent_proc could be NULL if we never
created the internal window. That could happen for example if setting
state to READY then setting a window_handle, and go back to NULL state.

https://bugzilla.gnome.org/show_bug.cgi?id=749601
This commit is contained in:
Xavier Claessens 2015-05-20 17:09:21 -04:00 committed by Tim-Philipp Müller
parent db0380a9ee
commit 77e1e70fdc

View file

@ -26,8 +26,6 @@
#include "gstglwindow_win32.h" #include "gstglwindow_win32.h"
#include "win32_message_source.h" #include "win32_message_source.h"
#define WM_GST_GL_WINDOW_QUIT (WM_APP+1)
LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam); LPARAM lParam);
LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
@ -71,6 +69,7 @@ static void gst_gl_window_win32_send_message_async (GstGLWindow * window,
GstGLWindowCB callback, gpointer data, GDestroyNotify destroy); GstGLWindowCB callback, gpointer data, GDestroyNotify destroy);
gboolean gst_gl_window_win32_open (GstGLWindow * window, GError ** error); gboolean gst_gl_window_win32_open (GstGLWindow * window, GError ** error);
void gst_gl_window_win32_close (GstGLWindow * window); void gst_gl_window_win32_close (GstGLWindow * window);
static void release_parent_win_id (GstGLWindowWin32 * window_win32);
static void static void
gst_gl_window_win32_finalize (GObject * object) gst_gl_window_win32_finalize (GObject * object)
@ -161,9 +160,21 @@ gst_gl_window_win32_close (GstGLWindow * window)
{ {
GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window); GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
release_parent_win_id (window_win32);
if (window_win32->internal_win_id) {
RemoveProp (window_win32->internal_win_id, "gl_window");
if (!DestroyWindow (window_win32->internal_win_id))
GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
", 0x%x", (guintptr) window_win32->internal_win_id,
(unsigned int) GetLastError ());
}
g_source_destroy (window_win32->msg_source); g_source_destroy (window_win32->msg_source);
g_source_unref (window_win32->msg_source); g_source_unref (window_win32->msg_source);
window_win32->msg_source = NULL; window_win32->msg_source = NULL;
window_win32->is_closed = TRUE;
} }
static void static void
@ -206,6 +217,28 @@ set_parent_win_id (GstGLWindowWin32 * window_win32)
rect.bottom, FALSE); rect.bottom, FALSE);
} }
static void
release_parent_win_id (GstGLWindowWin32 * window_win32)
{
WNDPROC parent_proc;
if (!window_win32->parent_win_id)
return;
parent_proc = GetProp (window_win32->parent_win_id, "gl_window_parent_proc");
if (!parent_proc)
return;
GST_DEBUG ("release parent %" G_GUINTPTR_FORMAT,
(guintptr) window_win32->parent_win_id);
SetWindowLongPtr (window_win32->parent_win_id, GWLP_WNDPROC,
(LONG_PTR) parent_proc);
SetParent (window_win32->internal_win_id, NULL);
RemoveProp (window_win32->parent_win_id, "gl_window_parent_proc");
}
gboolean gboolean
gst_gl_window_win32_create_window (GstGLWindowWin32 * window_win32, gst_gl_window_win32_create_window (GstGLWindowWin32 * window_win32,
GError ** error) GError ** error)
@ -304,7 +337,6 @@ static void
gst_gl_window_win32_set_window_handle (GstGLWindow * window, guintptr id) gst_gl_window_win32_set_window_handle (GstGLWindow * window, guintptr id)
{ {
GstGLWindowWin32 *window_win32; GstGLWindowWin32 *window_win32;
HWND parent_id;
window_win32 = GST_GL_WINDOW_WIN32 (window); window_win32 = GST_GL_WINDOW_WIN32 (window);
@ -313,27 +345,12 @@ gst_gl_window_win32_set_window_handle (GstGLWindow * window, guintptr id)
return; return;
} }
/* retrieve parent if previously set */
parent_id = window_win32->parent_win_id;
if (window_win32->visible) { if (window_win32->visible) {
ShowWindow (window_win32->internal_win_id, SW_HIDE); ShowWindow (window_win32->internal_win_id, SW_HIDE);
window_win32->visible = FALSE; window_win32->visible = FALSE;
} }
if (parent_id) { release_parent_win_id (window_win32);
WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc");
GST_DEBUG ("release parent %" G_GUINTPTR_FORMAT, (guintptr) parent_id);
g_return_if_fail (parent_proc);
SetWindowLongPtr (parent_id, GWLP_WNDPROC, (LONG_PTR) parent_proc);
SetParent (window_win32->internal_win_id, NULL);
RemoveProp (parent_id, "gl_window_parent_proc");
}
window_win32->parent_win_id = (HWND) id; window_win32->parent_win_id = (HWND) id;
set_parent_win_id (window_win32); set_parent_win_id (window_win32);
} }
@ -398,18 +415,11 @@ gst_gl_window_win32_run (GstGLWindow * window)
static void static void
gst_gl_window_win32_quit (GstGLWindow * window) gst_gl_window_win32_quit (GstGLWindow * window)
{ {
GstGLWindowWin32 *window_win32; GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
window_win32 = GST_GL_WINDOW_WIN32 (window);
window_win32->priv->thread = NULL; window_win32->priv->thread = NULL;
g_main_loop_quit (window_win32->loop);
if (window_win32 && window_win32->internal_win_id) {
LRESULT res =
PostMessage (window_win32->internal_win_id, WM_GST_GL_WINDOW_QUIT,
(WPARAM) 0, (LPARAM) 0);
GST_DEBUG ("end loop requested");
g_return_if_fail (SUCCEEDED (res));
}
} }
typedef struct _GstGLMessage typedef struct _GstGLMessage
@ -515,42 +525,6 @@ window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
window->close (window->close_data); window->close (window->close_data);
break; break;
} }
case WM_GST_GL_WINDOW_QUIT:
{
HWND parent_id = 0;
GST_TRACE ("WM_GST_GL_WINDOW_QUIT");
parent_id = window_win32->parent_win_id;
if (parent_id) {
WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc");
g_assert (parent_proc);
SetWindowLongPtr (parent_id, GWLP_WNDPROC, (LONG_PTR) parent_proc);
SetParent (hWnd, NULL);
RemoveProp (parent_id, "gl_window_parent_proc");
}
window_win32->is_closed = TRUE;
RemoveProp (hWnd, "gl_window");
if (window_win32->internal_win_id) {
if (!DestroyWindow (window_win32->internal_win_id))
GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
", 0x%x", (guintptr) hWnd, (unsigned int) GetLastError ());
}
PostQuitMessage (0);
break;
}
case WM_QUIT:
{
if (window_win32->loop)
g_main_loop_quit (window_win32->loop);
break;
}
case WM_CAPTURECHANGED: case WM_CAPTURECHANGED:
{ {
GST_DEBUG ("WM_CAPTURECHANGED"); GST_DEBUG ("WM_CAPTURECHANGED");