[349/906] can switch xoverlays while playing

Fixes bug #584877

Before this commit calling "gst_x_overlay_set_xwindow_id" more
than one time, had no effect.
It mainly affects the glimagesink implementation.
But on win32 (and CE), some stuff has to be done to
release the old parent.

And add a switchxoverlay example where the user
can click on left/right part of the main window to
switch the xoverlay.
This commit is contained in:
Julien Isorce 2009-06-06 14:34:57 +02:00 committed by Matthew Waters
parent 47beeb1083
commit 6292d5af16
4 changed files with 111 additions and 48 deletions

View file

@ -197,26 +197,58 @@ void
gst_gl_window_set_external_window_id (GstGLWindow * window, gulong id) gst_gl_window_set_external_window_id (GstGLWindow * window, gulong id)
{ {
GstGLWindowPrivate *priv = window->priv; GstGLWindowPrivate *priv = window->priv;
WNDPROC window_parent_proc =
(WNDPROC) GetWindowLongPtr ((HWND) id, GWL_WNDPROC);
RECT rect;
SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id); //retrieve parent if previously set
SetProp ((HWND) id, "gl_window_id", priv->internal_win_id); HWND parent_id = GetProp (priv->internal_win_id, "gl_window_parent_id");
SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc);
SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (LONG_PTR) sub_class_proc);
SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE); if (priv->visible) {
SetParent (priv->internal_win_id, (HWND) id); ShowWindow (priv->internal_win_id, SW_HIDE);
priv->visible = FALSE;
}
if (parent_id) {
WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc");
//take changes into account: SWP_FRAMECHANGED g_debug ("release parent %lud\n", (gulong) parent_id);
GetClientRect ((HWND) id, &rect);
SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, g_assert (parent_proc);
rect.right, rect.bottom,
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SetWindowLongPtr (parent_id, GWL_WNDPROC, (LONG) parent_proc);
SWP_FRAMECHANGED | SWP_NOACTIVATE); SetParent (priv->internal_win_id, NULL);
MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right,
rect.bottom, FALSE); RemoveProp (parent_id, "gl_window_parent_proc");
RemoveProp (priv->internal_win_id, "gl_window_parent_id");
}
//not 0
if (id) {
WNDPROC window_parent_proc =
(WNDPROC) GetWindowLongPtr ((HWND) id, GWL_WNDPROC);
RECT rect;
g_debug ("set parent %lud\n", (gulong) id);
SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id);
SetProp ((HWND) id, "gl_window_id", priv->internal_win_id);
SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc);
SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (LONG_PTR) sub_class_proc);
SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
SetParent (priv->internal_win_id, (HWND) id);
//take changes into account: SWP_FRAMECHANGED
GetClientRect ((HWND) id, &rect);
SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top,
rect.right, rect.bottom,
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_FRAMECHANGED | SWP_NOACTIVATE);
MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right,
rect.bottom, FALSE);
} else {
//no parent so the internal window needs borders and system menu
SetWindowLongPtr (priv->internal_win_id, GWL_STYLE,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW);
}
} }
/* Must be called in the gl thread */ /* Must be called in the gl thread */

View file

@ -204,26 +204,58 @@ void
gst_gl_window_set_external_window_id (GstGLWindow * window, gulong id) gst_gl_window_set_external_window_id (GstGLWindow * window, gulong id)
{ {
GstGLWindowPrivate *priv = window->priv; GstGLWindowPrivate *priv = window->priv;
WNDPROC window_parent_proc =
(WNDPROC) (guint64) GetWindowLongPtr ((HWND) id, GWL_WNDPROC);
RECT rect;
SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id); //retrieve parent if previously set
SetProp ((HWND) id, "gl_window_id", priv->internal_win_id); HWND parent_id = GetProp (priv->internal_win_id, "gl_window_parent_id");
SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc);
SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (DWORD) (guint64) sub_class_proc);
SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE); if (priv->visible) {
SetParent (priv->internal_win_id, (HWND) id); ShowWindow (priv->internal_win_id, SW_HIDE);
priv->visible = FALSE;
}
if (parent_id) {
WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc");
//take changes into account: SWP_FRAMECHANGED g_debug ("release parent %lud\n", (gulong) parent_id);
GetClientRect ((HWND) id, &rect);
SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, g_assert (parent_proc);
rect.right, rect.bottom,
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SetWindowLongPtr (parent_id, GWL_WNDPROC, (LONG) parent_proc);
SWP_FRAMECHANGED | SWP_NOACTIVATE); SetParent (priv->internal_win_id, NULL);
MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right,
rect.bottom, FALSE); RemoveProp (parent_id, "gl_window_parent_proc");
RemoveProp (priv->internal_win_id, "gl_window_parent_id");
}
//not 0
if (id) {
WNDPROC window_parent_proc =
(WNDPROC) GetWindowLongPtr ((HWND) id, GWL_WNDPROC);
RECT rect;
g_debug ("set parent %lud\n", (gulong) id);
SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id);
SetProp ((HWND) id, "gl_window_id", priv->internal_win_id);
SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc);
SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (LONG_PTR) sub_class_proc);
SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
SetParent (priv->internal_win_id, (HWND) id);
//take changes into account: SWP_FRAMECHANGED
GetClientRect ((HWND) id, &rect);
SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top,
rect.right, rect.bottom,
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_FRAMECHANGED | SWP_NOACTIVATE);
MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right,
rect.bottom, FALSE);
} else {
//no parent so the internal window needs borders and system menu
SetWindowLongPtr (priv->internal_win_id, GWL_STYLE,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW);
}
} }
/* Must be called in the gl thread */ /* Must be called in the gl thread */

View file

@ -251,6 +251,7 @@ gst_glimage_sink_init (GstGLImageSink * glimage_sink,
{ {
glimage_sink->display_name = NULL; glimage_sink->display_name = NULL;
glimage_sink->window_id = 0; glimage_sink->window_id = 0;
glimage_sink->new_window_id = 0;
glimage_sink->display = NULL; glimage_sink->display = NULL;
glimage_sink->stored_buffer = NULL; glimage_sink->stored_buffer = NULL;
glimage_sink->clientReshapeCallback = NULL; glimage_sink->clientReshapeCallback = NULL;
@ -416,6 +417,9 @@ gst_glimage_sink_stop (GstBaseSink * bsink)
glimage_sink->display = NULL; glimage_sink->display = NULL;
} }
glimage_sink->window_id = 0;
//but do not reset glimage_sink->new_window_id
return TRUE; return TRUE;
} }
@ -485,7 +489,7 @@ gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
glimage_sink->par_n = par_n; glimage_sink->par_n = par_n;
glimage_sink->par_d = par_d; glimage_sink->par_d = par_d;
if (!glimage_sink->window_id) if (!glimage_sink->window_id && !glimage_sink->new_window_id)
gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (glimage_sink)); gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (glimage_sink));
return TRUE; return TRUE;
@ -510,10 +514,6 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
if (glimage_sink->display == NULL) { if (glimage_sink->display == NULL) {
glimage_sink->display = g_object_ref (gl_buffer->display); glimage_sink->display = g_object_ref (gl_buffer->display);
if (glimage_sink->window_id)
gst_gl_display_set_window_id (glimage_sink->display,
glimage_sink->window_id);
gst_gl_display_set_client_reshape_callback (glimage_sink->display, gst_gl_display_set_client_reshape_callback (glimage_sink->display,
glimage_sink->clientReshapeCallback); glimage_sink->clientReshapeCallback);
@ -532,10 +532,6 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
gst_gl_display_create_context (glimage_sink->display, gst_gl_display_create_context (glimage_sink->display,
glimage_sink->width, glimage_sink->height, 0); glimage_sink->width, glimage_sink->height, 0);
if (glimage_sink->window_id)
gst_gl_display_set_window_id (glimage_sink->display,
glimage_sink->window_id);
//init colorspace conversion if needed //init colorspace conversion if needed
gst_gl_display_init_upload (glimage_sink->display, glimage_sink->format, gst_gl_display_init_upload (glimage_sink->display, glimage_sink->format,
glimage_sink->width, glimage_sink->height, glimage_sink->width, glimage_sink->height,
@ -558,6 +554,12 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
//gl_buffer is created in this block, so the gl buffer is already referenced //gl_buffer is created in this block, so the gl buffer is already referenced
} }
if (glimage_sink->window_id != glimage_sink->new_window_id) {
glimage_sink->window_id = glimage_sink->new_window_id;
gst_gl_display_set_window_id (glimage_sink->display,
glimage_sink->window_id);
}
//the buffer is cleared when an other comes in //the buffer is cleared when an other comes in
if (glimage_sink->stored_buffer) { if (glimage_sink->stored_buffer) {
gst_buffer_unref (GST_BUFFER_CAST (glimage_sink->stored_buffer)); gst_buffer_unref (GST_BUFFER_CAST (glimage_sink->stored_buffer));
@ -594,11 +596,7 @@ gst_glimage_sink_set_xwindow_id (GstXOverlay * overlay, gulong window_id)
GST_DEBUG ("set_xwindow_id %ld", window_id); GST_DEBUG ("set_xwindow_id %ld", window_id);
if (glimage_sink->window_id == window_id) glimage_sink->new_window_id = window_id;
return;
if (window_id)
glimage_sink->window_id = window_id;
} }

View file

@ -53,6 +53,7 @@ struct _GstGLImageSink
gchar *display_name; gchar *display_name;
gulong window_id; gulong window_id;
gulong new_window_id;
//caps //caps
GstCaps *caps; GstCaps *caps;